diff options
963 files changed, 4978 insertions, 4232 deletions
diff --git a/FS/FS/API.pm b/FS/FS/API.pm new file mode 100644 index 000000000..36587da59 --- /dev/null +++ b/FS/FS/API.pm @@ -0,0 +1,374 @@ +package FS::API; + +use FS::Conf; +use FS::Record qw( qsearch qsearchs ); +use FS::cust_main; +use FS::cust_location; +use FS::cust_pay; +use FS::cust_credit; +use FS::cust_refund; + +=head1 NAME + +FS::API - Freeside backend API + +=head1 SYNOPSIS + + use FS::API; + +=head1 DESCRIPTION + +This module implements a backend API for advanced back-office integration. + +In contrast to the self-service API, which authenticates an end-user and offers +functionality to that end user, the backend API performs a simple shared-secret +authentication and offers full, administrator functionality, enabling +integration with other back-office systems. + +If accessing this API remotely with XML-RPC or JSON-RPC, be careful to block +the port by default, only allow access from back-office servers with the same +security precations as the Freeside server, and encrypt the communication +channel (for exampple, with an SSH tunnel or VPN) rather than accessing it +in plaintext. + +=head1 METHODS + +=over 4 + +=item insert_payment + +Example: + + my $result = FS::API->insert_payment( + 'secret' => 'sharingiscaring', + 'custnum' => 181318, + 'payby' => 'CASH', + 'paid' => '54.32', + + #optional + '_date' => 1397977200, #UNIX timestamp + ); + + if ( $result->{'error'} ) { + die $result->{'error'}; + } else { + #payment was inserted + print "paynum ". $result->{'paynum'}; + } + +=cut + +#enter cash payment +sub insert_payment { + my($class, %opt) = @_; + my $conf = new FS::Conf; + return { 'error' => 'Incorrect shared secret' } + unless $opt{secret} eq $conf->config('api_shared_secret'); + + #less "raw" than this? we are the backoffice API, and aren't worried + # about version migration ala cust_main/cust_location here + my $cust_pay = new FS::cust_pay { %opt }; + my $error = $cust_pay->insert( 'manual'=>1 ); + return { 'error' => $error, + 'paynum' => $cust_pay->paynum, + }; +} + +# pass the phone number ( from svc_phone ) +sub insert_payment_phonenum { + my($class, %opt) = @_; + my $conf = new FS::Conf; + return { 'error' => 'Incorrect shared secret' } + unless $opt{secret} eq $conf->config('api_shared_secret'); + + $class->_by_phonenum('insert_payment', %opt); + +} + +sub _by_phonenum { + my($class, $method, %opt) = @_; + my $conf = new FS::Conf; + return { 'error' => 'Incorrect shared secret' } + unless $opt{secret} eq $conf->config('api_shared_secret'); + + my $phonenum = delete $opt{'phonenum'}; + + my $svc_phone = qsearchs('svc_phone', { 'phonenum' => $phonenum } ) + or return { 'error' => 'Unknown phonenum' }; + + my $cust_pkg = $svc_phone->cust_svc->cust_pkg + or return { 'error' => 'Unlinked phonenum' }; + + $opt{'custnum'} = $cust_pkg->custnum; + + $class->$method(%opt); + +} + +=item insert_credit + +Example: + + my $result = FS::API->insert_credit( + 'secret' => 'sharingiscaring', + 'custnum' => 181318, + 'amount' => '54.32', + + #optional + '_date' => 1397977200, #UNIX timestamp + ); + + if ( $result->{'error'} ) { + die $result->{'error'}; + } else { + #credit was inserted + print "crednum ". $result->{'crednum'}; + } + +=cut + +#Enter credit +sub insert_credit { + my($class, %opt) = @_; + my $conf = new FS::Conf; + return { 'error' => 'Incorrect shared secret' } + unless $opt{secret} eq $conf->config('api_shared_secret'); + + $opt{'reasonnum'} ||= $conf->config('api_credit_reason'); + + #less "raw" than this? we are the backoffice API, and aren't worried + # about version migration ala cust_main/cust_location here + my $cust_credit = new FS::cust_credit { %opt }; + my $error = $cust_credit->insert; + return { 'error' => $error, + 'crednum' => $cust_credit->crednum, + }; +} + +# pass the phone number ( from svc_phone ) +sub insert_credit_phonenum { + my($class, %opt) = @_; + my $conf = new FS::Conf; + return { 'error' => 'Incorrect shared secret' } + unless $opt{secret} eq $conf->config('api_shared_secret'); + + $class->_by_phonenum('insert_credit', %opt); + +} + +=item insert_refund + +Example: + + my $result = FS::API->insert_refund( + 'secret' => 'sharingiscaring', + 'custnum' => 181318, + 'payby' => 'CASH', + 'refund' => '54.32', + + #optional + '_date' => 1397977200, #UNIX timestamp + ); + + if ( $result->{'error'} ) { + die $result->{'error'}; + } else { + #refund was inserted + print "refundnum ". $result->{'crednum'}; + } + +=cut + +#Enter cash refund. +sub insert_refund { + my($class, %opt) = @_; + my $conf = new FS::Conf; + return { 'error' => 'Incorrect shared secret' } + unless $opt{secret} eq $conf->config('api_shared_secret'); + + # when github pull request #24 is merged, + # will have to change over to default reasonnum like credit + # but until then, this will do + $opt{'reason'} ||= 'API refund'; + + #less "raw" than this? we are the backoffice API, and aren't worried + # about version migration ala cust_main/cust_location here + my $cust_refund = new FS::cust_refund { %opt }; + my $error = $cust_refund->insert; + return { 'error' => $error, + 'refundnum' => $cust_refund->refundnum, + }; +} + +# pass the phone number ( from svc_phone ) +sub insert_refund_phonenum { + my($class, %opt) = @_; + my $conf = new FS::Conf; + return { 'error' => 'Incorrect shared secret' } + unless $opt{secret} eq $conf->config('api_shared_secret'); + + $class->_by_phonenum('insert_refund', %opt); + +} + +#--- + +# "2 way syncing" ? start with non-sync pulling info here, then if necessary +# figure out how to trigger something when those things change + +# long-term: package changes? + +=item new_customer + +=cut + +#certainly false laziness w/ClientAPI::Signup new_customer/new_customer_minimal +# but approaching this from a clean start / back-office perspective +# i.e. no package/service, no immediate credit card run, etc. + +sub new_customer { + my( $class, %opt ) = @_; + my $conf = new FS::Conf; + return { 'error' => 'Incorrect shared secret' } + unless $opt{secret} eq $conf->config('api_shared_secret'); + + #default agentnum like signup_server-default_agentnum? + + #same for refnum like signup_server-default_refnum + + my $cust_main = new FS::cust_main ( { + 'agentnum' => $agentnum, + 'refnum' => $opt{refnum} + || $conf->config('signup_server-default_refnum'), + 'payby' => 'BILL', + + map { $_ => $opt{$_} } qw( + agentnum refnum agent_custid referral_custnum + last first company + daytime night fax mobile + payby payinfo paydate paycvv payname + ), + + } ); + + my @invoicing_list = $opt{'invoicing_list'} + ? split( /\s*\,\s*/, $opt{'invoicing_list'} ) + : (); + push @invoicing_list, 'POST' if $opt{'postal_invoicing'}; + + my ($bill_hash, $ship_hash); + foreach my $f (FS::cust_main->location_fields) { + # avoid having to change this in front-end code + $bill_hash->{$f} = $opt{"bill_$f"} || $opt{$f}; + $ship_hash->{$f} = $opt{"ship_$f"}; + } + + my $bill_location = FS::cust_location->new($bill_hash); + my $ship_location; + # we don't have an equivalent of the "same" checkbox in selfservice^Wthis API + # so is there a ship address, and if so, is it different from the billing + # address? + if ( length($ship_hash->{address1}) > 0 and + grep { $bill_hash->{$_} ne $ship_hash->{$_} } keys(%$ship_hash) + ) { + + $ship_location = FS::cust_location->new( $ship_hash ); + + } else { + $ship_location = $bill_location; + } + + $cust_main->set('bill_location' => $bill_location); + $cust_main->set('ship_location' => $ship_location); + + $error = $cust_main->insert( {}, \@invoicing_list ); + return { 'error' => $error } if $error; + + return { 'error' => '', + 'custnum' => $cust_main->custnum, + }; + +} + +=item customer_info + +=cut + +#some false laziness w/ClientAPI::Myaccount customer_info/customer_info_short + +use vars qw( @cust_main_editable_fields @location_editable_fields ); +@cust_main_editable_fields = qw( + first last company daytime night fax mobile +); +# locale +# payby payinfo payname paystart_month paystart_year payissue payip +# ss paytype paystate stateid stateid_state +@location_editable_fields = qw( + address1 address2 city county state zip country +); + +sub customer_info { + my( $class, %opt ) = @_; + my $conf = new FS::Conf; + return { 'error' => 'Incorrect shared secret' } + unless $opt{secret} eq $conf->config('api_shared_secret'); + + my $cust_main = qsearchs('cust_main', { 'custnum' => $opt{custnum} }) + or return { 'error' => 'Unknown custnum' }; + + my %return = ( + 'error' => '', + 'display_custnum' => $cust_main->display_custnum, + 'name' => $cust_main->first. ' '. $cust_main->get('last'), + 'balance' => $cust_main->balance, + 'status' => $cust_main->status, + 'statuscolor' => $cust_main->statuscolor, + ); + + $return{$_} = $cust_main->get($_) + foreach @cust_main_editable_fields; + + for (@location_editable_fields) { + $return{$_} = $cust_main->bill_location->get($_) + if $cust_main->bill_locationnum; + $return{'ship_'.$_} = $cust_main->ship_location->get($_) + if $cust_main->ship_locationnum; + } + + my @invoicing_list = $cust_main->invoicing_list; + $return{'invoicing_list'} = + join(', ', grep { $_ !~ /^(POST|FAX)$/ } @invoicing_list ); + $return{'postal_invoicing'} = + 0 < ( grep { $_ eq 'POST' } @invoicing_list ); + + #generally, the more useful data from the cust_main record the better. + # well, tell me what you want + + return \%return; + +} + +#I also monitor for changes to the additional locations that are applied to +# packages, and would like for those to be exportable as well. basically the +# location data passed with the custnum. +sub location_info { + my( $class, %opt ) = @_; + my $conf = new FS::Conf; + return { 'error' => 'Incorrect shared secret' } + unless $opt{secret} eq $conf->config('api_shared_secret'); + + my @cust_location = qsearch('cust_location', { 'custnum' => $opt{custnum} }); + + my %return = ( + 'error' => '', + 'locations' => [ map $_->hashref, @cust_location ], + ); + + return \%return; +} + +#Advertising sources? + +=back + +1; diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm index 862cceb2a..4f4121900 100644 --- a/FS/FS/ClientAPI/MyAccount.pm +++ b/FS/FS/ClientAPI/MyAccount.pm @@ -555,8 +555,8 @@ sub customer_info_short { 1, ##nobalance ); -warn $return{first} = $cust_main->first; -warn $return{'last'} = $cust_main->get('last'); + $return{first} = $cust_main->first; + $return{'last'} = $cust_main->get('last'); $return{name} = $cust_main->first. ' '. $cust_main->get('last'); $return{payby} = $cust_main->payby; diff --git a/FS/FS/ClientAPI/Signup.pm b/FS/FS/ClientAPI/Signup.pm index 29ec23972..5407a8fa6 100644 --- a/FS/FS/ClientAPI/Signup.pm +++ b/FS/FS/ClientAPI/Signup.pm @@ -532,7 +532,7 @@ sub new_customer { || $conf->config('signup_server-default_refnum'), ( map { $_ => $template_cust->$_ } qw( - last first company daytime night fax + last first company daytime night fax mobile ) ), @@ -563,7 +563,8 @@ sub new_customer { map { $_ => $packet->{$_} } qw( last first ss company - daytime night fax stateid stateid_state + daytime night fax mobile + stateid stateid_state payby payinfo paycvv paydate payname paystate paytype paystart_month paystart_year payissue @@ -930,7 +931,7 @@ sub new_customer_minimal { map { $_ => $packet->{$_} } qw( last first ss company - daytime night fax + daytime night fax mobile ), } ); diff --git a/FS/FS/ClientAPI_XMLRPC.pm b/FS/FS/ClientAPI_XMLRPC.pm index 6ebdcec4d..62f61d6e5 100644 --- a/FS/FS/ClientAPI_XMLRPC.pm +++ b/FS/FS/ClientAPI_XMLRPC.pm @@ -30,7 +30,7 @@ L<FS::SelfService::XMLRPC>, L<FS::SelfService> use strict; use vars qw($DEBUG $AUTOLOAD); -use XMLRPC::Lite; # for XMLRPC::Data +use FS::XMLRPC_Lite; #XMLRPC::Lite, for XMLRPC::Data use FS::ClientAPI; $DEBUG = 0; @@ -188,17 +188,4 @@ sub ss2clientapi { }; } - -#XXX submit patch to SOAP::Lite - -use XMLRPC::Transport::HTTP; - -package XMLRPC::Transport::HTTP::Server; - -@XMLRPC::Transport::HTTP::Server::ISA = qw(SOAP::Transport::HTTP::Server); - -sub initialize; *initialize = \&XMLRPC::Server::initialize; -sub make_fault; *make_fault = \&XMLRPC::Transport::HTTP::CGI::make_fault; -sub make_response; *make_response = \&XMLRPC::Transport::HTTP::CGI::make_response; - 1; diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 48b39c5b2..34254c6d6 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -2920,6 +2920,7 @@ and customer address. Include units.', 'section' => 'self-service', 'description' => 'Suspend reason when customers suspend their own packages. Set to nothing to disallow self-suspension.', 'type' => 'select-sub', + #false laziness w/api_credit_reason 'options_sub' => sub { require FS::Record; require FS::reason; my $type = qsearchs('reason_type', @@ -5606,6 +5607,52 @@ and customer address. Include units.', 'type' => 'text', }, + { + 'key' => 'api_shared_secret', + 'section' => 'API', + 'description' => 'Shared secret for back-office API authentication', + 'type' => 'text', + }, + + { + 'key' => 'xmlrpc_api', + 'section' => 'API', + 'description' => 'Enable the back-office API XML-RPC server (on port 8008).', + 'type' => 'checkbox', + }, + +# { +# 'key' => 'jsonrpc_api', +# 'section' => 'API', +# 'description' => 'Enable the back-office API JSON-RPC server (on port 8081).', +# 'type' => 'checkbox', +# }, + + { + 'key' => 'api_credit_reason', + 'section' => 'API', + 'description' => 'Default reason for back-office API credits', + 'type' => 'select-sub', + #false laziness w/api_credit_reason + 'options_sub' => sub { require FS::Record; + require FS::reason; + my $type = qsearchs('reason_type', + { class => 'R' }) + or return (); + map { $_->reasonnum => $_->reason } + FS::Record::qsearch('reason', + { reason_type => $type->typenum } + ); + }, + 'option_sub' => sub { require FS::Record; + require FS::reason; + my $reason = FS::Record::qsearchs( + 'reason', { 'reasonnum' => shift } + ); + $reason ? $reason->reason : ''; + }, + }, + { key => "apacheroot", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" }, { key => "apachemachine", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" }, { key => "apachemachines", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" }, diff --git a/FS/FS/Daemon/Preforking.pm b/FS/FS/Daemon/Preforking.pm new file mode 100644 index 000000000..98b4fa68c --- /dev/null +++ b/FS/FS/Daemon/Preforking.pm @@ -0,0 +1,358 @@ +package FS::Daemon::Preforking; +use base 'Exporter'; + +=head1 NAME + +FS::Daemon::Preforking - A preforking web server + +=head1 SYNOPSIS + + use FS::Daemon::Preforking qw( freeside_init1 freeside_init2 daemon_run ); + + my $me = 'mydaemon'; #keep unique among fs daemons, for logfiles etc. + + freeside_init1($me); #daemonize, drop root and connect to freeside + + #do setup tasks which should throw an error to the shell starting the daemon + + freeside_init2($me); #move logging to logfile and disassociate from terminal + + #do setup tasks which will warn/error to the log file, such as declining to + # run if our config is not in place + + daemon_run( + 'port' => 5454, #keep unique among fs daemons + 'handle_request' => \&handle_request, + ); + + sub handle_request { + my $request = shift; #HTTP::Request object + + #... do your thing + + return $response; #HTTP::Response object + + } + +=head1 AUTHOR + +Based on L<http://www.perlmonks.org/?node_id=582781> by Justin Hawkins + +and L<http://poe.perl.org/?POE_Cookbook/Web_Server_With_Forking> + +=cut + +use warnings; +use strict; + +use constant DEBUG => 0; # Enable much runtime information. +use constant MAX_PROCESSES => 10; # Total server process count. +#use constant TESTING_CHURN => 0; # Randomly test process respawning. + +use vars qw( @EXPORT_OK $FREESIDE_LOG $SERVER_PORT $user $handle_request ); +@EXPORT_OK = qw( freeside_init1 freeside_init2 daemon_run ); +$FREESIDE_LOG = '%%%FREESIDE_LOG%%%'; + +use POE 1.2; # Base features. +use POE::Filter::HTTPD; # For serving HTTP content. +use POE::Wheel::ReadWrite; # For socket I/O. +use POE::Wheel::SocketFactory; # For serving socket connections. + +use FS::Daemon qw( daemonize1 drop_root logfile daemonize2 ); +use FS::UID qw( adminsuidsetup forksuidsetup dbh ); + +#use FS::TicketSystem; + +sub freeside_init1 { + my $name = shift; + + $user = shift @ARGV or die &usage($name); + + $FS::Daemon::NOSIG = 1; + $FS::Daemon::PID_NEWSTYLE = 1; + daemonize1($name); + + POE::Kernel->has_forked(); #daemonize forks... + + drop_root(); + + adminsuidsetup($user); +} + +sub freeside_init2 { + my $name = shift; + + logfile("$FREESIDE_LOG/$name.log"); + + daemonize2(); + +} + +sub daemon_run { + my %opt = @_; + $SERVER_PORT = $opt{port}; + $handle_request = $opt{handle_request}; + + #parent doesn't need to hold a DB connection open + dbh->disconnect; + undef $FS::UID::dbh; + + server_spawn(MAX_PROCESSES); + POE::Kernel->run(); + #exit; + +} + +### Spawn the main server. This will run as the parent process. + +sub server_spawn { + my ($max_processes) = @_; + + POE::Session->create( + inline_states => { + _start => \&server_start, + _stop => \&server_stop, + do_fork => \&server_do_fork, + got_error => \&server_got_error, + got_sig_int => \&server_got_sig_int, + got_sig_child => \&server_got_sig_child, + got_connection => \&server_got_connection, + _child => sub { undef }, + }, + heap => { max_processes => MAX_PROCESSES }, + ); +} + +### The main server session has started. Set up the server socket and +### bookkeeping information, then fork the initial child processes. + +sub server_start { + my ( $kernel, $heap ) = @_[ KERNEL, HEAP ]; + + $heap->{server} = POE::Wheel::SocketFactory->new + ( BindPort => $SERVER_PORT, + SuccessEvent => "got_connection", + FailureEvent => "got_error", + Reuse => "yes", + ); + + $kernel->sig( INT => "got_sig_int" ); + $kernel->sig( TERM => "got_sig_int" ); #huh + + $heap->{children} = {}; + $heap->{is_a_child} = 0; + + warn "Server $$ has begun listening on port $SERVER_PORT\n"; + + $kernel->yield("do_fork"); +} + +### The server session has shut down. If this process has any +### children, signal them to shutdown too. + +sub server_stop { + my $heap = $_[HEAP]; + DEBUG and warn "Server $$ stopped.\n"; + + if ( my @children = keys %{ $heap->{children} } ) { + DEBUG and warn "Server $$ is signaling children to stop.\n"; + kill INT => @children; + } +} + +### The server session has encountered an error. Shut it down. + +sub server_got_error { + my ( $heap, $syscall, $errno, $error ) = @_[ HEAP, ARG0 .. ARG2 ]; + warn( "Server $$ got $syscall error $errno: $error\n", + "Server $$ is shutting down.\n", + ); + delete $heap->{server}; +} + +### The server has a need to fork off more children. Only honor that +### request form the parent, otherwise we would surely "forkbomb". +### Fork off as many child processes as we need. + +sub server_do_fork { + my ( $kernel, $heap ) = @_[ KERNEL, HEAP ]; + + return if $heap->{is_a_child}; + + #my $current_children = keys %{ $heap->{children} }; + #for ( $current_children + 2 .. $heap->{max_processes} ) { + while (scalar(keys %{$heap->{children}}) < $heap->{max_processes}) { + + DEBUG and warn "Server $$ is attempting to fork.\n"; + + my $pid = fork(); + + unless ( defined($pid) ) { + DEBUG and + warn( "Server $$ fork failed: $!\n", + "Server $$ will retry fork shortly.\n", + ); + $kernel->delay( do_fork => 1 ); + return; + } + + # Parent. Add the child process to its list. + if ($pid) { + $heap->{children}->{$pid} = 1; + $kernel->sig_child($pid, "got_sig_child"); + next; + } + + # Child. Clear the child process list. + $kernel->has_forked(); + DEBUG and warn "Server $$ forked successfully.\n"; + $heap->{is_a_child} = 1; + $heap->{children} = {}; + + #freeside db connection, etc. + forksuidsetup($user); + + #why isn't this needed ala freeside-selfservice-server?? + #FS::TicketSystem->init(); + + return; + } +} + +### The server session received SIGINT. Don't handle the signal, +### which in turn will trigger the process to exit gracefully. + +sub server_got_sig_int { + my ( $kernel, $heap ) = @_[ KERNEL, HEAP ]; + DEBUG and warn "Server $$ received SIGINT/TERM.\n"; + + if ( my @children = keys %{ $heap->{children} } ) { + DEBUG and warn "Server $$ is signaling children to stop.\n"; + kill INT => @children; + } + + delete $heap->{server}; + $kernel->sig_handled(); +} + +### The server session received a SIGCHLD, indicating that some child +### server has gone away. Remove the child's process ID from our +### list, and trigger more fork() calls to spawn new children. + +sub server_got_sig_child { + my ( $kernel, $heap, $child_pid ) = @_[ KERNEL, HEAP, ARG1 ]; + + return unless delete $heap->{children}->{$child_pid}; + + DEBUG and warn "Server $$ reaped child $child_pid.\n"; + $kernel->yield("do_fork") if exists $_[HEAP]->{server}; +} + +### The server session received a connection request. Spawn off a +### client handler session to parse the request and respond to it. + +sub server_got_connection { + my ( $heap, $socket, $peer_addr, $peer_port ) = @_[ HEAP, ARG0, ARG1, ARG2 ]; + + DEBUG and warn "Server $$ received a connection.\n"; + + POE::Session->create( + inline_states => { + _start => \&client_start, + _stop => \&client_stop, + got_request => \&client_got_request, + got_flush => \&client_flushed_request, + got_error => \&client_got_error, + _parent => sub { 0 }, + }, + heap => { + socket => $socket, + peer_addr => $peer_addr, + peer_port => $peer_port, + }, + ); + +# # Gracefully exit if testing process churn. +# delete $heap->{server} +# if TESTING_CHURN and $heap->{is_a_child} and ( rand() < 0.1 ); +} + +### The client handler has started. Wrap its socket in a ReadWrite +### wheel to begin interacting with it. + +sub client_start { + my $heap = $_[HEAP]; + + $heap->{client} = POE::Wheel::ReadWrite->new + ( Handle => $heap->{socket}, + Filter => POE::Filter::HTTPD->new(), + InputEvent => "got_request", + ErrorEvent => "got_error", + FlushedEvent => "got_flush", + ); + + DEBUG and warn "Client handler $$/", $_[SESSION]->ID, " started.\n"; +} + +### The client handler has stopped. Log that fact. + +sub client_stop { + DEBUG and warn "Client handler $$/", $_[SESSION]->ID, " stopped.\n"; +} + +### The client handler has received a request. If it's an +### HTTP::Response object, it means some error has occurred while +### parsing the request. Send that back and return immediately. +### Otherwise parse and process the request, generating and sending an +### HTTP::Response object in response. + +sub client_got_request { + my ( $heap, $request ) = @_[ HEAP, ARG0 ]; + + DEBUG and + warn "Client handler $$/", $_[SESSION]->ID, " is handling a request.\n"; + + if ( $request->isa("HTTP::Response") ) { + $heap->{client}->put($request); + return; + } + + forksuidsetup($user) unless dbh && dbh->ping; + + my $response = &{ $handle_request }( $request ); + + $heap->{client}->put($response); +} + +### The client handler received an error. Stop the ReadWrite wheel, +### which also closes the socket. + +sub client_got_error { + my ( $heap, $operation, $errnum, $errstr ) = @_[ HEAP, ARG0, ARG1, ARG2 ]; + DEBUG and + warn( "Client handler $$/", $_[SESSION]->ID, + " got $operation error $errnum: $errstr\n", + "Client handler $$/", $_[SESSION]->ID, " is shutting down.\n" + ); + delete $heap->{client}; +} + +### The client handler has flushed its response to the socket. We're +### done with the client connection, so stop the ReadWrite wheel. + +sub client_flushed_request { + my $heap = $_[HEAP]; + DEBUG and + warn( "Client handler $$/", $_[SESSION]->ID, + " flushed its response.\n", + "Client handler $$/", $_[SESSION]->ID, " is shutting down.\n" + ); + delete $heap->{client}; +} + +sub usage { + my $name = shift; + die "Usage:\n\n freeside-$name user\n"; +} + +1; diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm index 7bf5446ec..caa2e6046 100644 --- a/FS/FS/Mason.pm +++ b/FS/FS/Mason.pm @@ -78,8 +78,6 @@ if ( -e $addl_handler_use_file ) { use HTML::FormatText; use HTML::Defang; use JSON::XS; -# use XMLRPC::Transport::HTTP; -# use XMLRPC::Lite; # for XMLRPC::Serializer use MIME::Base64; use IO::Handle; use IO::File; @@ -215,7 +213,6 @@ if ( -e $addl_handler_use_file ) { use FS::usage_class; use FS::payment_gateway; use FS::agent_payment_gateway; - use FS::XMLRPC; use FS::payby; use FS::cdr; use FS::cdr_batch; @@ -377,6 +374,7 @@ if ( -e $addl_handler_use_file ) { use FS::part_fee; use FS::cust_bill_pkg_fee; use FS::part_fee_msgcat; + use FS::part_fee_usage; # Sammath Naur if ( $FS::Mason::addl_handler_use ) { diff --git a/FS/FS/Misc.pm b/FS/FS/Misc.pm index 9c18961ea..c598507cc 100644 --- a/FS/FS/Misc.pm +++ b/FS/FS/Misc.pm @@ -267,7 +267,7 @@ sub send_email { } # Logging - if ( $conf->exists('log_sent_mail') and $options{'custnum'} ) { + if ( $conf->exists('log_sent_mail') ) { my $cust_msg = FS::cust_msg->new({ 'env_from' => $options{'from'}, 'env_to' => join(', ', @to), @@ -278,6 +278,7 @@ sub send_email { 'custnum' => $options{'custnum'}, 'msgnum' => $options{'msgnum'}, 'status' => ($error ? 'failed' : 'sent'), + 'msgtype' => $options{'msgtype'}, }); $cust_msg->insert; # ignore errors } @@ -337,7 +338,7 @@ sub generate_email { my $me = '[FS::Misc::generate_email]'; - my @fields = qw(from to bcc subject custnum msgnum); + my @fields = qw(from to bcc subject custnum msgnum msgtype); my %return; @return{@fields} = @args{@fields}; diff --git a/FS/FS/Report/Table.pm b/FS/FS/Report/Table.pm index 7f593846e..17b12ae23 100644 --- a/FS/FS/Report/Table.pm +++ b/FS/FS/Report/Table.pm @@ -141,7 +141,7 @@ sub payments { sub credits { my( $self, $speriod, $eperiod, $agentnum, %opt ) = @_; $self->scalar_sql(" - SELECT SUM(amount) + SELECT SUM(cust_credit.amount) FROM cust_credit LEFT JOIN cust_main USING ( custnum ) WHERE ". $self->in_time_period_and_agent($speriod, $eperiod, $agentnum). @@ -390,9 +390,6 @@ unspecified, defaults to all three. 'use_override': for line items generated by an add-on package, use the class of the add-on rather than the base package. -'freq': limit to packages with this frequency. Currently uses the part_pkg -frequency, so term discounted packages may give odd results. - 'distribute': for non-monthly recurring charges, ignore the invoice date. Instead, consider the line item's starting/ending dates. Determine the fraction of the line item duration that falls within the specified @@ -421,7 +418,8 @@ my $cust_bill_pkg_join = ' LEFT JOIN cust_main USING ( custnum ) LEFT JOIN cust_pkg USING ( pkgnum ) LEFT JOIN part_pkg USING ( pkgpart ) - LEFT JOIN part_pkg AS override ON pkgpart_override = override.pkgpart'; + LEFT JOIN part_pkg AS override ON pkgpart_override = override.pkgpart + LEFT JOIN part_fee USING ( feepart )'; sub cust_bill_pkg_setup { my $self = shift; @@ -434,7 +432,7 @@ sub cust_bill_pkg_setup { $agentnum ||= $opt{'agentnum'}; my @where = ( - 'pkgnum != 0', + '(pkgnum != 0 OR feepart IS NOT NULL)', $self->with_classnum($opt{'classnum'}, $opt{'use_override'}), $self->with_report_option(%opt), $self->in_time_period_and_agent($speriod, $eperiod, $agentnum), @@ -461,7 +459,7 @@ sub cust_bill_pkg_recur { my $cust_bill_pkg = $opt{'project'} ? 'v_cust_bill_pkg' : 'cust_bill_pkg'; my @where = ( - 'pkgnum != 0', + '(pkgnum != 0 OR feepart IS NOT NULL)', $self->with_classnum($opt{'classnum'}, $opt{'use_override'}), $self->with_report_option(%opt), ); @@ -476,13 +474,14 @@ sub cust_bill_pkg_recur { $item_usage = 'usage'; #already calculated } else { - $item_usage = '( SELECT COALESCE(SUM(amount),0) + $item_usage = '( SELECT COALESCE(SUM(cust_bill_pkg_detail.amount),0) FROM cust_bill_pkg_detail WHERE cust_bill_pkg_detail.billpkgnum = cust_bill_pkg.billpkgnum )'; } my $recur_fraction = ''; if ( $opt{'distribute'} ) { + $where[0] = 'pkgnum != 0'; # specifically exclude fees push @where, "cust_main.agentnum = $agentnum" if $agentnum; push @where, "$cust_bill_pkg.sdate < $eperiod", @@ -521,7 +520,8 @@ Arguments as for C<cust_bill_pkg>, plus: sub cust_bill_pkg_detail { my( $self, $speriod, $eperiod, $agentnum, %opt ) = @_; - my @where = ( "cust_bill_pkg.pkgnum != 0" ); + my @where = + ( "(cust_bill_pkg.pkgnum != 0 OR cust_bill_pkg.feepart IS NOT NULL)" ); push @where, 'cust_main.refnum = '. $opt{'refnum'} if $opt{'refnum'}; @@ -536,7 +536,9 @@ sub cust_bill_pkg_detail { ; if ( $opt{'distribute'} ) { - # then limit according to the usage time, not the billing date + # exclude fees + $where[0] = 'cust_bill_pkg.pkgnum != 0'; + # and limit according to the usage time, not the billing date push @where, $self->in_time_period_and_agent($speriod, $eperiod, $agentnum, 'cust_bill_pkg_detail.startdate' ); @@ -547,7 +549,7 @@ sub cust_bill_pkg_detail { ); } - my $total_sql = " SELECT SUM(amount) "; + my $total_sql = " SELECT SUM(cust_bill_pkg_detail.amount) "; $total_sql .= " / CASE COUNT(cust_pkg.*) WHEN 0 THEN 1 ELSE COUNT(cust_pkg.*) END " @@ -561,6 +563,7 @@ sub cust_bill_pkg_detail { LEFT JOIN cust_pkg ON cust_bill_pkg.pkgnum = cust_pkg.pkgnum LEFT JOIN part_pkg USING ( pkgpart ) LEFT JOIN part_pkg AS override ON pkgpart_override = override.pkgpart + LEFT JOIN part_fee USING ( feepart ) WHERE ".join( ' AND ', grep $_, @where ); $self->scalar_sql($total_sql); @@ -683,14 +686,14 @@ sub with_classnum { @$classnum = grep /^\d+$/, @$classnum; my $in = 'IN ('. join(',', @$classnum). ')'; - if ( $use_override ) { - "( + my $expr = " ( COALESCE(part_pkg.classnum, 0) $in AND pkgpart_override IS NULL) - OR ( COALESCE(override.classnum, 0) $in AND pkgpart_override IS NOT NULL ) - )"; - } else { - "COALESCE(part_pkg.classnum, 0) $in"; + OR ( COALESCE(part_fee.classnum, 0) $in AND feepart IS NOT NULL )"; + if ( $use_override ) { + $expr .= " + OR ( COALESCE(override.classnum, 0) $in AND pkgpart_override IS NOT NULL )"; } + "( $expr )"; } sub with_usageclass { @@ -834,7 +837,8 @@ sub init_projection { # sdate/edate overlapping the ROI, for performance "INSERT INTO v_cust_bill_pkg ( SELECT cust_bill_pkg.*, - (SELECT COALESCE(SUM(amount),0) FROM cust_bill_pkg_detail + (SELECT COALESCE(SUM(cust_bill_pkg_detail.amount),0) + FROM cust_bill_pkg_detail WHERE cust_bill_pkg_detail.billpkgnum = cust_bill_pkg.billpkgnum), cust_bill._date, cust_pkg.expire diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index ec4a1b3e2..bf756d129 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -943,6 +943,7 @@ sub tables_hashref { 'eventnum', 'int', '', '', '', '', 'billpkgnum', 'int', 'NULL', '', '', '', 'feepart', 'int', '', '', '', '', + 'nextbill', 'char', 'NULL', 1, '', '', ], 'primary_key' => 'eventfeenum', # I'd rather just use eventnum 'unique' => [ [ 'billpkgnum' ], [ 'eventnum' ] ], # one-to-one link @@ -2234,6 +2235,7 @@ sub tables_hashref { 'gatewaynum', 'int', 'NULL', '', '', '', #'cust_balance', @money_type, '', '', 'paynum', 'int', 'NULL', '', '', '', + 'void_paynum', 'int', 'NULL', '', '', '', 'jobnum', 'bigint', 'NULL', '', '', '', 'invnum', 'int', 'NULL', '', '', '', 'manual', 'char', 'NULL', 1, '', '', @@ -2256,6 +2258,10 @@ sub tables_hashref { { columns => [ 'paynum' ], table => 'cust_pay', }, + { columns => [ 'void_paynum' ], + table => 'cust_pay_void', + references => [ 'paynum' ], + }, { columns => [ 'jobnum' ], table => 'queue', }, @@ -3188,6 +3194,26 @@ sub tables_hashref { ], }, + 'part_fee_usage' => { + 'columns' => [ + 'feepartusagenum','serial', '', '', '', '', + 'feepart', 'int', '', '', '', '', + 'classnum', 'int', '', '', '', '', + 'amount', @money_type, '', '', + 'percent', 'decimal', '', '7,4', '', '', + ], + 'primary_key' => 'feepartusagenum', + 'unique' => [ [ 'feepart', 'classnum' ] ], + 'index' => [], + 'foreign_keys' => [ + { columns => [ 'feepart' ], + table => 'part_fee', + }, + { columns => [ 'classnum' ], + table => 'usage_class', + }, + ], + }, 'part_pkg_link' => { 'columns' => [ @@ -4427,9 +4453,9 @@ sub tables_hashref { 'unique' => [ [ 'blocknum', 'routernum' ] ], 'index' => [], 'foreign_keys' => [ - { columns => [ 'routernum' ], - table => 'router', - }, + #{ columns => [ 'routernum' ], + # table => 'router', + #}, { columns => [ 'agentnum' ], table => 'agent', }, @@ -5991,7 +6017,7 @@ sub tables_hashref { 'cust_msg' => { 'columns' => [ 'custmsgnum', 'serial', '', '', '', '', - 'custnum', 'int', '', '', '', '', + 'custnum', 'int', 'NULL', '', '', '', 'msgnum', 'int', 'NULL', '', '', '', '_date', @date_type, '', '', 'env_from', 'varchar', 'NULL', 255, '', '', @@ -6000,6 +6026,7 @@ sub tables_hashref { 'body', 'blob', 'NULL', '', '', '', 'error', 'varchar', 'NULL', 255, '', '', 'status', 'varchar', '',$char_d, '', '', + 'msgtype', 'varchar', 'NULL', 16, '', '', ], 'primary_key' => 'custmsgnum', 'unique' => [ ], diff --git a/FS/FS/TemplateItem_Mixin.pm b/FS/FS/TemplateItem_Mixin.pm index bf857a98a..fa20c240f 100644 --- a/FS/FS/TemplateItem_Mixin.pm +++ b/FS/FS/TemplateItem_Mixin.pm @@ -61,14 +61,19 @@ sub desc { my( $self, $locale ) = @_; if ( $self->pkgnum > 0 ) { - $self->itemdesc || $self->part_pkg->pkg_locale($locale); + return $self->itemdesc if $self->itemdesc; + my $part_pkg = $self->part_pkg or return 'UNKNOWN'; + return $part_pkg->pkg_locale($locale); + } elsif ( $self->feepart ) { - $self->part_fee->itemdesc_locale($locale); + return $self->part_fee->itemdesc_locale($locale); + } else { # by the process of elimination it must be a tax my $desc = $self->itemdesc || 'Tax'; $desc .= ' '. $self->itemcomment if $self->itemcomment =~ /\S/; - $desc; + return $desc; } + } =item time_period_pretty PART_PKG, AGENTNUM diff --git a/FS/FS/Template_Mixin.pm b/FS/FS/Template_Mixin.pm index c4c2d7fb0..131a23643 100644 --- a/FS/FS/Template_Mixin.pm +++ b/FS/FS/Template_Mixin.pm @@ -2452,6 +2452,8 @@ sub _items_cust_bill_pkg { warn "$me _items_cust_bill_pkg cust_bill_pkg is quotation_pkg\n" if $DEBUG > 1; + # quotation_pkgs are never fees, so don't worry about the case where + # part_pkg is undefined if ( $cust_bill_pkg->setup != 0 ) { my $description = $desc; @@ -2471,7 +2473,7 @@ sub _items_cust_bill_pkg { }; } - } elsif ( $cust_bill_pkg->pkgnum > 0 ) { + } elsif ( $cust_bill_pkg->pkgnum > 0 ) { # and it's not a quotation_pkg warn "$me _items_cust_bill_pkg cust_bill_pkg is non-tax\n" if $DEBUG > 1; @@ -2739,29 +2741,21 @@ sub _items_cust_bill_pkg { } # recurring or usage with recurring charge - } else { #pkgnum tax or one-shot line item (??) + } else { # taxes and fees warn "$me _items_cust_bill_pkg cust_bill_pkg is tax\n" if $DEBUG > 1; - if ( $cust_bill_pkg->setup != 0 ) { - push @b, { - 'description' => $desc, - 'amount' => sprintf("%.2f", $cust_bill_pkg->setup), - }; - } - if ( $cust_bill_pkg->recur != 0 ) { - push @b, { - 'description' => "$desc (". - $self->time2str_local('short', $cust_bill_pkg->sdate). ' - '. - $self->time2str_local('short', $cust_bill_pkg->edate). ')', - 'amount' => sprintf("%.2f", $cust_bill_pkg->recur), - }; - } + # items of this kind should normally not have sdate/edate. + push @b, { + 'description' => $desc, + 'amount' => sprintf('%.2f', $cust_bill_pkg->setup + + $cust_bill_pkg->recur) + }; - } + } # if quotation / package line item / other line item - } + } # foreach $display $discount_show_always = ($cust_bill_pkg->cust_bill_pkg_discount && $conf->exists('discount-show-always')); diff --git a/FS/FS/XMLRPC.pm b/FS/FS/XMLRPC.pm deleted file mode 100644 index 62ae43d18..000000000 --- a/FS/FS/XMLRPC.pm +++ /dev/null @@ -1,164 +0,0 @@ - package FS::XMLRPC; - -use strict; -use vars qw( $DEBUG ); -use Frontier::RPC2; - -# Instead of 'use'ing freeside modules on the fly below, just preload them now. -use FS; -use FS::CGI; -use FS::Conf; -use FS::Record; -use FS::cust_main; - -use Data::Dumper; - -$DEBUG = 0; - -=head1 NAME - -FS::XMLRPC - Object methods for handling XMLRPC requests - -=head1 SYNOPSIS - - use FS::XMLRPC; - - $xmlrpc = new FS::XMLRPC; - - ($error, $response_xml) = $xmlrpc->serve($request_xml); - -=head1 DESCRIPTION - -The FS::XMLRPC object is a mechanisim to access read-only data from freeside's subroutines. It does not, at least not at this point, give you the ability to access methods of freeside objects remotely. It can, however, be used to call subroutines such as FS::cust_main::smart_search and FS::Record::qsearch. - -See the serve method below for calling syntax. - -=head1 METHODS - -=over 4 - -=item new - -Provides a FS::XMLRPC object used to handle incoming XMLRPC requests. - -=cut - -sub new { - - my $class = shift; - my $self = {}; - bless($self, $class); - - $self->{_coder} = new Frontier::RPC2; - - return $self; - -} - -=item serve REQUEST_XML_SCALAR - -The serve method takes a scalar containg an XMLRPC request for one of freeside's subroutines (not object methods). Parameters passed in the 'methodCall' will be passed as a list to the subroutine untouched. The return value of the called subroutine _must_ be a freeside object reference (eg. qsearchs) or a list of freeside object references (eg. qsearch, smart_search), _and_, the object(s) returned must support the hashref method. This will be checked first by calling UNIVERSAL::can('FS::class::subroutine', 'hashref'). - -Return value is an XMLRPC methodResponse containing the results of the call. The result of the subroutine call itself will be coded in the methodResponse as an array of structs, regardless of whether there was many or a single object returned. In other words, after you decode the response, you'll always have an array. - -=cut - -sub serve { - - my ($self, $request_xml) = (shift, shift); - my $response_xml; - - my $coder = $self->{_coder}; - my $call = $coder->decode($request_xml); - - warn "Got methodCall with method_name='" . $call->{method_name} . "'" - if $DEBUG; - - $response_xml = $coder->encode_response(&_serve($call->{method_name}, $call->{value})); - - return ('', $response_xml); - -} - -sub _serve { #Subroutine, not method - - my ($method_name, $params) = (shift, shift); - - - #die 'Called _serve without parameters' unless ref($params) eq 'ARRAY'; - $params = [] unless (ref($params) eq 'ARRAY'); - - if ($method_name =~ /^(\w+)\.(\w+)/) { - - #my ($class, $sub) = split(/\./, $method_name); - my ($class, $sub) = ($1, $2); - my $fssub = "FS::${class}::${sub}"; - warn "fssub: ${fssub}" if $DEBUG; - warn "params: " . Dumper($params) if $DEBUG; - - my @result; - - if ($class eq 'Conf') { #Special case for FS::Conf because we need an obj. - - if ($sub eq 'config') { - my $conf = new FS::Conf; - @result = ($conf->config(@$params)); - } else { - warn "FS::XMLRPC: Can't call undefined subroutine '${fssub}'"; - } - - } else { - - unless (UNIVERSAL::can("FS::${class}", $sub)) { - warn "FS::XMLRPC: Can't call undefined subroutine '${fssub}'"; - # Should we encode an error in the response, - # or just break silently to the remote caller and complain locally? - return []; - } - - eval { - no strict 'refs'; - my $fssub = "FS::${class}::${sub}"; - @result = (&$fssub(@$params)); - }; - - if ($@) { - warn "FS::XMLRPC: Error while calling '${fssub}': $@"; - return []; - } - - } - - if ( scalar(@result) == 1 && ref($result[0]) eq 'HASH' ) { - return $result[0]; - } elsif (grep { UNIVERSAL::can($_, 'hashref') ? 0 : 1 } @result) { - #warn "FS::XMLRPC: One or more objects returned from '${fssub}' doesn't " . - # "support the 'hashref' method."; - - # If they're not FS::Record decendants, just return the results unmap'd? - # This is more flexible, but possibly more error-prone. - return [ @result ]; - } else { - return [ map { $_->hashref } @result ]; - } - } elsif ($method_name eq 'version') { - return [ $FS::VERSION ]; - } # else... - - warn "Unhandled XMLRPC request '${method_name}'"; - return {}; - -} - -=head1 BUGS - -Probably lots. - -=head1 SEE ALSO - -L<Frontier::RPC2>. - -=cut - -1; - diff --git a/FS/FS/XMLRPC_Lite.pm b/FS/FS/XMLRPC_Lite.pm new file mode 100644 index 000000000..9d3059d69 --- /dev/null +++ b/FS/FS/XMLRPC_Lite.pm @@ -0,0 +1,17 @@ +package FS::XMLRPC_Lite; + +use XMLRPC::Lite; + +use XMLRPC::Transport::HTTP; + +#XXX submit patch to SOAP::Lite + +package XMLRPC::Transport::HTTP::Server; + +@XMLRPC::Transport::HTTP::Server::ISA = qw(SOAP::Transport::HTTP::Server); + +sub initialize; *initialize = \&XMLRPC::Server::initialize; +sub make_fault; *make_fault = \&XMLRPC::Transport::HTTP::CGI::make_fault; +sub make_response; *make_response = \&XMLRPC::Transport::HTTP::CGI::make_response; + +1; diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index 83ddb6566..3c0e3e7da 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -1065,6 +1065,8 @@ sub generate_email { my %return = ( 'from' => $args{'from'}, 'subject' => ($args{'subject'} || $self->email_subject), + 'custnum' => $self->custnum, + 'msgtype' => 'invoice', ); $args{'unsquelch_cdr'} = $conf->exists('voip-cdr_email'); diff --git a/FS/FS/cust_bill_pkg.pm b/FS/FS/cust_bill_pkg.pm index a9439217c..066ddf160 100644 --- a/FS/FS/cust_bill_pkg.pm +++ b/FS/FS/cust_bill_pkg.pm @@ -968,6 +968,31 @@ sub tax_locationnum { } } +sub tax_location { + my $self = shift; + FS::cust_location->by_key($self->tax_locationnum); +} + +=item part_X + +Returns the L<FS::part_pkg> or L<FS::part_fee> object that defines this +charge. If called on a tax line, returns nothing. + +=cut + +sub part_X { + my $self = shift; + if ( $self->override_pkgpart ) { + return FS::part_pkg->by_key($self->override_pkgpart); + } elsif ( $self->pkgnum ) { + return $self->cust_pkg->part_pkg; + } elsif ( $self->feepart ) { + return $self->part_fee; + } else { + return; + } +} + =back =head1 CLASS METHODS diff --git a/FS/FS/cust_bill_pkg_fee.pm b/FS/FS/cust_bill_pkg_fee.pm index 8ea73c9dc..b9adfafa0 100644 --- a/FS/FS/cust_bill_pkg_fee.pm +++ b/FS/FS/cust_bill_pkg_fee.pm @@ -26,8 +26,8 @@ FS::cust_bill_pkg_fee - Object methods for cust_bill_pkg_fee records =head1 DESCRIPTION An FS::cust_bill_pkg_fee object records the origin of a fee. -. FS::cust_bill_pkg_fee inherits from -FS::Record. The following fields are currently supported: +FS::cust_bill_pkg_fee inherits from FS::Record. The following fields +are currently supported: =over 4 @@ -70,8 +70,8 @@ sub check { my $error = $self->ut_numbern('billpkgfeenum') || $self->ut_number('billpkgnum') - || $self->ut_foreign_key('origin_invnum', 'cust_bill', 'invnum') - || $self->ut_foreign_keyn('origin_billpkgnum', 'cust_bill_pkg', 'billpkgnum') + || $self->ut_foreign_key('base_invnum', 'cust_bill', 'invnum') + || $self->ut_foreign_keyn('base_billpkgnum', 'cust_bill_pkg', 'billpkgnum') || $self->ut_money('amount') ; return $error if $error; diff --git a/FS/FS/cust_credit.pm b/FS/FS/cust_credit.pm index 567be21d6..58bd475b1 100644 --- a/FS/FS/cust_credit.pm +++ b/FS/FS/cust_credit.pm @@ -815,14 +815,9 @@ sub credit_lineitems { # recalculate taxes with new amounts $taxlisthash{$invnum} ||= {}; - my $part_pkg = $cust_bill_pkg->part_pkg; - $cust_main->_handle_taxes( $part_pkg, - $taxlisthash{$invnum}, - $cust_bill_pkg, - $cust_bill_pkg->cust_pkg, - $cust_bill_pkg->cust_bill->_date, #invoice time - $cust_bill_pkg->cust_pkg->pkgpart, - ); + my $part_pkg = $cust_bill_pkg->part_pkg + if $cust_bill_pkg->pkgpart_override; + $cust_main->_handle_taxes( $taxlisthash{$invnum}, $cust_bill_pkg ); } ### @@ -918,12 +913,12 @@ sub credit_lineitems { # we still have to deal with the possibility that the tax links don't # cover the whole amount of tax because of an incomplete upgrade... - if ($amount > 0) { + if ($amount > 0.005) { $cust_credit_bill{$invnum} += $amount; push @{ $cust_credit_bill_pkg{$invnum} }, new FS::cust_credit_bill_pkg { 'billpkgnum' => $tax_item->billpkgnum, - 'amount' => $amount, + 'amount' => sprintf('%.2f', $amount), 'setuprecur' => 'setup', }; diff --git a/FS/FS/cust_credit_bill_pkg.pm b/FS/FS/cust_credit_bill_pkg.pm index be9cd70bd..1f741b289 100644 --- a/FS/FS/cust_credit_bill_pkg.pm +++ b/FS/FS/cust_credit_bill_pkg.pm @@ -166,11 +166,16 @@ sub insert { 'amount' => sprintf('%.2f', 0-$amount), }; - my $error = $cust_tax_exempt_pkg->insert; - if ( $error ) { - $dbh->rollback if $oldAutoCommit; - return "error inserting cust_tax_exempt_pkg: $error"; + if ( $cust_tax_exempt_pkg->cust_main_county ) { + + my $error = $cust_tax_exempt_pkg->insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "error inserting cust_tax_exempt_pkg: $error"; + } + } + } #foreach $exemption } diff --git a/FS/FS/cust_event_fee.pm b/FS/FS/cust_event_fee.pm index 78794fdfe..181640ddc 100644 --- a/FS/FS/cust_event_fee.pm +++ b/FS/FS/cust_event_fee.pm @@ -45,6 +45,9 @@ time billing runs for the customer. =item feepart - key of the fee definition (L<FS::part_fee>). +=item nextbill - 'Y' if the fee should be charged on the customer's next +bill, rather than causing a bill to be produced immediately. + =back =head1 METHODS @@ -93,6 +96,7 @@ sub check { || $self->ut_foreign_key('eventnum', 'cust_event', 'eventnum') || $self->ut_foreign_keyn('billpkgnum', 'cust_bill_pkg', 'billpkgnum') || $self->ut_foreign_key('feepart', 'part_fee', 'feepart') + || $self->ut_flag('nextbill') ; return $error if $error; @@ -108,7 +112,8 @@ sub check { =item by_cust CUSTNUM[, PARAMS] Finds all cust_event_fee records belonging to the customer CUSTNUM. Currently -fee events can be cust_main or cust_bill events; this will return both. +fee events can be cust_main, cust_pkg, or cust_bill events; this will return +all of them. PARAMS can be additional params to pass to qsearch; this really only works for 'hashref' and 'order_by'. @@ -141,6 +146,15 @@ sub by_cust { extra_sql => "$where eventtable = 'cust_bill' ". "AND cust_bill.custnum = $custnum", %params + }), + qsearch({ + table => 'cust_event_fee', + addl_from => 'JOIN cust_event USING (eventnum) ' . + 'JOIN part_event USING (eventpart) ' . + 'JOIN cust_pkg ON (cust_event.tablenum = cust_pkg.pkgnum)', + extra_sql => "$where eventtable = 'cust_pkg' ". + "AND cust_pkg.custnum = $custnum", + %params }) } diff --git a/FS/FS/cust_main/Billing.pm b/FS/FS/cust_main/Billing.pm index 6bd82d133..8d389928b 100644 --- a/FS/FS/cust_main/Billing.pm +++ b/FS/FS/cust_main/Billing.pm @@ -533,8 +533,6 @@ sub bill { my @cust_bill_pkg = _omit_zero_value_bundles(@{ $cust_bill_pkg{$pass} }); - next unless @cust_bill_pkg; #don't create an invoice w/o line items - warn "$me billing pass $pass\n" #.Dumper(\@cust_bill_pkg)."\n" if $DEBUG > 2; @@ -547,13 +545,26 @@ sub bill { hashref => { 'billpkgnum' => '' } ); warn "$me found pending fee events:\n".Dumper(\@pending_event_fees)."\n" - if @pending_event_fees; + if @pending_event_fees and $DEBUG > 1; + + # determine whether to generate an invoice + my $generate_bill = scalar(@cust_bill_pkg) > 0; + + foreach my $event_fee (@pending_event_fees) { + $generate_bill = 1 unless $event_fee->nextbill; + } + + # don't create an invoice with no line items, or where the only line + # items are fees that are supposed to be held until the next invoice + next if !$generate_bill; + # calculate fees... my @fee_items; foreach my $event_fee (@pending_event_fees) { my $object = $event_fee->cust_event->cust_X; + my $part_fee = $event_fee->part_fee; my $cust_bill; - if ( $object->isa('FS::cust_main') ) { + if ( $object->isa('FS::cust_main') or $object->isa('FS::cust_pkg') ) { # Not the real cust_bill object that will be inserted--in particular # there are no taxes yet. If you want to charge a fee on the total # invoice amount including taxes, you have to put the fee on the next @@ -564,12 +575,20 @@ sub bill { 'charged' => ${ $total_setup{$pass} } + ${ $total_recur{$pass} }, }); + + # If this is a package event, only apply the fee to line items + # from that package. + if ($object->isa('FS::cust_pkg')) { + $cust_bill->set('cust_bill_pkg', + [ grep { $_->pkgnum == $object->pkgnum } @cust_bill_pkg ] + ); + } + } elsif ( $object->isa('FS::cust_bill') ) { # simple case: applying the fee to a previous invoice (late fee, # etc.) $cust_bill = $object; } - my $part_fee = $event_fee->part_fee; # if the fee def belongs to a different agent, don't charge the fee. # event conditions should prevent this, but just in case they don't, # skip the fee. @@ -581,11 +600,14 @@ sub bill { # also skip if it's disabled next if $part_fee->disabled eq 'Y'; # calculate the fee - my $fee_item = $event_fee->part_fee->lineitem($cust_bill); + my $fee_item = $part_fee->lineitem($cust_bill) or next; # link this so that we can clear the marker on inserting the line item $fee_item->set('cust_event_fee', $event_fee); push @fee_items, $fee_item; + } + + # add fees to the invoice foreach my $fee_item (@fee_items) { push @cust_bill_pkg, $fee_item; @@ -596,12 +618,9 @@ sub bill { my $fee_location = $self->ship_location; # I think? my $error = $self->_handle_taxes( - $part_fee, $taxlisthash{$pass}, $fee_item, - $fee_location, - $options{invoice_time}, - {} # no options + location => $fee_location ); return $error if $error; @@ -1319,14 +1338,7 @@ sub _make_lines { # handle taxes ### - my $error = $self->_handle_taxes( - $part_pkg, - $taxlisthash, - $cust_bill_pkg, - $cust_location, - $options{invoice_time}, - \%options # I have serious objections to this - ); + my $error = $self->_handle_taxes( $taxlisthash, $cust_bill_pkg ); return $error if $error; $cust_bill_pkg->set_display( @@ -1423,15 +1435,13 @@ sub _transfer_balance { return @transfers; } -=item _handle_taxes PART_ITEM TAXLISTHASH CUST_BILL_PKG CUST_LOCATION TIME [ OPTIONS ] +=item handle_taxes TAXLISTHASH CUST_BILL_PKG [ OPTIONS ] This is _handle_taxes. It's called once for each cust_bill_pkg generated -from _make_lines, along with the part_pkg (or part_fee), cust_location, -invoice time, a flag indicating whether the package is being canceled, and a -partridge in a pear tree. +from _make_lines. -The most important argument is 'taxlisthash'. This is shared across the -entire invoice. It looks like this: +TAXLISTHASH is a hashref shared across the entire invoice. It looks like +this: { 'cust_main_county 1001' => [ [FS::cust_main_county], ... ], 'cust_main_county 1002' => [ [FS::cust_main_county], ... ], @@ -1444,16 +1454,27 @@ That "..." is a list of FS::cust_bill_pkg objects that will be fed to the 'taxline' method to calculate the amount of the tax. This doesn't happen until calculate_taxes, though. +OPTIONS may include: +- part_item: a part_pkg or part_fee object to be used as the package/fee + definition. +- location: a cust_location to be used as the billing location. + +If not supplied, part_item will be inferred from the pkgnum or feepart of the +cust_bill_pkg, and location from the pkgnum (or, for fees, the invnum and +the customer's default service location). + =cut sub _handle_taxes { my $self = shift; - my $part_item = shift; my $taxlisthash = shift; my $cust_bill_pkg = shift; - my $location = shift; - my $invoice_time = shift; - my $options = shift; + my %options = @_; + + # at this point I realize that we have enough information to infer all this + # stuff, instead of passing around giant honking argument lists + my $location = $options{location} || $cust_bill_pkg->tax_location; + my $part_item = $options{part_item} || $cust_bill_pkg->part_X; local($DEBUG) = $FS::cust_main::DEBUG if $FS::cust_main::DEBUG > $DEBUG; @@ -1473,9 +1494,8 @@ sub _handle_taxes { my @classes; #push @classes, $cust_bill_pkg->usage_classes if $cust_bill_pkg->type eq 'U'; push @classes, $cust_bill_pkg->usage_classes if $cust_bill_pkg->usage; - # debatable - push @classes, 'setup' if ($cust_bill_pkg->setup && !$options->{cancel}); - push @classes, 'recur' if ($cust_bill_pkg->recur && !$options->{cancel}); + push @classes, 'setup' if $cust_bill_pkg->setup; + push @classes, 'recur' if $cust_bill_pkg->recur; my $exempt = $conf->exists('cust_class-tax_exempt') ? ( $self->cust_class ? $self->cust_class->tax : '' ) @@ -1543,10 +1563,7 @@ sub _handle_taxes { warn "adding $totname to taxed taxes\n" if $DEBUG > 2; # calculate the tax amount that the tax_on_tax will apply to my $hashref_or_error = - $tax_object->taxline( $localtaxlisthash{$tax}, - 'custnum' => $self->custnum, - 'invoice_time' => $invoice_time, - ); + $tax_object->taxline( $localtaxlisthash{$tax} ); return $hashref_or_error unless ref($hashref_or_error); diff --git a/FS/FS/cust_msg.pm b/FS/FS/cust_msg.pm index c9cf68663..8d57a54ac 100644 --- a/FS/FS/cust_msg.pm +++ b/FS/FS/cust_msg.pm @@ -22,9 +22,9 @@ FS::cust_msg - Object methods for cust_msg records =head1 DESCRIPTION -An FS::cust_msg object represents a template-generated message sent to -a customer (see L<FS::msg_template>). FS::cust_msg inherits from -FS::Record. The following fields are currently supported: +An FS::cust_msg object represents an email message generated by Freeside +and sent to a customer (see L<FS::msg_template>). FS::cust_msg inherits +from FS::Record. The following fields are currently supported: =over 4 @@ -34,6 +34,8 @@ FS::Record. The following fields are currently supported: =item msgnum - template number +=item msgtype - the message type + =item _date - the time the message was sent =item env_from - envelope From address @@ -125,8 +127,8 @@ sub check { my $error = $self->ut_numbern('custmsgnum') - || $self->ut_number('custnum') - || $self->ut_foreign_key('custnum', 'cust_main', 'custnum') + || $self->ut_numbern('custnum') + || $self->ut_foreign_keyn('custnum', 'cust_main', 'custnum') || $self->ut_numbern('msgnum') || $self->ut_foreign_keyn('msgnum', 'msg_template', 'msgnum') || $self->ut_numbern('_date') @@ -136,6 +138,11 @@ sub check { || $self->ut_anything('body') || $self->ut_enum('status', \@statuses) || $self->ut_textn('error') + || $self->ut_enum('msgtype', [ '', + 'invoice', + 'receipt', + 'admin', + ]) ; return $error if $error; diff --git a/FS/FS/cust_pay.pm b/FS/FS/cust_pay.pm index 63d7c4835..10b51ad7a 100644 --- a/FS/FS/cust_pay.pm +++ b/FS/FS/cust_pay.pm @@ -414,12 +414,17 @@ sub void { } ); $cust_pay_void->reason(shift) if scalar(@_); my $error = $cust_pay_void->insert; - if ( $error ) { - $dbh->rollback if $oldAutoCommit; - return $error; + + my $cust_pay_pending = + qsearchs('cust_pay_pending', { paynum => $self->paynum }); + if ( $cust_pay_pending ) { + $cust_pay_pending->set('void_paynum', $self->paynum); + $cust_pay_pending->set('paynum', ''); + $error ||= $cust_pay_pending->replace; } - $error = $self->delete; + $error ||= $self->delete; + if ( $error ) { $dbh->rollback if $oldAutoCommit; return $error; @@ -611,11 +616,12 @@ sub send_receipt { 'custnum' => $cust_main->custnum, }; $error = $queue->insert( - FS::msg_template->by_key($msgnum)->prepare( + FS::msg_template->by_key($msgnum)->prepare( 'cust_main' => $cust_main, 'object' => $self, 'from_config' => 'payment_receipt_from', - ) + ), + 'msgtype' => 'receipt', # override msg_template's default ); } elsif ( $conf->exists('payment_receipt_email') ) { @@ -658,6 +664,7 @@ sub send_receipt { 'job' => 'FS::Misc::process_send_generated_email', 'paynum' => $self->paynum, 'custnum' => $cust_main->custnum, + 'msgtype' => 'receipt', }; $error = $queue->insert( 'from' => $conf->config('invoice_from', $cust_main->agentnum), diff --git a/FS/FS/cust_pay_pending.pm b/FS/FS/cust_pay_pending.pm index f5de73dbe..63274b184 100644 --- a/FS/FS/cust_pay_pending.pm +++ b/FS/FS/cust_pay_pending.pm @@ -135,6 +135,10 @@ L<FS::payment_gateway> id. Payment number (L<FS::cust_pay>) of the completed payment. +=item void_paynum + +Payment number of the payment if it's been voided. + =item invnum Invoice number (L<FS::cust_bill>) to try to apply this payment to. @@ -224,6 +228,7 @@ sub check { || $self->ut_foreign_keyn('paynum', 'cust_pay', 'paynum' ) || $self->ut_foreign_keyn('pkgnum', 'cust_pkg', 'pkgnum') || $self->ut_foreign_keyn('invnum', 'cust_bill', 'invnum') + || $self->ut_foreign_keyn('void_paynum', 'cust_pay_void', 'paynum' ) || $self->ut_flag('manual') || $self->ut_numbern('discount_term') || $self->payinfo_check() #payby/payinfo/paymask/paydate diff --git a/FS/FS/cust_pay_void.pm b/FS/FS/cust_pay_void.pm index 55b6c6743..b2f777b32 100644 --- a/FS/FS/cust_pay_void.pm +++ b/FS/FS/cust_pay_void.pm @@ -133,12 +133,16 @@ sub unvoid { map { $_ => $self->get($_) } fields('cust_pay') } ); my $error = $cust_pay->insert; - if ( $error ) { - $dbh->rollback if $oldAutoCommit; - return $error; + + my $cust_pay_pending = + qsearchs('cust_pay_pending', { void_paynum => $self->paynum }); + if ( $cust_pay_pending ) { + $cust_pay_pending->set('paynum', $cust_pay->paynum); + $cust_pay_pending->set('void_paynum', ''); + $error ||= $cust_pay_pending->replace; } - $error = $self->delete; + $error ||= $self->delete; if ( $error ) { $dbh->rollback if $oldAutoCommit; return $error; diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index 668de754d..4ea3966c0 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -923,6 +923,8 @@ sub cancel { 'to' => \@invoicing_list, 'subject' => ( $conf->config('cancelsubject') || 'Cancellation Notice' ), 'body' => [ map "$_\n", $conf->config('cancelmessage') ], + 'custnum' => $self->custnum, + 'msgtype' => '', #admin? ); } #should this do something on errors? @@ -1343,6 +1345,8 @@ sub suspend { 'Package : #'. $self->pkgnum. " (". $self->part_pkg->pkg_comment. ")\n", ( map { "Service : $_\n" } @labels ), ], + 'custnum' => $self->custnum, + 'msgtype' => 'admin' ); if ( $error ) { @@ -1589,6 +1593,8 @@ sub unsuspend { : '' ), ], + 'custnum' => $self->custnum, + 'msgtype' => 'admin', ); if ( $error ) { diff --git a/FS/FS/cust_pkg/Search.pm b/FS/FS/cust_pkg/Search.pm index 43b870340..47efd3140 100644 --- a/FS/FS/cust_pkg/Search.pm +++ b/FS/FS/cust_pkg/Search.pm @@ -397,12 +397,18 @@ sub search { ); if( exists($params->{'active'} ) ) { - # This overrides all the other date-related fields + # This overrides all the other date-related fields, and includes packages + # that were active at some time during the interval. It excludes: + # - packages that were set up after the end of the interval + # - packages that were canceled before the start of the interval + # - packages that were suspended before the start of the interval + # and are still suspended now my($beginning, $ending) = @{$params->{'active'}}; push @where, "cust_pkg.setup IS NOT NULL", "cust_pkg.setup <= $ending", "(cust_pkg.cancel IS NULL OR cust_pkg.cancel >= $beginning )", + "(cust_pkg.susp IS NULL OR cust_pkg.susp >= $beginning )", "NOT (".FS::cust_pkg->onetime_sql . ")"; } else { diff --git a/FS/FS/cust_svc.pm b/FS/FS/cust_svc.pm index 7bf41ee5d..be5a9eb6a 100644 --- a/FS/FS/cust_svc.pm +++ b/FS/FS/cust_svc.pm @@ -5,6 +5,7 @@ use strict; use vars qw( $DEBUG $me $ignore_quantity $conf $ticket_system ); use Carp; #use Scalar::Util qw( blessed ); +use List::Util qw( max ); use FS::Conf; use FS::Record qw( qsearch qsearchs dbh str2time_sql ); use FS::part_pkg; @@ -363,15 +364,26 @@ sub check { return "Unknown svcpart" unless $part_svc; if ( $self->pkgnum && ! $ignore_quantity ) { - my $cust_pkg = qsearchs( 'cust_pkg', { 'pkgnum' => $self->pkgnum } ); - return "Unknown pkgnum" unless $cust_pkg; - ($part_svc) = grep { $_->svcpart == $self->svcpart } $cust_pkg->part_svc; - return "No svcpart ". $self->svcpart. - " services in pkgpart ". $cust_pkg->pkgpart - unless $part_svc || $ignore_quantity; - return "Already ". $part_svc->get('num_cust_svc'). " ". $part_svc->svc. + + #slightly inefficient since ->pkg_svc will also look it up, but fixing + # a much larger perf problem and have bigger fish to fry + my $cust_pkg = $self->cust_pkg; + + my $pkg_svc = $self->pkg_svc + or return "No svcpart ". $self->svcpart. + " services in pkgpart ". $cust_pkg->pkgpart; + + my $num_cust_svc = $cust_pkg->num_cust_svc( $self->svcpart ); + + #false laziness w/cust_pkg->part_svc + my $num_avail = max( 0, ($cust_pkg->quantity || 1) * $pkg_svc->quantity + - $num_cust_svc + ); + + return "Already $num_cust_svc ". $pkg_svc->part_svc->svc. " services for pkgnum ". $self->pkgnum - if !$ignore_quantity && $part_svc->get('num_avail') <= 0 ; + if $num_avail <= 0; + } $self->SUPER::check; diff --git a/FS/FS/option_Common.pm b/FS/FS/option_Common.pm index c1dda22af..74adbede8 100644 --- a/FS/FS/option_Common.pm +++ b/FS/FS/option_Common.pm @@ -134,13 +134,7 @@ sub delete { my $oldAutoCommit = $FS::UID::AutoCommit; local $FS::UID::AutoCommit = 0; my $dbh = dbh; - - my $error = $self->SUPER::delete; - if ( $error ) { - $dbh->rollback if $oldAutoCommit; - return $error; - } - + my $pkey = $self->primary_key; #my $option_table = $self->option_table; @@ -152,6 +146,12 @@ sub delete { } } + my $error = $self->SUPER::delete; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + $dbh->commit or die $dbh->errstr if $oldAutoCommit; ''; diff --git a/FS/FS/part_event/Action/Mixin/fee.pm b/FS/FS/part_event/Action/Mixin/fee.pm index 8eb86fa1d..a49782de0 100644 --- a/FS/FS/part_event/Action/Mixin/fee.pm +++ b/FS/FS/part_event/Action/Mixin/fee.pm @@ -2,6 +2,7 @@ package FS::part_event::Action::Mixin::fee; use strict; use base qw( FS::part_event::Action ); +use FS::Record qw( qsearch ); sub event_stage { 'pre-bill'; } @@ -15,16 +16,34 @@ sub option_fields { value_col => 'feepart', disable_empty => 1, }, - ); + ), + } sub default_weight { 10; } +sub hold_until_bill { 1 } + sub do_action { my( $self, $cust_object, $cust_event ) = @_; - die "no fee definition selected for event '".$self->event."'\n" - unless $self->option('feepart'); + my $feepart = $self->option('feepart') + or die "no fee definition selected for event '".$self->event."'\n"; + my $tablenum = $cust_object->get($cust_object->primary_key); + + # see if there's already a pending fee for this customer/invoice + my @existing = qsearch({ + table => 'cust_event_fee', + addl_from => 'JOIN cust_event USING (eventnum)', + hashref => { feepart => $feepart, + billpkgnum => '' }, + extra_sql => " AND tablenum = $tablenum", + }); + if (scalar @existing > 0) { + warn $self->event." event, object $tablenum: already scheduled\n" + if $FS::part_fee::DEBUG; + return; + } # mark the event so that the fee will be charged # the logic for calculating the fee amount is in FS::part_fee @@ -32,8 +51,9 @@ sub do_action { # FS::cust_bill_pkg my $cust_event_fee = FS::cust_event_fee->new({ 'eventnum' => $cust_event->eventnum, - 'feepart' => $self->option('feepart'), + 'feepart' => $feepart, 'billpkgnum' => '', + 'nextbill' => $self->hold_until_bill ? 'Y' : '', }); my $error = $cust_event_fee->insert; diff --git a/FS/FS/part_event/Action/cust_bill_fee.pm b/FS/FS/part_event/Action/cust_bill_fee.pm index fc185e439..5d962b131 100644 --- a/FS/FS/part_event/Action/cust_bill_fee.pm +++ b/FS/FS/part_event/Action/cust_bill_fee.pm @@ -9,4 +9,20 @@ sub eventtable_hashref { { 'cust_bill' => 1 }; } +sub option_fields { + ( + __PACKAGE__->SUPER::option_fields, + 'nextbill' => { label => 'Hold fee until the customer\'s next bill', + type => 'checkbox', + value => 'Y' + }, + ) +} + +# it makes sense for this to be optional for previous-invoice fees +sub hold_until_bill { + my $self = shift; + $self->option('nextbill'); +} + 1; diff --git a/FS/FS/part_event/Action/cust_fee.pm b/FS/FS/part_event/Action/cust_fee.pm index a6f1078e8..9373091ab 100644 --- a/FS/FS/part_event/Action/cust_fee.pm +++ b/FS/FS/part_event/Action/cust_fee.pm @@ -9,6 +9,8 @@ sub eventtable_hashref { { 'cust_main' => 1 }; } +sub hold_until_bill { 1 } + # Otherwise identical to cust_bill_fee. We only have a separate event # because it behaves differently as an invoice event than as a customer # event, and needs a different description. diff --git a/FS/FS/part_event/Action/fee.pm b/FS/FS/part_event/Action/fee.pm index c2b4673fa..f1d5891ac 100644 --- a/FS/FS/part_event/Action/fee.pm +++ b/FS/FS/part_event/Action/fee.pm @@ -1,5 +1,7 @@ package FS::part_event::Action::fee; +# DEPRECATED; will most likely be removed in 4.x + use strict; use base qw( FS::part_event::Action ); @@ -53,11 +55,9 @@ sub _calc_fee { my $part_pkg = FS::part_pkg->new({ taxclass => $self->option('taxclass') }); - my $error = $cust_main->_handle_taxes( - FS::part_pkg->new({ taxclass => ($self->option('taxclass') || '') }), - $taxlisthash, - $charge, - FS::cust_pkg->new({custnum => $cust_main->custnum}), + my $error = $cust_main->_handle_taxes( $taxlisthash, $charge, + location => $cust_main->ship_location, + part_item => $part_pkg, ); if ( $error ) { warn "error estimating taxes for breakage charge: custnum ".$cust_main->custnum."\n"; diff --git a/FS/FS/part_event/Action/pkg_fee.pm b/FS/FS/part_event/Action/pkg_fee.pm new file mode 100644 index 000000000..7e409a556 --- /dev/null +++ b/FS/FS/part_event/Action/pkg_fee.pm @@ -0,0 +1,16 @@ +package FS::part_event::Action::pkg_fee; + +use strict; +use base qw( FS::part_event::Action::Mixin::fee ); + +sub description { 'Charge a fee when this package is billed'; } + +sub eventtable_hashref { + { 'cust_pkg' => 1 }; +} + +sub hold_until_bill { 1 } + +# Functionally identical to cust_fee. + +1; diff --git a/FS/FS/part_export.pm b/FS/FS/part_export.pm index 8e10ea712..9d261f02d 100644 --- a/FS/FS/part_export.pm +++ b/FS/FS/part_export.pm @@ -161,6 +161,10 @@ sub delete { 'link_table' => 'export_nas', 'target_table' => 'nas', 'params' => [], + ) || $self->process_m2m( + 'link_table' => 'export_svc', + 'target_table' => 'part_svc', + 'params' => [], ) || $self->SUPER::delete; if ( $error ) { $dbh->rollback if $oldAutoCommit; diff --git a/FS/FS/part_export/send_email.pm b/FS/FS/part_export/send_email.pm index 1fcb828b7..41f04093e 100644 --- a/FS/FS/part_export/send_email.pm +++ b/FS/FS/part_export/send_email.pm @@ -6,7 +6,6 @@ use FS::part_export; use FS::Record qw(qsearch qsearchs); use FS::Conf; use FS::msg_template; -use FS::Misc qw(send_email); @ISA = qw(FS::part_export); diff --git a/FS/FS/part_fee.pm b/FS/FS/part_fee.pm index 67da245d8..ccf13513b 100644 --- a/FS/FS/part_fee.pm +++ b/FS/FS/part_fee.pm @@ -5,7 +5,7 @@ use base qw( FS::o2m_Common FS::Record ); use vars qw( $DEBUG ); use FS::Record qw( qsearch qsearchs ); -$DEBUG = 1; +$DEBUG = 0; =head1 NAME @@ -126,6 +126,9 @@ and replace methods. sub check { my $self = shift; + $self->set('amount', 0) unless $self->amount; + $self->set('percent', 0) unless $self->percent; + my $error = $self->ut_numbern('feepart') || $self->ut_textn('comment') @@ -138,28 +141,25 @@ sub check { || $self->ut_floatn('credit_weight') || $self->ut_agentnum_acl('agentnum', [ 'Edit global package definitions' ]) - || $self->ut_moneyn('amount') - || $self->ut_floatn('percent') + || $self->ut_money('amount') + || $self->ut_float('percent') || $self->ut_moneyn('minimum') || $self->ut_moneyn('maximum') || $self->ut_flag('limit_credit') - || $self->ut_enum('basis', [ '', 'charged', 'owed' ]) + || $self->ut_enum('basis', [ 'charged', 'owed', 'usage' ]) || $self->ut_enum('setuprecur', [ 'setup', 'recur' ]) ; return $error if $error; - return "For a percentage fee, the basis must be set" - if $self->get('percent') > 0 and $self->get('basis') eq ''; - - if ( ! $self->get('percent') and ! $self->get('limit_credit') ) { - # then it makes no sense to apply minimum/maximum - $self->set('minimum', ''); - $self->set('maximum', ''); - } if ( $self->get('limit_credit') ) { $self->set('maximum', ''); } + if ( $self->get('basis') eq 'usage' ) { + # to avoid confusion, don't also allow charging a percentage + $self->set('percent', 0); + } + $self->SUPER::check; } @@ -175,7 +175,7 @@ sub explanation { my $money_char = FS::Conf->new->config('money_char') || '$'; my $money = $money_char . '%.2f'; my $percent = '%.1f%%'; - my $string; + my $string = ''; if ( $self->amount > 0 ) { $string = sprintf($money, $self->amount); } @@ -190,7 +190,14 @@ sub explanation { } elsif ( $self->basis('owed') ) { $string .= 'unpaid invoice balance'; } + } elsif ( $self->basis eq 'usage' ) { + if ( $string ) { + $string .= " plus \n"; + } + # append per-class descriptions + $string .= join("\n", map { $_->explanation } $self->part_fee_usage); } + if ( $self->minimum or $self->maximum or $self->limit_credit ) { $string .= "\nbut"; if ( $self->minimum ) { @@ -219,11 +226,17 @@ representing the invoice line item for the fee, with linked L<FS::cust_bill_pkg_fee> record(s) allocating the fee to the invoice or its line items, as appropriate. +If the fee is going to be charged on the upcoming invoice (credit card +processing fees, postal invoice fees), INVOICE should be an uninserted +L<FS::cust_bill> object where the 'cust_bill_pkg' property is an arrayref +of the non-fee line items that will appear on the invoice. + =cut sub lineitem { my $self = shift; my $cust_bill = shift; + my $cust_main = $cust_bill->cust_main; my $amount = 0 + $self->get('amount'); my $total_base; # sum of base line items @@ -235,37 +248,72 @@ sub lineitem { warn "Calculating fee: ".$self->itemdesc." on ". ($cust_bill->invnum ? "invoice #".$cust_bill->invnum : "current invoice"). "\n" if $DEBUG; - if ( $self->percent > 0 and $self->basis ne '' ) { - warn $self->percent . "% of amount ".$self->basis.")\n" - if $DEBUG; - - # $total_base: the total charged/owed on the invoice - # %item_base: billpkgnum => fraction of base amount - if ( $cust_bill->invnum ) { - my $basis = $self->basis; - $total_base = $cust_bill->$basis; # "charged", "owed" + my $basis = $self->basis; + + # $total_base: the total charged/owed on the invoice + # %item_base: billpkgnum => fraction of base amount + if ( $cust_bill->invnum ) { - # calculate the fee on an already-inserted past invoice. This may have - # payments or credits, so if basis = owed, we need to consider those. + # calculate the fee on an already-inserted past invoice. This may have + # payments or credits, so if basis = owed, we need to consider those. + @items = $cust_bill->cust_bill_pkg; + if ( $basis ne 'usage' ) { + + $total_base = $cust_bill->$basis; # "charged", "owed" my $basis_sql = $basis.'_sql'; my $sql = 'SELECT ' . FS::cust_bill_pkg->$basis_sql . ' FROM cust_bill_pkg WHERE billpkgnum = ?'; - @items = $cust_bill->cust_bill_pkg; @item_base = map { FS::Record->scalar_sql($sql, $_->billpkgnum) } @items; - } else { - # the fee applies to _this_ invoice. It has no payments or credits, so - # "charged" and "owed" basis are both just the invoice amount, and - # the line item amounts (setup + recur) + + $amount += $total_base * $self->percent / 100; + } + } else { + # the fee applies to _this_ invoice. It has no payments or credits, so + # "charged" and "owed" basis are both just the invoice amount, and + # the line item amounts (setup + recur) + @items = @{ $cust_bill->get('cust_bill_pkg') }; + if ( $basis ne 'usage' ) { $total_base = $cust_bill->charged; - @items = @{ $cust_bill->get('cust_bill_pkg') }; @item_base = map { $_->setup + $_->recur } @items; - } - $amount += $total_base * $self->percent / 100; + $amount += $total_base * $self->percent / 100; + } } + if ( $basis eq 'usage' ) { + + my %part_fee_usage = map { $_->classnum => $_ } $self->part_fee_usage; + + foreach my $item (@items) { # cust_bill_pkg objects + my $usage_fee = 0; + $item->regularize_details; + my $details; + if ( $item->billpkgnum ) { + $details = [ + qsearch('cust_bill_pkg_detail', { billpkgnum => $item->billpkgnum }) + ]; + } else { + $details = $item->get('details') || []; + } + foreach my $d (@$details) { + # if there's a usage fee defined for this class... + next if $d->amount eq '' # not a real usage detail + or $d->amount == 0 # zero charge, probably shouldn't charge fee + ; + my $p = $part_fee_usage{$d->classnum} or next; + $usage_fee += ($d->amount * $p->percent / 100) + + $p->amount; + # we'd create detail records here if we were doing that + } + # bypass @item_base entirely + push @item_fee, $usage_fee; + $amount += $usage_fee; + } + + } # if $basis eq 'usage' + if ( $self->minimum ne '' and $amount < $self->minimum ) { warn "Applying mininum fee\n" if $DEBUG; $amount = $self->minimum; @@ -273,9 +321,10 @@ sub lineitem { my $maximum = $self->maximum; if ( $self->limit_credit ) { - my $balance = $cust_bill->cust_main; + my $balance = $cust_bill->cust_main->balance; if ( $balance >= 0 ) { - $maximum = 0; + warn "Credit balance is zero, so fee is zero" if $DEBUG; + return; # don't bother doing estimated tax, etc. } elsif ( -1 * $balance < $maximum ) { $maximum = -1 * $balance; } @@ -296,8 +345,36 @@ sub lineitem { setup => 0, recur => 0, }); + + if ( $maximum and $self->taxable ) { + warn "Estimating taxes on fee.\n" if $DEBUG; + # then we need to estimate tax to respect the maximum + # XXX currently doesn't work with external (tax_rate) taxes + # or batch taxes, obviously + my $taxlisthash = {}; + my $error = $cust_main->_handle_taxes( + $taxlisthash, + $cust_bill_pkg, + location => $cust_main->ship_location + ); + my $total_rate = 0; + # $taxlisthash: tax identifier => [ cust_main_county, cust_bill_pkg... ] + my @taxes = map { $_->[0] } values %$taxlisthash; + foreach (@taxes) { + $total_rate += $_->tax; + } + if ($total_rate > 0) { + my $max_cents = $maximum * 100; + my $charge_cents = sprintf('%0.f', $max_cents * 100/(100 + $total_rate)); + # the actual maximum that we can charge... + $maximum = sprintf('%.2f', $charge_cents / 100.00); + $amount = $maximum if $amount > $maximum; + } + } # if $maximum and $self->taxable + + # set the amount that we'll charge $cust_bill_pkg->set( $self->setuprecur, $amount ); - + if ( $self->classnum ) { my $pkg_category = $self->pkg_class->pkg_category; $cust_bill_pkg->set('section' => $pkg_category->categoryname) @@ -327,25 +404,25 @@ sub lineitem { } } } - # and add them to the cust_bill_pkg + } + if ( @item_fee ) { + # add allocation records to the cust_bill_pkg for (my $i = 0; $i < scalar(@items); $i++) { if ( $item_fee[$i] > 0 ) { push @cust_bill_pkg_fee, FS::cust_bill_pkg_fee->new({ cust_bill_pkg => $cust_bill_pkg, - base_invnum => $cust_bill->invnum, + base_invnum => $cust_bill->invnum, # may be null amount => $item_fee[$i], base_cust_bill_pkg => $items[$i], # late resolve }); } } - } else { # if !@item_base + } else { # if !@item_fee # then this isn't a proportional fee, so it just applies to the # entire invoice. - # (if it's the current invoice, $cust_bill->invnum is null and that - # will be fixed later) push @cust_bill_pkg_fee, FS::cust_bill_pkg_fee->new({ cust_bill_pkg => $cust_bill_pkg, - base_invnum => $cust_bill->invnum, + base_invnum => $cust_bill->invnum, # may be null amount => $amount, }); } diff --git a/FS/FS/part_fee_usage.pm b/FS/FS/part_fee_usage.pm new file mode 100644 index 000000000..a1b85ae9d --- /dev/null +++ b/FS/FS/part_fee_usage.pm @@ -0,0 +1,130 @@ +package FS::part_fee_usage; + +use strict; +use base qw( FS::Record ); +use FS::Record qw( qsearch qsearchs ); +use FS::Conf; + +=head1 NAME + +FS::part_fee_usage - Object methods for part_fee_usage records + +=head1 SYNOPSIS + + use FS::part_fee_usage; + + $record = new FS::part_fee_usage \%hash; + $record = new FS::part_fee_usage { 'column' => 'value' }; + + $error = $record->insert; + + $error = $new_record->replace($old_record); + + $error = $record->delete; + + $error = $record->check; + +=head1 DESCRIPTION + +An FS::part_fee_usage object is the part of a processing fee definition +(L<FS::part_fee>) that applies to a specific telephone usage class +(L<FS::usage_class>). FS::part_fee_usage inherits from +FS::Record. The following fields are currently supported: + +=over 4 + +=item feepartusagenum - primary key + +=item feepart - foreign key to L<FS::part_pkg> + +=item classnum - foreign key to L<FS::usage_class> + +=item amount - fixed amount to charge per usage record + +=item percent - percentage of rated price to charge per usage record + +=back + +=head1 METHODS + +=over 4 + +=cut + +sub table { 'part_fee_usage'; } + +sub check { + my $self = shift; + + $self->set('amount', 0) unless ($self->amount || 0) > 0; + $self->set('percent', 0) unless ($self->percent || 0) > 0; + + my $error = + $self->ut_numbern('feepartusagenum') + || $self->ut_foreign_key('feepart', 'part_fee', 'feepart') + || $self->ut_foreign_key('classnum', 'usage_class', 'classnum') + || $self->ut_money('amount') + || $self->ut_float('percent') + ; + return $error if $error; + + $self->SUPER::check; +} + +# silently discard records with percent = 0 and amount = 0 + +sub insert { + my $self = shift; + if ( $self->amount > 0 or $self->percent > 0 ) { + return $self->SUPER::insert; + } + ''; +} + +sub replace { + my ($new, $old) = @_; + $old ||= $new->replace_old; + if ( $new->amount > 0 or $new->percent > 0 ) { + return $new->SUPER::replace($old); + } elsif ( $old->feepartusagenum ) { + return $old->delete; + } + ''; +} + +=item explanation + +Returns a string describing how this fee is calculated. + +=cut + +sub explanation { + my $self = shift; + my $string = ''; + my $money = (FS::Conf->new->config('money_char') || '$') . '%.2f'; + my $percent = '%.1f%%'; + if ( $self->amount > 0 ) { + $string = sprintf($money, $self->amount); + } + if ( $self->percent > 0 ) { + if ( $string ) { + $string .= ' plus '; + } + $string .= sprintf($percent, $self->percent); + $string .= ' of the rated charge'; + } + $string .= ' per '. $self->usage_class->classname . ' call'; + + return $string; +} + +=back + +=head1 SEE ALSO + +L<FS::Record>, schema.html from the base documentation. + +=cut + +1; + diff --git a/FS/FS/pay_batch/nacha.pm b/FS/FS/pay_batch/nacha.pm index 0662c3fd5..d6786e035 100644 --- a/FS/FS/pay_batch/nacha.pm +++ b/FS/FS/pay_batch/nacha.pm @@ -185,7 +185,7 @@ $DEBUG = 0; # 200 mixed debits&credits) sprintf('%06d', $batchcount). #Entry / Addenda Count $entry_hash. - sprintf('%012d', $batchtotal * 100). #Debit total + sprintf('%012.0f', $batchtotal * 100). #Debit total '000000000000'. #Credit total $origin. #Company Identification (Immediate Origin) (' 'x19). #Message Authentication Code (19 char blank) @@ -202,7 +202,7 @@ $DEBUG = 0; sprintf('%06d', $batchcount + 4). #num of physical blocks on the file..? sprintf('%08d', $batchcount). #total # of entry detail and addenda $entry_hash. - sprintf('%012d', $batchtotal * 100). #Debit total + sprintf('%012.0f', $batchtotal * 100). #Debit total '000000000000'. #Credit total ( ' 'x39 ) #Reserved / blank diff --git a/FS/FS/quotation_pkg.pm b/FS/FS/quotation_pkg.pm index c73f857ce..c98e0f98b 100644 --- a/FS/FS/quotation_pkg.pm +++ b/FS/FS/quotation_pkg.pm @@ -2,6 +2,8 @@ package FS::quotation_pkg; use base qw( FS::TemplateItem_Mixin FS::Record ); use strict; +use FS::Record qw( qsearchs ); #qsearch +use FS::part_pkg; use FS::quotation_pkg_discount; #so its loaded when TemplateItem_Mixin needs it =head1 NAME @@ -126,6 +128,13 @@ sub check { $self->SUPER::check; } +#it looks redundant with a v4.x+ auto-generated method, but need to override +# FS::TemplateItem_Mixin's version +sub part_pkg { + my $self = shift; + qsearchs('part_pkg', { 'pkgpart' => $self->pkgpart } ); +} + sub desc { my $self = shift; $self->part_pkg->pkg; diff --git a/FS/FS/tax_rate.pm b/FS/FS/tax_rate.pm index 3d37677fb..451600432 100644 --- a/FS/FS/tax_rate.pm +++ b/FS/FS/tax_rate.pm @@ -371,7 +371,7 @@ sub passtype_name { $tax_passtypes{$self->passtype}; } -=item taxline TAXABLES, [ OPTIONSHASH ] +=item taxline TAXABLES Returns a listref of a name and an amount of tax calculated for the list of packages/amounts referenced by TAXABLES. If an error occurs, a message @@ -381,13 +381,13 @@ is returned as a scalar. sub taxline { my $self = shift; + # this used to accept a hash of options but none of them did anything + # so it's been removed. my $taxables; - my %opt = (); if (ref($_[0]) eq 'ARRAY') { $taxables = shift; - %opt = @_; }else{ $taxables = [ @_ ]; #exemptions would be broken in this case diff --git a/FS/MANIFEST b/FS/MANIFEST index 129ee64df..637401a8f 100644 --- a/FS/MANIFEST +++ b/FS/MANIFEST @@ -24,6 +24,7 @@ bin/freeside-sqlradius-reset bin/freeside-sqlradius-seconds bin/freeside-torrus-srvderive FS.pm +FS/API.pm FS/AccessRight.pm FS/AuthCookieHandler.pm FS/AuthCookieHandler24.pm @@ -46,6 +47,7 @@ FS/Cron/backup.pm FS/Cron/bill.pm FS/Cron/vacuum.pm FS/Daemon.pm +FS/Daemon/Preforking.pm FS/Misc.pm FS/Record.pm FS/Report.pm @@ -766,3 +768,5 @@ FS/cust_bill_pkg_fee.pm t/cust_bill_pkg_fee.t FS/part_fee_msgcat.pm t/part_fee_msgcat.t +FS/part_fee_usage.pm +FS/part_fee_usage.t diff --git a/FS/bin/freeside-selfservice-xmlrpcd b/FS/bin/freeside-selfservice-xmlrpcd index 423d2c30b..6413b2b8a 100755 --- a/FS/bin/freeside-selfservice-xmlrpcd +++ b/FS/bin/freeside-selfservice-xmlrpcd @@ -1,299 +1,40 @@ #!/usr/bin/perl -# -# based on http://www.perlmonks.org/?node_id=582781 by Justin Hawkins -# and http://poe.perl.org/?POE_Cookbook/Web_Server_With_Forking - -### -# modules and constants and variables, oh my -### - -use warnings; -use strict; -use constant DEBUG => 1; # Enable much runtime information. -use constant MAX_PROCESSES => 10; # Total server process count. -use constant SERVER_PORT => 8080; # Server port. -use constant TESTING_CHURN => 0; # Randomly test process respawning. - -use POE 1.2; # Base features. -use POE::Filter::HTTPD; # For serving HTTP content. -use POE::Wheel::ReadWrite; # For socket I/O. -use POE::Wheel::SocketFactory; # For serving socket connections. +use FS::Daemon::Preforking qw( freeside_init1 freeside_init2 daemon_run ); use XMLRPC::Transport::HTTP; #SOAP::Transport::HTTP; use XMLRPC::Lite; # for XMLRPC::Serializer -use FS::Daemon qw( daemonize1 drop_root logfile daemonize2 ); -use FS::UID qw( adminsuidsetup forksuidsetup dbh ); use FS::Conf; use FS::ClientAPI qw( load_clientapi_modules ); use FS::ClientAPI_XMLRPC; #FS::SelfService::XMLRPC; -use FS::TicketSystem; - -#freeside -my $FREESIDE_LOG = "%%%FREESIDE_LOG%%%"; -my $FREESIDE_LOCK = "%%%FREESIDE_LOCK%%%"; -my $lock_file = "$FREESIDE_LOCK/selfservice-xmlrpcd.writelock"; #freeside xmlrpc.cgi my %typelookup = ( #not utf-8 safe# base64 => [10, sub {$_[0] =~ /[^\x09\x0a\x0d\x20-\x7f]/}, 'as_base64'], dateTime => [35, sub {$_[0] =~ /^\d{8}T\d\d:\d\d:\d\d$/}, 'as_dateTime'], - string => [40, sub {1}, 'as_string'], + string => [40, sub {1}, 'as_string'], ); -### -# freeside init -### +use constant ME => 'selfservice-xmlrpcd'; -my $user = shift or die &usage; - -$FS::Daemon::NOSIG = 1; -$FS::Daemon::PID_NEWSTYLE = 1; -daemonize1('selfservice-xmlrpcd'); - -POE::Kernel->has_forked(); #daemonize forks... - -drop_root(); +# -adminsuidsetup($user); +freeside_init1(ME); load_clientapi_modules; -logfile("$FREESIDE_LOG/selfservice-xmlrpcd.log"); - -daemonize2(); +freeside_init2(ME); FS::ClientAPI::Signup::clear_cache(); my $conf = new FS::Conf; - die "not running; selfservice-xmlrpc conf option is off\n" unless $conf->exists('selfservice-xmlrpc'); -#parent doesn't need to hold a DB connection open -dbh->disconnect; -undef $FS::UID::dbh; - -### -# the main loop -### - -server_spawn(MAX_PROCESSES); -POE::Kernel->run(); -exit; - -### -# the subroutines -### - -### Spawn the main server. This will run as the parent process. - -sub server_spawn { - my ($max_processes) = @_; - - POE::Session->create( - inline_states => { - _start => \&server_start, - _stop => \&server_stop, - do_fork => \&server_do_fork, - got_error => \&server_got_error, - got_sig_int => \&server_got_sig_int, - got_sig_child => \&server_got_sig_child, - got_connection => \&server_got_connection, - _child => sub { undef }, - }, - heap => { max_processes => MAX_PROCESSES }, - ); -} - -### The main server session has started. Set up the server socket and -### bookkeeping information, then fork the initial child processes. - -sub server_start { - my ( $kernel, $heap ) = @_[ KERNEL, HEAP ]; - - $heap->{server} = POE::Wheel::SocketFactory->new - ( BindPort => SERVER_PORT, - SuccessEvent => "got_connection", - FailureEvent => "got_error", - Reuse => "yes", - ); - - $kernel->sig( INT => "got_sig_int" ); - $kernel->sig( TERM => "got_sig_int" ); #huh - - $heap->{children} = {}; - $heap->{is_a_child} = 0; - - warn "Server $$ has begun listening on port ", SERVER_PORT, "\n"; - - $kernel->yield("do_fork"); -} - -### The server session has shut down. If this process has any -### children, signal them to shutdown too. - -sub server_stop { - my $heap = $_[HEAP]; - DEBUG and warn "Server $$ stopped.\n"; - - if ( my @children = keys %{ $heap->{children} } ) { - DEBUG and warn "Server $$ is signaling children to stop.\n"; - kill INT => @children; - } -} - -### The server session has encountered an error. Shut it down. - -sub server_got_error { - my ( $heap, $syscall, $errno, $error ) = @_[ HEAP, ARG0 .. ARG2 ]; - warn( "Server $$ got $syscall error $errno: $error\n", - "Server $$ is shutting down.\n", - ); - delete $heap->{server}; -} - -### The server has a need to fork off more children. Only honor that -### request form the parent, otherwise we would surely "forkbomb". -### Fork off as many child processes as we need. - -sub server_do_fork { - my ( $kernel, $heap ) = @_[ KERNEL, HEAP ]; - - return if $heap->{is_a_child}; - - #my $current_children = keys %{ $heap->{children} }; - #for ( $current_children + 2 .. $heap->{max_processes} ) { - while (scalar(keys %{$heap->{children}}) < $heap->{max_processes}) { - - DEBUG and warn "Server $$ is attempting to fork.\n"; - - my $pid = fork(); - - unless ( defined($pid) ) { - DEBUG and - warn( "Server $$ fork failed: $!\n", - "Server $$ will retry fork shortly.\n", - ); - $kernel->delay( do_fork => 1 ); - return; - } - - # Parent. Add the child process to its list. - if ($pid) { - $heap->{children}->{$pid} = 1; - $kernel->sig_child($pid, "got_sig_child"); - next; - } - - # Child. Clear the child process list. - $kernel->has_forked(); - DEBUG and warn "Server $$ forked successfully.\n"; - $heap->{is_a_child} = 1; - $heap->{children} = {}; - - #freeside db connection, etc. - forksuidsetup($user); - - #why isn't this needed ala freeside-selfservice-server?? - #FS::TicketSystem->init(); - - return; - } -} - -### The server session received SIGINT. Don't handle the signal, -### which in turn will trigger the process to exit gracefully. - -sub server_got_sig_int { - my ( $kernel, $heap ) = @_[ KERNEL, HEAP ]; - DEBUG and warn "Server $$ received SIGINT/TERM.\n"; - - if ( my @children = keys %{ $heap->{children} } ) { - DEBUG and warn "Server $$ is signaling children to stop.\n"; - kill INT => @children; - } - - delete $heap->{server}; - $kernel->sig_handled(); -} - -### The server session received a SIGCHLD, indicating that some child -### server has gone away. Remove the child's process ID from our -### list, and trigger more fork() calls to spawn new children. - -sub server_got_sig_child { - my ( $kernel, $heap, $child_pid ) = @_[ KERNEL, HEAP, ARG1 ]; - - return unless delete $heap->{children}->{$child_pid}; - - DEBUG and warn "Server $$ reaped child $child_pid.\n"; - $kernel->yield("do_fork") if exists $_[HEAP]->{server}; -} - -### The server session received a connection request. Spawn off a -### client handler session to parse the request and respond to it. - -sub server_got_connection { - my ( $heap, $socket, $peer_addr, $peer_port ) = @_[ HEAP, ARG0, ARG1, ARG2 ]; - - DEBUG and warn "Server $$ received a connection.\n"; - - POE::Session->create( - inline_states => { - _start => \&client_start, - _stop => \&client_stop, - got_request => \&client_got_request, - got_flush => \&client_flushed_request, - got_error => \&client_got_error, - _parent => sub { 0 }, - }, - heap => { - socket => $socket, - peer_addr => $peer_addr, - peer_port => $peer_port, - }, - ); - - # Gracefully exit if testing process churn. - delete $heap->{server} - if TESTING_CHURN and $heap->{is_a_child} and ( rand() < 0.1 ); -} - -### The client handler has started. Wrap its socket in a ReadWrite -### wheel to begin interacting with it. - -sub client_start { - my $heap = $_[HEAP]; - - $heap->{client} = POE::Wheel::ReadWrite->new - ( Handle => $heap->{socket}, - Filter => POE::Filter::HTTPD->new(), - InputEvent => "got_request", - ErrorEvent => "got_error", - FlushedEvent => "got_flush", - ); - - DEBUG and warn "Client handler $$/", $_[SESSION]->ID, " started.\n"; -} - -### The client handler has stopped. Log that fact. - -sub client_stop { - DEBUG and warn "Client handler $$/", $_[SESSION]->ID, " stopped.\n"; -} - -### The client handler has received a request. If it's an -### HTTP::Response object, it means some error has occurred while -### parsing the request. Send that back and return immediately. -### Otherwise parse and process the request, generating and sending an -### HTTP::Response object in response. - -sub client_got_request { - my ( $heap, $request ) = @_[ HEAP, ARG0 ]; - - forksuidsetup($user) unless dbh && dbh->ping; +daemon_run( 'port' => 8080, 'handle_request' => + sub { + my $request = shift; my $serializer = new XMLRPC::Serializer(typelookup => \%typelookup); @@ -303,53 +44,11 @@ sub client_got_request { -> dispatch_to('FS::ClientAPI_XMLRPC') -> serializer($serializer); - DEBUG and - warn "Client handler $$/", $_[SESSION]->ID, " is handling a request.\n"; - - if ( $request->isa("HTTP::Response") ) { - $heap->{client}->put($request); - return; - } - $soap->request($request); $soap->handle; - my $response = $soap->response; - - $heap->{client}->put($response); -} - -### The client handler received an error. Stop the ReadWrite wheel, -### which also closes the socket. - -sub client_got_error { - my ( $heap, $operation, $errnum, $errstr ) = @_[ HEAP, ARG0, ARG1, ARG2 ]; - DEBUG and - warn( "Client handler $$/", $_[SESSION]->ID, - " got $operation error $errnum: $errstr\n", - "Client handler $$/", $_[SESSION]->ID, " is shutting down.\n" - ); - delete $heap->{client}; -} -### The client handler has flushed its response to the socket. We're -### done with the client connection, so stop the ReadWrite wheel. - -sub client_flushed_request { - my $heap = $_[HEAP]; - DEBUG and - warn( "Client handler $$/", $_[SESSION]->ID, - " flushed its response.\n", - "Client handler $$/", $_[SESSION]->ID, " is shutting down.\n" - ); - delete $heap->{client}; -} - -sub usage { - die "Usage:\n\n freeside-selfservice-xmlrpcd user\n"; -} - -### -# the end -### + return $soap->response; + } +); 1; diff --git a/FS/bin/freeside-xmlrpcd b/FS/bin/freeside-xmlrpcd new file mode 100644 index 000000000..e22d0f063 --- /dev/null +++ b/FS/bin/freeside-xmlrpcd @@ -0,0 +1,58 @@ +#!/usr/bin/perl + +use FS::Daemon::Preforking qw( freeside_init1 freeside_init2 daemon_run ); + +use FS::XMLRPC_Lite; #XMLRPC::Lite for XMLRPC::Serializer + #and XMLRPC::Transport::HTTP + +use FS::Conf; + +##use FS::ClientAPI qw( load_clientapi_modules ); +##use FS::ClientAPI_XMLRPC; #FS::SelfService::XMLRPC; +use FS::API; + +#freeside xmlrpc.cgi +my %typelookup = ( +#not utf-8 safe# base64 => [10, sub {$_[0] =~ /[^\x09\x0a\x0d\x20-\x7f]/}, 'as_base64'], + dateTime => [35, sub {$_[0] =~ /^\d{8}T\d\d:\d\d:\d\d$/}, 'as_dateTime'], + string => [40, sub {1}, 'as_string'], +); + +use constant ME => 'xmlrpcd'; + +# + +freeside_init1(ME); + +#load_clientapi_modules; + +freeside_init2(ME); + +#FS::ClientAPI::Signup::clear_cache(); + +my $conf = new FS::Conf; +die "not running; xmlrpc_api conf option is off\n" + unless $conf->exists('xmlrpc_api'); +die "not running; api_shared_secret conf option is not set\n" + unless $conf->config('api_shared_secret'); + +daemon_run( 'port' => 8008, 'handle_request' => + sub { + my $request = shift; + + my $serializer = new XMLRPC::Serializer(typelookup => \%typelookup); + + #my $soap = SOAP::Transport::HTTP::Server + my $soap = XMLRPC::Transport::HTTP::Server + -> new + -> dispatch_to('FS::API') + -> serializer($serializer); + + $soap->request($request); + $soap->handle; + + return $soap->response; + } +); + +1; diff --git a/FS/t/part_fee_usage.t b/FS/t/part_fee_usage.t new file mode 100644 index 000000000..cb7fb220e --- /dev/null +++ b/FS/t/part_fee_usage.t @@ -0,0 +1,5 @@ +BEGIN { $| = 1; print "1..1\n" } +END {print "not ok 1\n" unless $loaded;} +use FS::part_fee_usage; +$loaded=1; +print "ok 1\n"; @@ -87,6 +87,7 @@ INSTALLGROUP = root #edit the stuff below to have the daemons start QUEUED_USER=fs_queue +API_USER = fs_api SELFSERVICE_USER = fs_selfservice #never run on the same machine in production!!! @@ -228,6 +229,9 @@ perl-modules: s|%%%FREESIDE_CACHE%%%|${FREESIDE_CACHE}|g;\ " blib/lib/FS/cust_main/*.pm blib/lib/FS/cust_pkg/*.pm;\ perl -p -i -e "\ + s|%%%FREESIDE_LOG%%%|${FREESIDE_LOG}|g;\ + " blib/lib/FS/Daemon/*.pm;\ + perl -p -i -e "\ s|%%%FREESIDE_CONF%%%|${FREESIDE_CONF}|g;\ s|%%%FREESIDE_LOG%%%|${FREESIDE_LOG}|g;\ s|%%%FREESIDE_LOCK%%%|${FREESIDE_LOCK}|g;\ @@ -267,6 +271,7 @@ install-init: install -o root -g ${INSTALLGROUP} -m 711 init.d/freeside-init ${INIT_FILE} perl -p -i -e "\ s/%%%QUEUED_USER%%%/${QUEUED_USER}/g;\ + s/%%%API_USER%%%/${API_USER}/g;\ s/%%%SELFSERVICE_USER%%%/${SELFSERVICE_USER}/g;\ s/%%%SELFSERVICE_MACHINES%%%/${SELFSERVICE_MACHINES}/g;\ " ${INIT_FILE} diff --git a/bin/freeside-init b/bin/freeside-init deleted file mode 100755 index fe12931fc..000000000 --- a/bin/freeside-init +++ /dev/null @@ -1,60 +0,0 @@ -#! /bin/sh -# -# start the freeside job queue daemon - -#PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin -DAEMON=/usr/local/bin/freeside-queued -NAME=freeside-queued -DESC="freeside job queue daemon" -USER="ivan" - -test -f $DAEMON || exit 0 - -set -e - -case "$1" in - start) - echo -n "Starting $DESC: " -# start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid -b -m\ -# --exec $DAEMON - $DAEMON $USER & - echo "$NAME." - ;; - stop) - echo -n "Stopping $DESC: " - start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid \ - --exec $DAEMON - echo "$NAME." - rm /var/run/$NAME.pid - ;; - #reload) - # - # If the daemon can reload its config files on the fly - # for example by sending it SIGHUP, do it here. - # - # If the daemon responds to changes in its config file - # directly anyway, make this a do-nothing entry. - # - # echo "Reloading $DESC configuration files." - # start-stop-daemon --stop --signal 1 --quiet --pidfile \ - # /var/run/$NAME.pid --exec $DAEMON - #;; - restart|force-reload) - # - # If the "reload" option is implemented, move the "force-reload" - # option to the "reload" entry above. If not, "force-reload" is - # just the same as "restart". - # - $0 stop - sleep 1 - $0 start - ;; - *) - N=/etc/init.d/$NAME - # echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2 - echo "Usage: $N {start|stop|restart|force-reload}" >&2 - exit 1 - ;; -esac - -exit 0 diff --git a/bin/test_scrub_sql b/bin/test_scrub_sql index fb26fe940..fe66805d3 100755 --- a/bin/test_scrub_sql +++ b/bin/test_scrub_sql @@ -15,11 +15,11 @@ foreach my $table (qw( part_export_option - payment_gateway payment_gateway_option + payment_gateway agent_payment_gateway - queue queue_arg + queue cust_pay_batch )) { print "DELETE FROM $table;\n"; diff --git a/bin/xmlrpc-customer_info b/bin/xmlrpc-customer_info new file mode 100755 index 000000000..8086a8dc4 --- /dev/null +++ b/bin/xmlrpc-customer_info @@ -0,0 +1,21 @@ +#!/usr/bin/perl + +use strict; +use Frontier::Client; +use Data::Dumper; + +my $uri = new URI 'http://localhost:8008/'; + +my $server = new Frontier::Client ( 'url' => $uri ); + +my $result = $server->call( + 'FS.API.customer_info', + 'secret' => 'sharingiscaring', + 'custnum' => 181318, +); + +#die $result->{'error'} if $result->{'error'}; + +print Dumper($result); + +1; diff --git a/bin/xmlrpc-insert_credit_phonenum b/bin/xmlrpc-insert_credit_phonenum new file mode 100755 index 000000000..a8774a45b --- /dev/null +++ b/bin/xmlrpc-insert_credit_phonenum @@ -0,0 +1,25 @@ +#!/usr/bin/perl + +use strict; +use Frontier::Client; +use Data::Dumper; + +my $uri = new URI 'http://localhost:8008/'; + +my $server = new Frontier::Client ( 'url' => $uri ); + +my $result = $server->call( + 'FS.API.insert_credit_phonenum', + 'secret' => 'sharingiscaring', + 'phonenum' => '3125550001', + 'amount' => '54.32', + + #optional + '_date' => 1397977200, #UNIX timestamp +); + +#die $result->{'error'} if $result->{'error'}; + +print Dumper($result); + +1; diff --git a/bin/xmlrpc-insert_payment b/bin/xmlrpc-insert_payment new file mode 100755 index 000000000..a0d60fd17 --- /dev/null +++ b/bin/xmlrpc-insert_payment @@ -0,0 +1,26 @@ +#!/usr/bin/perl + +use strict; +use Frontier::Client; +use Data::Dumper; + +my $uri = new URI 'http://localhost:8008/'; + +my $server = new Frontier::Client ( 'url' => $uri ); + +my $result = $server->call( + 'FS.API.insert_payment', + 'secret' => 'sharingiscaring', + 'custnum' => 181318, + 'payby' => 'CASH', + 'paid' => '54.32', + + #optional + '_date' => 1397977200, #UNIX timestamp +); + +#die $result->{'error'} if $result->{'error'}; + +print Dumper($result); + +1; diff --git a/bin/xmlrpc-insert_payment_phonenum b/bin/xmlrpc-insert_payment_phonenum new file mode 100755 index 000000000..21f01f05b --- /dev/null +++ b/bin/xmlrpc-insert_payment_phonenum @@ -0,0 +1,26 @@ +#!/usr/bin/perl + +use strict; +use Frontier::Client; +use Data::Dumper; + +my $uri = new URI 'http://localhost:8008/'; + +my $server = new Frontier::Client ( 'url' => $uri ); + +my $result = $server->call( + 'FS.API.insert_payment_phonenum', + 'secret' => 'sharingiscaring', + 'phonenum' => '3125550001', + 'payby' => 'CASH', + 'paid' => '54.32', + + #optional + '_date' => 1397977200, #UNIX timestamp +); + +#die $result->{'error'} if $result->{'error'}; + +print Dumper($result); + +1; diff --git a/bin/xmlrpc-insert_refund_phonenum b/bin/xmlrpc-insert_refund_phonenum new file mode 100755 index 000000000..bdcd50459 --- /dev/null +++ b/bin/xmlrpc-insert_refund_phonenum @@ -0,0 +1,26 @@ +#!/usr/bin/perl + +use strict; +use Frontier::Client; +use Data::Dumper; + +my $uri = new URI 'http://localhost:8008/'; + +my $server = new Frontier::Client ( 'url' => $uri ); + +my $result = $server->call( + 'FS.API.insert_refund_phonenum', + 'secret' => 'sharingiscaring', + 'phonenum' => '3125550001', + 'payby' => 'CASH', + 'refund' => '54.32', + + #optional + '_date' => 1397977200, #UNIX timestamp +); + +#die $result->{'error'} if $result->{'error'}; + +print Dumper($result); + +1; diff --git a/bin/xmlrpc-location_info b/bin/xmlrpc-location_info new file mode 100755 index 000000000..b2595ddc3 --- /dev/null +++ b/bin/xmlrpc-location_info @@ -0,0 +1,21 @@ +#!/usr/bin/perl + +use strict; +use Frontier::Client; +use Data::Dumper; + +my $uri = new URI 'http://localhost:8008/'; + +my $server = new Frontier::Client ( 'url' => $uri ); + +my $result = $server->call( + 'FS.API.location_info', + 'secret' => 'sharingiscaring', + 'custnum' => 181318, +); + +#die $result->{'error'} if $result->{'error'}; + +print Dumper($result); + +1; diff --git a/bin/xmlrpc-new_customer b/bin/xmlrpc-new_customer new file mode 100755 index 000000000..aea8053ce --- /dev/null +++ b/bin/xmlrpc-new_customer @@ -0,0 +1,63 @@ +#!/usr/bin/perl + +use strict; +use Frontier::Client; +use Data::Dumper; + +my( $username, $password ) = ( @ARGV ); + +my $uri = new URI 'http://localhost:8008/'; + +my $server = new Frontier::Client ( 'url' => $uri ); + +my $result = $server->call('FS.API.new_customer', + #API shared secret + 'secret' => 'sharingiscaring', + + #customer informaiton + 'agentnum' => 1, + 'refnum' => 1, #advertising source + 'agent_custid' => '', #'323', + 'referral_custnum' => 1, + + 'first' => 'Tofu', + 'last' => 'Beast', + 'company' => 'Bank of Soymerica', + + #address + 'address1' => '1234 Soybean Ln.', + 'city' => 'Tofutown', + 'county' => '', + 'state' => 'CA', + 'zip' => '54321', + 'country' => 'US', + 'latitude' => '', + 'longitude' => '', + 'geocode' => '', + 'censustract' => '', + 'censusyear' => '', + + #phones + 'daytime' => '555 444 3211', + 'night' => '', + 'fax' => '', + 'mobile' => '123 466 3332', + + #invoicing info + 'invoicing_list' => 'tofu@example.com', #comma-separated email addresses + 'postal_invoicing' => 1, + + #billing information + 'payby' => 'CARD', # DCRD, CHEK, DCHK, BILL, etc. + 'payinfo' => '4111111111111111',#card number / acctno@routing / PO# + 'paydate' => '11/2019', #card expiration + 'paycvv' => '123', #card CVV/security code + 'payname' => 'Thomas Beast', #"Exact name on card" if different +); + +die $result->{'error'} if $result->{'error'}; + +my $custnum = $result->{'custnum'}; +warn "added new customer w/custnum $custnum\n"; + +1; diff --git a/bin/xmlrpcd-phonenum_balance.pl b/bin/xmlrpcd-phonenum_balance.pl index 8aeeb11c2..7a3e0a7a9 100755 --- a/bin/xmlrpcd-phonenum_balance.pl +++ b/bin/xmlrpcd-phonenum_balance.pl @@ -8,7 +8,7 @@ my $uri = new URI 'http://localhost:8080/'; my $server = new Frontier::Client ( 'url' => $uri ); -my $result = $server->call('phonenum_balance', 'phonenum' => '9567566022', ); +my $result = $server->call('FS.ClientAPI_XMLRPC.phonenum_balance', 'phonenum' => '9567566022', ); #die $result->{'error'} if $result->{'error'}; diff --git a/eg/xmlrpc-example.pl b/eg/xmlrpc-example.pl deleted file mode 100755 index 7a2a0a6f0..000000000 --- a/eg/xmlrpc-example.pl +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/perl - -use strict; -use Frontier::Client; -use Data::Dumper; - -my $server = new Frontier::Client ( - url => 'http://user:pass@freesidehost/misc/xmlrpc.cgi', -); - -#my $method = 'cust_main.smart_search'; -#my @args = (search => '1'); - -my $method = 'Record.qsearch'; -my @args = (cust_main => { }); - -my $result = $server->call($method, @args); - -if (ref($result) eq 'ARRAY') { - print "Result:\n"; - print Dumper(@$result); -} - diff --git a/httemplate/browse/part_fee.html b/httemplate/browse/part_fee.html index 0370fe06d..482c692d7 100644 --- a/httemplate/browse/part_fee.html +++ b/httemplate/browse/part_fee.html @@ -1,16 +1,16 @@ <& elements/browse.html, - 'title' => 'Fee definitions', - 'name_singular' => 'fee definition', - 'query' => $query, - 'count_query' => $count_query, - 'header' => [ '#', + title => 'Fee definitions', + name_singular => 'fee definition', + query => $query, + count_query => $count_query, + header => [ '#', 'Description', 'Comment', 'Class', 'Amount', 'Tax status', ], - 'fields' => [ 'feepart', + fields => [ 'feepart', 'itemdesc', 'comment', 'classname', @@ -27,6 +27,7 @@ $link, ], align => 'cllccc', + menubar => \@menubar, &> <%init> my $curuser = $FS::CurrentUser::CurrentUser; @@ -64,4 +65,7 @@ my $sub_tax = sub { }; my $link = [ $p.'edit/part_fee.html?', 'feepart' ]; + +my @menubar = ( 'Add a new fee definition', + $p.'edit/part_fee.html' ); </%init> diff --git a/httemplate/config/config-view.cgi b/httemplate/config/config-view.cgi index 864a61279..8472dd68e 100644 --- a/httemplate/config/config-view.cgi +++ b/httemplate/config/config-view.cgi @@ -415,8 +415,10 @@ my @config_items = grep { !defined($locale) or $_->per_locale } my @deleteable = qw( invoice_latexreturnaddress invoice_htmlreturnaddress ); my %deleteable = map { $_ => 1 } @deleteable; -my @sections = qw(required billing invoicing notification UI self-service ticketing network_monitoring username password session shell BIND telephony ); -push @sections, '', 'deprecated'; +my @sections = qw( + required billing invoicing notification UI API self-service ticketing + network_monitoring username password session shell BIND telephony +), '', 'deprecated'; my %section_items = (); foreach my $section (@sections) { diff --git a/httemplate/edit/credit-cust_bill_pkg.html b/httemplate/edit/credit-cust_bill_pkg.html index a5ecb69e3..40faddc46 100644 --- a/httemplate/edit/credit-cust_bill_pkg.html +++ b/httemplate/edit/credit-cust_bill_pkg.html @@ -269,7 +269,8 @@ my @cust_bill_pkg = qsearch({ 'select' => 'cust_bill_pkg.*', 'table' => 'cust_bill_pkg', 'addl_from' => 'LEFT JOIN cust_bill USING (invnum)', - 'extra_sql' => "WHERE custnum = $custnum AND pkgnum != 0", + 'extra_sql' => "WHERE custnum = $custnum ". + "AND (pkgnum != 0 or feepart IS NOT NULL)", 'order_by' => 'ORDER BY invnum ASC, billpkgnum ASC', }); diff --git a/httemplate/edit/part_fee.html b/httemplate/edit/part_fee.html index dada23360..e057a752d 100644 --- a/httemplate/edit/part_fee.html +++ b/httemplate/edit/part_fee.html @@ -14,7 +14,6 @@ 'credit_weight' => 'Credit weight', 'agentnum' => 'Agent', 'amount' => 'Flat fee amount', - 'percent' => 'Percentage of invoice amount', 'basis' => 'Based on', 'setuprecur' => 'Report this fee as', 'minimum' => 'Minimum fee', @@ -55,8 +54,8 @@ my $n = 0; my (@locale_fields, %locale_labels); foreach (@locales) { push @locale_fields, - { field => 'feepartmsgnum'. $n, type => 'hidden' }, - { field => 'feepartmsgnum'. $n. '_locale', type => 'hidden' }, + { field => 'feepartmsgnum'. $n, type => 'hidden' }, + { field => 'feepartmsgnum'. $n. '_locale', type => 'hidden', value => $_ }, { field => 'feepartmsgnum'. $n. '_itemdesc', type => 'text', size => 40 }, ; $locale_labels{ 'feepartmsgnum'.$n.'_itemdesc' } = @@ -64,6 +63,19 @@ foreach (@locales) { $n++; } +$n = 0; +my %layer_fields = ( + 'charged' => [ + 'percent' => { label => 'Fraction of invoice total', type => 'percentage', }, + ], + 'owed' => [ + 'percent' => { label => 'Fraction of balance', type => 'percentage', }, + ], + 'usage' => [ + 'usage' => { type => 'part_fee_usage' } + ], +); + my @fields = ( { field => 'itemdesc', type => 'text', size => 40, }, @@ -95,15 +107,23 @@ my @fields = ( { type => 'justtitle', value => 'Fee calculation' }, { field => 'amount', type => 'money', }, - { field => 'percent', type => 'percentage', }, { field => 'basis', - type => 'select', - options => [ 'charged', 'owed' ], - labels => { 'charged' => 'amount charged', - 'owed' => 'balance due', }, + type => 'selectlayers', + options => [ 'charged', 'owed', 'usage' ], + labels => { 'charged' => 'amount charged', + 'owed' => 'balance due', + 'usage' => 'usage charges' }, + layer_fields => \%layer_fields, + layer_values_callback => sub { + my ($cgi, $obj) = @_; + { + 'charged' => { percent => $obj->percent }, + 'owed' => { percent => $obj->percent }, + 'usage' => { usage => [ $obj->part_fee_usage ] }, + } + }, }, - { field => 'minimum', type => 'money', }, { field => 'maximum', type => 'money', }, { field => 'limit_credit', diff --git a/httemplate/edit/process/part_fee.html b/httemplate/edit/process/part_fee.html index 25656e9b0..1fca231ec 100755 --- a/httemplate/edit/process/part_fee.html +++ b/httemplate/edit/process/part_fee.html @@ -1,13 +1,22 @@ <& elements/process.html, - 'debug' => 1, + #'debug' => 1, 'table' => 'part_fee', 'agent_virt' => 1, 'agent_null_right' => 'Edit global fee definitions', 'viewall_dir' => 'browse', - 'process_o2m' => { - 'table' => 'part_fee_msgcat', - 'fields' => [ 'locale', 'itemdesc' ], - }, + 'process_o2m' => [ + { + 'table' => 'part_fee_msgcat', + 'fields' => [ 'locale', 'itemdesc' ], + }, + { + 'table' => 'part_fee_usage', + 'fields' => [ 'classnum', + 'amount', + 'percent' + ], + }, + ], &> <%init> diff --git a/httemplate/elements/email-link.html b/httemplate/elements/email-link.html index 692e5bc2e..2612faabb 100644 --- a/httemplate/elements/email-link.html +++ b/httemplate/elements/email-link.html @@ -1,9 +1,10 @@ % if ( $FS::CurrentUser::CurrentUser->access_right('Bulk send customer notices') ) { -<A HREF="<%$p%>misc/email-customers.html?table=<%$table%>&<%$query%>"><%$label%></A> +<A HREF="<%$p%>misc/email-customers.html?table=<%$table%>&agent_virt_agentnum=<%$agent_virt_agentnum%>&<%$query%>"><%$label%></A> % } <%init> my %opt = @_; my $table = $opt{'table'}; +my $agent_virt_agentnum = $opt{'agent_virt_agentnum'}; my $search_hash = $opt{'search_hash'}; die "'table' required" if !$table; die "'search_hash' required" if !$search_hash; diff --git a/httemplate/elements/tr-part_fee_usage.html b/httemplate/elements/tr-part_fee_usage.html new file mode 100644 index 000000000..00f4e122a --- /dev/null +++ b/httemplate/elements/tr-part_fee_usage.html @@ -0,0 +1,29 @@ +% my $n = 0; +% foreach my $class (@classes) { +% my $pre = "feepartusagenum$n"; +% my $x = $part_fee_usage{$class->classnum} || FS::part_fee_usage->new({}); +<tr> + <td align="right"> + <input type="hidden" name="<%$pre%>" value="<% $x->partfeeusagenum %>"> + <input type="hidden" name="<%$pre%>_classnum" value="<% $class->classnum %>"> + <% $class->classname %>:</td> + <td> + <%$money_char%><input size=4 name="<%$pre%>_amount" \ + value="<% sprintf("%.2f", $x->amount) %>"> + </td> + <td>per call<b> + </b></td> + <td> + <input size=4 name="<%$pre%>_percent" \ + value="<% sprintf("%.1f", $x->percent) %>">% + </td> +</tr> +% $n++; +% } +<%init> +my %opt = @_; +my $value = $opt{'curr_value'} || $opt{'value'}; +# values is an arrayref of part_fee_usage objects +my %part_fee_usage = map { $_->classnum => $_ } @$value; +my @classes = qsearch('usage_class', { disabled => '' }); +my $money_char = FS::Conf->new->config('money_char') || '$'; +</%init> diff --git a/httemplate/elements/tr-select-from_to.html b/httemplate/elements/tr-select-from_to.html index ad9b40a6b..57b2388b1 100644 --- a/httemplate/elements/tr-select-from_to.html +++ b/httemplate/elements/tr-select-from_to.html @@ -39,7 +39,7 @@ my %hash = ( 'show_month_abbr' => 1, 'start_year' => '1999', - 'end_year' => '2014', + 'end_year' => '2016', @_, ); </%init> diff --git a/httemplate/misc/cust-part_pkg.cgi b/httemplate/misc/cust-part_pkg.cgi index afe8e4249..e129347ec 100644 --- a/httemplate/misc/cust-part_pkg.cgi +++ b/httemplate/misc/cust-part_pkg.cgi @@ -37,7 +37,8 @@ my $date_format = $conf->config('date_format') || '%m/%d/%Y'; my $default_start_date = $conf->exists('order_pkg-no_start_date') ? '' - : $cust_main->next_bill_date; + : $cust_main ? $cust_main->next_bill_date + : ''; #num_billing_pkgs may be slightly better (will allow you to fill in a start # date in the weird edge case where you're using sync_next_bill and diff --git a/httemplate/misc/email-customers.html b/httemplate/misc/email-customers.html index b47f4414f..15926308e 100644 --- a/httemplate/misc/email-customers.html +++ b/httemplate/misc/email-customers.html @@ -103,13 +103,13 @@ Template: <& /elements/tr-td-label.html, 'label' => 'From:' &> <TD><& /elements/input-text.html, 'field' => 'from_name', - 'value' => $conf->config('company_name'), #? + 'value' => $conf->config('company_name', $agent_virt_agentnum), #? 'size' => 20, &> <\ <& /elements/input-text.html, 'field' => 'from_addr', 'type' => 'email', # HTML5, woot - 'value' => $conf->config('invoice_from'), + 'value' => $conf->config('invoice_from', $agent_virt_agentnum), 'size' => 20, &>></TD> @@ -154,7 +154,10 @@ die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Bulk send customer notices'); my $conf = FS::Conf->new; + my $table = $cgi->param('table') or die "'table' required"; +my $agent_virt_agentnum = $cgi->param('agent_virt_agentnum') || ''; + my %search; if ( $cgi->param('search') ) { %search = %{ thaw(decode_base64($cgi->param('search'))) }; diff --git a/httemplate/misc/xmlhttp-calculate_taxes.html b/httemplate/misc/xmlhttp-calculate_taxes.html index ed7bd0173..2bb1f4cce 100644 --- a/httemplate/misc/xmlhttp-calculate_taxes.html +++ b/httemplate/misc/xmlhttp-calculate_taxes.html @@ -62,14 +62,7 @@ if ( $sub eq 'calculate_taxes' ) { my $taxlisthash = {}; foreach my $cust_bill_pkg (values %cust_bill_pkg) { - my $part_pkg = $cust_bill_pkg->part_pkg; - $cust_main->_handle_taxes( $part_pkg, - $taxlisthash, - $cust_bill_pkg, - $cust_bill_pkg->cust_pkg, - $cust_bill_pkg->cust_bill->_date, - $cust_bill_pkg->cust_pkg->pkgpart, - ); + $cust_main->_handle_taxes( $taxlisthash, $cust_bill_pkg ); } my $listref_or_error = $cust_main->calculate_taxes( [ values %cust_bill_pkg ], $taxlisthash, [ values %cust_bill_pkg ]->[0]->cust_bill->_date ); diff --git a/httemplate/misc/xmlhttp-cust_bill_pkg-calculate_taxes.html b/httemplate/misc/xmlhttp-cust_bill_pkg-calculate_taxes.html index c0db3e2c4..4558682bd 100644 --- a/httemplate/misc/xmlhttp-cust_bill_pkg-calculate_taxes.html +++ b/httemplate/misc/xmlhttp-cust_bill_pkg-calculate_taxes.html @@ -62,15 +62,7 @@ if ( $sub eq 'calculate_taxes' ) { push @cust_bill_pkg, $cust_bill_pkg; - my $part_pkg = $cust_bill_pkg->part_pkg; - $cust_main->_handle_taxes( $part_pkg, - $taxlisthash, - $cust_bill_pkg, - $cust_bill_pkg->cust_pkg, - $cust_bill_pkg->cust_bill->_date, - $cust_bill_pkg->cust_pkg->pkgpart, - ); - + $cust_main->_handle_taxes( $taxlisthash, $cust_bill_pkg ); } if ( @cust_bill_pkg ) { @@ -89,7 +81,10 @@ if ( $sub eq 'calculate_taxes' ) { foreach my $taxline ( @$listref_or_error ) { my $amount = $taxline->setup; my $desc = $taxline->desc; - foreach my $location ( @{$taxline->cust_bill_pkg_tax_location}, @{$taxline->cust_bill_pkg_tax_rate_location} ) { + foreach my $location ( + @{$taxline->get('cust_bill_pkg_tax_location')}, + @{$taxline->get('cust_bill_pkg_tax_rate_location')} ) + { my $taxlocnum = $location->locationnum || ''; my $taxratelocnum = $location->taxratelocationnum || ''; $location->cust_bill_pkg_desc($taxline->desc); #ugh @ that kludge diff --git a/httemplate/misc/xmlrpc.cgi b/httemplate/misc/xmlrpc.cgi deleted file mode 100644 index 14bf9ef92..000000000 --- a/httemplate/misc/xmlrpc.cgi +++ /dev/null @@ -1,16 +0,0 @@ -<% $response_xml %>\ -<%init> - -my $request_xml = $cgi->param('POSTDATA'); - -#warn $request_xml; - -my $fsxmlrpc = new FS::XMLRPC; -my ($error, $response_xml) = $fsxmlrpc->serve($request_xml); - -#warn $error; - -http_header('Content-Type' => 'text/xml', - 'Content-Length' => length($response_xml)); - -</%init> diff --git a/httemplate/search/477.html b/httemplate/search/477.html index eed3df946..3e7888c40 100755 --- a/httemplate/search/477.html +++ b/httemplate/search/477.html @@ -49,18 +49,22 @@ <& "477part${part}.html", 'tech_code' => $tech, 'url' => $url, - 'type' => $type + 'type' => $type, + 'date' => $date, &> % if ( $type eq 'xml' ) { </<% 'Part_IA_'. chr(65 + $tech) %>> % } % } -% } else { +% } else { # not part IA % if ( $type eq 'xml' ) { <<% 'Part_'. $part %>> % } % my $url = &{$url_mangler}($part); -<& "477part${part}.html", 'url' => $url &> +<& "477part${part}.html", + 'url' => $url, + 'date' => $date, +&> % if ( $type eq 'xml' ) { </<% 'Part_'. $part %>> % } @@ -80,6 +84,9 @@ my $curuser = $FS::CurrentUser::CurrentUser; die "access denied" unless $curuser->access_right('List packages'); +my $date = $cgi->param('date') ? parse_datetime($cgi->param('date')) + : time; + my $state = uc($cgi->param('state')); $state =~ /^[A-Z]{2}$/ or die "illegal state: $state"; diff --git a/httemplate/search/477partIA.html b/httemplate/search/477partIA.html index 6b4bffd41..aa7381139 100755 --- a/httemplate/search/477partIA.html +++ b/httemplate/search/477partIA.html @@ -84,7 +84,6 @@ my %search_hash; for ( qw(agentnum state) ) { $search_hash{$_} = $cgi->param($_) if $cgi->param($_); } -$search_hash{'status'} = 'active'; $search_hash{'country'} = 'US'; $search_hash{'classnum'} = [ $cgi->param('classnum') ]; @@ -114,6 +113,13 @@ if ( $technology eq 'Symmetric xDSL' or $technology eq 'Other Wireline' ) { # whether to show residential percentages in each cell of the matrix my $percentages = ($technology eq 'Terrestrial Mobile Wireless'); +# as of date +# FCC 477 instructions: "Only count connections that are in service." +# So we count packages that were in active status as of the specified date, +# not over any sort of range. +$search_hash{'active'} = [ $opt{date}, $opt{date} ]; +warn Dumper \%search_hash; + my $query = FS::cust_pkg->search(\%search_hash); my $count_query = $query->{'count_query'}; diff --git a/httemplate/search/477partIIA.html b/httemplate/search/477partIIA.html index 907a176e5..467b19c5f 100755 --- a/httemplate/search/477partIIA.html +++ b/httemplate/search/477partIIA.html @@ -40,25 +40,25 @@ </TABLE> % } #XML/HTML <%init> - my $curuser = $FS::CurrentUser::CurrentUser; die "access denied" unless $curuser->access_right('List packages'); +my %opt = @_; my %search_hash = (); $search_hash{'agentnum'} = $cgi->param('agentnum'); $search_hash{'state'} = $cgi->param('state'); $search_hash{'classnum'} = [ $cgi->param('classnum') ]; -$search_hash{'status'} = 'active'; +$search_hash{'active'} = [ $opt{date}, $opt{date} ]; my @row_option; foreach ($cgi->param('part2a_row_option')) { push @row_option, (/^\d+$/ ? $_ : undef); } -my $is_residential = "AND COALESCE(cust_main.company, '') = ''"; +my $is_residential = " AND COALESCE(cust_main.company, '') = ''"; my $has_report_option = sub { map { defined($row_option[$_]) ? diff --git a/httemplate/search/477partIIB.html b/httemplate/search/477partIIB.html index cb181f4fd..ce1ac03f0 100755 --- a/httemplate/search/477partIIB.html +++ b/httemplate/search/477partIIB.html @@ -46,28 +46,29 @@ my $curuser = $FS::CurrentUser::CurrentUser; die "access denied" unless $curuser->access_right('List packages'); +my %opt = @_; my %search_hash = (); $search_hash{'agentnum'} = $cgi->param('agentnum'); $search_hash{'state'} = $cgi->param('state'); $search_hash{'classnum'} = [ $cgi->param('classnum') ]; -$search_hash{'status'} = 'active'; +$search_hash{'active'} = [ $opt{date}, $opt{date} ]; my @row_option; foreach ($cgi->param('part2b_row_option')) { push @row_option, (/^\d+$/ ? $_ : undef); } -my $is_residential = "AND COALESCE(cust_main.company, '') = ''"; +my $is_residential = " AND COALESCE(cust_main.company, '') = ''"; my $has_report_option = sub { map { defined($row_option[$_]) ? - "AND EXISTS( + " AND EXISTS( SELECT 1 FROM part_pkg_option WHERE part_pkg_option.pkgpart = part_pkg.pkgpart AND optionname = 'report_option_" . $row_option[$_]."' AND optionvalue = '1' - )" : 'AND FALSE' + )" : ' AND FALSE' } @_ }; diff --git a/httemplate/search/477partV.html b/httemplate/search/477partV.html index b2dd9ca95..5f7708140 100755 --- a/httemplate/search/477partV.html +++ b/httemplate/search/477partV.html @@ -33,13 +33,14 @@ my %search_hash = (); my @sql_query = (); my @count_query = (); -for ( qw(agentnum magic state) ) { +for ( qw(agentnum state) ) { $search_hash{$_} = $cgi->param($_) if $cgi->param($_); } $search_hash{'country'} = 'US'; $search_hash{'classnum'} = [ $cgi->param('classnum') ]; $search_hash{report_option} = $cgi->param('part5_report_option') if $cgi->param('part5_report_option'); +$search_hash{'active'} = [ $opt{date}, $opt{date} ]; my $sql_query = FS::cust_pkg->search( { %search_hash, 'fcc_line' => 1, diff --git a/httemplate/search/477partVI_census.html b/httemplate/search/477partVI_census.html index 0dafc6b21..b4f6ddc01 100755 --- a/httemplate/search/477partVI_census.html +++ b/httemplate/search/477partVI_census.html @@ -81,9 +81,11 @@ push @fields, my %search_hash = (); my @sql_query = (); -for ( qw(agentnum magic state) ) { +for ( qw(agentnum state) ) { $search_hash{$_} = $cgi->param($_) if $cgi->param($_); } + +$search_hash{'active'} = [ $opt{date}, $opt{date} ]; $search_hash{'country'} = 'US'; $search_hash{'classnum'} = [ $cgi->param('classnum') ] if grep { $_ eq 'classnum' } $cgi->param; @@ -115,12 +117,11 @@ foreach my $row ( @row_option ) { ($report_option ? ( 'report_option' => $report_option ) : () ), } ); +warn Dumper($sql_query) if $rowcount==1 and $columncount==3; my $extracolumns = "$rowcount AS upload, $columncount AS download, $tech_code as technology_code"; my $percent = "CASE WHEN count(*) > 0 THEN 100-100*cast(count(cust_main.company) as numeric)/cast(count(*) as numeric) ELSE cast(0 as numeric) END AS residential"; $sql_query->{select} = "count(*) AS quantity, $extracolumns, cust_location.censustract, $percent"; - $sql_query->{order_by} =~ /^(.*)(ORDER BY pkgnum)(.*)$/s - or die "couldn't parse order_by"; - $sql_query->{order_by} = "$1 GROUP BY cust_location.censustract $3"; + $sql_query->{order_by} = " GROUP BY cust_location.censustract "; push @sql_query, $sql_query; } $columncount++; diff --git a/httemplate/search/cust_bill_pkg.cgi b/httemplate/search/cust_bill_pkg.cgi index 6b7a5e6e2..440ab150c 100644 --- a/httemplate/search/cust_bill_pkg.cgi +++ b/httemplate/search/cust_bill_pkg.cgi @@ -137,9 +137,9 @@ Filtering parameters: - use_override: Apply "classnum" and "taxclass" filtering based on the override (bundle) pkgpart, rather than always using the true pkgpart. -- nottax: Limit to items that are not taxes (pkgnum > 0). +- nottax: Limit to items that are not taxes (pkgnum > 0 or feepart > 0). -- istax: Limit to items that are taxes (pkgnum == 0). +- istax: Limit to items that are taxes (pkgnum == 0 and feepart = null). - taxnum: Limit to items whose tax definition matches this taxnum. With "nottax" that means items that are subject to that tax; @@ -305,7 +305,8 @@ if ( $cgi->param('custnum') =~ /^(\d+)$/ ) { # we want the package and its definition if available my $join_pkg = ' LEFT JOIN cust_pkg USING (pkgnum) - LEFT JOIN part_pkg USING (pkgpart)'; + LEFT JOIN part_pkg USING (pkgpart) + LEFT JOIN part_fee USING (feepart)'; my $part_pkg = 'part_pkg'; # "Separate sub-packages from parents" @@ -319,12 +320,16 @@ if ( $use_override ) { $part_pkg = 'override'; } push @select, "$part_pkg.pkgpart", "$part_pkg.pkg"; -push @select, "$part_pkg.taxclass" if $conf->exists('enable_taxclasses'); +push @select, "COALESCE($part_pkg.taxclass, part_fee.taxclass) AS taxclass" + if $conf->exists('enable_taxclasses'); # the non-tax case if ( $cgi->param('nottax') ) { - push @where, 'cust_bill_pkg.pkgnum > 0'; + push @select, "part_fee.itemdesc"; + + push @where, + '(cust_bill_pkg.pkgnum > 0 OR cust_bill_pkg.feepart IS NOT NULL)'; my @tax_where; # will go into a subquery my @exempt_where; # will also go into a subquery @@ -335,7 +340,7 @@ if ( $cgi->param('nottax') ) { # N: classnum if ( grep { $_ eq 'classnum' } $cgi->param ) { my @classnums = grep /^\d*$/, $cgi->param('classnum'); - push @where, "COALESCE($part_pkg.classnum, 0) IN ( ". + push @where, "COALESCE(part_fee.classnum, $part_pkg.classnum, 0) IN ( ". join(',', @classnums ). ' )' if @classnums; @@ -360,7 +365,7 @@ if ( $cgi->param('nottax') ) { # effective taxclass, not the real one push @tax_where, 'cust_main_county.taxclass IS NULL' } elsif ( $cgi->param('taxclass') ) { - push @tax_where, "$part_pkg.taxclass IN (" . + push @tax_where, "COALESCE(part_fee.taxclass, $part_pkg.taxclass) IN (" . join(', ', map {dbh->quote($_)} $cgi->param('taxclass') ). ')'; } @@ -681,7 +686,7 @@ if ( $cgi->param('salesnum') =~ /^(\d+)$/ ) { 'paid' => ($cgi->param('paid') ? 1 : 0), 'classnum' => scalar($cgi->param('classnum')) ); - $join_pkg .= " JOIN sales_pkg_class ON ( COALESCE(sales_pkg_class.classnum, 0) = COALESCE( part_pkg.classnum, 0) )"; + $join_pkg .= " JOIN sales_pkg_class ON ( COALESCE(sales_pkg_class.classnum, 0) = COALESCE( part_fee.classnum, part_pkg.classnum, 0) )"; my $extra_sql = $subsearch->{extra_sql}; $extra_sql =~ s/^WHERE//; diff --git a/httemplate/search/cust_bill_pkg_referral.html b/httemplate/search/cust_bill_pkg_referral.html index c4dde32a0..f8e2ea72d 100644 --- a/httemplate/search/cust_bill_pkg_referral.html +++ b/httemplate/search/cust_bill_pkg_referral.html @@ -41,8 +41,11 @@ 'classname', sub { # report_option my $cust_bill_pkg = shift; - my $pkgpart = $cust_bill_pkg->pkgpart_override - || $cust_bill_pkg->cust_pkg->pkgpart; + my $pkgpart = $cust_bill_pkg->pkgpart_override; + unless ( $pkgpart ) { + my $cust_pkg = $cust_bill_pkg->cust_pkg or return ''; + $pkgpart = $cust_pkg->pkgpart; + } if ( !exists($report_classes{$pkgpart}) ) { my $part_pkg = FS::part_pkg->by_key($pkgpart); my %opts = $part_pkg->options; @@ -130,7 +133,9 @@ my $agentnums_sql = my($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi); my @where = ( $agentnums_sql, - 'cust_bill_pkg.pkgnum != 0', # exclude taxes + # exclude taxes + '(cust_bill_pkg.pkgnum != 0 OR '. + 'cust_bill_pkg.feepart IS NOT NULL)', "cust_bill._date >= $beginning", "cust_bill._date <= $ending", ); @@ -184,11 +189,13 @@ if ( $cgi->param('classnum') =~ /^(\d+)$/ ) { if ( $use_override ) { push @where, "( - part_pkg.classnum $comparison AND pkgpart_override IS NULL OR - override.classnum $comparison AND pkgpart_override IS NOT NULL + (part_pkg.classnum $comparison AND pkgpart_override IS NULL) OR + (override.classnum $comparison AND pkgpart_override IS NOT NULL) OR + (part_fee.classnum $comparison AND feepart IS NOT NULL) )"; } else { - push @where, "part_pkg.classnum $comparison"; + push @where, + "(part_pkg.classnum $comparison) OR (part_fee.classnum $comparison)"; } } @@ -228,15 +235,19 @@ $join_pkg .= ' LEFT JOIN cust_pkg USING ( pkgnum ) LEFT JOIN part_pkg USING ( pkgpart ) LEFT JOIN part_pkg AS override ON pkgpart_override = override.pkgpart + LEFT JOIN part_fee USING ( feepart ) LEFT JOIN pkg_class ON '; #... if ( $use_override ) { # join to whichever pkgpart is appropriate $join_pkg .= ' ( pkgpart_override IS NULL AND part_pkg.classnum = pkg_class.classnum ) - OR ( pkgpart_override IS NOT NULL AND override.classnum = pkg_class.classnum )'; + OR ( pkgpart_override IS NOT NULL AND override.classnum = pkg_class.classnum ) + OR ( feepart IS NOT NULL AND part_fee.classnum = pkg_class.classnum )'; } else { - $join_pkg .= 'part_pkg.classnum = pkg_class.classnum'; + $join_pkg .= ' + ( part_pkg.classnum = pkg_class.classnum ) + OR ( part_fee.classnum = pkg_class.classnum )'; } my $where = ' WHERE '. join(' AND ', @where); @@ -258,7 +269,7 @@ my $last_pay_sql = "SELECT MAX(_date) FROM cust_bill_pay JOIN cust_bill_pay_pkg USING (billpaynum) WHERE cust_bill_pay_pkg.billpkgnum = cust_bill_pkg.billpkgnum"; -push @select, 'part_pkg.pkg', +push @select, 'COALESCE(part_pkg.pkg, part_fee.itemdesc) AS pkg', 'part_pkg.freq', 'cust_main.custnum', 'cust_main.first', diff --git a/httemplate/search/cust_msg.html b/httemplate/search/cust_msg.html index f71a86607..716addfd6 100644 --- a/httemplate/search/cust_msg.html +++ b/httemplate/search/cust_msg.html @@ -5,7 +5,7 @@ 'count_query' => $count_query, 'header' => [ 'Date', - 'Template', + 'Type', 'Destination', 'Status', '', #error @@ -15,7 +15,9 @@ my $date = $_[0]->_date; $date ? time2str('%Y-%m-%d %T',$_[0]->_date) : '' }, - 'msgname', + sub { + ucfirst($_[0]->msgtype) || $_[0]->msgname + }, sub { join('<BR>', split(/,\s*/, $_[0]->env_to) ) }, @@ -31,9 +33,11 @@ '', '', ], - 'color' => [ ('') x 3, - $statuscolor, - $statuscolor, + 'color' => [ '', + $typecolor, + '', + $statuscolor, + $statuscolor, ], 'html_init' => $html_init, 'really_disable_download' => 1, @@ -51,6 +55,9 @@ my @where; if ( $cgi->param('status') =~ /^(\w+)$/ ) { push @where, "status = '$1'"; } +if ( $cgi->param('msgtype') =~ /^(\w+)$/ ) { + push @where, "msgtype = '$1'"; +} my ($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi, ''); push @where, "(_date >= $beginning AND _date <= $ending)"; @@ -79,16 +86,22 @@ my $sub_popup_link = sub { include('/elements/popup_link_onclick.html', 'action' => $p. 'view/cust_msg.html?' . $custmsgnum, 'actionlabel' => 'Message detail', - 'width' => 600, - 'height' => 500, + 'width' => 680, + 'height' => 550, ); }; my %color = ( 'failed' => 'FF0000', 'sent' => '', + + 'invoice' => '00CC00', + 'receipt' => '0000CC', + 'admin' => 'CC0000', + '' => '000000', ); my $statuscolor = sub { $color{$_[0]->status} }; +my $typecolor = sub { $color{$_[0]->msgtype} }; my $html_init = qq!<FORM ACTION="$p/search/cust_msg.html" METHOD="GET"> <TABLE cellspacing="10">!. @@ -110,6 +123,17 @@ include('/elements/select.html', 'failed' => 'failed', 'sent' => 'sent', }, ) . +'</TD><TD> Type '. +include('/elements/select.html', + 'field' => 'msgtype', + 'curr_value' => $cgi->param('msgtype') || '', + 'options' => [ '', 'invoice', 'receipt', 'admin' ], + 'labels' => { '' => '(any)', + 'invoice' => 'Invoices', + 'receipt' => 'Receipts', + 'admin' => 'Admin notices', + }, +) . '</TD> <TD><INPUT type="submit" value="Search"></TD></TR> </TABLE></FORM><BR> diff --git a/httemplate/search/elements/search-html.html b/httemplate/search/elements/search-html.html index bee33cfe8..10cc95539 100644 --- a/httemplate/search/elements/search-html.html +++ b/httemplate/search/elements/search-html.html @@ -446,7 +446,7 @@ % $cstyle = qq(STYLE="$cstyle") % if $cstyle; - <TD CLASS="<% $class %>" BGCOLOR="<% $bgcolor %>" <% $align %> <% $cstyle %>><% $font %><% $a %><% $s %><% $field %><% $es %><% $a ? '</A>' : '' %><% $font ? '</FONT>' : '' %></TD> + <TD CLASS="<% $class %>" BGCOLOR="<% $bgcolor %>" <% $align %> <% $cstyle %>><% $a %><% $font %><% $s %><% $field %><% $es %><% $font ? '</FONT>' : '' %><% $a ? '</A>' : '' %></TD> % } % diff --git a/httemplate/search/report_477.html b/httemplate/search/report_477.html index b842b1f3f..a5dd70b7c 100755 --- a/httemplate/search/report_477.html +++ b/httemplate/search/report_477.html @@ -29,6 +29,13 @@ 'records' => \@states, &> + <& /elements/tr-input-date-field.html, { + 'label' => 'As of date', + 'name' => 'date', + 'value' => '', + 'format' => '%m/%d/%Y' + } &> + <% include( '/elements/tr-select-pkg_class.html', 'multiple' => 1, 'empty_label' => '(empty class)', diff --git a/httemplate/search/report_tax.cgi b/httemplate/search/report_tax.cgi index 111f22d3d..916d44bce 100755 --- a/httemplate/search/report_tax.cgi +++ b/httemplate/search/report_tax.cgi @@ -274,7 +274,8 @@ if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) { $where .= ' AND cust_main.agentnum = '. $agent->agentnum; } -my $nottax = 'cust_bill_pkg.pkgnum != 0'; +my $nottax = + '(cust_bill_pkg.pkgnum != 0 OR cust_bill_pkg.feepart IS NOT NULL)'; # one query for each column of the report # plus separate queries for the totals row diff --git a/httemplate/search/sales_commission.html b/httemplate/search/sales_commission.html index e74f3792e..57b6cdcd5 100644 --- a/httemplate/search/sales_commission.html +++ b/httemplate/search/sales_commission.html @@ -33,7 +33,12 @@ my $date_format = $conf->config('date_format') || '%m/%d/%Y'; my %query = ( 'table' => 'sales' ); my $count_query = "SELECT COUNT(*) FROM sales"; -my $salesnum; +if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) { + $query{hashref}->{agentnum} = $1; + $count_query .= " WHERE agentnum = $1"; +} + +my $salesnum = ''; if ( $cgi->param('salesnum') =~ /^(\d+)$/ ) { $salesnum = $1; } else { diff --git a/httemplate/search/sqlradius.cgi b/httemplate/search/sqlradius.cgi index c8f7932c5..f7873e72f 100644 --- a/httemplate/search/sqlradius.cgi +++ b/httemplate/search/sqlradius.cgi @@ -4,11 +4,8 @@ % # and finally, display the thing % ### % -% foreach my $part_export ( -% #grep $_->can('usage_sessions'), qsearch( 'part_export' ) -% qsearch( 'part_export', { 'exporttype' => 'sqlradius' } ), -% qsearch( 'part_export', { 'exporttype' => 'sqlradius_withdomain' } ) -% ) { +% foreach my $part_export ( @part_export ) { +% % %user2svc = (); % % my $efields = tie my %efields, 'Tie::IxHash', %fields; @@ -27,10 +24,12 @@ % }, % ); % } -% -% - <% $part_export->exporttype %> to <% $part_export->machine %><BR> + <FONT CLASS="fsinnerbox-title"> + <% $part_export->exportname || $part_export->exporttype |h %> + <% $part_export->machine ? ' to '. $part_export->machine : '' |h %> + </FONT><BR> + <% include( '/elements/table-grid.html' ) %> % my $bgcolor1 = '#eeeeee'; % my $bgcolor2 = '#ffffff'; @@ -150,6 +149,23 @@ if ( $cgi->param('svcnum') =~ /^(\d+)$/ ) { $cgi_svc = qsearchs( 'svc_acct', { 'username' => $1 } ); } +my @part_export = (); +if ( $cgi_svc ) { + my $part_svc = $cgi_svc->cust_svc->part_svc; + @part_export = ( + $part_svc->part_export('sqlradius'), + $part_svc->part_export('sqlradius_withdomain'), + $part_svc->part_export('broadband_sqlradius'), + ); +} else { + @part_export = ( + #grep $_->can('usage_sessions'), qsearch( 'part_export' ) + qsearch( 'part_export', { 'exporttype' => 'sqlradius' } ), + qsearch( 'part_export', { 'exporttype' => 'sqlradius_withdomain' } ), + qsearch( 'part_export', { 'exporttype' => 'broadband_sqlradius' } ), + ); +} + my $ip = ''; if ( $cgi->param('ip') =~ /^((\d+\.){3}\d+)$/ ) { $ip = $1; diff --git a/httemplate/view/cust_main.cgi b/httemplate/view/cust_main.cgi index 391988190..3dfe003a3 100755 --- a/httemplate/view/cust_main.cgi +++ b/httemplate/view/cust_main.cgi @@ -125,9 +125,10 @@ function areyousure(href, message) { % % my $email_link = ($cust_main->invoicing_list_emailonly) && % include('/elements/email-link.html', -% 'table' => 'cust_main', -% 'search_hash' => { 'custnum' => $custnum }, -% 'label' => 'Email a notice to this customer', +% 'table' => 'cust_main', +% 'search_hash' => { 'custnum' => $custnum }, +% 'agent_virt_agentnum' => $cust_main->agentnum, +% 'label' => 'Email a notice to this customer', % ); % if ( $email_link and $br ) { | diff --git a/init.d/freeside-init b/init.d/freeside-init index 9d8530739..92e3fdfe0 100644 --- a/init.d/freeside-init +++ b/init.d/freeside-init @@ -16,6 +16,7 @@ ### END INIT INFO QUEUED_USER=%%%QUEUED_USER%%% +API_USER=%%%API_USER%%% SELFSERVICE_USER=%%%SELFSERVICE_USER%%% SELFSERVICE_MACHINES="%%%SELFSERVICE_MACHINES%%%" @@ -31,6 +32,25 @@ export PATH case "$1" in start) # Start daemons. + + for MACHINE in $SELFSERVICE_MACHINES; do + echo -n "Starting freeside-selfservice-server to $MACHINE: " + freeside-selfservice-server $SELFSERVICE_USER $MACHINE + echo "done." + done + + echo -n "Starting freeside-selfservice-xmlrpcd: " + freeside-selfservice-xmlrpcd $SELFSERVICE_USER + echo "done." + + echo -n "Starting freeside-xmlrpcd: " + freeside-xmlrpcd $API_USER + echo "done." + +# echo -n "Starting freeside-jsonrpcd: " +# freeside-jsonrpcd $API_USER +# echo "done." + echo -n "Starting freeside-queued: " #perl -MDBIx::Profile /usr/local/bin/freeside-queued $QUEUED_USER freeside-queued $QUEUED_USER @@ -58,16 +78,6 @@ case "$1" in freeside-cdrrated $QUEUED_USER echo "done." - for MACHINE in $SELFSERVICE_MACHINES; do - echo -n "Starting freeside-selfservice-server to $MACHINE: " - freeside-selfservice-server $SELFSERVICE_USER $MACHINE - echo "done." - done - - echo -n "Starting freeside-selfservice-xmlrpcd: " - freeside-selfservice-xmlrpcd $SELFSERVICE_USER - echo "done." - if [ -e /usr/local/bin/torrus ]; then echo -n "Starting torrus collector: " /usr/local/bin/torrus collector --tree=main @@ -122,6 +132,30 @@ case "$1" in echo "done." fi + if [ -e /var/run/freeside/torrus-srvderive.pid ]; then + echo -n "Stopping freeside-torrus-srvderive: " + kill `cat /var/run/freeside/torrus-srvderive.pid` + echo "done." + fi + + if [ -e /var/run/torrus/collector.main_?.pid ]; then + echo -n "Stopping torrus collector: " + kill `cat /var/run/torrus/collector.main_?.pid` + echo "done." + fi + + if [ -e /var/run/freeside/xmlrpcd.pid ]; then + echo -n "Stopping freeside-xmlrpcd: " + kill `cat /var/run/freeside/xmlrpcd.pid` + echo "done." + fi + +# if [ -e /var/run/freeside/jsonrpcd.pid ]; then +# echo -n "Stopping freeside-jsonrpcd: " +# kill `cat /var/run/freeside/jsonrpcd.pid` +# echo "done." +# fi + if [ -e /var/run/freeside-selfservice-server.$SELFSERVICE_USER.pid ] then echo -n "Stopping (old) freeside-selfservice-server: " @@ -146,18 +180,6 @@ case "$1" in echo "done." fi - if [ -e /var/run/freeside/torrus-srvderive.pid ]; then - echo -n "Stopping freeside-torrus-srvderive: " - kill `cat /var/run/freeside/torrus-srvderive.pid` - echo "done." - fi - - if [ -e /var/run/torrus/collector.main_?.pid ]; then - echo -n "Stopping torrus collector: " - kill `cat /var/run/torrus/collector.main_?.pid` - echo "done." - fi - ;; restart) diff --git a/rt/Makefile.in b/rt/Makefile.in index 2823d5474..89d4bf1e6 100644 --- a/rt/Makefile.in +++ b/rt/Makefile.in @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -351,7 +351,7 @@ dirs: install: testdeps config-install dirs files-install fixperms instruct -files-install: libs-install etc-install config-install bin-install sbin-install html-install local-install doc-install font-install po-install +files-install: libs-install etc-install config-install bin-install sbin-install html-install doc-install font-install po-install config-install: @COMMENT_INPLACE_LAYOUT@ $(INSTALL) -m 0755 -o $(BIN_OWNER) -g $(RTGROUP) -d $(DESTDIR)$(CONFIG_FILE_PATH) @@ -461,25 +461,6 @@ bin-install: @COMMENT_INPLACE_LAYOUT@ $(INSTALL) -o $(BIN_OWNER) -g $(RTGROUP) -m 0755 "bin/$$file" "$(DESTDIR)$(RT_BIN_PATH)/" ; \ @COMMENT_INPLACE_LAYOUT@ done -local-install: - -( cd local/html && find . -type d -print ) | while read dir ; do \ - $(INSTALL) -m 0755 -d "$(DESTDIR)$(MASON_LOCAL_HTML_PATH)/$$dir" ; \ - done - -( cd local/html && find . -type f -print ) | while read file ; do \ - $(INSTALL) -m 0644 "local/html/$$file" "$(DESTDIR)$(MASON_LOCAL_HTML_PATH)/$$file" ; \ - done - -( cd local/po && find . -type d -print ) | while read dir ; do \ - $(INSTALL) -m 0755 -d "$(DESTDIR)$(LOCAL_LEXICON_PATH)/$$dir" ; \ - done - -( cd local/po && find . -type f -print ) | while read file ; do \ - $(INSTALL) -m 0644 "local/po/$$file" "$(DESTDIR)$(LOCAL_LEXICON_PATH)/$$file" ; \ - done - -( cd local/etc && find . -type d -print ) | while read dir ; do \ - $(INSTALL) -m 0755 -d "$(DESTDIR)$(LOCAL_ETC_PATH)/$$dir" ; \ - done - -( cd local/etc && find . -type f -print ) | while read file ; do \ - $(INSTALL) -m 0644 "etc/$$file" "$(DESTDIR)$(LOCAL_ETC_PATH)/$$file" ; \ - done regenerate-catalogs: @@ -295,7 +295,7 @@ fix them. To report a bug, send email to <rt-bugs@bestpractical.com>. # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -472,7 +472,7 @@ sub show { sub edit { my ($action) = @_; my (%data, $type, @objects); - my ($cl, $text, $edit, $input, $output); + my ($cl, $text, $edit, $input, $output, $content_type); use vars qw(%set %add %del); %set = %add = %del = (); @@ -486,6 +486,7 @@ sub edit { if (/^-e$/) { $edit = 1 } elsif (/^-i$/) { $input = 1 } elsif (/^-o$/) { $output = 1 } + elsif (/^-ct$/) { $content_type = shift @ARGV } elsif (/^-t$/) { $bad = 1, last unless defined($type = get_type_argument()); } @@ -655,24 +656,54 @@ sub edit { return 0; } + my @files; + @files = @{ vsplit($set{'attachment'}) } if exists $set{'attachment'}; + my $synerr = 0; EDIT: # We'll let the user edit the form before sending it to the server, # unless we have enough information to submit it non-interactively. + if ( $type && $type eq 'ticket' && $text !~ /^Content-Type:/m ) { + $text .= "Content-Type: $content_type\n" + if $content_type and $content_type ne "text/plain"; + } + if ($edit || (!$input && !$cl)) { - my $newtext = vi($text); + my ($newtext) = vi_form_while( + $text, + sub { + my ($text, $form) = @_; + return 1 unless exists $form->[2]{'Attachment'}; + + foreach my $f ( @{ vsplit($form->[2]{'Attachment'}) } ) { + return (0, "File '$f' doesn't exist") unless -f $f; + } + @files = @{ vsplit($form->[2]{'Attachment'}) }; + return 1; + }, + ); + return $newtext unless $newtext; # We won't resubmit a bad form unless it was changed. $text = ($synerr && $newtext eq $text) ? undef : $newtext; } + delete @data{ grep /^attachment_\d+$/, keys %data }; + my $i = 1; + foreach my $file (@files) { + $data{"attachment_$i"} = bless([ $file ], "Attachment"); + $i++; + } + if ($text) { my $r = submit("$REST/edit", {content => $text, %data}); if ($r->code == 409) { # If we submitted a bad form, we'll give the user a chance # to correct it and resubmit. if ($edit || (!$input && !$cl)) { - $text = $r->content; + my $content = $r->content . "\n"; + $content =~ s/^(?!#)/# /mg; + $text = $content . $text; $synerr = 1; goto EDIT; } @@ -738,7 +769,7 @@ sub setcommand { sub comment { my ($action) = @_; - my (%data, $id, @files, @bcc, @cc, $msg, $wtime, $edit); + my (%data, $id, @files, @bcc, @cc, $msg, $content_type, $wtime, $edit); my $bad = 0; while (@ARGV) { @@ -747,7 +778,7 @@ sub comment { if (/^-e$/) { $edit = 1; } - elsif (/^-[abcmw]$/) { + elsif (/^-(?:[abcmw]|ct)$/) { unless (@ARGV) { whine "No argument specified with $_."; $bad = 1; last; @@ -760,6 +791,9 @@ sub comment { } push @files, shift @ARGV; } + elsif (/-ct/) { + $content_type = shift @ARGV; + } elsif (/-([bc])/) { my $a = $_ eq "-b" ? \@bcc : \@cc; @$a = split /\s*,\s*/, shift @ARGV; @@ -771,7 +805,6 @@ sub comment { while (<STDIN>) { $msg .= $_ } } } - elsif (/-w/) { $wtime = shift @ARGV } } elsif (!$id && m|^(?:ticket/)?($idlist)$|) { @@ -793,7 +826,7 @@ sub comment { my $form = [ "", - [ "Ticket", "Action", "Cc", "Bcc", "Attachment", "TimeWorked", "Text" ], + [ "Ticket", "Action", "Cc", "Bcc", "Attachment", "TimeWorked", "Content-Type", "Text" ], { Ticket => $id, Action => $action, @@ -801,6 +834,7 @@ sub comment { Bcc => [ @bcc ], Attachment => [ @files ], TimeWorked => $wtime || '', + 'Content-Type' => $content_type || 'text/plain', Text => $msg || '', Status => '' } @@ -809,30 +843,19 @@ sub comment { my $text = Form::compose([ $form ]); if ($edit || !$msg) { - my $error = 0; - my ($c, $o, $k, $e); - - do { - my $ntext = vi($text); - return if ($error && $ntext eq $text); - $text = $ntext; - $form = Form::parse($text); - $error = 0; - - ($c, $o, $k, $e) = @{ $form->[0] }; - if ($e) { - $error = 1; - $c = "# Syntax error."; - goto NEXT; - } - elsif (!@$o) { - return 0; - } - @files = @{ vsplit($k->{Attachment}) }; - - NEXT: - $text = Form::compose([[$c, $o, $k, $e]]); - } while ($error); + my ($tmp) = vi_form_while( + $text, + sub { + my ($text, $form) = @_; + foreach my $f ( @{ vsplit($form->[2]{'Attachment'}) } ) { + return (0, "File '$f' doesn't exist") unless -f $f; + } + @files = @{ vsplit($form->[2]{'Attachment'}) }; + return 1; + }, + ); + return $tmp unless $tmp; + $text = $tmp; } my $i = 1; @@ -1466,6 +1489,43 @@ sub read_passwd { return $passwd; } +sub vi_form_while { + my $text = shift; + my $cb = shift; + + my $error = 0; + my ($c, $o, $k, $e); + do { + my $ntext = vi($text); + return undef if ($error && $ntext eq $text); + + $text = $ntext; + + my $form = Form::parse($text); + $error = 0; + ($c, $o, $k, $e) = @{ $form->[0] }; + if ( $e ) { + $error = 1; + $c = "# Syntax error."; + goto NEXT; + } + elsif (!@$o) { + return 0; + } + + my ($status, $msg) = $cb->( $text, [$c, $o, $k, $e] ); + unless ( $status ) { + $error = 1; + $c = "# $msg"; + } + + NEXT: + $text = Form::compose([[$c, $o, $k, $e]]); + } while ($error); + + return $text; +} + sub vi { my ($text) = @_; my $editor = $ENV{EDITOR} || $ENV{VISUAL} || "vi"; @@ -1525,15 +1585,15 @@ sub vsplit { } push @words, $s; } - elsif ( $a =~ /^q{/ ) { + elsif ( $a =~ /^q\{/ ) { my $s = $a; - while ( $a !~ /}$/ ) { + while ( $a !~ /\}$/ ) { ( $a, $b ) = split /\s*,\s*/, $b, 2; $s .= ',' . $a; } - $s =~ s/^q{/'/; - $s =~ s/}/'/; + $s =~ s/^q\{/'/; + $s =~ s/\}/'/; push @words, $s; } else { @@ -2273,12 +2333,14 @@ Text: -S var=val Submits the specified variable with the request. -t type Specifies object type. + -ct content-type Specifies content type of message(tickets only). Examples: # Interactive (starts $EDITOR with a form). rt edit ticket/3 rt create -t ticket + rt create -t ticket -ct text/html # Non-interactive. rt edit ticket/1-3 add cc=foo@example.com set priority=3 due=tomorrow @@ -2310,6 +2372,7 @@ Text: Options: -m <text> Specify comment text. + -ct <content-type> Specify content-type of comment text. -a <file> Attach a file to the comment. (May be used more than once to attach multiple files.) -c <addrs> A comma-separated list of Cc addresses. diff --git a/rt/bin/rt-crontool.in b/rt/bin/rt-crontool.in index 5498da751..e2026985a 100644 --- a/rt/bin/rt-crontool.in +++ b/rt/bin/rt-crontool.in @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/bin/rt-mailgate.in b/rt/bin/rt-mailgate.in index be1c03224..df2ab5a8b 100644 --- a/rt/bin/rt-mailgate.in +++ b/rt/bin/rt-mailgate.in @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/bin/rt.in b/rt/bin/rt.in index 4a3eadadf..480f178b4 100644 --- a/rt/bin/rt.in +++ b/rt/bin/rt.in @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -472,7 +472,7 @@ sub show { sub edit { my ($action) = @_; my (%data, $type, @objects); - my ($cl, $text, $edit, $input, $output); + my ($cl, $text, $edit, $input, $output, $content_type); use vars qw(%set %add %del); %set = %add = %del = (); @@ -486,6 +486,7 @@ sub edit { if (/^-e$/) { $edit = 1 } elsif (/^-i$/) { $input = 1 } elsif (/^-o$/) { $output = 1 } + elsif (/^-ct$/) { $content_type = shift @ARGV } elsif (/^-t$/) { $bad = 1, last unless defined($type = get_type_argument()); } @@ -655,24 +656,54 @@ sub edit { return 0; } + my @files; + @files = @{ vsplit($set{'attachment'}) } if exists $set{'attachment'}; + my $synerr = 0; EDIT: # We'll let the user edit the form before sending it to the server, # unless we have enough information to submit it non-interactively. + if ( $type && $type eq 'ticket' && $text !~ /^Content-Type:/m ) { + $text .= "Content-Type: $content_type\n" + if $content_type and $content_type ne "text/plain"; + } + if ($edit || (!$input && !$cl)) { - my $newtext = vi($text); + my ($newtext) = vi_form_while( + $text, + sub { + my ($text, $form) = @_; + return 1 unless exists $form->[2]{'Attachment'}; + + foreach my $f ( @{ vsplit($form->[2]{'Attachment'}) } ) { + return (0, "File '$f' doesn't exist") unless -f $f; + } + @files = @{ vsplit($form->[2]{'Attachment'}) }; + return 1; + }, + ); + return $newtext unless $newtext; # We won't resubmit a bad form unless it was changed. $text = ($synerr && $newtext eq $text) ? undef : $newtext; } + delete @data{ grep /^attachment_\d+$/, keys %data }; + my $i = 1; + foreach my $file (@files) { + $data{"attachment_$i"} = bless([ $file ], "Attachment"); + $i++; + } + if ($text) { my $r = submit("$REST/edit", {content => $text, %data}); if ($r->code == 409) { # If we submitted a bad form, we'll give the user a chance # to correct it and resubmit. if ($edit || (!$input && !$cl)) { - $text = $r->content; + my $content = $r->content . "\n"; + $content =~ s/^(?!#)/# /mg; + $text = $content . $text; $synerr = 1; goto EDIT; } @@ -738,7 +769,7 @@ sub setcommand { sub comment { my ($action) = @_; - my (%data, $id, @files, @bcc, @cc, $msg, $wtime, $edit); + my (%data, $id, @files, @bcc, @cc, $msg, $content_type, $wtime, $edit); my $bad = 0; while (@ARGV) { @@ -747,7 +778,7 @@ sub comment { if (/^-e$/) { $edit = 1; } - elsif (/^-[abcmw]$/) { + elsif (/^-(?:[abcmw]|ct)$/) { unless (@ARGV) { whine "No argument specified with $_."; $bad = 1; last; @@ -760,6 +791,9 @@ sub comment { } push @files, shift @ARGV; } + elsif (/-ct/) { + $content_type = shift @ARGV; + } elsif (/-([bc])/) { my $a = $_ eq "-b" ? \@bcc : \@cc; @$a = split /\s*,\s*/, shift @ARGV; @@ -771,7 +805,6 @@ sub comment { while (<STDIN>) { $msg .= $_ } } } - elsif (/-w/) { $wtime = shift @ARGV } } elsif (!$id && m|^(?:ticket/)?($idlist)$|) { @@ -793,7 +826,7 @@ sub comment { my $form = [ "", - [ "Ticket", "Action", "Cc", "Bcc", "Attachment", "TimeWorked", "Text" ], + [ "Ticket", "Action", "Cc", "Bcc", "Attachment", "TimeWorked", "Content-Type", "Text" ], { Ticket => $id, Action => $action, @@ -801,6 +834,7 @@ sub comment { Bcc => [ @bcc ], Attachment => [ @files ], TimeWorked => $wtime || '', + 'Content-Type' => $content_type || 'text/plain', Text => $msg || '', Status => '' } @@ -809,30 +843,19 @@ sub comment { my $text = Form::compose([ $form ]); if ($edit || !$msg) { - my $error = 0; - my ($c, $o, $k, $e); - - do { - my $ntext = vi($text); - return if ($error && $ntext eq $text); - $text = $ntext; - $form = Form::parse($text); - $error = 0; - - ($c, $o, $k, $e) = @{ $form->[0] }; - if ($e) { - $error = 1; - $c = "# Syntax error."; - goto NEXT; - } - elsif (!@$o) { - return 0; - } - @files = @{ vsplit($k->{Attachment}) }; - - NEXT: - $text = Form::compose([[$c, $o, $k, $e]]); - } while ($error); + my ($tmp) = vi_form_while( + $text, + sub { + my ($text, $form) = @_; + foreach my $f ( @{ vsplit($form->[2]{'Attachment'}) } ) { + return (0, "File '$f' doesn't exist") unless -f $f; + } + @files = @{ vsplit($form->[2]{'Attachment'}) }; + return 1; + }, + ); + return $tmp unless $tmp; + $text = $tmp; } my $i = 1; @@ -1466,6 +1489,43 @@ sub read_passwd { return $passwd; } +sub vi_form_while { + my $text = shift; + my $cb = shift; + + my $error = 0; + my ($c, $o, $k, $e); + do { + my $ntext = vi($text); + return undef if ($error && $ntext eq $text); + + $text = $ntext; + + my $form = Form::parse($text); + $error = 0; + ($c, $o, $k, $e) = @{ $form->[0] }; + if ( $e ) { + $error = 1; + $c = "# Syntax error."; + goto NEXT; + } + elsif (!@$o) { + return 0; + } + + my ($status, $msg) = $cb->( $text, [$c, $o, $k, $e] ); + unless ( $status ) { + $error = 1; + $c = "# $msg"; + } + + NEXT: + $text = Form::compose([[$c, $o, $k, $e]]); + } while ($error); + + return $text; +} + sub vi { my ($text) = @_; my $editor = $ENV{EDITOR} || $ENV{VISUAL} || "vi"; @@ -1525,15 +1585,15 @@ sub vsplit { } push @words, $s; } - elsif ( $a =~ /^q{/ ) { + elsif ( $a =~ /^q\{/ ) { my $s = $a; - while ( $a !~ /}$/ ) { + while ( $a !~ /\}$/ ) { ( $a, $b ) = split /\s*,\s*/, $b, 2; $s .= ',' . $a; } - $s =~ s/^q{/'/; - $s =~ s/}/'/; + $s =~ s/^q\{/'/; + $s =~ s/\}/'/; push @words, $s; } else { @@ -2273,12 +2333,14 @@ Text: -S var=val Submits the specified variable with the request. -t type Specifies object type. + -ct content-type Specifies content type of message(tickets only). Examples: # Interactive (starts $EDITOR with a form). rt edit ticket/3 rt create -t ticket + rt create -t ticket -ct text/html # Non-interactive. rt edit ticket/1-3 add cc=foo@example.com set priority=3 due=tomorrow @@ -2310,6 +2372,7 @@ Text: Options: -m <text> Specify comment text. + -ct <content-type> Specify content-type of comment text. -a <file> Attach a file to the comment. (May be used more than once to attach multiple files.) -c <addrs> A comma-separated list of Cc addresses. diff --git a/rt/configure b/rt/configure index d37616745..3abb324ba 100755 --- a/rt/configure +++ b/rt/configure @@ -1,7 +1,7 @@ #! /bin/sh # From configure.ac Revision. # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.68 for RT rt-4.0.13. +# Generated by GNU Autoconf 2.68 for RT rt-4.0.19. # # Report bugs to <rt-bugs@bestpractical.com>. # @@ -560,8 +560,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='RT' PACKAGE_TARNAME='rt' -PACKAGE_VERSION='rt-4.0.13' -PACKAGE_STRING='RT rt-4.0.13' +PACKAGE_VERSION='rt-4.0.19' +PACKAGE_STRING='RT rt-4.0.19' PACKAGE_BUGREPORT='rt-bugs@bestpractical.com' PACKAGE_URL='' @@ -1311,7 +1311,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures RT rt-4.0.13 to adapt to many kinds of systems. +\`configure' configures RT rt-4.0.19 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1372,7 +1372,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of RT rt-4.0.13:";; + short | recursive ) echo "Configuration of RT rt-4.0.19:";; esac cat <<\_ACEOF @@ -1496,7 +1496,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -RT configure rt-4.0.13 +RT configure rt-4.0.19 generated by GNU Autoconf 2.68 Copyright (C) 2010 Free Software Foundation, Inc. @@ -1597,7 +1597,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by RT $as_me rt-4.0.13, which was +It was created by RT $as_me rt-4.0.19, which was generated by GNU Autoconf 2.68. Invocation command line was $ $0 $@ @@ -1954,7 +1954,7 @@ rt_version_major=4 rt_version_minor=0 -rt_version_patch=13 +rt_version_patch=19 test "x$rt_version_major" = 'x' && rt_version_major=0 test "x$rt_version_minor" = 'x' && rt_version_minor=0 @@ -3923,7 +3923,7 @@ RT_LOG_PATH_R=${exp_logfiledir} fi -ac_config_files="$ac_config_files etc/upgrade/3.8-branded-queues-extension etc/upgrade/3.8-ical-extension etc/upgrade/split-out-cf-categories etc/upgrade/generate-rtaddressregexp etc/upgrade/upgrade-articles etc/upgrade/vulnerable-passwords sbin/rt-attributes-viewer sbin/rt-preferences-viewer sbin/rt-session-viewer sbin/rt-dump-metadata sbin/rt-setup-database sbin/rt-test-dependencies sbin/rt-email-digest sbin/rt-email-dashboards sbin/rt-clean-sessions sbin/rt-shredder sbin/rt-validator sbin/rt-validate-aliases sbin/rt-email-group-admin sbin/rt-server sbin/rt-server.fcgi sbin/standalone_httpd sbin/rt-setup-fulltext-index sbin/rt-fulltext-indexer bin/rt-crontool bin/rt-mailgate bin/rt" +ac_config_files="$ac_config_files etc/upgrade/3.8-ical-extension etc/upgrade/split-out-cf-categories etc/upgrade/generate-rtaddressregexp etc/upgrade/upgrade-articles etc/upgrade/vulnerable-passwords sbin/rt-attributes-viewer sbin/rt-preferences-viewer sbin/rt-session-viewer sbin/rt-dump-metadata sbin/rt-setup-database sbin/rt-test-dependencies sbin/rt-email-digest sbin/rt-email-dashboards sbin/rt-clean-sessions sbin/rt-shredder sbin/rt-validator sbin/rt-validate-aliases sbin/rt-email-group-admin sbin/rt-server sbin/rt-server.fcgi sbin/standalone_httpd sbin/rt-setup-fulltext-index sbin/rt-fulltext-indexer bin/rt-crontool bin/rt-mailgate bin/rt" ac_config_files="$ac_config_files Makefile etc/RT_Config.pm lib/RT/Generated.pm t/data/configs/apache2.2+mod_perl.conf t/data/configs/apache2.2+fastcgi.conf" @@ -4482,7 +4482,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by RT $as_me rt-4.0.13, which was +This file was extended by RT $as_me rt-4.0.19, which was generated by GNU Autoconf 2.68. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -4535,7 +4535,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -RT config.status rt-4.0.13 +RT config.status rt-4.0.19 configured by $0, generated by GNU Autoconf 2.68, with options \\"\$ac_cs_config\\" @@ -4646,7 +4646,6 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 for ac_config_target in $ac_config_targets do case $ac_config_target in - "etc/upgrade/3.8-branded-queues-extension") CONFIG_FILES="$CONFIG_FILES etc/upgrade/3.8-branded-queues-extension" ;; "etc/upgrade/3.8-ical-extension") CONFIG_FILES="$CONFIG_FILES etc/upgrade/3.8-ical-extension" ;; "etc/upgrade/split-out-cf-categories") CONFIG_FILES="$CONFIG_FILES etc/upgrade/split-out-cf-categories" ;; "etc/upgrade/generate-rtaddressregexp") CONFIG_FILES="$CONFIG_FILES etc/upgrade/generate-rtaddressregexp" ;; @@ -5098,8 +5097,6 @@ which seems to be undefined. Please make sure it is defined" >&2;} case $ac_file$ac_mode in - "etc/upgrade/3.8-branded-queues-extension":F) chmod ug+x $ac_file - ;; "etc/upgrade/3.8-ical-extension":F) chmod ug+x $ac_file ;; "etc/upgrade/split-out-cf-categories":F) chmod ug+x $ac_file diff --git a/rt/configure.ac b/rt/configure.ac index a168e285c..47ec7c954 100644 --- a/rt/configure.ac +++ b/rt/configure.ac @@ -407,7 +407,6 @@ dnl Configure the output files, and generate them. dnl Binaries that should be +x AC_CONFIG_FILES([ - etc/upgrade/3.8-branded-queues-extension etc/upgrade/3.8-ical-extension etc/upgrade/split-out-cf-categories etc/upgrade/generate-rtaddressregexp diff --git a/rt/devel/tools/change-loc-msgstr b/rt/devel/tools/change-loc-msgstr index 9eb9ac697..bd1892a85 100644 --- a/rt/devel/tools/change-loc-msgstr +++ b/rt/devel/tools/change-loc-msgstr @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/devel/tools/extract-message-catalog b/rt/devel/tools/extract-message-catalog index b95c99047..0afec0b2c 100644 --- a/rt/devel/tools/extract-message-catalog +++ b/rt/devel/tools/extract-message-catalog @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/devel/tools/factory b/rt/devel/tools/factory index 5f9c49b46..5d05d0853 100644 --- a/rt/devel/tools/factory +++ b/rt/devel/tools/factory @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/devel/tools/license_tag b/rt/devel/tools/license_tag index 05bcf83e9..4cf09174a 100644 --- a/rt/devel/tools/license_tag +++ b/rt/devel/tools/license_tag @@ -5,7 +5,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -54,7 +54,7 @@ my $LICENSE = <<'EOL'; COPYRIGHT: -This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC <sales@bestpractical.com> (Except where explicitly superseded by other copyright notices) @@ -103,12 +103,15 @@ use File::Find; my @MAKE = qw(Makefile); File::Find::find({ no_chdir => 1, wanted => \&tag_pm}, 'lib'); -File::Find::find({ no_chdir => 1, wanted => \&tag_mason}, 'share/html'); -File::Find::find({ no_chdir => 1, wanted => \&tag_script}, 'sbin'); -File::Find::find({ no_chdir => 1, wanted => \&tag_script}, 'bin'); -File::Find::find({ no_chdir => 1, wanted => \&tag_script}, 'etc/upgrade'); -File::Find::find({ no_chdir => 1, wanted => \&tag_script}, 'devel/tools'); -tag_makefile ('Makefile.in'); +for my $masondir (qw( html share/html )) { + next unless -d $masondir; + File::Find::find({ no_chdir => 1, wanted => \&tag_mason}, $masondir); +} +for my $bindir (qw( sbin bin etc/upgrade devel/tools )) { + next unless -d $bindir; + File::Find::find({ no_chdir => 1, wanted => \&tag_script}, $bindir); +} +tag_makefile ('Makefile.in') if -f 'Makefile.in'; tag_makefile ('README'); @@ -125,16 +128,16 @@ sub tag_mason { my $pmlic = $LICENSE; $pmlic =~ s/^/%# /mg; $pmlic =~ s/\s*$//mg; - if ($file =~ /^%# BEGIN BPS TAGGED BLOCK {{{/ms) { + if ($file =~ /^%# BEGIN BPS TAGGED BLOCK \{\{\{/ms) { print "has license section"; - $file =~ s/^%# BEGIN BPS TAGGED BLOCK {{{(.*?)%# END BPS TAGGED BLOCK }}}/%# BEGIN BPS TAGGED BLOCK {{{\n$pmlic\n%# END BPS TAGGED BLOCK }}}/ms; + $file =~ s/^%# BEGIN BPS TAGGED BLOCK \{\{\{(.*?)%# END BPS TAGGED BLOCK \}\}\}/%# BEGIN BPS TAGGED BLOCK {{{\n$pmlic\n%# END BPS TAGGED BLOCK }}}/ms; } else { print "no license section"; $file ="%# BEGIN BPS TAGGED BLOCK {{{\n$pmlic\n%# END BPS TAGGED BLOCK }}}\n". $file; } - $file =~ s/%# END BPS TAGGED BLOCK }}}(\n+)/%# END BPS TAGGED BLOCK }}}\n/mg; + $file =~ s/%# END BPS TAGGED BLOCK \}\}\}(\n+)/%# END BPS TAGGED BLOCK }}}\n/mg; print "\n"; @@ -158,16 +161,16 @@ sub tag_makefile { my $pmlic = $LICENSE; $pmlic =~ s/^/# /mg; $pmlic =~ s/\s*$//mg; - if ($file =~ /^# BEGIN BPS TAGGED BLOCK {{{/ms) { + if ($file =~ /^# BEGIN BPS TAGGED BLOCK \{\{\{/ms) { print "has license section"; - $file =~ s/^# BEGIN BPS TAGGED BLOCK {{{(.*?)# END BPS TAGGED BLOCK }}}/# BEGIN BPS TAGGED BLOCK {{{\n$pmlic\n# END BPS TAGGED BLOCK }}}/ms; + $file =~ s/^# BEGIN BPS TAGGED BLOCK \{\{\{(.*?)# END BPS TAGGED BLOCK \}\}\}/# BEGIN BPS TAGGED BLOCK {{{\n$pmlic\n# END BPS TAGGED BLOCK }}}/ms; } else { print "no license section"; $file ="# BEGIN BPS TAGGED BLOCK {{{\n$pmlic\n# END BPS TAGGED BLOCK }}}\n". $file; } - $file =~ s/# END BPS TAGGED BLOCK }}}(\n+)/# END BPS TAGGED BLOCK }}}\n/mg; + $file =~ s/# END BPS TAGGED BLOCK \}\}\}(\n+)/# END BPS TAGGED BLOCK }}}\n/mg; print "\n"; @@ -182,7 +185,7 @@ sub tag_makefile { sub tag_pm { my $pm = $_; - next unless $pm =~ /\.pm/s; + return unless $pm =~ /\.pm/s; open( FILE, '<', $pm ) or die "Failed to open $pm"; my $file = (join "", <FILE>); close (FILE); @@ -192,16 +195,16 @@ sub tag_pm { my $pmlic = $LICENSE; $pmlic =~ s/^/# /mg; $pmlic =~ s/\s*$//mg; - if ($file =~ /^# BEGIN BPS TAGGED BLOCK {{{/ms) { + if ($file =~ /^# BEGIN BPS TAGGED BLOCK \{\{\{/ms) { print "has license section"; - $file =~ s/^# BEGIN BPS TAGGED BLOCK {{{(.*?)# END BPS TAGGED BLOCK }}}/# BEGIN BPS TAGGED BLOCK {{{\n$pmlic\n# END BPS TAGGED BLOCK }}}/ms; + $file =~ s/^# BEGIN BPS TAGGED BLOCK \{\{\{(.*?)# END BPS TAGGED BLOCK \}\}\}/# BEGIN BPS TAGGED BLOCK {{{\n$pmlic\n# END BPS TAGGED BLOCK }}}/ms; } else { print "no license section"; $file ="# BEGIN BPS TAGGED BLOCK {{{\n$pmlic\n# END BPS TAGGED BLOCK }}}\n". $file; } - $file =~ s/# END BPS TAGGED BLOCK }}}(\n+)/# END BPS TAGGED BLOCK }}}\n\n/mg; + $file =~ s/# END BPS TAGGED BLOCK \}\}\}(\n+)/# END BPS TAGGED BLOCK }}}\n\n/mg; print "\n"; @@ -226,9 +229,9 @@ sub tag_script { my $pmlic = $LICENSE; $pmlic =~ s/^/# /msg; $pmlic =~ s/\s*$//mg; - if ($file =~ /^# BEGIN BPS TAGGED BLOCK {{{/ms) { + if ($file =~ /^# BEGIN BPS TAGGED BLOCK \{\{\{/ms) { print "has license section"; - $file =~ s/^# BEGIN BPS TAGGED BLOCK {{{(.*?)# END BPS TAGGED BLOCK }}}/# BEGIN BPS TAGGED BLOCK {{{\n$pmlic\n# END BPS TAGGED BLOCK }}}/ms; + $file =~ s/^# BEGIN BPS TAGGED BLOCK \{\{\{(.*?)# END BPS TAGGED BLOCK \}\}\}/# BEGIN BPS TAGGED BLOCK {{{\n$pmlic\n# END BPS TAGGED BLOCK }}}/ms; } else { @@ -240,7 +243,7 @@ sub tag_script { } } - $file =~ s/# END BPS TAGGED BLOCK }}}(\n+)/# END BPS TAGGED BLOCK }}}\n/mg; + $file =~ s/# END BPS TAGGED BLOCK \}\}\}(\n+)/# END BPS TAGGED BLOCK }}}\n/mg; print "\n"; diff --git a/rt/devel/tools/merge-rosetta.pl b/rt/devel/tools/merge-rosetta.pl index a0ef3e2a7..ec587add2 100644 --- a/rt/devel/tools/merge-rosetta.pl +++ b/rt/devel/tools/merge-rosetta.pl @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/devel/tools/rt-attributes-editor b/rt/devel/tools/rt-attributes-editor index d3443177a..92998a472 100644 --- a/rt/devel/tools/rt-attributes-editor +++ b/rt/devel/tools/rt-attributes-editor @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/devel/tools/tweak-template-locstring b/rt/devel/tools/tweak-template-locstring index d77ef9e94..ca44d39db 100644 --- a/rt/devel/tools/tweak-template-locstring +++ b/rt/devel/tools/tweak-template-locstring @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/docs/UPGRADING-3.8 b/rt/docs/UPGRADING-3.8 index cfe01dfbf..ba7177764 100644 --- a/rt/docs/UPGRADING-3.8 +++ b/rt/docs/UPGRADING-3.8 @@ -168,11 +168,7 @@ Change this line to read: been assigned an ID of { $Ticket->SubjectTag }." If you were previously using RT::Extension::BrandedQueues, you MUST uninstall -it before upgrading. In addition, you must run the -'etc/upgrade/3.8-branded-queues-extension' perl script. This will -convert the extension's configuration into the new format. Finally, in -templates where you were using the Tag method ($Ticket->QueueObj->Tag), -you will need to replace it with $Ticket->SubjectTag +it before upgrading. RT::Action::LinearEscalate extension has been integrated into core, so you MUST uninstall it before upgrading. diff --git a/rt/docs/UPGRADING-4.0 b/rt/docs/UPGRADING-4.0 index 687dfbc61..63dd2eecc 100644 --- a/rt/docs/UPGRADING-4.0 +++ b/rt/docs/UPGRADING-4.0 @@ -126,6 +126,14 @@ database level. =back +=head2 Ticket content searches (full text search) + +Since 4.0.0, RT's ticket content search is disabled by default because of +performance issues when used without full text indexing. For details on how to +re-enable it with (or without) full text indexing, see +F<docs/full_text_indexing.pod>. + + =head1 UPGRADING FROM 4.0.5 AND EARLIER @@ -189,3 +197,52 @@ these types before insertion. Site-specific custom types (anything but ticket, reminder or approval) are not affected by these changes. + +=head1 UPGRADING FROM 4.0.13 AND EARLIER + +=head2 Outgoing mail From: header + +The "Default" key of the C<$OverrideOutgoingMailFrom> config option now, +as previously documented, only applies when no ticket is involved. +Previously it was also used when a ticket was involved but the +associated queue had no specific correspond address. In such cases the +global correspond address is now used. + +The config option C<$SetOutgoingMailFrom> now accepts an email address +as a value which will act as a global default. This covers the simple +case of sending all bounces to a specific address, without the previous +solution of resorting to defining all queues in +$OverrideOutgoingMailFrom. Any definitions in the Override option +(including Default) still take precedence. See +L<RT_Config/$SetOutgoingMailFrom> for more information. + +=head2 Reminder statuses + +New reminders are now created in the "reminder_on_open" status defined in your +lifecycles. For the default lifecycle, this means reminders will start as +"open" instead of "new". This change is for consistency when a completed +reminder is reopened at a later date. If you use custom lifecycles and added +further transition restrictions, you may need to adjust the L<"reminder_on_open" +setting|RT_Config/reminder_on_open> in your lifecycles. + +=head2 Bookmarks + +Previously, the list of Bookmarks on your homepage was unlimited (if you +had 100 bookmarked tickets, you would see a 100 item list on your RT at +a Glance). 'Bookmarked Tickets' now uses the same size limits as any +other search on your homepage. This can be customized using the 'Rows +per box' setting on your RT at a Glance configuration page. + +=head2 PostgreSQL 9.2 + +If you are upgrading an RT from 3.8 (or earlier) to 4.0 on PostgreSQL +9.2, you should make sure that you have installed DBD::Pg 2.19.3 or +higher. If you start your upgrade without installing a recent-enough +version of DBD::Pg RT will stop the upgrade during the 3.9.8 step and +remind you to upgrade DBD::Pg. If this happens, you can re-start your +upgrade by running: + + ./sbin/rt-setup-database --action insert --datadir etc/upgrade/3.9.8/ + +Followed by re-running make upgrade-database and answering 3.9.8 when +prompted for which RT version you're upgrading from. diff --git a/rt/etc/RT_Config.pm.in b/rt/etc/RT_Config.pm.in index 36a4c3014..a52965a9d 100644 --- a/rt/etc/RT_Config.pm.in +++ b/rt/etc/RT_Config.pm.in @@ -388,9 +388,10 @@ already, you can generate a naive first pass regexp by using: perl etc/upgrade/generate-rtaddressregexp -If left blank, RT will generate a regexp for you, based on your -comment and correspond address settings on your queues; this comes at -a small cost in start-up speed. +If left blank, RT will compare each address to your configured +C<$CorrespondAddress> and C<$CommentAddress> before searching for a +Queue configured with a matching "Reply Address" or "Comment Address" +on the Queue Admin page. =cut @@ -524,6 +525,15 @@ world, you can set C<$MailCommand> to 'testfile' which writes all mail to a temporary file. RT will log the location of the temporary file so you can extract mail from it afterward. +On shutdown, RT will clean up the temporary file created when using +the 'testfile' option. If testing while the RT server is still running, +you can find the files in the location noted in the log file. If you run +a tool like C<rt-crontool> however, or if you look after stopping the server, +the files will have been deleted when the process completed. If you need to +keep the files for development or debugging, you can manually set +C<< UNLINK => 0 >> where the testfile config is processed in +F<lib/RT/Interface/Email.pm>. + =cut #Set($MailCommand, "sendmailpipe"); @@ -537,6 +547,12 @@ Correspond mail address of the ticket's queue. Warning: If you use this setting, bounced mails will appear to be incoming mail to the system, thus creating new tickets. +If the value contains an C<@>, it is assumed to be an email address and used as +a global envelope sender. Expected usage in this case is to simply set the +same envelope sender on all mail from RT, without defining +C<$OverrideOutgoingMailFrom>. If you do define C<$OverrideOutgoingMailFrom>, +anything specified there overrides the global value (including Default). + This option only works if C<$MailCommand> is set to 'sendmailpipe'. =cut @@ -1220,7 +1236,7 @@ Set ($DefaultSearchResultFormat, qq{ OwnerName, Priority, '__NEWLINE__', - '', + '__NBSP__', '<small>__Requestors__</small>', '<small>__CustomerTags__</small>', '<small>__CreatedRelative__</small>', @@ -1733,9 +1749,11 @@ Set(@Active_MakeClicky, qw()); If C<$ParseNewMessageForTicketCcs> is set to 1, RT will attempt to divine Ticket 'Cc' watchers from the To and Cc lines of incoming -messages. Be forewarned that if you have I<any> addresses which forward -mail to RT automatically and you enable this option without modifying -C<$RTAddressRegexp> below, you will get yourself into a heap of trouble. +messages that create new Tickets. This option does not apply to replies +or comments on existing Tickets. Be forewarned that if you have I<any> +addresses which forward mail to RT automatically and you enable this +option without modifying C<$RTAddressRegexp> below, you will get +yourself into a heap of trouble. =cut @@ -2189,7 +2207,7 @@ Set(%GnuPGOptions, # 'auto-key-locate' => 'keyserver', # enables the automatic retrieving of keys when verifying signatures -# 'auto-key-retrieve' => undef, +# 'keyserver-options' => 'auto-key-retrieve', ); =back diff --git a/rt/etc/schema.mysql b/rt/etc/schema.mysql index 9ed0337aa..e0ccecb52 100644 --- a/rt/etc/schema.mysql +++ b/rt/etc/schema.mysql @@ -22,9 +22,9 @@ CREATE TABLE Queues ( id INTEGER NOT NULL AUTO_INCREMENT, Name varchar(200) NOT NULL , Description varchar(255) NULL , - CorrespondAddress varchar(120) CHARACTER SET ascii NULL, - CommentAddress varchar(120) CHARACTER SET ascii NULL, - Lifecycle varchar(32) CHARACTER SET ascii NULL, + CorrespondAddress varchar(120) NULL, + CommentAddress varchar(120) NULL, + Lifecycle varchar(32) NULL, SubjectTag varchar(120) NULL, InitialPriority integer NOT NULL DEFAULT 0 , FinalPriority integer NOT NULL DEFAULT 0 , diff --git a/rt/etc/upgrade/3.7.19/content b/rt/etc/upgrade/3.7.19/content index 31ab1c84a..ff43dd053 100644 --- a/rt/etc/upgrade/3.7.19/content +++ b/rt/etc/upgrade/3.7.19/content @@ -24,14 +24,25 @@ sub add_description_to_all_scrips { sub gen_scrip_description { my $scrip = shift; - my $condition = $scrip->ConditionObj->Name + + my $condition; + eval{ + $condition = $scrip->ConditionObj->Name || $scrip->ConditionObj->Description - || ('On Condition #'. $scrip->Condition); + || ('On Condition #'. $scrip->Condition); + }; + + if ($@){ + print STDERR $@; + print STDERR "Reference to missing scrip condition found. If you have ScripCondition = 0 in the Scrips table, update with a real condition number.\n"; + $condition = 'On undefined Condition # 0'; + } + my $action = $scrip->ActionObj->Name || $scrip->ActionObj->Description || ('Run Action #'. $scrip->Action); return join ' ', $condition, $action; -} + } } 1; diff --git a/rt/etc/upgrade/3.8-ical-extension.in b/rt/etc/upgrade/3.8-ical-extension.in index 0bbba7b2d..47b184682 100644 --- a/rt/etc/upgrade/3.8-ical-extension.in +++ b/rt/etc/upgrade/3.8-ical-extension.in @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/etc/upgrade/3.9.8/content b/rt/etc/upgrade/3.9.8/content index db717cd95..24242fda2 100644 --- a/rt/etc/upgrade/3.9.8/content +++ b/rt/etc/upgrade/3.9.8/content @@ -1,9 +1,6 @@ @Initial = sub { - my $dbh = $RT::Handle->dbh; - my $sth = $dbh->table_info( '', undef, undef, "'TABLE'"); my $found_fm_tables = {}; - while ( my $table = $sth->fetchrow_hashref ) { - my $name = $table->{TABLE_NAME} || $table->{table_name}; + foreach my $name ( $RT::Handle->_TableNames ) { next unless $name =~ /^fm_/i; $found_fm_tables->{lc $name}++; } @@ -16,6 +13,7 @@ $RT::Logger->error("We found RTFM tables in your database. Checking for content."); + my $dbh = $RT::Handle->dbh; my $result = $dbh->selectall_arrayref("SELECT count(*) AS articlecount FROM FM_Articles", { Slice => {} } ); if ($result->[0]{articlecount} > 0) { diff --git a/rt/etc/upgrade/generate-rtaddressregexp.in b/rt/etc/upgrade/generate-rtaddressregexp.in index 751122a99..a6be3f59a 100644 --- a/rt/etc/upgrade/generate-rtaddressregexp.in +++ b/rt/etc/upgrade/generate-rtaddressregexp.in @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/etc/upgrade/sanity-check-stylesheets.pl b/rt/etc/upgrade/sanity-check-stylesheets.pl index 6ae1cc61c..3171bda80 100644 --- a/rt/etc/upgrade/sanity-check-stylesheets.pl +++ b/rt/etc/upgrade/sanity-check-stylesheets.pl @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/etc/upgrade/shrink_cgm_table.pl b/rt/etc/upgrade/shrink_cgm_table.pl index bb6c8d487..fcfe8c5f1 100644 --- a/rt/etc/upgrade/shrink_cgm_table.pl +++ b/rt/etc/upgrade/shrink_cgm_table.pl @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/etc/upgrade/shrink_transactions_table.pl b/rt/etc/upgrade/shrink_transactions_table.pl index b4f07f090..66bdcf50c 100644 --- a/rt/etc/upgrade/shrink_transactions_table.pl +++ b/rt/etc/upgrade/shrink_transactions_table.pl @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/etc/upgrade/split-out-cf-categories.in b/rt/etc/upgrade/split-out-cf-categories.in index dcb56d08d..d9d2ffaf5 100644 --- a/rt/etc/upgrade/split-out-cf-categories.in +++ b/rt/etc/upgrade/split-out-cf-categories.in @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/etc/upgrade/upgrade-articles b/rt/etc/upgrade/upgrade-articles index 0b4663213..dbd481442 100755 --- a/rt/etc/upgrade/upgrade-articles +++ b/rt/etc/upgrade/upgrade-articles @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -64,10 +64,8 @@ my $db_type = RT->Config->Get('DatabaseType'); my $dbh = $RT::Handle->dbh; -my $sth = $dbh->table_info( '', undef, undef, "'TABLE'"); my $found_fm_tables; -while ( my $table = $sth->fetchrow_hashref ) { - my $name = $table->{TABLE_NAME} || $table->{'table_name'}; # Oracle's table_info affected by NAME_lc +foreach my $name ( $RT::Handle->_TableNames ) { next unless $name =~ /^fm_/i; $found_fm_tables->{lc $name}++; } @@ -159,6 +157,7 @@ sub copy_tables { use RT::CustomFields; my $cfs = RT::CustomFields->new(RT->SystemUser); $cfs->Limit( FIELD => 'LookupType', VALUE => 'RT::FM::Class-RT::FM::Article' ); + $cfs->{'find_disabled_rows'} = 1; while ( my $cf = $cfs->Next ) { my ($ret, $msg) = $cf->__Set( Field => 'LookupType', Value => 'RT::Class-RT::Article' ); warn "Update Custom Field LookupType for CF.".$cf->Id." $msg"; @@ -169,6 +168,7 @@ sub copy_tables { use RT::ObjectCustomFieldValues; my $ocfvs = RT::ObjectCustomFieldValues->new(RT->System); $ocfvs->Limit( FIELD => 'ObjectType', VALUE => 'RT::FM::Article' ); + $ocfvs->{'find_expired_rows'} = 1; while ( my $ocfv = $ocfvs->Next ) { my ($ret, $msg) = $ocfv->__Set( Field => 'ObjectType', Value => 'RT::Article' ); warn "Updated CF ".$ocfv->__Value('CustomField')." Value for Article ".$ocfv->__Value('ObjectId'); diff --git a/rt/etc/upgrade/upgrade-articles.in b/rt/etc/upgrade/upgrade-articles.in index 6e8d1d7c8..0aab0e22b 100644 --- a/rt/etc/upgrade/upgrade-articles.in +++ b/rt/etc/upgrade/upgrade-articles.in @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -64,10 +64,8 @@ my $db_type = RT->Config->Get('DatabaseType'); my $dbh = $RT::Handle->dbh; -my $sth = $dbh->table_info( '', undef, undef, "'TABLE'"); my $found_fm_tables; -while ( my $table = $sth->fetchrow_hashref ) { - my $name = $table->{TABLE_NAME} || $table->{'table_name'}; # Oracle's table_info affected by NAME_lc +foreach my $name ( $RT::Handle->_TableNames ) { next unless $name =~ /^fm_/i; $found_fm_tables->{lc $name}++; } @@ -159,6 +157,7 @@ sub copy_tables { use RT::CustomFields; my $cfs = RT::CustomFields->new(RT->SystemUser); $cfs->Limit( FIELD => 'LookupType', VALUE => 'RT::FM::Class-RT::FM::Article' ); + $cfs->{'find_disabled_rows'} = 1; while ( my $cf = $cfs->Next ) { my ($ret, $msg) = $cf->__Set( Field => 'LookupType', Value => 'RT::Class-RT::Article' ); warn "Update Custom Field LookupType for CF.".$cf->Id." $msg"; @@ -169,6 +168,7 @@ sub copy_tables { use RT::ObjectCustomFieldValues; my $ocfvs = RT::ObjectCustomFieldValues->new(RT->System); $ocfvs->Limit( FIELD => 'ObjectType', VALUE => 'RT::FM::Article' ); + $ocfvs->{'find_expired_rows'} = 1; while ( my $ocfv = $ocfvs->Next ) { my ($ret, $msg) = $ocfv->__Set( Field => 'ObjectType', Value => 'RT::Article' ); warn "Updated CF ".$ocfv->__Value('CustomField')." Value for Article ".$ocfv->__Value('ObjectId'); diff --git a/rt/etc/upgrade/upgrade-mysql-schema.pl b/rt/etc/upgrade/upgrade-mysql-schema.pl index 98eb7b4e3..8d6615d6b 100755 --- a/rt/etc/upgrade/upgrade-mysql-schema.pl +++ b/rt/etc/upgrade/upgrade-mysql-schema.pl @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -184,8 +184,8 @@ my %charset = ( Queues => { Name => 'utf8', Description => 'utf8', - CorrespondAddress => 'ascii', - CommentAddress => 'ascii', + CorrespondAddress => 'utf8', + CommentAddress => 'utf8', }, ScripActions => { Name => 'utf8', @@ -239,7 +239,7 @@ my %charset = ( Password => 'binary', Comments => 'utf8', Signature => 'utf8', - EmailAddress => 'ascii', + EmailAddress => 'utf8', FreeformContactInfo => 'utf8', Organization => 'utf8', RealName => 'utf8', diff --git a/rt/etc/upgrade/vulnerable-passwords.in b/rt/etc/upgrade/vulnerable-passwords.in index 22c56fd23..b1027a432 100755 --- a/rt/etc/upgrade/vulnerable-passwords.in +++ b/rt/etc/upgrade/vulnerable-passwords.in @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT.pm b/rt/lib/RT.pm index da60ef77d..0f0c79a55 100644 --- a/rt/lib/RT.pm +++ b/rt/lib/RT.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -181,8 +181,8 @@ up logging|/InitLogging>, and L<loads plugins|/InitPlugins>. =cut sub Init { - - my @arg = @_; + shift if @_%2; # code is inconsistent about calling as method + my %args = (@_); CheckPerlRequirements(); @@ -191,8 +191,8 @@ sub Init { #Get a database connection ConnectToDatabase(); InitSystemObjects(); - InitClasses(); - InitLogging(@arg); + InitClasses(%args); + InitLogging(%args); InitPlugins(); RT::I18N->Init; RT->Config->PostLoadCheck; @@ -264,7 +264,7 @@ sub InitLogging { my ($package, $filename, $line) = caller($frame); $p{'message'} =~ s/(?:\r*\n)+$//; - return "[". gmtime(time) ."] [". $p{'level'} ."]: " + return "[$$] [". gmtime(time) ."] [". $p{'level'} ."]: " . $p{'message'} ." ($filename:$line)\n"; }; @@ -283,9 +283,9 @@ sub InitLogging { $p{message} =~ s/(?:\r*\n)+$//; if ($p{level} eq 'debug') { - return "$p{message}\n"; + return "[$$] $p{message} ($filename:$line)\n"; } else { - return "$p{message} ($filename:$line)\n"; + return "[$$] $p{message}\n"; } }; diff --git a/rt/lib/RT/ACE.pm b/rt/lib/RT/ACE.pm index c752aa2dc..baf6fb2fd 100755 --- a/rt/lib/RT/ACE.pm +++ b/rt/lib/RT/ACE.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/ACL.pm b/rt/lib/RT/ACL.pm index d1e0df5ad..0662b3955 100755 --- a/rt/lib/RT/ACL.pm +++ b/rt/lib/RT/ACL.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Action.pm b/rt/lib/RT/Action.pm index dc10d0da6..88e5b15d4 100755 --- a/rt/lib/RT/Action.pm +++ b/rt/lib/RT/Action.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Action/AutoOpen.pm b/rt/lib/RT/Action/AutoOpen.pm index 8566c62d5..e819ca989 100644 --- a/rt/lib/RT/Action/AutoOpen.pm +++ b/rt/lib/RT/Action/AutoOpen.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Action/Autoreply.pm b/rt/lib/RT/Action/Autoreply.pm index 89b7536fa..a2703e51d 100755 --- a/rt/lib/RT/Action/Autoreply.pm +++ b/rt/lib/RT/Action/Autoreply.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Action/CreateTickets.pm b/rt/lib/RT/Action/CreateTickets.pm index 80308020f..e3c7b53e0 100644 --- a/rt/lib/RT/Action/CreateTickets.pm +++ b/rt/lib/RT/Action/CreateTickets.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Action/EscalatePriority.pm b/rt/lib/RT/Action/EscalatePriority.pm index 1300b4fe3..38cad9407 100644 --- a/rt/lib/RT/Action/EscalatePriority.pm +++ b/rt/lib/RT/Action/EscalatePriority.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Action/ExtractSubjectTag.pm b/rt/lib/RT/Action/ExtractSubjectTag.pm index 6a3898e74..92a72148f 100644 --- a/rt/lib/RT/Action/ExtractSubjectTag.pm +++ b/rt/lib/RT/Action/ExtractSubjectTag.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Action/LinearEscalate.pm b/rt/lib/RT/Action/LinearEscalate.pm index 13913e6cd..9b75286cf 100755 --- a/rt/lib/RT/Action/LinearEscalate.pm +++ b/rt/lib/RT/Action/LinearEscalate.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Action/Notify.pm b/rt/lib/RT/Action/Notify.pm index 3553cbc39..26aae47b0 100755 --- a/rt/lib/RT/Action/Notify.pm +++ b/rt/lib/RT/Action/Notify.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Action/NotifyAsComment.pm b/rt/lib/RT/Action/NotifyAsComment.pm index 0016a364a..a2c57db2d 100755 --- a/rt/lib/RT/Action/NotifyAsComment.pm +++ b/rt/lib/RT/Action/NotifyAsComment.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Action/NotifyGroup.pm b/rt/lib/RT/Action/NotifyGroup.pm index 1dece60a3..789c182e4 100644 --- a/rt/lib/RT/Action/NotifyGroup.pm +++ b/rt/lib/RT/Action/NotifyGroup.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Action/NotifyGroupAsComment.pm b/rt/lib/RT/Action/NotifyGroupAsComment.pm index cf6952aff..135ef7f9c 100644 --- a/rt/lib/RT/Action/NotifyGroupAsComment.pm +++ b/rt/lib/RT/Action/NotifyGroupAsComment.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Action/RecordComment.pm b/rt/lib/RT/Action/RecordComment.pm index a384af347..8f55ff187 100644 --- a/rt/lib/RT/Action/RecordComment.pm +++ b/rt/lib/RT/Action/RecordComment.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Action/RecordCorrespondence.pm b/rt/lib/RT/Action/RecordCorrespondence.pm index cc21503de..2304f2857 100644 --- a/rt/lib/RT/Action/RecordCorrespondence.pm +++ b/rt/lib/RT/Action/RecordCorrespondence.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Action/SendEmail.pm b/rt/lib/RT/Action/SendEmail.pm index 0a52904dd..0f11cc141 100755 --- a/rt/lib/RT/Action/SendEmail.pm +++ b/rt/lib/RT/Action/SendEmail.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -382,7 +382,7 @@ sub AddAttachments { =head2 AddAttachment $attachment -Takes one attachment object of L<RT::Attachmment> class and attaches it to the message +Takes one attachment object of L<RT::Attachment> class and attaches it to the message we're building. =cut @@ -397,14 +397,15 @@ sub AddAttachment { and $attach->TransactionObj->CurrentUserCanSee; # ->attach expects just the disposition type; extract it if we have the header + # or default to "attachment" my $disp = ($attach->GetHeader('Content-Disposition') || '') - =~ /^\s*(inline|attachment)/i ? $1 : undef; + =~ /^\s*(inline|attachment)/i ? $1 : "attachment"; $MIMEObj->attach( Type => $attach->ContentType, Charset => $attach->OriginalEncoding, Data => $attach->OriginalContent, - Disposition => $disp, # a false value defaults to inline in MIME::Entity + Disposition => $disp, Filename => $self->MIMEEncodeString( $attach->Filename ), 'RT-Attachment:' => $self->TicketObj->Id . "/" . $self->TransactionObj->Id . "/" @@ -975,7 +976,7 @@ sub SetSubject { $subject =~ s/(\r\n|\n|\s)/ /g; - $self->SetHeader( 'Subject', $subject ); + $self->SetHeader( 'Subject', Encode::encode_utf8( $subject ) ); } @@ -989,11 +990,14 @@ sub SetSubjectToken { my $self = shift; my $head = $self->TemplateObj->MIMEObj->head; - $head->replace( - Subject => RT::Interface::Email::AddSubjectTag( - Encode::decode_utf8( $head->get('Subject') ), - $self->TicketObj, - ), + $self->SetHeader( + Subject => + Encode::encode_utf8( + RT::Interface::Email::AddSubjectTag( + Encode::decode_utf8( $head->get('Subject') ), + $self->TicketObj, + ), + ), ); } diff --git a/rt/lib/RT/Action/SetPriority.pm b/rt/lib/RT/Action/SetPriority.pm index 2043532f7..7385c13d9 100644 --- a/rt/lib/RT/Action/SetPriority.pm +++ b/rt/lib/RT/Action/SetPriority.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Action/SetStatus.pm b/rt/lib/RT/Action/SetStatus.pm index be00396ce..c7a3127f1 100644 --- a/rt/lib/RT/Action/SetStatus.pm +++ b/rt/lib/RT/Action/SetStatus.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Action/UserDefined.pm b/rt/lib/RT/Action/UserDefined.pm index b259323d7..adc40e948 100644 --- a/rt/lib/RT/Action/UserDefined.pm +++ b/rt/lib/RT/Action/UserDefined.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Approval.pm b/rt/lib/RT/Approval.pm index dc60222a8..34cf10012 100644 --- a/rt/lib/RT/Approval.pm +++ b/rt/lib/RT/Approval.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Approval/Rule.pm b/rt/lib/RT/Approval/Rule.pm index 6892f41ec..1b7b7aca5 100644 --- a/rt/lib/RT/Approval/Rule.pm +++ b/rt/lib/RT/Approval/Rule.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Approval/Rule/Created.pm b/rt/lib/RT/Approval/Rule/Created.pm index 8fcaeb273..91063d179 100644 --- a/rt/lib/RT/Approval/Rule/Created.pm +++ b/rt/lib/RT/Approval/Rule/Created.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Approval/Rule/NewPending.pm b/rt/lib/RT/Approval/Rule/NewPending.pm index 97d3cfbb5..3fdb99d2b 100644 --- a/rt/lib/RT/Approval/Rule/NewPending.pm +++ b/rt/lib/RT/Approval/Rule/NewPending.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Approval/Rule/Passed.pm b/rt/lib/RT/Approval/Rule/Passed.pm index acc49161f..241e6046e 100644 --- a/rt/lib/RT/Approval/Rule/Passed.pm +++ b/rt/lib/RT/Approval/Rule/Passed.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Approval/Rule/Rejected.pm b/rt/lib/RT/Approval/Rule/Rejected.pm index 0a025684f..adc30634b 100644 --- a/rt/lib/RT/Approval/Rule/Rejected.pm +++ b/rt/lib/RT/Approval/Rule/Rejected.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Article.pm b/rt/lib/RT/Article.pm index ec1ae3cae..e9f3d43f1 100644 --- a/rt/lib/RT/Article.pm +++ b/rt/lib/RT/Article.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Articles.pm b/rt/lib/RT/Articles.pm index d69eabf82..9bee84472 100644 --- a/rt/lib/RT/Articles.pm +++ b/rt/lib/RT/Articles.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -597,7 +597,11 @@ sub Search { require Time::ParseDate; foreach my $date (qw(Created< Created> LastUpdated< LastUpdated>)) { next unless ( $args{$date} ); - my $seconds = Time::ParseDate::parsedate( $args{$date}, FUZZY => 1, PREFER_PAST => 1 ); + my ($seconds, $error) = Time::ParseDate::parsedate( $args{$date}, FUZZY => 1, PREFER_PAST => 1 ); + unless ( defined $seconds ) { + $RT::Logger->warning( + "Couldn't parse date '$args{$date}' by Time::ParseDate" ); + } my $date_obj = RT::Date->new( $self->CurrentUser ); $date_obj->Set( Format => 'unix', Value => $seconds ); $dates->{$date} = $date_obj; diff --git a/rt/lib/RT/Attachment.pm b/rt/lib/RT/Attachment.pm index 54217b32b..07fdea3b2 100755 --- a/rt/lib/RT/Attachment.pm +++ b/rt/lib/RT/Attachment.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Attachments.pm b/rt/lib/RT/Attachments.pm index 5b087a493..7f6f258c9 100755 --- a/rt/lib/RT/Attachments.pm +++ b/rt/lib/RT/Attachments.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Attribute.pm b/rt/lib/RT/Attribute.pm index 10971a279..745f95fd2 100644 --- a/rt/lib/RT/Attribute.pm +++ b/rt/lib/RT/Attribute.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -148,7 +148,7 @@ sub Create { @_); if ($args{Object} and UNIVERSAL::can($args{Object}, 'Id')) { - $args{ObjectType} = ref($args{Object}); + $args{ObjectType} = $args{Object}->isa("RT::CurrentUser") ? "RT::User" : ref($args{Object}); $args{ObjectId} = $args{Object}->Id; } else { return(0, $self->loc("Required parameter '[_1]' not specified", 'Object')); diff --git a/rt/lib/RT/Attributes.pm b/rt/lib/RT/Attributes.pm index 9c18c1a0f..c556756ae 100644 --- a/rt/lib/RT/Attributes.pm +++ b/rt/lib/RT/Attributes.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -210,7 +210,10 @@ sub LimitToObject { unless (eval { $obj->id} ){ return undef; } - $self->Limit(FIELD => 'ObjectType', OPERATOR=> '=', VALUE => ref($obj), ENTRYAGGREGATOR => 'OR'); + + my $type = $obj->isa("RT::CurrentUser") ? "RT::User" : ref($obj); + + $self->Limit(FIELD => 'ObjectType', OPERATOR=> '=', VALUE => $type, ENTRYAGGREGATOR => 'OR'); $self->Limit(FIELD => 'ObjectId', OPERATOR=> '=', VALUE => $obj->id, ENTRYAGGREGATOR => 'OR', QUOTEVALUE => 0); } diff --git a/rt/lib/RT/Base.pm b/rt/lib/RT/Base.pm index 403c318b4..f83ed8e0e 100644 --- a/rt/lib/RT/Base.pm +++ b/rt/lib/RT/Base.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/CachedGroupMember.pm b/rt/lib/RT/CachedGroupMember.pm index b334d4d6c..66e7c7a93 100644 --- a/rt/lib/RT/CachedGroupMember.pm +++ b/rt/lib/RT/CachedGroupMember.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/CachedGroupMembers.pm b/rt/lib/RT/CachedGroupMembers.pm index 4d8f356fb..f65796acb 100644 --- a/rt/lib/RT/CachedGroupMembers.pm +++ b/rt/lib/RT/CachedGroupMembers.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Class.pm b/rt/lib/RT/Class.pm index dfe8eb386..8f6892456 100644 --- a/rt/lib/RT/Class.pm +++ b/rt/lib/RT/Class.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Classes.pm b/rt/lib/RT/Classes.pm index 60122c7eb..6b50d5dce 100644 --- a/rt/lib/RT/Classes.pm +++ b/rt/lib/RT/Classes.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -54,6 +54,15 @@ use base 'RT::SearchBuilder'; sub Table {'Classes'} +=head2 _Init + +=cut + + sub _Init { + my $self = shift; + $self->{'with_disabled_column'} = 1; + return ($self->SUPER::_Init(@_)); + } =head2 Next diff --git a/rt/lib/RT/Condition.pm b/rt/lib/RT/Condition.pm index 07518151f..80cf01992 100755 --- a/rt/lib/RT/Condition.pm +++ b/rt/lib/RT/Condition.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Condition/AnyTransaction.pm b/rt/lib/RT/Condition/AnyTransaction.pm index 2c9129c0f..5d8b3bc76 100644 --- a/rt/lib/RT/Condition/AnyTransaction.pm +++ b/rt/lib/RT/Condition/AnyTransaction.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Condition/BeforeDue.pm b/rt/lib/RT/Condition/BeforeDue.pm index 8df73cacd..73015bcc8 100644 --- a/rt/lib/RT/Condition/BeforeDue.pm +++ b/rt/lib/RT/Condition/BeforeDue.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Condition/CloseTicket.pm b/rt/lib/RT/Condition/CloseTicket.pm index bdeaf2d5d..2e027f4de 100644 --- a/rt/lib/RT/Condition/CloseTicket.pm +++ b/rt/lib/RT/Condition/CloseTicket.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Condition/Overdue.pm b/rt/lib/RT/Condition/Overdue.pm index 547aea25b..462fa407c 100644 --- a/rt/lib/RT/Condition/Overdue.pm +++ b/rt/lib/RT/Condition/Overdue.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Condition/OwnerChange.pm b/rt/lib/RT/Condition/OwnerChange.pm index 85005482c..407d5a5ae 100644 --- a/rt/lib/RT/Condition/OwnerChange.pm +++ b/rt/lib/RT/Condition/OwnerChange.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Condition/PriorityChange.pm b/rt/lib/RT/Condition/PriorityChange.pm index a600453a3..25e6bfb5b 100644 --- a/rt/lib/RT/Condition/PriorityChange.pm +++ b/rt/lib/RT/Condition/PriorityChange.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Condition/PriorityExceeds.pm b/rt/lib/RT/Condition/PriorityExceeds.pm index a28d6df15..e35d0b5b8 100644 --- a/rt/lib/RT/Condition/PriorityExceeds.pm +++ b/rt/lib/RT/Condition/PriorityExceeds.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Condition/QueueChange.pm b/rt/lib/RT/Condition/QueueChange.pm index ba7a8a495..91cd88c4e 100644 --- a/rt/lib/RT/Condition/QueueChange.pm +++ b/rt/lib/RT/Condition/QueueChange.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Condition/ReopenTicket.pm b/rt/lib/RT/Condition/ReopenTicket.pm index a057e401d..69ef8f9ab 100644 --- a/rt/lib/RT/Condition/ReopenTicket.pm +++ b/rt/lib/RT/Condition/ReopenTicket.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Condition/StatusChange.pm b/rt/lib/RT/Condition/StatusChange.pm index e84915d19..55fe2347f 100644 --- a/rt/lib/RT/Condition/StatusChange.pm +++ b/rt/lib/RT/Condition/StatusChange.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Condition/UserDefined.pm b/rt/lib/RT/Condition/UserDefined.pm index 1abee67f2..4f4ff1816 100644 --- a/rt/lib/RT/Condition/UserDefined.pm +++ b/rt/lib/RT/Condition/UserDefined.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Config.pm b/rt/lib/RT/Config.pm index ee426bfa8..fee6c5106 100644 --- a/rt/lib/RT/Config.pm +++ b/rt/lib/RT/Config.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Crypt/GnuPG.pm b/rt/lib/RT/Crypt/GnuPG.pm index 6164a4241..d0587d4fe 100644 --- a/rt/lib/RT/Crypt/GnuPG.pm +++ b/rt/lib/RT/Crypt/GnuPG.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -2160,7 +2160,10 @@ sub GetKeysInfo { } $RT::Logger->debug( $res{'status'} ) if $res{'status'}; $RT::Logger->warning( $res{'stderr'} ) if $res{'stderr'}; - $RT::Logger->error( $res{'logger'} ) if $res{'logger'} && $?; + if ( $res{'logger'} && $? ) { + $RT::Logger->error( $res{'logger'} ); + $RT::Logger->error( 'The above error may result from an unconfigured RT/GPG installation. See perldoc etc/RT_Config.pm for information about configuring or disabling GPG support for RT' ); + } if ( $@ || $? ) { $res{'message'} = $@? $@: "gpg exitted with error code ". ($? >> 8); return %res; diff --git a/rt/lib/RT/CurrentUser.pm b/rt/lib/RT/CurrentUser.pm index fa0d4ca7a..c11d46031 100755 --- a/rt/lib/RT/CurrentUser.pm +++ b/rt/lib/RT/CurrentUser.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/CustomField.pm b/rt/lib/RT/CustomField.pm index 01b4970c4..e71bbf78a 100644 --- a/rt/lib/RT/CustomField.pm +++ b/rt/lib/RT/CustomField.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -51,7 +51,7 @@ package RT::CustomField; use strict; use warnings; - +use Scalar::Util 'blessed'; use base 'RT::Record'; @@ -1111,11 +1111,6 @@ sub SetRenderType { $self->FriendlyType)); } - # XXX: Remove this restriction once we support lists and cascaded selects - if ( $self->BasedOnObj->id and $type =~ /List/ ) { - return (0, $self->loc("We can't currently render as a List when basing categories on another custom field. Please use another render type.")); - } - return $self->_Set( Field => 'RenderType', Value => $type, @_ ); } @@ -1193,7 +1188,7 @@ Returns an array of LookupTypes available sub LookupTypes { my $self = shift; - return keys %FRIENDLY_OBJECT_TYPES; + return sort keys %FRIENDLY_OBJECT_TYPES; } my @FriendlyObjectTypes = ( @@ -1222,14 +1217,57 @@ sub FriendlyLookupType { return ( $self->loc( $FriendlyObjectTypes[$#types], @types ) ); } +=head1 RecordClassFromLookupType + +Returns the type of Object referred to by ObjectCustomFields' ObjectId column + +Optionally takes a LookupType to use instead of using the value on the loaded +record. In this case, the method may be called on the class instead of an +object. + +=cut + sub RecordClassFromLookupType { my $self = shift; - my ($class) = ($self->LookupType =~ /^([^-]+)/); + my $type = shift || $self->LookupType; + my ($class) = ($type =~ /^([^-]+)/); unless ( $class ) { - $RT::Logger->error( - "Custom Field #". $self->id - ." has incorrect LookupType '". $self->LookupType ."'" - ); + if (blessed($self) and $self->LookupType eq $type) { + $RT::Logger->error( + "Custom Field #". $self->id + ." has incorrect LookupType '$type'" + ); + } else { + RT->Logger->error("Invalid LookupType passed as argument: $type"); + } + return undef; + } + return $class; +} + +=head1 ObjectTypeFromLookupType + +Returns the ObjectType used in ObjectCustomFieldValues rows for this CF + +Optionally takes a LookupType to use instead of using the value on the loaded +record. In this case, the method may be called on the class instead of an +object. + +=cut + +sub ObjectTypeFromLookupType { + my $self = shift; + my $type = shift || $self->LookupType; + my ($class) = ($type =~ /([^-]+)$/); + unless ( $class ) { + if (blessed($self) and $self->LookupType eq $type) { + $RT::Logger->error( + "Custom Field #". $self->id + ." has incorrect LookupType '$type'" + ); + } else { + RT->Logger->error("Invalid LookupType passed as argument: $type"); + } return undef; } return $class; diff --git a/rt/lib/RT/CustomFieldValue.pm b/rt/lib/RT/CustomFieldValue.pm index 6dffc3455..4adb84d9e 100644 --- a/rt/lib/RT/CustomFieldValue.pm +++ b/rt/lib/RT/CustomFieldValue.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/CustomFieldValues.pm b/rt/lib/RT/CustomFieldValues.pm index e3380b7e5..18bc6b4b0 100644 --- a/rt/lib/RT/CustomFieldValues.pm +++ b/rt/lib/RT/CustomFieldValues.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/CustomFieldValues/External.pm b/rt/lib/RT/CustomFieldValues/External.pm index e6bf2f87d..375f5c538 100644 --- a/rt/lib/RT/CustomFieldValues/External.pm +++ b/rt/lib/RT/CustomFieldValues/External.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/CustomFieldValues/Groups.pm b/rt/lib/RT/CustomFieldValues/Groups.pm index feeeadbd7..48234e293 100644 --- a/rt/lib/RT/CustomFieldValues/Groups.pm +++ b/rt/lib/RT/CustomFieldValues/Groups.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -53,10 +53,42 @@ use warnings; use base qw(RT::CustomFieldValues::External); +=head1 NAME + +RT::CustomFieldValues::Groups - Provide RT's groups as a dynamic list of CF values + +=head1 SYNOPSIS + +To use as a source of CF values, add the following to your F<RT_SiteConfig.pm> +and restart RT. + + # In RT_SiteConfig.pm + Set( @CustomFieldValuesSources, "RT::CustomFieldValues::Groups" ); + +Then visit the modify CF page in the RT admin configuration. + +=head1 METHODS + +Most methods are inherited from L<RT::CustomFieldValues::External>, except the +ones below. + +=head2 SourceDescription + +Returns a brief string describing this data source. + +=cut + sub SourceDescription { return 'RT user defined groups'; } +=head2 ExternalValues + +Returns an arrayref containing a hashref for each possible value in this data +source, where the value name is the group name. + +=cut + sub ExternalValues { my $self = shift; diff --git a/rt/lib/RT/CustomFields.pm b/rt/lib/RT/CustomFields.pm index 017018ef4..7c7701580 100644 --- a/rt/lib/RT/CustomFields.pm +++ b/rt/lib/RT/CustomFields.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -141,6 +141,25 @@ sub LimitToParentType { $self->Limit( FIELD => 'LookupType', STARTSWITH => "$lookup" ); } +=head2 LimitToObjectId + +Takes an ObjectId and limits the collection to CFs applied to said object. + +When called multiple times the ObjectId limits are joined with OR. + +=cut + +sub LimitToObjectId { + my $self = shift; + my $id = shift; + $self->Limit( + ALIAS => $self->_OCFAlias, + FIELD => 'ObjectId', + OPERATOR => '=', + VALUE => $id || 0, + ENTRYAGGREGATOR => 'OR' + ); +} =head2 LimitToGlobalOrObjectId @@ -155,19 +174,11 @@ sub LimitToGlobalOrObjectId { foreach my $id (@_) { - $self->Limit( ALIAS => $self->_OCFAlias, - FIELD => 'ObjectId', - OPERATOR => '=', - VALUE => $id || 0, - ENTRYAGGREGATOR => 'OR' ); - $global_only = 0 if $id; + $self->LimitToObjectId($id); + $global_only = 0 if $id; } - $self->Limit( ALIAS => $self->_OCFAlias, - FIELD => 'ObjectId', - OPERATOR => '=', - VALUE => 0, - ENTRYAGGREGATOR => 'OR' ) unless $global_only; + $self->LimitToObjectId(0) unless $global_only; } sub _LimitToOCFs { diff --git a/rt/lib/RT/Dashboard.pm b/rt/lib/RT/Dashboard.pm index 349864e12..6d4c51562 100644 --- a/rt/lib/RT/Dashboard.pm +++ b/rt/lib/RT/Dashboard.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Dashboard/Mailer.pm b/rt/lib/RT/Dashboard/Mailer.pm index 9d28c4942..eb620e65d 100644 --- a/rt/lib/RT/Dashboard/Mailer.pm +++ b/rt/lib/RT/Dashboard/Mailer.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -146,7 +146,7 @@ sub IsSubscriptionReady { my $sub_hour = $subscription->SubValue('Hour'); my $sub_dow = $subscription->SubValue('Dow'); my $sub_dom = $subscription->SubValue('Dom'); - my $sub_fow = $subscription->SubValue('Fow'); + my $sub_fow = $subscription->SubValue('Fow') || 1; my ($hour, $dow, $dom) = @{ $args{LocalTime} }; @@ -165,8 +165,6 @@ sub IsSubscriptionReady { return 0 if $sub_dow ne $dow; # does it match the "every N weeks" clause? - $sub_fow = 1 if !$sub_fow; - return 1 if $counter % $sub_fow == 0; $subscription->SetSubValues(Counter => $counter + 1) @@ -422,12 +420,15 @@ sub BuildEmail { Type => 'text/html', Charset => 'UTF-8', Disposition => 'inline', + Encoding => "base64", ); for my $part (@parts) { $entity->add_part($part); } + $entity->make_singlepart; + return $entity; } diff --git a/rt/lib/RT/Dashboards.pm b/rt/lib/RT/Dashboards.pm index f9cbbe877..1c5fe3d97 100644 --- a/rt/lib/RT/Dashboards.pm +++ b/rt/lib/RT/Dashboards.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Date.pm b/rt/lib/RT/Date.pm index 031f9c8d4..db56cfeb9 100644 --- a/rt/lib/RT/Date.pm +++ b/rt/lib/RT/Date.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -208,7 +208,7 @@ sub Set { # should be applied to absolute times, so compensate shift in NOW my $now = time; $now += ($self->Localtime( $args{Timezone}, $now ))[9]; - my $date = Time::ParseDate::parsedate( + my ($date, $error) = Time::ParseDate::parsedate( $args{'Value'}, GMT => 1, NOW => $now, @@ -216,6 +216,13 @@ sub Set { PREFER_PAST => RT->Config->Get('AmbiguousDayInPast'), PREFER_FUTURE => RT->Config->Get('AmbiguousDayInFuture'), ); + unless ( defined $date ) { + $RT::Logger->warning( + "Couldn't parse date '$args{'Value'}' by Time::ParseDate" + ); + return $self->Unix(0); + } + # apply timezone offset $date -= ($self->Localtime( $args{Timezone}, $date ))[9]; @@ -895,7 +902,7 @@ sub RFC2822 { my ($date, $time) = ('',''); $date .= "$DAYS_OF_WEEK[$wday], " if $args{'DayOfWeek'} && $args{'Date'}; - $date .= "$mday $MONTHS[$mon] $year" if $args{'Date'}; + $date .= sprintf("%02d %s %04d", $mday, $MONTHS[$mon], $year) if $args{'Date'}; if ( $args{'Time'} ) { $time .= sprintf("%02d:%02d", $hour, $min); @@ -960,21 +967,20 @@ sub iCal { Date => 1, Time => 1, @_, ); - my ($sec,$min,$hour,$mday,$mon,$year,$wday,$ydaym,$isdst,$offset) = - $self->Localtime( 'utc' ); - - #the month needs incrementing, as gmtime returns 0-11 - $mon++; my $res; if ( $args{'Date'} && !$args{'Time'} ) { - $res = sprintf( '%04d%02d%02d', $year, $mon, $mday ); - } - elsif ( !$args{'Date'} && $args{'Time'} ) { + my (undef, undef, undef, $mday, $mon, $year) = + $self->Localtime( 'user' ); + $res = sprintf( '%04d%02d%02d', $year, $mon+1, $mday ); + } elsif ( !$args{'Date'} && $args{'Time'} ) { + my ($sec, $min, $hour) = + $self->Localtime( 'utc' ); $res = sprintf( 'T%02d%02d%02dZ', $hour, $min, $sec ); - } - else { - $res = sprintf( '%04d%02d%02dT%02d%02d%02dZ', $year, $mon, $mday, $hour, $min, $sec ); + } else { + my ($sec, $min, $hour, $mday, $mon, $year) = + $self->Localtime( 'utc' ); + $res = sprintf( '%04d%02d%02dT%02d%02d%02dZ', $year, $mon+1, $mday, $hour, $min, $sec ); } return $res; } diff --git a/rt/lib/RT/EmailParser.pm b/rt/lib/RT/EmailParser.pm index 19dc2c9e8..89f7ea4f9 100644 --- a/rt/lib/RT/EmailParser.pm +++ b/rt/lib/RT/EmailParser.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -110,7 +110,7 @@ sub SmartParseMIMEEntityFromScalar { # accommodate this by pausing and retrying. last if ( $fh, $temp_file ) = - eval { File::Temp::tempfile( undef, UNLINK => 0 ) }; + eval { File::Temp::tempfile( UNLINK => 0 ) }; sleep 1; } if ($fh) { @@ -546,10 +546,38 @@ sub ParseEmailAddress { @addresses = Email::Address->parse($address_string); } + $self->CleanupAddresses(@addresses); + return @addresses; } +=head2 CleanupAddresses ARRAY + +Massages an array of L<Email::Address> objects to make their email addresses +more palatable. + +Currently this strips off surrounding single quotes around C<< ->address >> and +B<< modifies the L<Email::Address> objects in-place >>. + +Returns the list of objects for convienence in C<map>/C<grep> chains. + +=cut + +sub CleanupAddresses { + my $self = shift; + + for my $addr (@_) { + next unless defined $addr; + # Outlook sometimes sends addresses surrounded by single quotes; + # clean them all up + if ((my $email = $addr->address) =~ s/^'(.+)'$/$1/) { + $addr->address($email); + } + } + return @_; +} + =head2 RescueOutlook Outlook 2007/2010 have a bug when you write an email with the html format. diff --git a/rt/lib/RT/Generated.pm b/rt/lib/RT/Generated.pm index 4f74ea984..5edd7e3f8 100644 --- a/rt/lib/RT/Generated.pm +++ b/rt/lib/RT/Generated.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -50,7 +50,7 @@ package RT; use warnings; use strict; -our $VERSION = '4.0.13'; +our $VERSION = '4.0.19'; diff --git a/rt/lib/RT/Generated.pm.in b/rt/lib/RT/Generated.pm.in index 91aa84073..dc4163e34 100644 --- a/rt/lib/RT/Generated.pm.in +++ b/rt/lib/RT/Generated.pm.in @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Graph/Tickets.pm b/rt/lib/RT/Graph/Tickets.pm index 753ff20e7..477a5d077 100644 --- a/rt/lib/RT/Graph/Tickets.pm +++ b/rt/lib/RT/Graph/Tickets.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Group.pm b/rt/lib/RT/Group.pm index d4d2802ad..dc5295758 100755 --- a/rt/lib/RT/Group.pm +++ b/rt/lib/RT/Group.pm @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/GroupMember.pm b/rt/lib/RT/GroupMember.pm index e3c5e1dda..1d4090cc6 100755 --- a/rt/lib/RT/GroupMember.pm +++ b/rt/lib/RT/GroupMember.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/GroupMembers.pm b/rt/lib/RT/GroupMembers.pm index 52244bd09..49cd8debc 100755 --- a/rt/lib/RT/GroupMembers.pm +++ b/rt/lib/RT/GroupMembers.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Groups.pm b/rt/lib/RT/Groups.pm index e7734e095..c2348584e 100755 --- a/rt/lib/RT/Groups.pm +++ b/rt/lib/RT/Groups.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Handle.pm b/rt/lib/RT/Handle.pm index b449d2037..4ea1576dc 100644 --- a/rt/lib/RT/Handle.pm +++ b/rt/lib/RT/Handle.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -114,6 +114,7 @@ sub Connect { $self->SUPER::Connect( User => RT->Config->Get('DatabaseUser'), Password => RT->Config->Get('DatabasePassword'), + DisconnectHandleOnDestroy => 1, %args, ); @@ -161,7 +162,6 @@ sub BuildDSN { Port => $db_port, Driver => $db_type, RequireSSL => RT->Config->Get('DatabaseRequireSSL'), - DisconnectHandleOnDestroy => 1, ); if ( $db_type eq 'Oracle' && $db_host ) { $args{'SID'} = delete $args{'Database'}; @@ -361,6 +361,9 @@ sub CreateDatabase { elsif ( $db_type eq 'Pg' ) { $status = $dbh->do("CREATE DATABASE $db_name WITH ENCODING='UNICODE' TEMPLATE template0"); } + elsif ( $db_type eq 'mysql' ) { + $status = $dbh->do("CREATE DATABASE $db_name DEFAULT CHARACTER SET utf8"); + } else { $status = $dbh->do("CREATE DATABASE $db_name"); } @@ -872,7 +875,9 @@ sub InsertData { } if ( $item->{'BasedOn'} ) { - if ( $item->{'LookupType'} ) { + if ( $item->{'BasedOn'} =~ /^\d+$/) { + # Already have an ID -- should be fine + } elsif ( $item->{'LookupType'} ) { my $basedon = RT::CustomField->new($RT::SystemUser); my ($ok, $msg ) = $basedon->LoadByCols( Name => $item->{'BasedOn'}, LookupType => $item->{'LookupType'} ); @@ -1203,6 +1208,32 @@ sub _LogSQLStatement { push @{$self->{'StatementLog'}} , ([Time::HiRes::time(), $statement, [@bind], $duration, HTML::Mason::Exception->new->as_string]); } + +sub _TableNames { + my $self = shift; + my $dbh = shift || $self->dbh; + + { + local $@; + if ( + $dbh->{Driver}->{Name} eq 'Pg' + && $dbh->{'pg_server_version'} >= 90200 + && !eval { DBD::Pg->VERSION('2.19.3'); 1 } + ) { + die "You're using PostgreSQL 9.2 or newer. You have to upgrade DBD::Pg module to 2.19.3 or newer: $@"; + } + } + + my @res; + + my $sth = $dbh->table_info( '', undef, undef, "'TABLE'"); + while ( my $table = $sth->fetchrow_hashref ) { + push @res, $table->{TABLE_NAME} || $table->{table_name}; + } + + return @res; +} + __PACKAGE__->FinalizeDatabaseType; RT::Base->_ImportOverlays(); diff --git a/rt/lib/RT/I18N.pm b/rt/lib/RT/I18N.pm index 0e75b9f3b..bc267e438 100644 --- a/rt/lib/RT/I18N.pm +++ b/rt/lib/RT/I18N.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -388,6 +388,7 @@ sub DecodeMIMEWordsToEncoding { $enc_str = qq{"$enc_str"} if $enc_str =~ /[,;]/ and $enc_str !~ /^".*"$/ + and $prefix !~ /"$/ and $trailing !~ /^"/ and (!$field || $field =~ /^(?:To$|From$|B?Cc$|Content-)/i); $str .= $prefix . $enc_str . $trailing; diff --git a/rt/lib/RT/I18N/cs.pm b/rt/lib/RT/I18N/cs.pm index faea9d70b..30da114d0 100644 --- a/rt/lib/RT/I18N/cs.pm +++ b/rt/lib/RT/I18N/cs.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/I18N/i_default.pm b/rt/lib/RT/I18N/i_default.pm index 2b48c629c..316f51a64 100644 --- a/rt/lib/RT/I18N/i_default.pm +++ b/rt/lib/RT/I18N/i_default.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/I18N/ru.pm b/rt/lib/RT/I18N/ru.pm index a98636f19..5b34d777a 100755 --- a/rt/lib/RT/I18N/ru.pm +++ b/rt/lib/RT/I18N/ru.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Installer.pm b/rt/lib/RT/Installer.pm index d876e10aa..c48b06c1f 100644 --- a/rt/lib/RT/Installer.pm +++ b/rt/lib/RT/Installer.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Interface/CLI.pm b/rt/lib/RT/Interface/CLI.pm index c1a6f4fe8..feef6b802 100644 --- a/rt/lib/RT/Interface/CLI.pm +++ b/rt/lib/RT/Interface/CLI.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Interface/Email.pm b/rt/lib/RT/Interface/Email.pm index ab319e665..74120ba07 100755 --- a/rt/lib/RT/Interface/Email.pm +++ b/rt/lib/RT/Interface/Email.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -431,21 +431,24 @@ sub SendEmail { # SetOutgoingMailFrom and bounces conflict, since they both want -f if ( $args{'Bounce'} ) { push @args, shellwords(RT->Config->Get('SendmailBounceArguments')); - } elsif ( RT->Config->Get('SetOutgoingMailFrom') ) { - my $OutgoingMailAddress; + } elsif ( my $MailFrom = RT->Config->Get('SetOutgoingMailFrom') ) { + my $OutgoingMailAddress = $MailFrom =~ /\@/ ? $MailFrom : undef; + my $Overrides = RT->Config->Get('OverrideOutgoingMailFrom') || {}; if ($TicketObj) { my $QueueName = $TicketObj->QueueObj->Name; - my $QueueAddressOverride = RT->Config->Get('OverrideOutgoingMailFrom')->{$QueueName}; + my $QueueAddressOverride = $Overrides->{$QueueName}; if ($QueueAddressOverride) { $OutgoingMailAddress = $QueueAddressOverride; } else { - $OutgoingMailAddress = $TicketObj->QueueObj->CorrespondAddress; + $OutgoingMailAddress ||= $TicketObj->QueueObj->CorrespondAddress + || RT->Config->Get('CorrespondAddress'); } } - - $OutgoingMailAddress ||= RT->Config->Get('OverrideOutgoingMailFrom')->{'Default'}; + elsif ($Overrides->{'Default'}) { + $OutgoingMailAddress = $Overrides->{'Default'}; + } push @args, "-f", $OutgoingMailAddress if $OutgoingMailAddress; @@ -1084,7 +1087,7 @@ sub ParseCcAddressesFromHead { && !IgnoreCcAddress( $_ ) } map lc $user->CanonicalizeEmailAddress( $_->address ), - map Email::Address->parse( $args{'Head'}->get( $_ ) ), + map RT::EmailParser->CleanupAddresses( Email::Address->parse( $args{'Head'}->get( $_ ) ) ), qw(To Cc); } @@ -1464,6 +1467,9 @@ sub Gateway { my $head = $Message->head; my $ErrorsTo = ParseErrorsToAddressFromHead( $head ); + my $Sender = (ParseSenderAddressFromHead( $head ))[0]; + my $From = $head->get("From"); + chomp $From if defined $From; my $MessageId = $head->get('Message-ID') || "<no-message-id-". time . rand(2000) .'@'. RT->Config->Get('Organization') .'>'; @@ -1548,7 +1554,8 @@ sub Gateway { ); return ( 0, - "$ErrorsTo tried to submit a message to " + ($CurrentUser->EmailAddress || $CurrentUser->Name) + . " ($Sender) tried to submit a message to " . $args{'Queue'} . " without permission.", undef @@ -1595,7 +1602,7 @@ sub Gateway { Explanation => $ErrStr, MIMEObj => $Message ); - return ( 0, "Ticket creation failed: $ErrStr", $Ticket ); + return ( 0, "Ticket creation From: $From failed: $ErrStr", $Ticket ); } # strip comments&corresponds from the actions we don't need @@ -1640,7 +1647,7 @@ sub Gateway { Explanation => $msg, MIMEObj => $Message ); - return ( 0, "Message not recorded: $msg", $Ticket ); + return ( 0, "Message From: $From not recorded: $msg", $Ticket ); } } elsif ($unsafe_actions) { my ( $status, $msg ) = _RunUnsafeAction( @@ -1739,6 +1746,8 @@ sub _RunUnsafeAction { @_ ); + my $From = $args{Message}->head->get("From"); + if ( $args{'Action'} =~ /^take$/i ) { my ( $status, $msg ) = $args{'Ticket'}->SetOwner( $args{'CurrentUser'}->id ); unless ($status) { @@ -1748,7 +1757,7 @@ sub _RunUnsafeAction { Explanation => $msg, MIMEObj => $args{'Message'} ); - return ( 0, "Ticket not taken" ); + return ( 0, "Ticket not taken, by email From: $From" ); } } elsif ( $args{'Action'} =~ /^resolve$/i ) { my $new_status = $args{'Ticket'}->FirstInactiveStatus; @@ -1763,11 +1772,11 @@ sub _RunUnsafeAction { Explanation => $msg, MIMEObj => $args{'Message'} ); - return ( 0, "Ticket not resolved" ); + return ( 0, "Ticket not resolved, by email From: $From" ); } } } else { - return ( 0, "Not supported unsafe action $args{'Action'}", $args{'Ticket'} ); + return ( 0, "Not supported unsafe action $args{'Action'}, by email From: $From", $args{'Ticket'} ); } return ( 1, "Success" ); } diff --git a/rt/lib/RT/Interface/Email/Auth/GnuPG.pm b/rt/lib/RT/Interface/Email/Auth/GnuPG.pm index c14bcf074..5137707e5 100755 --- a/rt/lib/RT/Interface/Email/Auth/GnuPG.pm +++ b/rt/lib/RT/Interface/Email/Auth/GnuPG.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Interface/Email/Auth/MailFrom.pm b/rt/lib/RT/Interface/Email/Auth/MailFrom.pm index bfe493958..b353907fb 100644 --- a/rt/lib/RT/Interface/Email/Auth/MailFrom.pm +++ b/rt/lib/RT/Interface/Email/Auth/MailFrom.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Interface/REST.pm b/rt/lib/RT/Interface/REST.pm index 5f8ff99b7..17fe44669 100644 --- a/rt/lib/RT/Interface/REST.pm +++ b/rt/lib/RT/Interface/REST.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -47,12 +47,13 @@ # END BPS TAGGED BLOCK }}} package RT::Interface::REST; +use LWP::MediaTypes qw(guess_media_type); use strict; use warnings; use RT; use base 'Exporter'; -our @EXPORT = qw(expand_list form_parse form_compose vpush vsplit); +our @EXPORT = qw(expand_list form_parse form_compose vpush vsplit process_attachments); sub custom_field_spec { my $self = shift; @@ -296,6 +297,45 @@ sub vsplit { return \@words; } +sub process_attachments { + my $entity = shift; + my @list = @_; + return 1 unless @list; + + my $m = $HTML::Mason::Commands::m; + my $cgi = $m->cgi_object; + + my $i = 1; + foreach my $e ( @list ) { + + my $fh = $cgi->upload("attachment_$i"); + return (0, "No attachment for $e") unless $fh; + + local $/=undef; + + my $file = $e; + $file =~ s#^.*[\\/]##; + + my ($tmp_fh, $tmp_fn) = File::Temp::tempfile( UNLINK => 1 ); + + my $buf; + while (sysread($fh, $buf, 8192)) { + syswrite($tmp_fh, $buf); + } + + my $info = $cgi->uploadInfo($fh); + my $new_entity = $entity->attach( + Path => $tmp_fn, + Type => $info->{'Content-Type'} || guess_media_type($tmp_fn), + Filename => $file, + Disposition => "attachment", + ); + $new_entity->bodyhandle->{'_dirty_hack_to_save_a_ref_tmp_fh'} = $tmp_fh; + $i++; + } + return (1); +} + RT::Base->_ImportOverlays(); 1; diff --git a/rt/lib/RT/Interface/Web.pm b/rt/lib/RT/Interface/Web.pm index 5ca4a9f63..1f2f488fb 100644 --- a/rt/lib/RT/Interface/Web.pm +++ b/rt/lib/RT/Interface/Web.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -1283,10 +1283,16 @@ our %is_whitelisted_component = ( # While these can be used for denial-of-service against RT # (construct a very inefficient query and trick lots of users into # running them against RT) it's incredibly useful to be able to link - # to a search result or bookmark a result page. + # to a search result (or chart) or bookmark a result page. '/Search/Results.html' => 1, '/Search/Simple.html' => 1, - '/m/tickets/search' => 1, + '/m/tickets/search' => 1, + '/Search/Chart.html' => 1, + + # This page takes Attachment and Transaction argument to figure + # out what to show, but it's read only and will deny information if you + # don't have ShowOutgoingEmail. + '/Ticket/ShowEmailRecord.html' => 1, ); # Components which are blacklisted from automatic, argument-based whitelisting. @@ -1762,7 +1768,7 @@ sub CreateTicket { $RT::Logger->error("Couldn't make multipart message") if !$rv || $rv !~ /^(?:DONE|ALREADY)$/; - foreach ( values %{ $ARGS{'Attachments'} } ) { + foreach ( map $ARGS{Attachments}->{$_}, sort keys %{ $ARGS{'Attachments'} } ) { unless ($_) { $RT::Logger->error("Couldn't add empty attachemnt"); next; @@ -2017,7 +2023,8 @@ sub ProcessUpdateMessage { if ( $args{ARGSRef}->{'UpdateAttachments'} ) { $Message->make_multipart; - $Message->add_part($_) foreach values %{ $args{ARGSRef}->{'UpdateAttachments'} }; + $Message->add_part($_) foreach map $args{ARGSRef}->{UpdateAttachments}{$_}, + sort keys %{ $args{ARGSRef}->{'UpdateAttachments'} }; } if ( $args{ARGSRef}->{'AttachTickets'} ) { @@ -2619,18 +2626,23 @@ sub ProcessTicketReminders { while ( my $reminder = $reminder_collection->Next ) { my $resolve_status = $reminder->QueueObj->Lifecycle->ReminderStatusOnResolve; if ( $reminder->Status ne $resolve_status && $args->{ 'Complete-Reminder-' . $reminder->id } ) { - $Ticket->Reminders->Resolve($reminder); + my ($status, $msg) = $Ticket->Reminders->Resolve($reminder); + push @results, loc("Reminder #[_1]: [_2]", $reminder->id, $msg); + } elsif ( $reminder->Status eq $resolve_status && !$args->{ 'Complete-Reminder-' . $reminder->id } ) { - $Ticket->Reminders->Open($reminder); + my ($status, $msg) = $Ticket->Reminders->Open($reminder); + push @results, loc("Reminder #[_1]: [_2]", $reminder->id, $msg); } if ( exists( $args->{ 'Reminder-Subject-' . $reminder->id } ) && ( $reminder->Subject ne $args->{ 'Reminder-Subject-' . $reminder->id } )) { - $reminder->SetSubject( $args->{ 'Reminder-Subject-' . $reminder->id } ) ; + my ($status, $msg) = $reminder->SetSubject( $args->{ 'Reminder-Subject-' . $reminder->id } ) ; + push @results, loc("Reminder #[_1]: [_2]", $reminder->id, $msg); } if ( exists( $args->{ 'Reminder-Owner-' . $reminder->id } ) && ( $reminder->Owner != $args->{ 'Reminder-Owner-' . $reminder->id } )) { - $reminder->SetOwner( $args->{ 'Reminder-Owner-' . $reminder->id } , "Force" ) ; + my ($status, $msg) = $reminder->SetOwner( $args->{ 'Reminder-Owner-' . $reminder->id } , "Force" ) ; + push @results, loc("Reminder #[_1]: [_2]", $reminder->id, $msg); } if ( exists( $args->{ 'Reminder-Due-' . $reminder->id } ) && $args->{ 'Reminder-Due-' . $reminder->id } ne '' ) { @@ -2640,7 +2652,8 @@ sub ProcessTicketReminders { Value => $args->{ 'Reminder-Due-' . $reminder->id } ); if ( defined $DateObj->Unix && $DateObj->Unix != $reminder->DueObj->Unix ) { - $reminder->SetDue( $DateObj->ISO ); + my ($status, $msg) = $reminder->SetDue( $DateObj->ISO ); + push @results, loc("Reminder #[_1]: [_2]", $reminder->id, $msg); } } } @@ -3180,7 +3193,8 @@ sub GetColumnMapEntry { } # complex things - elsif ( my ( $mainkey, $subkey ) = $args{'Name'} =~ /^(.*?)\.{(.+)}$/ ) { + elsif ( my ( $mainkey, $subkey ) = $args{'Name'} =~ /^(.*?)\.(.+)$/ ) { + $subkey =~ s/^\{(.*)\}$/$1/; return undef unless $args{'Map'}->{$mainkey}; return $args{'Map'}{$mainkey}{ $args{'Attribute'} } unless ref $args{'Map'}{$mainkey}{ $args{'Attribute'} } eq 'CODE'; diff --git a/rt/lib/RT/Interface/Web/Handler.pm b/rt/lib/RT/Interface/Web/Handler.pm index a1784c2cc..37031b18d 100644 --- a/rt/lib/RT/Interface/Web/Handler.pm +++ b/rt/lib/RT/Interface/Web/Handler.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Interface/Web/Menu.pm b/rt/lib/RT/Interface/Web/Menu.pm index e4e08d63b..e7833828c 100644 --- a/rt/lib/RT/Interface/Web/Menu.pm +++ b/rt/lib/RT/Interface/Web/Menu.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Interface/Web/QueryBuilder.pm b/rt/lib/RT/Interface/Web/QueryBuilder.pm index 546427833..a1b066227 100755 --- a/rt/lib/RT/Interface/Web/QueryBuilder.pm +++ b/rt/lib/RT/Interface/Web/QueryBuilder.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Interface/Web/QueryBuilder/Tree.pm b/rt/lib/RT/Interface/Web/QueryBuilder/Tree.pm index 9bbd876e5..f9305545f 100755 --- a/rt/lib/RT/Interface/Web/QueryBuilder/Tree.pm +++ b/rt/lib/RT/Interface/Web/QueryBuilder/Tree.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Interface/Web/Request.pm b/rt/lib/RT/Interface/Web/Request.pm index cdd4594d6..13d667288 100644 --- a/rt/lib/RT/Interface/Web/Request.pm +++ b/rt/lib/RT/Interface/Web/Request.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Interface/Web/Session.pm b/rt/lib/RT/Interface/Web/Session.pm index 4edd9bd2e..aded596c4 100644 --- a/rt/lib/RT/Interface/Web/Session.pm +++ b/rt/lib/RT/Interface/Web/Session.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -192,7 +192,7 @@ sub _ClearOldDB { die "couldn't execute query: ". $dbh->errstr unless defined $rows; } - $RT::Logger->info("successfuly deleted $rows sessions"); + $RT::Logger->info("successfully deleted $rows sessions"); return; } @@ -222,15 +222,53 @@ sub _ClearOldDir { next; } tied(%session)->delete; - $RT::Logger->info("successfuly deleted session '$id'"); + $RT::Logger->info("successfully deleted session '$id'"); } + # Apache::Session::Lock::File will clean out locks older than X, but it + # leaves around bogus locks if they're too new, even though they're + # guaranteed dead. On even just largeish installs, the accumulated number + # of them may bump into ext3/4 filesystem limits since Apache::Session + # doesn't use a fan-out tree. my $lock = Apache::Session::Lock::File->new; $lock->clean( $dir, $older_than ); + # Take matters into our own hands and clear bogus locks hanging around + # regardless of how recent they are. + $self->ClearOrphanLockFiles($dir); + return; } +=head3 ClearOrphanLockFiles + +Takes a directory in which to look for L<Apache::Session::Lock::File> locks +which no longer have a corresponding session file. If not provided, the +directory is taken from the session configuration data. + +=cut + +sub ClearOrphanLockFiles { + my $class = shift; + my $dir = shift || $class->Attributes->{Directory} + or return; + + if (opendir my $dh, $dir) { + for (readdir $dh) { + next unless /^Apache-Session-([0-9a-f]{32})\.lock$/; + next if -e "$dir/$1"; + + RT->Logger->debug("deleting orphaned session lockfile '$_'"); + + unlink "$dir/$_" + or warn "Failed to unlink session lockfile $dir/$_: $!"; + } + closedir $dh; + } else { + warn "Unable to open directory '$dir' for reading: $!"; + } +} + =head3 ClearByUser Checks all sessions and if user has more then one session @@ -243,6 +281,7 @@ sub ClearByUser { my $class = $self->Class; my $attrs = $self->Attributes; + my $deleted; my %seen = (); foreach my $id( @{ $self->Ids } ) { my %session; @@ -259,8 +298,10 @@ sub ClearByUser { } } tied(%session)->delete; - $RT::Logger->info("successfuly deleted session '$id'"); + $RT::Logger->info("successfully deleted session '$id'"); + $deleted++; } + $self->ClearOrphanLockFiles if $deleted; } sub TIEHASH { @@ -276,10 +317,8 @@ sub TIEHASH { eval { tie %session, $class, $id, $attrs }; eval { tie %session, $class, undef, $attrs } if $@; if ( $@ ) { - die loc("RT couldn't store your session.") . "\n" - . loc("This may mean that that the directory '[_1]' isn't writable or a database table is missing or corrupt.", - $RT::MasonSessionDir) - . "\n\n" + die "RT couldn't store your session. " + . "This may mean that that the directory '$RT::MasonSessionDir' isn't writable or a database table is missing or corrupt.\n\n" . $@; } diff --git a/rt/lib/RT/Lifecycle.pm b/rt/lib/RT/Lifecycle.pm index c90528258..accef228f 100644 --- a/rt/lib/RT/Lifecycle.pm +++ b/rt/lib/RT/Lifecycle.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -707,11 +707,11 @@ sub FillCache { } my %seen; - @statuses = grep !$seen{ $_ }++, @statuses; + @statuses = grep !$seen{ lc $_ }++, @statuses; $lifecycle->{''} = \@statuses; unless ( $lifecycle->{'transitions'}{''} ) { - $lifecycle->{'transitions'}{''} = [ grep $_ ne 'deleted', @statuses ]; + $lifecycle->{'transitions'}{''} = [ grep lc $_ ne 'deleted', @statuses ]; } my @actions; @@ -767,7 +767,7 @@ sub FillCache { foreach my $type ( qw(initial active inactive), '' ) { my %seen; - @{ $all{ $type } } = grep !$seen{ $_ }++, @{ $all{ $type } }; + @{ $all{ $type } } = grep !$seen{ lc $_ }++, @{ $all{ $type } }; push @{ $all{''} }, @{ $all{ $type } } if $type; } $LIFECYCLES_CACHE{''} = \%all; diff --git a/rt/lib/RT/Link.pm b/rt/lib/RT/Link.pm index 7a277473f..305c34503 100644 --- a/rt/lib/RT/Link.pm +++ b/rt/lib/RT/Link.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Links.pm b/rt/lib/RT/Links.pm index af36a5bdc..d90865daf 100644 --- a/rt/lib/RT/Links.pm +++ b/rt/lib/RT/Links.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/ObjectClass.pm b/rt/lib/RT/ObjectClass.pm index 684af132d..7fd8d9066 100644 --- a/rt/lib/RT/ObjectClass.pm +++ b/rt/lib/RT/ObjectClass.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/ObjectClasses.pm b/rt/lib/RT/ObjectClasses.pm index 01cf77f8e..b179180d7 100644 --- a/rt/lib/RT/ObjectClasses.pm +++ b/rt/lib/RT/ObjectClasses.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/ObjectCustomField.pm b/rt/lib/RT/ObjectCustomField.pm index e7f350a5a..1acf891f2 100644 --- a/rt/lib/RT/ObjectCustomField.pm +++ b/rt/lib/RT/ObjectCustomField.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/ObjectCustomFieldValue.pm b/rt/lib/RT/ObjectCustomFieldValue.pm index 63da581ce..de4bc748d 100644 --- a/rt/lib/RT/ObjectCustomFieldValue.pm +++ b/rt/lib/RT/ObjectCustomFieldValue.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/ObjectCustomFieldValues.pm b/rt/lib/RT/ObjectCustomFieldValues.pm index a1d5391f8..486265e26 100644 --- a/rt/lib/RT/ObjectCustomFieldValues.pm +++ b/rt/lib/RT/ObjectCustomFieldValues.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/ObjectCustomFields.pm b/rt/lib/RT/ObjectCustomFields.pm index 5bdc069ba..97e4f91fb 100644 --- a/rt/lib/RT/ObjectCustomFields.pm +++ b/rt/lib/RT/ObjectCustomFields.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/ObjectTopic.pm b/rt/lib/RT/ObjectTopic.pm index 8ca01ae9d..a5e36c348 100644 --- a/rt/lib/RT/ObjectTopic.pm +++ b/rt/lib/RT/ObjectTopic.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/ObjectTopics.pm b/rt/lib/RT/ObjectTopics.pm index bdcff7755..f376f53d7 100644 --- a/rt/lib/RT/ObjectTopics.pm +++ b/rt/lib/RT/ObjectTopics.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Plugin.pm b/rt/lib/RT/Plugin.pm index 1f97ec22d..82f4de2b2 100644 --- a/rt/lib/RT/Plugin.pm +++ b/rt/lib/RT/Plugin.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Pod/HTML.pm b/rt/lib/RT/Pod/HTML.pm index 689606323..69045595b 100644 --- a/rt/lib/RT/Pod/HTML.pm +++ b/rt/lib/RT/Pod/HTML.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -54,6 +54,10 @@ use base 'Pod::Simple::XHTML'; use HTML::Entities qw//; +__PACKAGE__->_accessorize( + "batch" +); + sub new { my $self = shift->SUPER::new(@_); $self->index(1); @@ -118,27 +122,35 @@ sub resolve_local_link { my $self = shift; my ($name, $section) = @_; + $name .= ""; # stringify name, it may be an object + $section = defined $section ? '#' . $self->idify($section, 1) : ''; my $local; - if ($name =~ /^RT::/) { + if ($name =~ /^RT(::(?!Extension::|Authen::)|$)/ or $self->batch->found($name)) { $local = join "/", map { $self->encode_entities($_) } split /::/, $name; } - elsif ($name =~ /^rt[-_]/) { + elsif ($name =~ /^rt([-_]|$)/) { $local = $self->encode_entities($name); } - elsif ($name eq "RT_Config" or $name eq "RT_Config.pm") { - $local = "RT_Config"; + elsif ($name =~ /^(\w+)_Config(\.pm)?$/) { + $name = "$1_Config"; + $local = "$1_Config"; + } + elsif ($name eq 'README') { + # We process README separately in devel/tools/rt-static-docs + $local = $name; } # These matches handle links that look like filenames, such as those we # parse out of F<> tags. elsif ( $name =~ m{^(?:lib/)(RT/[\w/]+?)\.pm$} or $name =~ m{^(?:docs/)(.+?)\.pod$}) { + $name = join "::", split '/', $1; $local = join "/", map { $self->encode_entities($_) } split /\//, $1; @@ -146,11 +158,20 @@ sub resolve_local_link { if ($local) { # Resolve links correctly by going up - my $depth = $self->batch_mode_current_level - 1; - return ($depth ? "../" x $depth : "") . "$local.html$section"; + my $found = $self->batch->found($name); + my $depth = $self->batch_mode_current_level + + ($found ? -1 : 1); + return ($depth ? "../" x $depth : "") . ($found ? "" : "rt/latest/") . "$local.html$section"; } else { return; } } +sub batch_mode_page_object_init { + my ($self, $batch, $module, $infile, $outfile, $depth) = @_; + $self->SUPER::batch_mode_page_object_init(@_[1..$#_]); + $self->batch( $batch ); + return $self; +} + 1; diff --git a/rt/lib/RT/Pod/HTMLBatch.pm b/rt/lib/RT/Pod/HTMLBatch.pm index f41a43acb..2545ea91c 100644 --- a/rt/lib/RT/Pod/HTMLBatch.pm +++ b/rt/lib/RT/Pod/HTMLBatch.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -84,7 +84,7 @@ sub classify { my %page = @_; local $_ = $page{name}; return 1 if /^(README|UPGRADING)/; - return 1 if $_ eq "RT_Config"; + return 1 if /^RT\w*?_Config$/; return 1 if $_ eq "web_deployment"; return 1 if $page{infile} =~ m{^configure(\.ac)?$}; return 0; @@ -176,4 +176,9 @@ sub esc { Pod::Simple::HTMLBatch::esc(@_); } +sub found { + my ($self, $module) = @_; + return grep { $_->[0] eq $module } @{$self->_contents}; +} + 1; diff --git a/rt/lib/RT/Pod/Search.pm b/rt/lib/RT/Pod/Search.pm index 29e7d437c..e0670ea3b 100644 --- a/rt/lib/RT/Pod/Search.pm +++ b/rt/lib/RT/Pod/Search.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Principal.pm b/rt/lib/RT/Principal.pm index 175f1b003..76582d675 100644 --- a/rt/lib/RT/Principal.pm +++ b/rt/lib/RT/Principal.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -263,8 +263,9 @@ sub HasRight { return 1; } - $args{'Right'} = RT::ACE->CanonicalizeRightName( $args{'Right'} ); - unless ( $args{'Right'} ) { + if ( my $right = RT::ACE->CanonicalizeRightName( $args{'Right'} ) ) { + $args{'Right'} = $right; + } else { $RT::Logger->error( "Invalid right. Couldn't canonicalize right '$args{'Right'}'"); return undef; diff --git a/rt/lib/RT/Principals.pm b/rt/lib/RT/Principals.pm index 9cf8cbb39..145ec17af 100644 --- a/rt/lib/RT/Principals.pm +++ b/rt/lib/RT/Principals.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -78,6 +78,7 @@ sub Table { 'Principals'} sub _Init { my $self = shift; + $self->{'with_disabled_column'} = 1; return ( $self->SUPER::_Init(@_) ); } diff --git a/rt/lib/RT/Queue.pm b/rt/lib/RT/Queue.pm index ee68b8195..677a05af8 100755 --- a/rt/lib/RT/Queue.pm +++ b/rt/lib/RT/Queue.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Queues.pm b/rt/lib/RT/Queues.pm index 45cb686e0..f5cd2b2b5 100755 --- a/rt/lib/RT/Queues.pm +++ b/rt/lib/RT/Queues.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Record.pm b/rt/lib/RT/Record.pm index 6601a0df2..59867aae8 100755 --- a/rt/lib/RT/Record.pm +++ b/rt/lib/RT/Record.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -730,9 +730,20 @@ sub _Accessible { } -=head2 _EncodeLOB BODY MIME_TYPE +=head2 _EncodeLOB BODY MIME_TYPE FILENAME -Takes a potentially large attachment. Returns (ContentEncoding, EncodedBody) based on system configuration and selected database +Takes a potentially large attachment. Returns (ContentEncoding, +EncodedBody, MimeType, Filename) based on system configuration and +selected database. Returns a custom (short) text/plain message if +DropLongAttachments causes an attachment to not be stored. + +Encodes your data as base64 or Quoted-Printable as needed based on your +Databases's restrictions and the UTF-8ness of the data being passed in. Since +we are storing in columns marked UTF8, we must ensure that binary data is +encoded on databases which are strict. + +This function expects to receive an octet string in order to properly +evaluate and encode it. It will return an octet string. =cut @@ -760,7 +771,7 @@ sub _EncodeLOB { $MaxSize = $MaxSize * 3 / 4; # Some databases (postgres) can't handle non-utf8 data } elsif ( !$RT::Handle->BinarySafeBLOBs - && $MIMEType !~ /text\/plain/gi + && $Body =~ /\P{ASCII}/ && !Encode::is_utf8( $Body, 1 ) ) { $ContentEncoding = 'quoted-printable'; } @@ -784,7 +795,7 @@ sub _EncodeLOB { . length($Body)); $RT::Logger->info( "It started: " . substr( $Body, 0, 60 ) ); $Filename .= ".txt" if $Filename; - return ("none", "Large attachment dropped", "plain/text", $Filename ); + return ("none", "Large attachment dropped", "text/plain", $Filename ); } } @@ -805,6 +816,27 @@ sub _EncodeLOB { } +=head2 _DecodeLOB + +Unpacks data stored in the database, which may be base64 or QP encoded +because of our need to store binary and badly encoded data in columns +marked as UTF-8. Databases such as PostgreSQL and Oracle care that you +are feeding them invalid UTF-8 and will refuse the content. This +function handles unpacking the encoded data. + +It returns textual data as a UTF-8 string which has been processed by Encode's +PERLQQ filter which will replace the invalid bytes with \x{HH} so you can see +the invalid byte but won't run into problems treating the data as UTF-8 later. + +This is similar to how we filter all data coming in via the web UI in +RT::Interface::Web::DecodeARGS. This filter should only end up being +applied to old data from less UTF-8-safe versions of RT. + +Important Note - This function expects an octet string and returns a +character string for non-binary data. + +=cut + sub _DecodeLOB { my $self = shift; my $ContentType = shift || ''; @@ -821,7 +853,7 @@ sub _DecodeLOB { return ( $self->loc( "Unknown ContentEncoding [_1]", $ContentEncoding ) ); } if ( RT::I18N::IsTextualContentType($ContentType) ) { - $Content = Encode::decode_utf8($Content) unless Encode::is_utf8($Content); + $Content = Encode::decode('UTF-8',$Content,Encode::FB_PERLQQ) unless Encode::is_utf8($Content); } return ($Content); } @@ -1372,7 +1404,7 @@ sub _AddLink { if ( $args{'Base'} and $args{'Target'} ) { $RT::Logger->debug( "$self tried to create a link. both base and target were specified" ); - return ( 0, $self->loc("Can't specifiy both base and target") ); + return ( 0, $self->loc("Can't specify both base and target") ); } elsif ( $args{'Base'} ) { $args{'Target'} = $self->URI(); @@ -1450,7 +1482,7 @@ sub _DeleteLink { if ( $args{'Base'} and $args{'Target'} ) { $RT::Logger->debug("$self ->_DeleteLink. got both Base and Target"); - return ( 0, $self->loc("Can't specifiy both base and target") ); + return ( 0, $self->loc("Can't specify both base and target") ); } elsif ( $args{'Base'} ) { $args{'Target'} = $self->URI(); @@ -1686,7 +1718,7 @@ Returns the path RT uses to figure out which custom fields apply to this object. sub CustomFieldLookupType { my $self = shift; - return ref($self); + return ref($self) || $self; } @@ -1789,7 +1821,7 @@ sub _AddCustomFieldValue { my $is_the_same = 1; if ( defined $args{'Value'} ) { $is_the_same = 0 unless defined $old_content - && lc $old_content eq lc $args{'Value'}; + && $old_content eq $args{'Value'}; } else { $is_the_same = 0 if defined $old_content; } diff --git a/rt/lib/RT/Reminders.pm b/rt/lib/RT/Reminders.pm index 42f4e1d2f..133dbf030 100644 --- a/rt/lib/RT/Reminders.pm +++ b/rt/lib/RT/Reminders.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -122,7 +122,7 @@ sub Add { return ( 0, $self->loc( "Failed to load ticket [_1]", $self->Ticket ) ); } - if ( $ticket->Status eq 'deleted' ) { + if ( lc $ticket->Status eq 'deleted' ) { return ( 0, $self->loc("Can't link to a deleted ticket") ); } @@ -134,6 +134,7 @@ sub Add { RefersTo => $self->Ticket, Type => 'reminder', Queue => $self->TicketObj->Queue, + Status => $self->TicketObj->QueueObj->Lifecycle->ReminderStatusOnOpen, ); $self->TicketObj->_NewTransaction( Type => 'AddReminder', diff --git a/rt/lib/RT/Report/Tickets.pm b/rt/lib/RT/Report/Tickets.pm index b73bbaaa3..aa27b17f3 100644 --- a/rt/lib/RT/Report/Tickets.pm +++ b/rt/lib/RT/Report/Tickets.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -111,7 +111,7 @@ sub Groupings { sub Label { my $self = shift; my $field = shift; - if ( $field =~ /^(?:CF|CustomField)\.{(.*)}$/ ) { + if ( $field =~ /^(?:CF|CustomField)\.\{(.*)\}$/ ) { my $cf = $1; return $self->CurrentUser->loc( "Custom field '[_1]'", $cf ) if $cf =~ /\D/; my $obj = RT::CustomField->new( $self->CurrentUser ); @@ -239,7 +239,7 @@ sub _FieldToFunction { $func = "SUBSTR($func,1,4)"; } $args{'FUNCTION'} = $func; - } elsif ( $field =~ /^(?:CF|CustomField)\.{(.*)}$/ ) { #XXX: use CFDecipher method + } elsif ( $field =~ /^(?:CF|CustomField)\.\{(.*)\}$/ ) { #XXX: use CFDecipher method my $cf_name = $1; my $cf = RT::CustomField->new( $self->CurrentUser ); $cf->Load($cf_name); diff --git a/rt/lib/RT/Report/Tickets/Entry.pm b/rt/lib/RT/Report/Tickets/Entry.pm index eb3899319..fc0b63394 100644 --- a/rt/lib/RT/Report/Tickets/Entry.pm +++ b/rt/lib/RT/Report/Tickets/Entry.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Rule.pm b/rt/lib/RT/Rule.pm index c5c8b0920..675191535 100644 --- a/rt/lib/RT/Rule.pm +++ b/rt/lib/RT/Rule.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Ruleset.pm b/rt/lib/RT/Ruleset.pm index 26227b759..e6267da06 100644 --- a/rt/lib/RT/Ruleset.pm +++ b/rt/lib/RT/Ruleset.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/SQL.pm b/rt/lib/RT/SQL.pm index 15715a762..94b56653c 100644 --- a/rt/lib/RT/SQL.pm +++ b/rt/lib/RT/SQL.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/SavedSearch.pm b/rt/lib/RT/SavedSearch.pm index 7c4df8b76..3e0e928eb 100644 --- a/rt/lib/RT/SavedSearch.pm +++ b/rt/lib/RT/SavedSearch.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/SavedSearches.pm b/rt/lib/RT/SavedSearches.pm index af8f48265..25c7e4a69 100644 --- a/rt/lib/RT/SavedSearches.pm +++ b/rt/lib/RT/SavedSearches.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Scrip.pm b/rt/lib/RT/Scrip.pm index 5fa7165b1..71080a00c 100755 --- a/rt/lib/RT/Scrip.pm +++ b/rt/lib/RT/Scrip.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/ScripAction.pm b/rt/lib/RT/ScripAction.pm index 44f9bd83c..be8b130d5 100755 --- a/rt/lib/RT/ScripAction.pm +++ b/rt/lib/RT/ScripAction.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/ScripActions.pm b/rt/lib/RT/ScripActions.pm index a3a162253..41ac60e92 100755 --- a/rt/lib/RT/ScripActions.pm +++ b/rt/lib/RT/ScripActions.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/ScripCondition.pm b/rt/lib/RT/ScripCondition.pm index e7e4652c9..0d0fa665e 100755 --- a/rt/lib/RT/ScripCondition.pm +++ b/rt/lib/RT/ScripCondition.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/ScripConditions.pm b/rt/lib/RT/ScripConditions.pm index 66684972d..368008b2b 100755 --- a/rt/lib/RT/ScripConditions.pm +++ b/rt/lib/RT/ScripConditions.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Scrips.pm b/rt/lib/RT/Scrips.pm index af8323e33..de9d1eae9 100755 --- a/rt/lib/RT/Scrips.pm +++ b/rt/lib/RT/Scrips.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Search.pm b/rt/lib/RT/Search.pm index 7ec50de88..8e13987aa 100755 --- a/rt/lib/RT/Search.pm +++ b/rt/lib/RT/Search.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Search/ActiveTicketsInQueue.pm b/rt/lib/RT/Search/ActiveTicketsInQueue.pm index da1cdb646..1c69e93b2 100644 --- a/rt/lib/RT/Search/ActiveTicketsInQueue.pm +++ b/rt/lib/RT/Search/ActiveTicketsInQueue.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Search/FromSQL.pm b/rt/lib/RT/Search/FromSQL.pm index 4cb17f5e5..2f27fee82 100644 --- a/rt/lib/RT/Search/FromSQL.pm +++ b/rt/lib/RT/Search/FromSQL.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Search/Googleish.pm b/rt/lib/RT/Search/Googleish.pm index f8465f00e..d11fa2b13 100644 --- a/rt/lib/RT/Search/Googleish.pm +++ b/rt/lib/RT/Search/Googleish.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -197,6 +197,7 @@ our @GUESS = ( [ 10 => sub { return "subject" if $_[1] } ], [ 20 => sub { return "id" if /^#?\d+$/ } ], [ 30 => sub { return "requestor" if /\w+@\w+/} ], + [ 35 => sub { return "domain" if /^@\w+/} ], [ 40 => sub { return "status" if RT::Queue->new( $_[2] )->IsValidStatus( $_ ) }], @@ -260,6 +261,7 @@ sub HandleWatcher { return watcher => (!$_[2] and $_[1] eq "me") ? "Watcher.id = '__CurrentUser__'" : "Watcher = '$_[1]'"; } sub HandleRequestor { return requestor => "Requestor STARTSWITH '$_[1]'"; } +sub HandleDomain { $_[1] =~ s/^@?/@/; return requestor => "Requestor ENDSWITH '$_[1]'"; } sub HandleQueue { return queue => "Queue = '$_[1]'"; } sub HandleQ { return queue => "Queue = '$_[1]'"; } sub HandleCf { return "cf.$_[3]" => "'CF.{$_[3]}' LIKE '$_[1]'"; } diff --git a/rt/lib/RT/SearchBuilder.pm b/rt/lib/RT/SearchBuilder.pm index adc8a98d7..8b808c69b 100644 --- a/rt/lib/RT/SearchBuilder.pm +++ b/rt/lib/RT/SearchBuilder.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -86,9 +86,13 @@ sub _Init { $self->SUPER::_Init( 'Handle' => $RT::Handle); } +sub _Handle { return $RT::Handle } + sub CleanSlate { my $self = shift; $self->{'_sql_aliases'} = {}; + delete $self->{'handled_disabled_column'}; + delete $self->{'find_disabled_rows'}; return $self->SUPER::CleanSlate(@_); } diff --git a/rt/lib/RT/SharedSetting.pm b/rt/lib/RT/SharedSetting.pm index 3467167cc..0bdd196ea 100644 --- a/rt/lib/RT/SharedSetting.pm +++ b/rt/lib/RT/SharedSetting.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/SharedSettings.pm b/rt/lib/RT/SharedSettings.pm index 6e7ec3b19..51b496552 100644 --- a/rt/lib/RT/SharedSettings.pm +++ b/rt/lib/RT/SharedSettings.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder.pm b/rt/lib/RT/Shredder.pm index bebd599b4..125ed0dc4 100644 --- a/rt/lib/RT/Shredder.pm +++ b/rt/lib/RT/Shredder.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -164,6 +164,21 @@ your F<RT_SiteConfig.pm>: Be sure to specify an absolute path. +=head1 Database Indexes + +We have found that the following indexes significantly speed up +shredding on most databases. + + CREATE INDEX SHREDDER_CGM1 ON CachedGroupMembers(MemberId, GroupId, Disabled); + CREATE INDEX SHREDDER_CGM2 ON CachedGroupMembers(ImmediateParentId,MemberId); + CREATE INDEX SHREDDER_CGM3 on CachedGroupMembers (Via, Id); + + CREATE UNIQUE INDEX SHREDDER_GM1 ON GroupMembers(MemberId, GroupId); + + CREATE INDEX SHREDDER_TXN1 ON Transactions(ReferenceType, OldReference); + CREATE INDEX SHREDDER_TXN2 ON Transactions(ReferenceType, NewReference); + CREATE INDEX SHREDDER_TXN3 ON Transactions(Type, OldValue); + CREATE INDEX SHREDDER_TXN4 ON Transactions(Type, NewValue) =head1 INFORMATION FOR DEVELOPERS diff --git a/rt/lib/RT/Shredder/ACE.pm b/rt/lib/RT/Shredder/ACE.pm index 7a50d9a90..1f882e2ff 100644 --- a/rt/lib/RT/Shredder/ACE.pm +++ b/rt/lib/RT/Shredder/ACE.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/Attachment.pm b/rt/lib/RT/Shredder/Attachment.pm index 9cd40884d..a3705fae1 100644 --- a/rt/lib/RT/Shredder/Attachment.pm +++ b/rt/lib/RT/Shredder/Attachment.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/CachedGroupMember.pm b/rt/lib/RT/Shredder/CachedGroupMember.pm index 9f1668f9e..ffd4ada04 100644 --- a/rt/lib/RT/Shredder/CachedGroupMember.pm +++ b/rt/lib/RT/Shredder/CachedGroupMember.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/Constants.pm b/rt/lib/RT/Shredder/Constants.pm index b09b52f7d..b71e19108 100644 --- a/rt/lib/RT/Shredder/Constants.pm +++ b/rt/lib/RT/Shredder/Constants.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/CustomField.pm b/rt/lib/RT/Shredder/CustomField.pm index 8c7dc2210..e6fcc5f01 100644 --- a/rt/lib/RT/Shredder/CustomField.pm +++ b/rt/lib/RT/Shredder/CustomField.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/CustomFieldValue.pm b/rt/lib/RT/Shredder/CustomFieldValue.pm index 9a9d36967..0cefc9be7 100644 --- a/rt/lib/RT/Shredder/CustomFieldValue.pm +++ b/rt/lib/RT/Shredder/CustomFieldValue.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/Dependencies.pm b/rt/lib/RT/Shredder/Dependencies.pm index 9364887fc..fdfcb8bf5 100644 --- a/rt/lib/RT/Shredder/Dependencies.pm +++ b/rt/lib/RT/Shredder/Dependencies.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/Dependency.pm b/rt/lib/RT/Shredder/Dependency.pm index 280077132..b94f43aea 100644 --- a/rt/lib/RT/Shredder/Dependency.pm +++ b/rt/lib/RT/Shredder/Dependency.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/Exceptions.pm b/rt/lib/RT/Shredder/Exceptions.pm index 8c1d6ed4c..d0cc2db9d 100644 --- a/rt/lib/RT/Shredder/Exceptions.pm +++ b/rt/lib/RT/Shredder/Exceptions.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/Group.pm b/rt/lib/RT/Shredder/Group.pm index bbf84ab88..ad74e976f 100644 --- a/rt/lib/RT/Shredder/Group.pm +++ b/rt/lib/RT/Shredder/Group.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/GroupMember.pm b/rt/lib/RT/Shredder/GroupMember.pm index a7e0b427f..ed632e3df 100644 --- a/rt/lib/RT/Shredder/GroupMember.pm +++ b/rt/lib/RT/Shredder/GroupMember.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/Link.pm b/rt/lib/RT/Shredder/Link.pm index a4429100e..32d583d26 100644 --- a/rt/lib/RT/Shredder/Link.pm +++ b/rt/lib/RT/Shredder/Link.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/ObjectCustomFieldValue.pm b/rt/lib/RT/Shredder/ObjectCustomFieldValue.pm index 7612f4ade..dab4d5bee 100644 --- a/rt/lib/RT/Shredder/ObjectCustomFieldValue.pm +++ b/rt/lib/RT/Shredder/ObjectCustomFieldValue.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/POD.pm b/rt/lib/RT/Shredder/POD.pm index 6cc869503..ee4fb09ca 100644 --- a/rt/lib/RT/Shredder/POD.pm +++ b/rt/lib/RT/Shredder/POD.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/Plugin.pm b/rt/lib/RT/Shredder/Plugin.pm index 60ba333c2..84d20eb1a 100644 --- a/rt/lib/RT/Shredder/Plugin.pm +++ b/rt/lib/RT/Shredder/Plugin.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/Plugin/Attachments.pm b/rt/lib/RT/Shredder/Plugin/Attachments.pm index f0f64a192..05f264ec3 100644 --- a/rt/lib/RT/Shredder/Plugin/Attachments.pm +++ b/rt/lib/RT/Shredder/Plugin/Attachments.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/Plugin/Base.pm b/rt/lib/RT/Shredder/Plugin/Base.pm index 0adadfd1e..7ada97e48 100644 --- a/rt/lib/RT/Shredder/Plugin/Base.pm +++ b/rt/lib/RT/Shredder/Plugin/Base.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/Plugin/Base/Dump.pm b/rt/lib/RT/Shredder/Plugin/Base/Dump.pm index 903a962b8..945bd93e8 100644 --- a/rt/lib/RT/Shredder/Plugin/Base/Dump.pm +++ b/rt/lib/RT/Shredder/Plugin/Base/Dump.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/Plugin/Base/Search.pm b/rt/lib/RT/Shredder/Plugin/Base/Search.pm index a493cd82f..bb21bd6af 100644 --- a/rt/lib/RT/Shredder/Plugin/Base/Search.pm +++ b/rt/lib/RT/Shredder/Plugin/Base/Search.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/Plugin/Objects.pm b/rt/lib/RT/Shredder/Plugin/Objects.pm index 20905748b..ebfe2a00f 100644 --- a/rt/lib/RT/Shredder/Plugin/Objects.pm +++ b/rt/lib/RT/Shredder/Plugin/Objects.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/Plugin/SQLDump.pm b/rt/lib/RT/Shredder/Plugin/SQLDump.pm index 2e7c25965..cc0d4cc08 100644 --- a/rt/lib/RT/Shredder/Plugin/SQLDump.pm +++ b/rt/lib/RT/Shredder/Plugin/SQLDump.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/Plugin/Summary.pm b/rt/lib/RT/Shredder/Plugin/Summary.pm index 9b533bc60..9ccd66e0a 100644 --- a/rt/lib/RT/Shredder/Plugin/Summary.pm +++ b/rt/lib/RT/Shredder/Plugin/Summary.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/Plugin/Tickets.pm b/rt/lib/RT/Shredder/Plugin/Tickets.pm index 034448723..180c45c9e 100644 --- a/rt/lib/RT/Shredder/Plugin/Tickets.pm +++ b/rt/lib/RT/Shredder/Plugin/Tickets.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/Plugin/Users.pm b/rt/lib/RT/Shredder/Plugin/Users.pm index 244a2621b..5b7ccae8f 100644 --- a/rt/lib/RT/Shredder/Plugin/Users.pm +++ b/rt/lib/RT/Shredder/Plugin/Users.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/Principal.pm b/rt/lib/RT/Shredder/Principal.pm index 5dc04b30b..14f446a88 100644 --- a/rt/lib/RT/Shredder/Principal.pm +++ b/rt/lib/RT/Shredder/Principal.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/Queue.pm b/rt/lib/RT/Shredder/Queue.pm index 80a1c84c6..426170e0d 100644 --- a/rt/lib/RT/Shredder/Queue.pm +++ b/rt/lib/RT/Shredder/Queue.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/Record.pm b/rt/lib/RT/Shredder/Record.pm index d70bf123b..6a8777a8e 100644 --- a/rt/lib/RT/Shredder/Record.pm +++ b/rt/lib/RT/Shredder/Record.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/Scrip.pm b/rt/lib/RT/Shredder/Scrip.pm index 74878b62b..9a80cf988 100644 --- a/rt/lib/RT/Shredder/Scrip.pm +++ b/rt/lib/RT/Shredder/Scrip.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/ScripAction.pm b/rt/lib/RT/Shredder/ScripAction.pm index cdad7e4d2..ebe7ce586 100644 --- a/rt/lib/RT/Shredder/ScripAction.pm +++ b/rt/lib/RT/Shredder/ScripAction.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/ScripCondition.pm b/rt/lib/RT/Shredder/ScripCondition.pm index 857f0623e..6d2b83e5c 100644 --- a/rt/lib/RT/Shredder/ScripCondition.pm +++ b/rt/lib/RT/Shredder/ScripCondition.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/Template.pm b/rt/lib/RT/Shredder/Template.pm index 4ac6daf79..89859a6e0 100644 --- a/rt/lib/RT/Shredder/Template.pm +++ b/rt/lib/RT/Shredder/Template.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/Ticket.pm b/rt/lib/RT/Shredder/Ticket.pm index 2e5453666..b70e8bb97 100644 --- a/rt/lib/RT/Shredder/Ticket.pm +++ b/rt/lib/RT/Shredder/Ticket.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/Transaction.pm b/rt/lib/RT/Shredder/Transaction.pm index 37e6ba5ad..1fe42f9f7 100644 --- a/rt/lib/RT/Shredder/Transaction.pm +++ b/rt/lib/RT/Shredder/Transaction.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Shredder/User.pm b/rt/lib/RT/Shredder/User.pm index 6e19da789..0cd5bf335 100644 --- a/rt/lib/RT/Shredder/User.pm +++ b/rt/lib/RT/Shredder/User.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Squish.pm b/rt/lib/RT/Squish.pm index e64b71198..e0e61065c 100644 --- a/rt/lib/RT/Squish.pm +++ b/rt/lib/RT/Squish.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Squish/CSS.pm b/rt/lib/RT/Squish/CSS.pm index 1e2a45326..5ce3882cd 100644 --- a/rt/lib/RT/Squish/CSS.pm +++ b/rt/lib/RT/Squish/CSS.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Squish/JS.pm b/rt/lib/RT/Squish/JS.pm index 4dd24b709..9a4cac582 100644 --- a/rt/lib/RT/Squish/JS.pm +++ b/rt/lib/RT/Squish/JS.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/System.pm b/rt/lib/RT/System.pm index cf3d2d00b..4c1f5f135 100644 --- a/rt/lib/RT/System.pm +++ b/rt/lib/RT/System.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Template.pm b/rt/lib/RT/Template.pm index fd4b511e9..d15c1cdcb 100755 --- a/rt/lib/RT/Template.pm +++ b/rt/lib/RT/Template.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -256,7 +256,7 @@ sub Create { $args{'Queue'} = $QueueObj->Id; } - my $result = $self->SUPER::Create( + my ( $result, $msg ) = $self->SUPER::Create( Content => $args{'Content'}, Queue => $args{'Queue'}, Description => $args{'Description'}, @@ -264,7 +264,11 @@ sub Create { Type => $args{'Type'}, ); - return ($result); + if ( wantarray ) { + return ( $result, $msg ); + } else { + return ( $result ); + } } diff --git a/rt/lib/RT/Templates.pm b/rt/lib/RT/Templates.pm index b4da63628..7d117fae3 100755 --- a/rt/lib/RT/Templates.pm +++ b/rt/lib/RT/Templates.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Test.pm b/rt/lib/RT/Test.pm index 55fd88af9..2a1f52b90 100644 --- a/rt/lib/RT/Test.pm +++ b/rt/lib/RT/Test.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -51,6 +51,7 @@ package RT::Test; use strict; use warnings; +BEGIN { $^W = 1 }; use base 'Test::More'; @@ -925,7 +926,7 @@ sub set_rights { $acl->Limit( FIELD => 'RightName', OPERATOR => '!=', VALUE => 'SuperUser' ); while ( my $ace = $acl->Next ) { my $obj = $ace->PrincipalObj->Object; - if ( $obj->isa('RT::Group') && $obj->Type eq 'UserEquiv' && $obj->Instance == RT->Nobody->id ) { + if ( $obj->isa('RT::Group') && ($obj->Type||'') eq 'UserEquiv' && $obj->Instance == RT->Nobody->id ) { next; } $ace->Delete; @@ -1502,9 +1503,7 @@ sub stop_server { my $in_end = shift; return unless @SERVERS; - my $sig = 'TERM'; - $sig = 'INT' if $ENV{'RT_TEST_WEB_HANDLER'} eq "plack"; - kill $sig, @SERVERS; + kill 'TERM', @SERVERS; foreach my $pid (@SERVERS) { if ($ENV{RT_TEST_WEB_HANDLER} =~ /^apache/) { sleep 1 while kill 0, $pid; diff --git a/rt/lib/RT/Test/Apache.pm b/rt/lib/RT/Test/Apache.pm index 256945afe..31ad9bcf8 100644 --- a/rt/lib/RT/Test/Apache.pm +++ b/rt/lib/RT/Test/Apache.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Test/Email.pm b/rt/lib/RT/Test/Email.pm index 8cf683946..54aa87dcd 100644 --- a/rt/lib/RT/Test/Email.pm +++ b/rt/lib/RT/Test/Email.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Test/GnuPG.pm b/rt/lib/RT/Test/GnuPG.pm index ec446724e..95c21f8ae 100644 --- a/rt/lib/RT/Test/GnuPG.pm +++ b/rt/lib/RT/Test/GnuPG.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Test/Web.pm b/rt/lib/RT/Test/Web.pm index 8611102c2..81644817c 100644 --- a/rt/lib/RT/Test/Web.pm +++ b/rt/lib/RT/Test/Web.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Ticket.pm b/rt/lib/RT/Ticket.pm index 61653789c..6a8b40cfb 100755 --- a/rt/lib/RT/Ticket.pm +++ b/rt/lib/RT/Ticket.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -642,7 +642,7 @@ sub Create { } } - if ( $obj && $obj->Status eq 'deleted' ) { + if ( $obj && lc $obj->Status eq 'deleted' ) { push @non_fatal_errors, $self->loc("Linking. Can't link to a deleted ticket"); next; @@ -2681,7 +2681,7 @@ sub AddLink { } return ( 0, "Can't link to a deleted ticket" ) - if $other_ticket && $other_ticket->Status eq 'deleted'; + if $other_ticket && lc $other_ticket->Status eq 'deleted'; return $self->_AddLink(%args); } diff --git a/rt/lib/RT/Tickets.pm b/rt/lib/RT/Tickets.pm index 06b17e263..2220a077f 100755 --- a/rt/lib/RT/Tickets.pm +++ b/rt/lib/RT/Tickets.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -142,9 +142,9 @@ our %FIELD_METADATA = ( QueueCc => [ 'WATCHERFIELD' => 'Cc' => 'Queue', ], #loc_left_pair QueueAdminCc => [ 'WATCHERFIELD' => 'AdminCc' => 'Queue', ], #loc_left_pair QueueWatcher => [ 'WATCHERFIELD' => undef => 'Queue', ], #loc_left_pair - CustomFieldValue => [ 'CUSTOMFIELD', ], #loc_left_pair - CustomField => [ 'CUSTOMFIELD', ], #loc_left_pair - CF => [ 'CUSTOMFIELD', ], #loc_left_pair + CustomFieldValue => [ 'CUSTOMFIELD' => 'Ticket' ], #loc_left_pair + CustomField => [ 'CUSTOMFIELD' => 'Ticket' ], #loc_left_pair + CF => [ 'CUSTOMFIELD' => 'Ticket' ], #loc_left_pair Updated => [ 'TRANSDATE', ], #loc_left_pair RequestorGroup => [ 'MEMBERSHIPFIELD' => 'Requestor', ], #loc_left_pair CCGroup => [ 'MEMBERSHIPFIELD' => 'Cc', ], #loc_left_pair @@ -443,10 +443,6 @@ sub _LinkLimit { my $is_null = 0; $is_null = 1 if !$value || $value =~ /^null$/io; - unless ($is_null) { - $value = RT::URI->new( $sb->CurrentUser )->CanonicalizeURI( $value ); - } - my $direction = $meta->[1] || ''; my ($matchfield, $linkfield) = ('', ''); if ( $direction eq 'To' ) { @@ -473,6 +469,7 @@ sub _LinkLimit { $op = ($op =~ /^(=|IS)$/i)? 'IS': 'IS NOT'; } elsif ( $value =~ /\D/ ) { + $value = RT::URI->new( $sb->CurrentUser )->CanonicalizeURI( $value ); $is_local = 0; } $matchfield = "Local$matchfield" if $is_local; @@ -977,13 +974,18 @@ sub _WatcherLimit { } $rest{SUBKEY} ||= 'EmailAddress'; - my $groups = $self->_RoleGroupsJoin( Type => $type, Class => $class, New => !$type ); + my ($groups, $group_members, $users); + if ( $rest{'BUNDLE'} ) { + ($groups, $group_members, $users) = @{ $rest{'BUNDLE'} }; + } else { + $groups = $self->_RoleGroupsJoin( Type => $type, Class => $class, New => !$type ); + } $self->_OpenParen; if ( $op =~ /^IS(?: NOT)?$/i ) { # is [not] empty case - my $group_members = $self->_GroupMembersJoin( GroupsAlias => $groups ); + $group_members ||= $self->_GroupMembersJoin( GroupsAlias => $groups ); # to avoid joining the table Users into the query, we just join GM # and make sure we don't match records where group is member of itself $self->SUPER::Limit( @@ -1021,7 +1023,7 @@ sub _WatcherLimit { $users_obj->RowsPerPage(2); my @users = @{ $users_obj->ItemsArrayRef }; - my $group_members = $self->_GroupMembersJoin( GroupsAlias => $groups ); + $group_members ||= $self->_GroupMembersJoin( GroupsAlias => $groups ); if ( @users <= 1 ) { my $uid = 0; $uid = $users[0]->id if @users; @@ -1046,7 +1048,7 @@ sub _WatcherLimit { VALUE => "$group_members.MemberId", QUOTEVALUE => 0, ); - my $users = $self->Join( + $users ||= $self->Join( TYPE => 'LEFT', ALIAS1 => $group_members, FIELD1 => 'MemberId', @@ -1072,10 +1074,10 @@ sub _WatcherLimit { } else { # positive condition case - my $group_members = $self->_GroupMembersJoin( + $group_members ||= $self->_GroupMembersJoin( GroupsAlias => $groups, New => 1, Left => 0 ); - my $users = $self->Join( + $users ||= $self->Join( TYPE => 'LEFT', ALIAS1 => $group_members, FIELD1 => 'MemberId', @@ -1092,6 +1094,7 @@ sub _WatcherLimit { ); } $self->_CloseParen; + return ($groups, $group_members, $users); } sub _RoleGroupsJoin { @@ -1342,33 +1345,44 @@ sub _WatcherMembershipLimit { Try and turn a CF descriptor into (cfid, cfname) object pair. +Takes an optional second parameter of the CF LookupType, defaults to Ticket CFs. + =cut sub _CustomFieldDecipher { - my ($self, $string) = @_; + my ($self, $string, $lookuptype) = @_; + $lookuptype ||= $self->_SingularClass->CustomFieldLookupType; - my ($queue, $field, $column) = ($string =~ /^(?:(.+?)\.)?{(.+)}(?:\.(Content|LargeContent))?$/); + my ($object, $field, $column) = ($string =~ /^(?:(.+?)\.)?\{(.+)\}(?:\.(Content|LargeContent))?$/); $field ||= ($string =~ /^{(.*?)}$/)[0] || $string; - my $cf; - if ( $queue ) { - my $q = RT::Queue->new( $self->CurrentUser ); - $q->Load( $queue ); + my ($cf, $applied_to); + + if ( $object ) { + my $record_class = RT::CustomField->RecordClassFromLookupType($lookuptype); + $applied_to = $record_class->new( $self->CurrentUser ); + $applied_to->Load( $object ); - if ( $q->id ) { - # $queue = $q->Name; # should we normalize the queue? - $cf = $q->CustomField( $field ); + if ( $applied_to->id ) { + RT->Logger->debug("Limiting to CFs identified by '$field' applied to $record_class #@{[$applied_to->id]} (loaded via '$object')"); } else { - $RT::Logger->warning("Queue '$queue' doesn't exist, parsed from '$string'"); - $queue = 0; + RT->Logger->warning("$record_class '$object' doesn't exist, parsed from '$string'"); + $object = 0; + undef $applied_to; } } - elsif ( $field =~ /\D/ ) { - $queue = ''; + + if ( $field =~ /\D/ ) { + $object ||= ''; my $cfs = RT::CustomFields->new( $self->CurrentUser ); - $cfs->Limit( FIELD => 'Name', VALUE => $field ); - $cfs->LimitToLookupType('RT::Queue-RT::Ticket'); + $cfs->Limit( FIELD => 'Name', VALUE => $field, ($applied_to ? (CASESENSITIVE => 0) : ()) ); + $cfs->LimitToLookupType($lookuptype); + + if ($applied_to) { + $cfs->SetContextObject($applied_to); + $cfs->LimitToObjectId($applied_to->id); + } # if there is more then one field the current user can # see with the same name then we shouldn't return cf object @@ -1381,9 +1395,11 @@ sub _CustomFieldDecipher { else { $cf = RT::CustomField->new( $self->CurrentUser ); $cf->Load( $field ); + $cf->SetContextObject($applied_to) + if $cf->id and $applied_to; } - return ($queue, $field, $cf, $column); + return ($object, $field, $cf, $column); } =head2 _CustomFieldJoin @@ -1392,8 +1408,14 @@ Factor out the Join of custom fields so we can use it for sorting too =cut +our %JOIN_ALIAS_FOR_LOOKUP_TYPE = ( + RT::Ticket->CustomFieldLookupType => sub { "main" }, +); + sub _CustomFieldJoin { - my ($self, $cfkey, $cfid, $field) = @_; + my ($self, $cfkey, $cfid, $field, $type) = @_; + $type ||= RT::Ticket->CustomFieldLookupType; + # Perform one Join per CustomField if ( $self->{_sql_object_cfv_alias}{$cfkey} || $self->{_sql_cf_alias}{$cfkey} ) @@ -1402,17 +1424,21 @@ sub _CustomFieldJoin { $self->{_sql_cf_alias}{$cfkey} ); } - my ($TicketCFs, $CFs); + my $ObjectAlias = $JOIN_ALIAS_FOR_LOOKUP_TYPE{$type} + ? $JOIN_ALIAS_FOR_LOOKUP_TYPE{$type}->($self) + : die "We don't know how to join on $type"; + + my ($ObjectCFs, $CFs); if ( $cfid ) { - $TicketCFs = $self->{_sql_object_cfv_alias}{$cfkey} = $self->Join( + $ObjectCFs = $self->{_sql_object_cfv_alias}{$cfkey} = $self->Join( TYPE => 'LEFT', - ALIAS1 => 'main', + ALIAS1 => $ObjectAlias, FIELD1 => 'id', TABLE2 => 'ObjectCustomFieldValues', FIELD2 => 'ObjectId', ); $self->SUPER::Limit( - LEFTJOIN => $TicketCFs, + LEFTJOIN => $ObjectCFs, FIELD => 'CustomField', VALUE => $cfid, ENTRYAGGREGATOR => 'AND' @@ -1444,7 +1470,7 @@ sub _CustomFieldJoin { LEFTJOIN => $CFs, ENTRYAGGREGATOR => 'AND', FIELD => 'LookupType', - VALUE => 'RT::Queue-RT::Ticket', + VALUE => $type, ); $self->SUPER::Limit( LEFTJOIN => $CFs, @@ -1453,7 +1479,7 @@ sub _CustomFieldJoin { VALUE => $field, ); - $TicketCFs = $self->{_sql_object_cfv_alias}{$cfkey} = $self->Join( + $ObjectCFs = $self->{_sql_object_cfv_alias}{$cfkey} = $self->Join( TYPE => 'LEFT', ALIAS1 => $CFs, FIELD1 => 'id', @@ -1461,28 +1487,29 @@ sub _CustomFieldJoin { FIELD2 => 'CustomField', ); $self->SUPER::Limit( - LEFTJOIN => $TicketCFs, + LEFTJOIN => $ObjectCFs, FIELD => 'ObjectId', - VALUE => 'main.id', + VALUE => "$ObjectAlias.id", QUOTEVALUE => 0, ENTRYAGGREGATOR => 'AND', ); } + $self->SUPER::Limit( - LEFTJOIN => $TicketCFs, + LEFTJOIN => $ObjectCFs, FIELD => 'ObjectType', - VALUE => 'RT::Ticket', + VALUE => RT::CustomField->ObjectTypeFromLookupType($type), ENTRYAGGREGATOR => 'AND' ); $self->SUPER::Limit( - LEFTJOIN => $TicketCFs, + LEFTJOIN => $ObjectCFs, FIELD => 'Disabled', OPERATOR => '=', VALUE => '0', ENTRYAGGREGATOR => 'AND' ); - return ($TicketCFs, $CFs); + return ($ObjectCFs, $CFs); } =head2 _CustomFieldLimit @@ -1501,12 +1528,16 @@ use Regexp::Common::net::CIDR; sub _CustomFieldLimit { my ( $self, $_field, $op, $value, %rest ) = @_; + my $meta = $FIELD_METADATA{ $_field }; + my $class = $meta->[1] || 'Ticket'; + my $type = "RT::$class"->CustomFieldLookupType; + my $field = $rest{'SUBKEY'} || die "No field specified"; # For our sanity, we can only limit on one queue at a time - my ($queue, $cfid, $cf, $column); - ($queue, $field, $cf, $column) = $self->_CustomFieldDecipher( $field ); + my ($object, $cfid, $cf, $column); + ($object, $field, $cf, $column) = $self->_CustomFieldDecipher( $field, $type ); $cfid = $cf ? $cf->id : 0 ; # If we're trying to find custom fields that don't match something, we @@ -1602,16 +1633,16 @@ sub _CustomFieldLimit { my $single_value = !$cf || !$cfid || $cf->SingleValue; - my $cfkey = $cfid ? $cfid : "$queue.$field"; + my $cfkey = $cfid ? $cfid : "$type-$object.$field"; if ( $null_op && !$column ) { # IS[ NOT] NULL without column is the same as has[ no] any CF value, # we can reuse our default joins for this operation # with column specified we have different situation - my ($TicketCFs, $CFs) = $self->_CustomFieldJoin( $cfkey, $cfid, $field ); + my ($ObjectCFs, $CFs) = $self->_CustomFieldJoin( $cfkey, $cfid, $field, $type ); $self->_OpenParen; $self->_SQLLimit( - ALIAS => $TicketCFs, + ALIAS => $ObjectCFs, FIELD => 'id', OPERATOR => $op, VALUE => $value, @@ -1634,11 +1665,11 @@ sub _CustomFieldLimit { $self->_OpenParen; if ( $op !~ /NOT|!=|<>/i ) { # positive equation $self->_CustomFieldLimit( - 'CF', '<=', $end_ip, %rest, + $_field, '<=', $end_ip, %rest, SUBKEY => $rest{'SUBKEY'}. '.Content', ); $self->_CustomFieldLimit( - 'CF', '>=', $start_ip, %rest, + $_field, '>=', $start_ip, %rest, SUBKEY => $rest{'SUBKEY'}. '.LargeContent', ENTRYAGGREGATOR => 'AND', ); @@ -1646,20 +1677,20 @@ sub _CustomFieldLimit { # estimations and scan less rows # have to disable this tweak because of ipv6 # $self->_CustomFieldLimit( -# $field, '>=', '000.000.000.000', %rest, +# $_field, '>=', '000.000.000.000', %rest, # SUBKEY => $rest{'SUBKEY'}. '.Content', # ENTRYAGGREGATOR => 'AND', # ); # $self->_CustomFieldLimit( -# $field, '<=', '255.255.255.255', %rest, +# $_field, '<=', '255.255.255.255', %rest, # SUBKEY => $rest{'SUBKEY'}. '.LargeContent', # ENTRYAGGREGATOR => 'AND', # ); } else { # negative equation - $self->_CustomFieldLimit($field, '>', $end_ip, %rest); + $self->_CustomFieldLimit($_field, '>', $end_ip, %rest); $self->_CustomFieldLimit( - $field, '<', $start_ip, %rest, + $_field, '<', $start_ip, %rest, SUBKEY => $rest{'SUBKEY'}. '.LargeContent', ENTRYAGGREGATOR => 'OR', ); @@ -1671,7 +1702,7 @@ sub _CustomFieldLimit { } elsif ( !$negative_op || $single_value ) { $cfkey .= '.'. $self->{'_sql_multiple_cfs_index'}++ if !$single_value && !$range_op; - my ($TicketCFs, $CFs) = $self->_CustomFieldJoin( $cfkey, $cfid, $field ); + my ($ObjectCFs, $CFs) = $self->_CustomFieldJoin( $cfkey, $cfid, $field, $type ); $self->_OpenParen; @@ -1682,7 +1713,7 @@ sub _CustomFieldLimit { # otherwise search in Content and in LargeContent if ( $column ) { $self->_SQLLimit( $fix_op->( - ALIAS => $TicketCFs, + ALIAS => $ObjectCFs, FIELD => $column, OPERATOR => $op, VALUE => $value, @@ -1708,7 +1739,7 @@ sub _CustomFieldLimit { $self->_OpenParen; $self->_SQLLimit( - ALIAS => $TicketCFs, + ALIAS => $ObjectCFs, FIELD => 'Content', OPERATOR => ">=", VALUE => $daystart, @@ -1716,7 +1747,7 @@ sub _CustomFieldLimit { ); $self->_SQLLimit( - ALIAS => $TicketCFs, + ALIAS => $ObjectCFs, FIELD => 'Content', OPERATOR => "<", VALUE => $dayend, @@ -1729,7 +1760,7 @@ sub _CustomFieldLimit { elsif ( $op eq '=' || $op eq '!=' || $op eq '<>' ) { if ( length( Encode::encode_utf8($value) ) < 256 ) { $self->_SQLLimit( - ALIAS => $TicketCFs, + ALIAS => $ObjectCFs, FIELD => 'Content', OPERATOR => $op, VALUE => $value, @@ -1740,14 +1771,14 @@ sub _CustomFieldLimit { else { $self->_OpenParen; $self->_SQLLimit( - ALIAS => $TicketCFs, + ALIAS => $ObjectCFs, FIELD => 'Content', OPERATOR => '=', VALUE => '', ENTRYAGGREGATOR => 'OR' ); $self->_SQLLimit( - ALIAS => $TicketCFs, + ALIAS => $ObjectCFs, FIELD => 'Content', OPERATOR => 'IS', VALUE => 'NULL', @@ -1755,7 +1786,7 @@ sub _CustomFieldLimit { ); $self->_CloseParen; $self->_SQLLimit( $fix_op->( - ALIAS => $TicketCFs, + ALIAS => $ObjectCFs, FIELD => 'LargeContent', OPERATOR => $op, VALUE => $value, @@ -1766,7 +1797,7 @@ sub _CustomFieldLimit { } else { $self->_SQLLimit( - ALIAS => $TicketCFs, + ALIAS => $ObjectCFs, FIELD => 'Content', OPERATOR => $op, VALUE => $value, @@ -1777,14 +1808,14 @@ sub _CustomFieldLimit { $self->_OpenParen; $self->_OpenParen; $self->_SQLLimit( - ALIAS => $TicketCFs, + ALIAS => $ObjectCFs, FIELD => 'Content', OPERATOR => '=', VALUE => '', ENTRYAGGREGATOR => 'OR' ); $self->_SQLLimit( - ALIAS => $TicketCFs, + ALIAS => $ObjectCFs, FIELD => 'Content', OPERATOR => 'IS', VALUE => 'NULL', @@ -1792,7 +1823,7 @@ sub _CustomFieldLimit { ); $self->_CloseParen; $self->_SQLLimit( $fix_op->( - ALIAS => $TicketCFs, + ALIAS => $ObjectCFs, FIELD => 'LargeContent', OPERATOR => $op, VALUE => $value, @@ -1826,7 +1857,7 @@ sub _CustomFieldLimit { if ($negative_op) { $self->_SQLLimit( - ALIAS => $TicketCFs, + ALIAS => $ObjectCFs, FIELD => $column || 'Content', OPERATOR => 'IS', VALUE => 'NULL', @@ -1840,7 +1871,7 @@ sub _CustomFieldLimit { } else { $cfkey .= '.'. $self->{'_sql_multiple_cfs_index'}++; - my ($TicketCFs, $CFs) = $self->_CustomFieldJoin( $cfkey, $cfid, $field ); + my ($ObjectCFs, $CFs) = $self->_CustomFieldJoin( $cfkey, $cfid, $field, $type ); # reverse operation $op =~ s/!|NOT\s+//i; @@ -1849,8 +1880,8 @@ sub _CustomFieldLimit { # otherwise search in Content and in LargeContent if ( $column ) { $self->SUPER::Limit( $fix_op->( - LEFTJOIN => $TicketCFs, - ALIAS => $TicketCFs, + LEFTJOIN => $ObjectCFs, + ALIAS => $ObjectCFs, FIELD => $column, OPERATOR => $op, VALUE => $value, @@ -1859,8 +1890,8 @@ sub _CustomFieldLimit { } else { $self->SUPER::Limit( - LEFTJOIN => $TicketCFs, - ALIAS => $TicketCFs, + LEFTJOIN => $ObjectCFs, + ALIAS => $ObjectCFs, FIELD => 'Content', OPERATOR => $op, VALUE => $value, @@ -1869,7 +1900,7 @@ sub _CustomFieldLimit { } $self->_SQLLimit( %rest, - ALIAS => $TicketCFs, + ALIAS => $ObjectCFs, FIELD => 'id', OPERATOR => 'IS', VALUE => 'NULL', @@ -1979,10 +2010,10 @@ sub OrderByCols { } push @res, { %$row, ALIAS => $users, FIELD => $subkey }; } elsif ( defined $meta->[0] && $meta->[0] eq 'CUSTOMFIELD' ) { - my ($queue, $field, $cf_obj, $column) = $self->_CustomFieldDecipher( $subkey ); - my $cfkey = $cf_obj ? $cf_obj->id : "$queue.$field"; + my ($object, $field, $cf_obj, $column) = $self->_CustomFieldDecipher( $subkey ); + my $cfkey = $cf_obj ? $cf_obj->id : "$object.$field"; $cfkey .= ".ordering" if !$cf_obj || ($cf_obj->MaxValues||0) != 1; - my ($TicketCFs, $CFs) = $self->_CustomFieldJoin( $cfkey, ($cf_obj ?$cf_obj->id :0) , $field ); + my ($ObjectCFs, $CFs) = $self->_CustomFieldJoin( $cfkey, ($cf_obj ?$cf_obj->id :0) , $field ); # this is described in _CustomFieldLimit $self->_SQLLimit( ALIAS => $CFs, @@ -2004,7 +2035,7 @@ sub OrderByCols { } my $CFvs = $self->Join( TYPE => 'LEFT', - ALIAS1 => $TicketCFs, + ALIAS1 => $ObjectCFs, FIELD1 => 'CustomField', TABLE2 => 'CustomFieldValues', FIELD2 => 'CustomField', @@ -2013,12 +2044,12 @@ sub OrderByCols { LEFTJOIN => $CFvs, FIELD => 'Name', QUOTEVALUE => 0, - VALUE => $TicketCFs . ".Content", + VALUE => $ObjectCFs . ".Content", ENTRYAGGREGATOR => 'AND' ); push @res, { %$row, ALIAS => $CFvs, FIELD => 'SortOrder' }; - push @res, { %$row, ALIAS => $TicketCFs, FIELD => 'Content' }; + push @res, { %$row, ALIAS => $ObjectCFs, FIELD => 'Content' }; } elsif ( $field eq "Custom" && $subkey eq "Ownership") { # PAW logic is "reversed" my $order = "ASC"; @@ -3144,7 +3175,7 @@ sub LimitCustomField { $self->Limit( VALUE => $args{VALUE}, FIELD => "CF" - .(defined $args{'QUEUE'}? ".{$args{'QUEUE'}}" : '' ) + .(defined $args{'QUEUE'}? ".$args{'QUEUE'}" : '' ) .".{" . $CF->Name . "}", OPERATOR => $args{OPERATOR}, CUSTOMFIELD => 1, diff --git a/rt/lib/RT/Tickets_SQL.pm b/rt/lib/RT/Tickets_SQL.pm index 608862a37..f667b0699 100644 --- a/rt/lib/RT/Tickets_SQL.pm +++ b/rt/lib/RT/Tickets_SQL.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -74,7 +74,7 @@ sub _InitSQL { sub _SQLLimit { my $self = shift; - my %args = (@_); + my %args = (FIELD => '', @_); if ($args{'FIELD'} eq 'EffectiveId' && (!$args{'ALIAS'} || $args{'ALIAS'} eq 'main' ) ) { $self->{'looking_at_effective_id'} = 1; @@ -171,19 +171,69 @@ sub _parser { my @bundle; my $ea = ''; + # Bundling of joins is implemented by dynamically tracking a parallel query + # tree in %sub_tree as the TicketSQL is parsed. Don't be fooled by + # _close_bundle(), @bundle, and %can_bundle; they are completely unused for + # quite a long time and removed in RT 4.2. For now they stay, a useless + # relic. + # + # Only positive, OR'd watcher conditions are bundled currently. Each key + # in %sub_tree is a watcher type (Requestor, Cc, AdminCc) or the generic + # "Watcher" for any watcher type. Owner is not bundled because it is + # denormalized into a Tickets column and doesn't need a join. AND'd + # conditions are not bundled since a record may have multiple watchers + # which independently match the conditions, thus necessitating two joins. + # + # The values of %sub_tree are arrayrefs made up of: + # + # * Open parentheses "(" pushed on by the OpenParen callback + # * Arrayrefs of bundled join aliases pushed on by the Condition callback + # * Entry aggregators (AND/OR) pushed on by the EntryAggregator callback + # + # The CloseParen callback takes care of backing off the query trees until + # outside of the just-closed parenthetical, thus restoring the tree state + # an equivalent of before the parenthetical was entered. + # + # The Condition callback handles starting a new subtree or extending an + # existing one, determining if bundling the current condition with any + # subtree is possible, and pruning any dangling entry aggregators from + # trees. + # + + my %sub_tree; + my $depth = 0; + my %callback; $callback{'OpenParen'} = sub { $self->_close_bundle(@bundle); @bundle = (); - $self->_OpenParen + $self->_OpenParen; + $depth++; + push @$_, '(' foreach values %sub_tree; }; $callback{'CloseParen'} = sub { $self->_close_bundle(@bundle); @bundle = (); $self->_CloseParen; + $depth--; + foreach my $list ( values %sub_tree ) { + if ( $list->[-1] eq '(' ) { + pop @$list; + pop @$list if $list->[-1] =~ /^(?:AND|OR)$/i; + } + else { + pop @$list while $list->[-2] ne '('; + $list->[-1] = pop @$list; + } + } + }; + $callback{'EntryAggregator'} = sub { + $ea = $_[0] || ''; + push @$_, $ea foreach grep @$_ && $_->[-1] ne '(', values %sub_tree; }; - $callback{'EntryAggregator'} = sub { $ea = $_[0] || '' }; $callback{'Condition'} = sub { my ($key, $op, $value) = @_; + my ($negative_op, $null_op, $inv_op, $range_op) + = $self->ClassifySQLOperation( $op ); # key has dot then it's compound variant and we have subkey my $subkey = ''; ($key, $subkey) = ($1, $2) if $key =~ /^([^\.]+)\.(.+)$/; @@ -225,10 +275,28 @@ sub _parser { } else { $self->_close_bundle(@bundle); @bundle = (); - $sub->( $self, $key, $op, $value, + my @res; my $bundle_with; + if ( $class eq 'WATCHERFIELD' && $key ne 'Owner' && !$negative_op && (!$null_op || $subkey) ) { + if ( !$sub_tree{$key} ) { + $sub_tree{$key} = [ ('(')x$depth, \@res ]; + } else { + $bundle_with = $self->_check_bundling_possibility( $string, @{ $sub_tree{$key} } ); + if ( $sub_tree{$key}[-1] eq '(' ) { + push @{ $sub_tree{$key} }, \@res; + } + } + } + + # Remove our aggregator from subtrees where our condition didn't get added + pop @$_ foreach grep @$_ && $_->[-1] =~ /^(?:AND|OR)$/i, values %sub_tree; + + # A reference to @res may be pushed onto $sub_tree{$key} from + # above, and we fill it here. + @res = $sub->( $self, $key, $op, $value, SUBCLAUSE => '', # don't need anymore ENTRYAGGREGATOR => $ea, SUBKEY => $subkey, + BUNDLE => $bundle_with, ); } $self->{_sql_looking_at}{lc $key} = 1; @@ -238,6 +306,29 @@ sub _parser { $self->_close_bundle(@bundle); @bundle = (); } +sub _check_bundling_possibility { + my $self = shift; + my $string = shift; + my @list = reverse @_; + while (my $e = shift @list) { + next if $e eq '('; + if ( lc($e) eq 'and' ) { + return undef; + } + elsif ( lc($e) eq 'or' ) { + return shift @list; + } + else { + # should not happen + $RT::Logger->error( + "Joins optimization failed when parsing '$string'. It's bug in RT, contact Best Practical" + ); + die "Internal error. Contact your system administrator."; + } + } + return undef; +} + =head2 ClausesToSQL =cut @@ -292,8 +383,9 @@ sub FromSQL { $self->{_sql_query} = $query; eval { $self->_parser( $query ); }; if ( $@ ) { - $RT::Logger->error( $@ ); - return (0, $@); + my $error = "$@"; + $RT::Logger->error("Couldn't parse query: $error"); + return (0, $error); } # We only want to look at EffectiveId's (mostly) for these searches. diff --git a/rt/lib/RT/Topic.pm b/rt/lib/RT/Topic.pm index 3e91e9dc3..d6a88e17c 100644 --- a/rt/lib/RT/Topic.pm +++ b/rt/lib/RT/Topic.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Topics.pm b/rt/lib/RT/Topics.pm index 01674fb66..5c735b7f1 100644 --- a/rt/lib/RT/Topics.pm +++ b/rt/lib/RT/Topics.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Transaction.pm b/rt/lib/RT/Transaction.pm index 48d4e8ce9..5c903e9f1 100755 --- a/rt/lib/RT/Transaction.pm +++ b/rt/lib/RT/Transaction.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -368,24 +368,9 @@ sub Content { } if ( $args{'Quote'} ) { + $content = $self->ApplyQuoteWrap(content => $content, + cols => $args{'Wrap'} ); - # What's the longest line like? - my $max = 0; - foreach ( split ( /\n/, $content ) ) { - $max = length if length > $max; - } - - if ( $max > $args{'Wrap'}+6 ) { # 76 ) { - require Text::Wrapper; - my $wrapper = Text::Wrapper->new( - columns => $args{'Wrap'}, - body_start => ( $max > 70 * 3 ? ' ' : '' ), - par_start => '' - ); - $content = $wrapper->wrap($content); - } - - $content =~ s/^/> /gm; $content = $self->QuoteHeader . "\n$content\n\n"; } @@ -405,6 +390,84 @@ sub QuoteHeader { return $self->loc("On [_1], [_2] wrote:", $self->CreatedAsString, $self->CreatorObj->Name); } +=head2 ApplyQuoteWrap PARAMHASH + +Wrapper to calculate wrap criteria and apply quote wrapping if needed. + +=cut + +sub ApplyQuoteWrap { + my $self = shift; + my %args = @_; + my $content = $args{content}; + + # What's the longest line like? + my $max = 0; + foreach ( split ( /\n/, $args{content} ) ) { + $max = length if length > $max; + } + + if ( $max > 76 ) { + require Text::Quoted; + require Text::Wrapper; + + my $structure = Text::Quoted::extract($args{content}); + $content = $self->QuoteWrap(content_ref => $structure, + cols => $args{cols}, + max => $max ); + } + + $content =~ s/^/> /gm; # use regex since string might be multi-line + return $content; +} + +=head2 QuoteWrap PARAMHASH + +Wrap the contents of transactions based on Wrap settings, maintaining +the quote character from the original. + +=cut + +sub QuoteWrap { + my $self = shift; + my %args = @_; + my $ref = $args{content_ref}; + my $final_string; + + if ( ref $ref eq 'ARRAY' ){ + foreach my $array (@$ref){ + $final_string .= $self->QuoteWrap(content_ref => $array, + cols => $args{cols}, + max => $args{max} ); + } + } + elsif ( ref $ref eq 'HASH' ){ + return $ref->{quoter} . "\n" if $ref->{empty}; # Blank line + + my $col = $args{cols} - (length $ref->{quoter}); + my $wrapper = Text::Wrapper->new( columns => $col ); + + # Wrap on individual lines to honor incoming line breaks + # Otherwise deliberate separate lines (like a list or a sig) + # all get combined incorrectly into single paragraphs. + + my @lines = split /\n/, $ref->{text}; + my $wrap = join '', map { $wrapper->wrap($_) } @lines; + my $quoter = $ref->{quoter}; + + # Only add the space if actually quoting + $quoter .= ' ' if length $quoter; + $wrap =~ s/^/$quoter/mg; # use regex since string might be multi-line + + return $wrap; + } + else{ + $RT::Logger->warning("Can't apply quoting with $ref"); + return; + } + return $final_string; +} + =head2 Addresses @@ -725,8 +788,9 @@ sub BriefDescription { my $self = shift; my $field = $self->loc('CustomField'); + my $cf; if ( $self->Field ) { - my $cf = RT::CustomField->new( $self->CurrentUser ); + $cf = RT::CustomField->new( $self->CurrentUser ); $cf->SetContextObject( $self->Object ); $cf->Load( $self->Field ); $field = $cf->Name(); @@ -736,6 +800,44 @@ sub BriefDescription { my $new = $self->NewValue; my $old = $self->OldValue; + if ( $cf ) { + + if ( $cf->Type eq 'DateTime' ) { + if ($old) { + my $date = RT::Date->new( $self->CurrentUser ); + $date->Set( Format => 'ISO', Value => $old ); + $old = $date->AsString; + } + + if ($new) { + my $date = RT::Date->new( $self->CurrentUser ); + $date->Set( Format => 'ISO', Value => $new ); + $new = $date->AsString; + } + } + elsif ( $cf->Type eq 'Date' ) { + if ($old) { + my $date = RT::Date->new( $self->CurrentUser ); + $date->Set( + Format => 'unknown', + Value => $old, + Timezone => 'UTC', + ); + $old = $date->AsString( Time => 0, Timezone => 'UTC' ); + } + + if ($new) { + my $date = RT::Date->new( $self->CurrentUser ); + $date->Set( + Format => 'unknown', + Value => $new, + Timezone => 'UTC', + ); + $new = $date->AsString( Time => 0, Timezone => 'UTC' ); + } + } + } + if ( !defined($old) || $old eq '' ) { return $self->loc("[_1] [_2] added", $field, $new); } @@ -938,7 +1040,8 @@ sub BriefDescription { else { return $self->loc( "[_1] changed from [_2] to [_3]", $self->loc($self->Field), - ($self->OldValue? "'".$self->OldValue ."'" : $self->loc("(no value)")) , "'". $self->NewValue."'" ); + ($self->OldValue? "'".$self->OldValue ."'" : $self->loc("(no value)")), + ($self->NewValue? "'".$self->NewValue ."'" : $self->loc("(no value)"))); } }, PurgeTransaction => sub { diff --git a/rt/lib/RT/Transactions.pm b/rt/lib/RT/Transactions.pm index 3c9dac4d7..82bd50f12 100755 --- a/rt/lib/RT/Transactions.pm +++ b/rt/lib/RT/Transactions.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/URI.pm b/rt/lib/RT/URI.pm index c0958ca36..11a9e3e06 100644 --- a/rt/lib/RT/URI.pm +++ b/rt/lib/RT/URI.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -199,6 +199,8 @@ sub _GetResolver { if ($resolver) { $self->{'resolver'} = $resolver; } else { + RT->Logger->warning("Failed to create new resolver object for scheme '$scheme': $@") + if $@ !~ m{Can't locate RT/URI/\Q$scheme\E}; $self->{'resolver'} = RT::URI::base->new($self->CurrentUser); } diff --git a/rt/lib/RT/URI/a.pm b/rt/lib/RT/URI/a.pm index 9475ba157..76bd4e831 100644 --- a/rt/lib/RT/URI/a.pm +++ b/rt/lib/RT/URI/a.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/URI/base.pm b/rt/lib/RT/URI/base.pm index 63af14063..820f83f79 100644 --- a/rt/lib/RT/URI/base.pm +++ b/rt/lib/RT/URI/base.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/URI/fsck_com_article.pm b/rt/lib/RT/URI/fsck_com_article.pm index 2b2132f5f..34c81a818 100644 --- a/rt/lib/RT/URI/fsck_com_article.pm +++ b/rt/lib/RT/URI/fsck_com_article.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/URI/fsck_com_rt.pm b/rt/lib/RT/URI/fsck_com_rt.pm index 34249d057..9f68aa5b1 100644 --- a/rt/lib/RT/URI/fsck_com_rt.pm +++ b/rt/lib/RT/URI/fsck_com_rt.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/URI/t.pm b/rt/lib/RT/URI/t.pm index 71c81fa91..d3a1214dd 100644 --- a/rt/lib/RT/URI/t.pm +++ b/rt/lib/RT/URI/t.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/User.pm b/rt/lib/RT/User.pm index 5511b9f6a..018ac8a62 100755 --- a/rt/lib/RT/User.pm +++ b/rt/lib/RT/User.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Users.pm b/rt/lib/RT/Users.pm index 0f5ca706a..1c75f4250 100755 --- a/rt/lib/RT/Users.pm +++ b/rt/lib/RT/Users.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/lib/RT/Util.pm b/rt/lib/RT/Util.pm index 38c3c20c9..9720f1da8 100644 --- a/rt/lib/RT/Util.pm +++ b/rt/lib/RT/Util.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -65,8 +65,11 @@ sub safe_run_child (&) { # values. Instead we set values, eval code, check pid # on failure and reset values only in our original # process + my ($oldv_dbh, $oldv_rth); my $dbh = $RT::Handle->dbh; + $oldv_dbh = $dbh->{'InactiveDestroy'} if $dbh; $dbh->{'InactiveDestroy'} = 1 if $dbh; + $oldv_rth = $RT::Handle->{'DisconnectHandleOnDestroy'}; $RT::Handle->{'DisconnectHandleOnDestroy'} = 0; my ($reader, $writer); @@ -90,8 +93,8 @@ sub safe_run_child (&) { my $err = $@; $err =~ s/^Stack:.*$//ms; if ( $our_pid == $$ ) { - $dbh->{'InactiveDestroy'} = 0 if $dbh; - $RT::Handle->{'DisconnectHandleOnDestroy'} = 1; + $dbh->{'InactiveDestroy'} = $oldv_dbh if $dbh; + $RT::Handle->{'DisconnectHandleOnDestroy'} = $oldv_rth; die "System Error: $err"; } else { print $writer "System Error: $err"; @@ -104,8 +107,8 @@ sub safe_run_child (&) { my ($response) = $reader->getline; warn $response if $response; - $dbh->{'InactiveDestroy'} = 0 if $dbh; - $RT::Handle->{'DisconnectHandleOnDestroy'} = 1; + $dbh->{'InactiveDestroy'} = $oldv_dbh if $dbh; + $RT::Handle->{'DisconnectHandleOnDestroy'} = $oldv_rth; return $want? (@res) : $res[0]; } diff --git a/rt/sbin/rt-attributes-viewer.in b/rt/sbin/rt-attributes-viewer.in index 59eb42361..31bae00c7 100644 --- a/rt/sbin/rt-attributes-viewer.in +++ b/rt/sbin/rt-attributes-viewer.in @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/sbin/rt-clean-sessions.in b/rt/sbin/rt-clean-sessions.in index 1d6e1cfb5..77730fe13 100644 --- a/rt/sbin/rt-clean-sessions.in +++ b/rt/sbin/rt-clean-sessions.in @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/sbin/rt-dump-metadata.in b/rt/sbin/rt-dump-metadata.in index 20c28538b..5e0e5c3db 100644 --- a/rt/sbin/rt-dump-metadata.in +++ b/rt/sbin/rt-dump-metadata.in @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -79,7 +79,11 @@ BEGIN { use Getopt::Long; my %opt; -GetOptions( \%opt, "help|h" ); +GetOptions( \%opt, "help|h", + "limit-to-privileged|l", + "skip-disabled|s", + "all|a", +); if ( $opt{help} ) { require Pod::Usage; @@ -93,8 +97,6 @@ require XML::Simple; RT::LoadConfig(); RT::Init(); -my $LocalOnly = @ARGV ? shift(@ARGV) : 1; - my %RV; my %Ignore = ( All => [ @@ -117,8 +119,15 @@ my @classes = qw( foreach my $class (@classes) { require "RT/$class.pm"; my $objects = "RT::$class"->new( RT->SystemUser ); - $objects->{find_disabled_rows} = 1; + $objects->{find_disabled_rows} = 1 unless $opt{'skip-disabled'}; $objects->UnLimit; + $objects->LimitToPrivileged if $class eq 'Users' + && $opt{'limit-to-privileged'}; + $objects->Limit( + FIELD => 'Domain', + OPERATOR => '=', + VALUE => 'UserDefined' + ) if $class eq 'Groups'; if ( $class eq 'CustomFields' ) { $objects->OrderByCols( @@ -130,7 +139,7 @@ foreach my $class (@classes) { $objects->OrderBy( FIELD => 'Id' ); } - if ($LocalOnly) { + unless ($opt{all}) { next if $class eq 'ACL'; # XXX - would go into infinite loop - XXX $objects->Limit( FIELD => 'LastUpdatedBy', @@ -142,14 +151,10 @@ foreach my $class (@classes) { OPERATOR => '!=', VALUE => $SystemUserId ) if $class eq 'Users'; - $objects->Limit( - FIELD => 'Domain', - OPERATOR => '=', - VALUE => 'UserDefined' - ) if $class eq 'Groups'; } my %fields; +OBJECT: while ( my $obj = $objects->Next ) { next if $obj->can('LastUpdatedBy') @@ -163,36 +168,116 @@ foreach my $class (@classes) { my $rv; - # next if $obj-> # skip default names - foreach my $field ( sort keys %fields ) { - my $value = $obj->__Value($field); - $rv->{$field} = $value if ( defined($value) && length($value) ); - } - delete $rv->{Disabled} unless $rv->{Disabled}; - - foreach my $record ( map { /ACL/ ? 'ACE' : substr( $_, 0, -1 ) } - @classes ) - { - foreach my $key ( map "$record$_", ( '', 'Id' ) ) { - next unless exists $rv->{$key}; - my $id = $rv->{$key} or next; - my $obj = "RT::$record"->new( RT->SystemUser ); - $obj->LoadByCols( Id => $id ) or next; - $rv->{$key} = $obj->__Value('Name') || 0; + if ( $class ne 'ACL' ) { + # next if $obj-> # skip default names + foreach my $field ( sort keys %fields ) { + my $value = $obj->__Value($field); + $rv->{$field} = $value if ( defined($value) && length($value) ); + } + delete $rv->{Disabled} unless $rv->{Disabled}; + + foreach my $record ( map { /ACL/ ? 'ACE' : substr( $_, 0, -1 ) } + @classes ) + { + foreach my $key ( map "$record$_", ( '', 'Id' ) ) { + next unless exists $rv->{$key}; + my $id = $rv->{$key} or next; + my $obj = "RT::$record"->new( RT->SystemUser ); + $obj->LoadByCols( Id => $id ) or next; + $rv->{$key} = $obj->__Value('Name') || 0; + } + } + + if ( $class eq 'Users' and defined $obj->Privileged ) { + $rv->{Privileged} = int( $obj->Privileged ); + } elsif ( $class eq 'CustomFields' ) { + my $values = $obj->Values; + while ( my $value = $values->Next ) { + push @{ $rv->{Values} }, { + map { ( $_ => $value->__Value($_) ) } + qw( + Name Description SortOrder + ), + }; + } + if ( $obj->LookupType eq 'RT::Queue-RT::Ticket' ) { + # XXX-TODO: unused CF's turn into global CF when importing + # as the sub InsertData in RT::Handle creates a global CF + # when no queue is specified. + $rv->{Queue} = []; + my $applies = $obj->AppliedTo; + while ( my $queue = $applies->Next ) { + push @{ $rv->{Queue} }, $queue->Name; + } + } } } + else { + # 1) pick the right + $rv->{Right} = $obj->RightName; + + # 2) Pick a level: Granted on Queue, CF, CF+Queue, or Globally? + for ( $obj->ObjectType ) { + if ( /^RT::Queue$/ ) { + next OBJECT if $opt{'skip-disabled'} && $obj->Object->Disabled; + $rv->{Queue} = $obj->Object->Name; + } + elsif ( /^RT::CustomField$/ ) { + next OBJECT if $opt{'skip-disabled'} && $obj->Object->Disabled; + $rv->{CF} = $obj->Object->Name; + } + elsif ( /^RT::Group$/ ) { + # No support for RT::Group ACLs in RT::Handle yet. + next OBJECT; + } + elsif ( /^RT::System$/ ) { + # skip setting anything on $rv; + # "Specifying none of the above will get you a global right." + } + } - if ( $class eq 'Users' and defined $obj->Privileged ) { - $rv->{Privileged} = int( $obj->Privileged ); - } elsif ( $class eq 'CustomFields' ) { - my $values = $obj->Values; - while ( my $value = $values->Next ) { - push @{ $rv->{Values} }, { - map { ( $_ => $value->__Value($_) ) } - qw( - Name Description SortOrder - ), - }; + # 3) Pick a Principal; User or Group or Role + if ( $obj->PrincipalType eq 'Group' ) { + next OBJECT if $opt{'skip-disabled'} && $obj->PrincipalObj->Disabled; + my $group = $obj->PrincipalObj->Object; + for ( $group->Domain ) { + # An internal user group + if ( /^SystemInternal$/ ) { + $rv->{GroupDomain} = $group->Domain; + $rv->{GroupType} = $group->Type; + } + # An individual user + elsif ( /^ACLEquivalence$/ ) { + my $member = $group->MembersObj->Next->MemberObj; + next OBJECT if $opt{'skip-disabled'} && $member->Disabled; + $rv->{UserId} = $member->Object->Name; + } + # A group you created + elsif ( /^UserDefined$/ ) { + $rv->{GroupDomain} = 'UserDefined'; + $rv->{GroupId} = $group->Name; + } + } + } else { + $rv->{GroupType} = $obj->PrincipalType; + # A system-level role + if ( $obj->ObjectType eq 'RT::System' ) { + $rv->{GroupDomain} = 'RT::System-Role'; + } + # A queue-level role + elsif ( $obj->ObjectType eq 'RT::Queue' ) { + $rv->{GroupDomain} = 'RT::Queue-Role'; + } + } + if ( $obj->LookupType eq 'RT::Queue-RT::Ticket' ) { + # XXX-TODO: unused CF's turn into global CF when importing + # as the sub InsertData in RT::Handle creates a global CF + # when no queue is specified. + $rv->{Queue} = []; + my $applies = $obj->AppliedTo; + while ( my $queue = $applies->Next ) { + push @{ $rv->{Queue} }, $queue->Name; + } } } @@ -200,6 +285,9 @@ foreach my $class (@classes) { my $attributes = $obj->Attributes; while ( my $attribute = $attributes->Next ) { my $content = $attribute->Content; + if ( $class eq 'Users' and $attribute->Name eq 'Bookmarks' ) { + next; + } $rv->{Attributes}{ $attribute->Name } = $content if length($content); } @@ -232,7 +320,7 @@ rt-dump-metadata - dump configuration metadata from an RT database =head1 SYNOPSIS - rt-dump-metdata [ 0 ] + rt-dump-metdata [--all] =head1 DESCRIPTION @@ -242,11 +330,28 @@ C<rt-setup-database>. To dump and load a full RT database, you should generally use the native database tools instead, as well as performing any necessary steps from UPGRADING. -When run without arguments, the metadata dump will only include 'local' +This is NOT a tool for backing up an RT database. See also +L<docs/initialdata> for more straightforward means of importing data. + +=head1 OPTIONS + +=over + +=item C<--all> or C<-a> + +When run with C<--all>, the dump will include all configuration +metadata; otherwise, the metadata dump will only include 'local' configuration changes, i.e. those done manually in the web interface. -When run with the argument '0', the dump will include all configuration -metadata. +=item C<--limit-to-privileged> or C<-l> + +Causes the dumper to only dump privileged users. + +=item C<--skip-disabled> or C<-s> + +Ignores disabled rows in the database. + +=back -This is NOT a tool for backing up an RT database. +=cut diff --git a/rt/sbin/rt-email-dashboards.in b/rt/sbin/rt-email-dashboards.in index f77ae6117..0fcb1268e 100644 --- a/rt/sbin/rt-email-dashboards.in +++ b/rt/sbin/rt-email-dashboards.in @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/sbin/rt-email-digest.in b/rt/sbin/rt-email-digest.in index 68f0b4c92..a535e3649 100644 --- a/rt/sbin/rt-email-digest.in +++ b/rt/sbin/rt-email-digest.in @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -95,6 +95,7 @@ sub usage { print "\t-p, --print\t" . loc("Print the resulting digest messages to STDOUT; don't mail them. Do not mark them as sent") . "\n"; + print "\t-v, --verbose\t" . loc("Give output even on messages successfully sent") . "\n"; print "\t-h, --help\t" . loc("Print this message") . "\n"; if ( $error eq 'help' ) { @@ -105,10 +106,11 @@ sub usage { } } -my ( $frequency, $print, $help ) = ( '', '', '' ); +my ( $frequency, $print, $verbose, $help ) = ( '', '', '', '' ); GetOptions( 'mode=s' => \$frequency, 'print' => \$print, + 'verbose' => \$verbose, 'help' => \$help, ); @@ -134,7 +136,7 @@ sub run { my ( $contents_list, $contents_body ) = build_digest_for_user( $user, $all_digest->{$user} ); # Now we have a content head and a content body. We can send a message. if ( send_digest( $user, $contents_list, $contents_body ) ) { - print "Sent message to $user\n"; + print "Sent message to $user\n" if $verbose; mark_transactions_sent( $frequency, $user, values %{$sent_transactions->{$user}} ) unless ($print); } else { print "Failed to send message to $user\n"; diff --git a/rt/sbin/rt-email-group-admin.in b/rt/sbin/rt-email-group-admin.in index f62662631..3306a3812 100755 --- a/rt/sbin/rt-email-group-admin.in +++ b/rt/sbin/rt-email-group-admin.in @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -245,10 +245,11 @@ sub _list { return; } -=head2 create NAME [--comment] [--group GNAME] [--user UNAME] +=head2 create NAME [--comment] [--group GNAME] [--user NAME-OR-EMAIL] Creates new action with NAME and adds users and/or groups to its -recipient list. Would be notify as comment if --comment specified. +recipient list. Would be notify as comment if --comment specified. The +user, if specified, will be autocreated if necessary. =cut @@ -295,8 +296,9 @@ sub __create_empty { sub _check_groups { - return grep { $_ ? 1: do { print STDERR "Group '$_' skipped, doesn't exist\n"; 0; } } - map { __check_group($_) } @_; + return map {$_->[1]} + grep { $_->[1] ? 1: do { print STDERR "Group '$_->[0]' skipped, doesn't exist\n"; 0; } } + map { [$_, __check_group($_)] } @_; } sub __check_group @@ -310,8 +312,9 @@ sub __check_group sub _check_users { - return grep { $_ ? 1: do { print STDERR "User '$_' skipped, doesn't exist\n"; 0; } } - map { __check_user($_) } @_; + return map {$_->[1]} + grep { $_->[1] ? 1: do { print STDERR "User '$_->[0]' skipped, doesn't exist and couldn't autocreate\n"; 0; } } + map { [$_, __check_user($_)] } @_; } sub __check_user @@ -320,12 +323,27 @@ sub __check_user require RT::User; my $obj = RT::User->new( RT->SystemUser ); $obj->Load( $instance ); + $obj->LoadByEmail( $instance ) + if not $obj->id and $instance =~ /@/; + + unless ($obj->id) { + my ($ok, $msg) = $obj->Create( + Name => $instance, + EmailAddress => $instance, + Privileged => 0, + Comments => 'Autocreated when added to notify action via rt-email-group-admin', + ); + print STDERR "Autocreate of user '$instance' failed: $msg\n" + unless $ok; + } + return $obj->id ? $obj : undef; } -=head2 add NAME [--group GNAME] [--user UNAME] +=head2 add NAME [--group GNAME] [--user NAME-OR-EMAIL] -Adds groups and/or users to recipients of the action NAME. +Adds groups and/or users to recipients of the action NAME. The user, if +specified, will be autocreated if necessary. =cut diff --git a/rt/sbin/rt-fulltext-indexer b/rt/sbin/rt-fulltext-indexer deleted file mode 100755 index 8ac0e9c21..000000000 --- a/rt/sbin/rt-fulltext-indexer +++ /dev/null @@ -1,465 +0,0 @@ -#!/usr/bin/perl -# BEGIN BPS TAGGED BLOCK {{{ -# -# COPYRIGHT: -# -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC -# <sales@bestpractical.com> -# -# (Except where explicitly superseded by other copyright notices) -# -# -# LICENSE: -# -# This work is made available to you under the terms of Version 2 of -# the GNU General Public License. A copy of that license should have -# been provided with this software, but in any event can be snarfed -# from www.gnu.org. -# -# This work is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301 or visit their web page on the internet at -# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. -# -# -# CONTRIBUTION SUBMISSION POLICY: -# -# (The following paragraph is not intended to limit the rights granted -# to you to modify and distribute this software under the terms of -# the GNU General Public License and is only of importance to you if -# you choose to contribute your changes and enhancements to the -# community by submitting them to Best Practical Solutions, LLC.) -# -# By intentionally submitting any modifications, corrections or -# derivatives to this work, or any other work intended for use with -# Request Tracker, to Best Practical Solutions, LLC, you confirm that -# you are the copyright holder for those contributions and you grant -# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, -# royalty-free, perpetual, license to use, copy, create derivative -# works based on those contributions, and sublicense and distribute -# those contributions and any derivatives thereof. -# -# END BPS TAGGED BLOCK }}} -use strict; -use warnings; -no warnings 'once'; - -# fix lib paths, some may be relative -BEGIN { - require File::Spec; - my @libs = ("/opt/rt3/lib", "/opt/rt3/local/lib"); - my $bin_path; - - for my $lib (@libs) { - unless ( File::Spec->file_name_is_absolute($lib) ) { - unless ($bin_path) { - if ( File::Spec->file_name_is_absolute(__FILE__) ) { - $bin_path = ( File::Spec->splitpath(__FILE__) )[1]; - } - else { - require FindBin; - no warnings "once"; - $bin_path = $FindBin::Bin; - } - } - $lib = File::Spec->catfile( $bin_path, File::Spec->updir, $lib ); - } - unshift @INC, $lib; - } -} - -BEGIN { - use RT; - RT::LoadConfig(); - RT::Init(); -}; -use RT::Interface::CLI (); - -my %OPT = ( - help => 0, - debug => 0, -); -my @OPT_LIST = qw(help|h! debug!); - -my $db_type = RT->Config->Get('DatabaseType'); -if ( $db_type eq 'Pg' ) { - %OPT = ( - %OPT, - limit => 0, - all => 0, - ); - push @OPT_LIST, 'limit=i', 'all!'; -} -elsif ( $db_type eq 'mysql' ) { - %OPT = ( - %OPT, - limit => 0, - all => 0, - xmlpipe2 => 0, - ); - push @OPT_LIST, 'limit=i', 'all!', 'xmlpipe2!'; -} -elsif ( $db_type eq 'Oracle' ) { - %OPT = ( - %OPT, - memory => '2M', - ); - push @OPT_LIST, qw(memory=s); -} - -use Getopt::Long qw(GetOptions); -GetOptions( \%OPT, @OPT_LIST ); - -if ( $OPT{'help'} ) { - RT::Interface::CLI->ShowHelp( - Sections => 'NAME|DESCRIPTION|'. uc($db_type), - ); -} - -my $fts_config = RT->Config->Get('FullTextSearch') || {}; -unless ( $fts_config->{'Enable'} ) { - print STDERR <<EOT; - -Full text search is disabled in your RT configuration. Run -/opt/rt3/sbin/rt-setup-fulltext-index to configure and enable it. - -EOT - exit 1; -} -unless ( $fts_config->{'Indexed'} ) { - print STDERR <<EOT; - -Full text search is enabled in your RT configuration, but not with any -full-text database indexing -- hence this tool is not required. Read -the documentation for %FullTextSearch in your RT_Config for more details. - -EOT - exit 1; -} - -if ( $db_type eq 'Oracle' ) { - my $index = $fts_config->{'IndexName'} || 'rt_fts_index'; - $RT::Handle->dbh->do( - "begin ctx_ddl.sync_index(?, ?); end;", undef, - $index, $OPT{'memory'} - ); - exit; -} elsif ( $db_type eq 'mysql' ) { - unless ($OPT{'xmlpipe2'}) { - print STDERR <<EOT; - -Updates to the external Sphinx index are done via running the sphinx -`indexer` tool: - - indexer rt - -EOT - exit 1; - } -} - -my @types = qw(text html); -foreach my $type ( @types ) { - REDO: - my $attachments = attachments($type); - $attachments->Limit( - FIELD => 'id', - OPERATOR => '>', - VALUE => last_indexed($type) - ); - $attachments->OrderBy( FIELD => 'id', ORDER => 'asc' ); - $attachments->RowsPerPage( $OPT{'limit'} || 100 ); - - my $found = 0; - while ( my $a = $attachments->Next ) { - next if filter( $type, $a ); - debug("Found attachment #". $a->id ); - my $txt = extract($type, $a) or next; - $found++; - process( $type, $a, $txt ); - debug("Processed attachment #". $a->id ); - } - finalize( $type, $attachments ) if $found; - clean( $type ); - goto REDO if $OPT{'all'} and $attachments->Count == ($OPT{'limit'} || 100) -} - -sub attachments { - my $type = shift; - my $res = RT::Attachments->new( RT->SystemUser ); - my $txn_alias = $res->Join( - ALIAS1 => 'main', - FIELD1 => 'TransactionId', - TABLE2 => 'Transactions', - FIELD2 => 'id', - ); - $res->Limit( - ALIAS => $txn_alias, - FIELD => 'ObjectType', - VALUE => 'RT::Ticket', - ); - my $ticket_alias = $res->Join( - ALIAS1 => $txn_alias, - FIELD1 => 'ObjectId', - TABLE2 => 'Tickets', - FIELD2 => 'id', - ); - $res->Limit( - ALIAS => $ticket_alias, - FIELD => 'Status', - OPERATOR => '!=', - VALUE => 'deleted' - ); - - # On newer DBIx::SearchBuilder's, indicate that making the query DISTINCT - # is unnecessary because the joins won't produce duplicates. This - # drastically improves performance when fetching attachments. - $res->{joins_are_distinct} = 1; - - return goto_specific( - suffix => $type, - error => "Don't know how to find $type attachments", - arguments => [$res], - ); -} - -sub last_indexed { - my ($type) = (@_); - return goto_specific( - suffix => $db_type, - error => "Don't know how to find last indexed $type attachment for $db_type DB", - arguments => \@_, - ); -} - -sub filter { - my $type = shift; - return goto_specific( - suffix => $type, - arguments => \@_, - ); -} - -sub extract { - my $type = shift; - return goto_specific( - suffix => $type, - error => "No way to convert $type attachment into text", - arguments => \@_, - ); -} - -sub process { - return goto_specific( - suffix => $db_type, - error => "No processer for $db_type DB", - arguments => \@_, - ); -} - -sub finalize { - return goto_specific( - suffix => $db_type, - arguments => \@_, - ); -} - -sub clean { - return goto_specific( - suffix => $db_type, - arguments => \@_, - ); -} - -{ -sub last_indexed_mysql { - my $type = shift; - my $attr = $RT::System->FirstAttribute('LastIndexedAttachments'); - return 0 unless $attr; - return 0 unless exists $attr->{ $type }; - return $attr->{ $type } || 0; -} - -sub process_mysql { - my ($type, $attachment, $text) = (@_); - - my $doc = sphinx_template(); - - my $element = $doc->createElement('sphinx:document'); - $element->setAttribute( id => $attachment->id ); - $element->appendTextChild( content => $$text ); - - $doc->documentElement->appendChild( $element ); -} - -my $doc = undef; -sub sphinx_template { - return $doc if $doc; - - require XML::LibXML; - $doc = XML::LibXML::Document->new('1.0', 'UTF-8'); - my $root = $doc->createElement('sphinx:docset'); - $doc->setDocumentElement( $root ); - - my $schema = $doc->createElement('sphinx:schema'); - $root->appendChild( $schema ); - foreach ( qw(content) ) { - my $field = $doc->createElement('sphinx:field'); - $field->setAttribute( name => $_ ); - $schema->appendChild( $field ); - } - - return $doc; -} - -sub finalize_mysql { - my ($type, $attachments) = @_; - sphinx_template()->toFH(*STDOUT, 1); -} - -sub clean_mysql { - $doc = undef; -} - -} - -sub last_indexed_pg { - my $type = shift; - my $attachments = attachments( $type ); - my $alias = 'main'; - if ( $fts_config->{'Table'} && $fts_config->{'Table'} ne 'Attachments' ) { - $alias = $attachments->Join( - TYPE => 'left', - FIELD1 => 'id', - TABLE2 => $fts_config->{'Table'}, - FIELD2 => 'id', - ); - } - $attachments->Limit( - ALIAS => $alias, - FIELD => $fts_config->{'Column'}, - OPERATOR => 'IS NOT', - VALUE => 'NULL', - ); - $attachments->OrderBy( FIELD => 'id', ORDER => 'desc' ); - $attachments->RowsPerPage( 1 ); - my $res = $attachments->First; - return 0 unless $res; - return $res->id; -} - -sub process_pg { - my ($type, $attachment, $text) = (@_); - - my $dbh = $RT::Handle->dbh; - my $table = $fts_config->{'Table'}; - my $column = $fts_config->{'Column'}; - - my $query; - if ( $table ) { - if ( my ($id) = $dbh->selectrow_array("SELECT id FROM $table WHERE id = ?", undef, $attachment->id) ) { - $query = "UPDATE $table SET $column = to_tsvector(?) WHERE id = ?"; - } else { - $query = "INSERT INTO $table($column, id) VALUES(to_tsvector(?), ?)"; - } - } else { - $query = "UPDATE Attachments SET $column = to_tsvector(?) WHERE id = ?"; - } - - my $status = eval { $dbh->do( $query, undef, $$text, $attachment->id ) }; - unless ( $status ) { - if ( $dbh->err == 7 && $dbh->state eq '54000' ) { - warn "Attachment @{[$attachment->id]} cannot be indexed, as it contains too many unique words"; - } elsif ( $dbh->err == 7 && $dbh->state eq '22021' ) { - warn "Attachment @{[$attachment->id]} cannot be indexed, as it contains invalid UTF8 bytes"; - } else { - die "error: ". $dbh->errstr; - } - - # Insert an empty tsvector, so we count this row as "indexed" - # for purposes of knowing where to pick up - eval { $dbh->do( $query, undef, "", $attachment->id ) } - or die "Failed to insert empty tsvector: " . $dbh->errstr; - } -} - -sub attachments_text { - my $res = shift; - $res->Limit( FIELD => 'ContentType', VALUE => 'text/plain' ); - return $res; -} - -sub extract_text { - my $attachment = shift; - my $text = $attachment->Content; - return undef unless defined $text && length($text); - return \$text; -} - -sub attachments_html { - my $res = shift; - $res->Limit( FIELD => 'ContentType', VALUE => 'text/html' ); - return $res; -} - -sub filter_html { - my $attachment = shift; - if ( my $parent = $attachment->ParentObj ) { -# skip html parts that are alternatives - return 1 if $parent->id - && $parent->ContentType eq 'mulitpart/alternative'; - } - return 0; -} - -sub extract_html { - my $attachment = shift; - my $text = $attachment->Content; - return undef unless defined $text && length($text); -# TODO: html -> text - return \$text; -} - -sub goto_specific { - my %args = (@_); - - my $func = (caller(1))[3]; - $func =~ s/.*:://; - my $call = $func ."_". lc $args{'suffix'}; - unless ( defined &$call ) { - return undef unless $args{'error'}; - require Carp; Carp::croak( $args{'error'} ); - } - @_ = @{ $args{'arguments'} }; - goto &$call; -} - - -# helper functions -sub debug { print @_, "\n" if $OPT{debug}; 1 } -sub error { $RT::Logger->error(_(@_)); 1 } -sub warning { $RT::Logger->warn(_(@_)); 1 } - -=head1 NAME - -rt-fulltext-indexer - Indexer for full text search - -=head1 DESCRIPTION - -This is a helper script to keep full text indexes in sync with data. -Read F<docs/full_text_indexing.pod> for complete details on how and when -to run it. - -=head1 AUTHOR - -Ruslan Zakirov E<lt>ruz@bestpractical.comE<gt>, -Alex Vandiver E<lt>alexmv@bestpractical.comE<gt> - -=cut - diff --git a/rt/sbin/rt-fulltext-indexer.in b/rt/sbin/rt-fulltext-indexer.in index 9ad6d26bd..b84ca9499 100644 --- a/rt/sbin/rt-fulltext-indexer.in +++ b/rt/sbin/rt-fulltext-indexer.in @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -375,9 +375,9 @@ sub process_pg { my $status = eval { $dbh->do( $query, undef, $$text, $attachment->id ) }; unless ( $status ) { if ( $dbh->err == 7 && $dbh->state eq '54000' ) { - warn "Attachment @{[$attachment->id]} cannot be indexed, as it contains too many unique words"; + warn "Attachment @{[$attachment->id]} cannot be indexed. Most probably it contains too many unique words. Error: ". $dbh->errstr; } elsif ( $dbh->err == 7 && $dbh->state eq '22021' ) { - warn "Attachment @{[$attachment->id]} cannot be indexed, as it contains invalid UTF8 bytes"; + warn "Attachment @{[$attachment->id]} cannot be indexed. Most probably it contains invalid UTF8 bytes. Error: ". $dbh->errstr; } else { die "error: ". $dbh->errstr; } diff --git a/rt/sbin/rt-message-catalog b/rt/sbin/rt-message-catalog index b31b58de7..b4283694f 100755 --- a/rt/sbin/rt-message-catalog +++ b/rt/sbin/rt-message-catalog @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/sbin/rt-preferences-viewer.in b/rt/sbin/rt-preferences-viewer.in index d32588eca..8eeb7c97d 100644 --- a/rt/sbin/rt-preferences-viewer.in +++ b/rt/sbin/rt-preferences-viewer.in @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/sbin/rt-server.fcgi.in b/rt/sbin/rt-server.fcgi.in index 632ba0ba6..0d11f0124 100644 --- a/rt/sbin/rt-server.fcgi.in +++ b/rt/sbin/rt-server.fcgi.in @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -127,7 +127,7 @@ EOF RT->InstallMode(1); } else { - RT->Init(); + RT->Init( Heavy => 1 ); my ($status, $msg) = RT::Handle->CheckCompatibility( $RT::Handle->dbh, 'post'); unless ( $status ) { diff --git a/rt/sbin/rt-server.in b/rt/sbin/rt-server.in index 632ba0ba6..0d11f0124 100644 --- a/rt/sbin/rt-server.in +++ b/rt/sbin/rt-server.in @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -127,7 +127,7 @@ EOF RT->InstallMode(1); } else { - RT->Init(); + RT->Init( Heavy => 1 ); my ($status, $msg) = RT::Handle->CheckCompatibility( $RT::Handle->dbh, 'post'); unless ( $status ) { diff --git a/rt/sbin/rt-session-viewer b/rt/sbin/rt-session-viewer deleted file mode 100755 index 1a6334d94..000000000 --- a/rt/sbin/rt-session-viewer +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/perl -# BEGIN BPS TAGGED BLOCK {{{ -# -# COPYRIGHT: -# -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC -# <jesse@bestpractical.com> -# -# (Except where explicitly superseded by other copyright notices) -# -# -# LICENSE: -# -# This work is made available to you under the terms of Version 2 of -# the GNU General Public License. A copy of that license should have -# been provided with this software, but in any event can be snarfed -# from www.gnu.org. -# -# This work is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301 or visit their web page on the internet at -# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. -# -# -# CONTRIBUTION SUBMISSION POLICY: -# -# (The following paragraph is not intended to limit the rights granted -# to you to modify and distribute this software under the terms of -# the GNU General Public License and is only of importance to you if -# you choose to contribute your changes and enhancements to the -# community by submitting them to Best Practical Solutions, LLC.) -# -# By intentionally submitting any modifications, corrections or -# derivatives to this work, or any other work intended for use with -# Request Tracker, to Best Practical Solutions, LLC, you confirm that -# you are the copyright holder for those contributions and you grant -# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, -# royalty-free, perpetual, license to use, copy, create derivative -# works based on those contributions, and sublicense and distribute -# those contributions and any derivatives thereof. -# -# END BPS TAGGED BLOCK }}} -use strict; -use warnings; - -# fix lib paths, some may be relative -BEGIN { - require File::Spec; - my @libs = ("/opt/rt3/lib", "/opt/rt3/local/lib"); - my $bin_path; - - for my $lib (@libs) { - unless ( File::Spec->file_name_is_absolute($lib) ) { - unless ($bin_path) { - if ( File::Spec->file_name_is_absolute(__FILE__) ) { - $bin_path = ( File::Spec->splitpath(__FILE__) )[1]; - } - else { - require FindBin; - no warnings "once"; - $bin_path = $FindBin::Bin; - } - } - $lib = File::Spec->catfile( $bin_path, File::Spec->updir, $lib ); - } - unshift @INC, $lib; - } -} - -use Getopt::Long; -my %opt; -GetOptions( \%opt, 'help|h', ); - -my $session_id = shift; - -if ( $opt{help} || !$session_id ) { - require Pod::Usage; - Pod::Usage::pod2usage({ verbose => 2 }); - exit; -} - -require RT; -RT::LoadConfig(); -RT::Init(); - -require RT::Interface::Web::Session; -my %session; - -tie %session, 'RT::Interface::Web::Session', $session_id; -unless ( $session{'_session_id'} eq $session_id ) { - print STDERR "Couldn't load session $session_id\n"; - exit 1; -} - -use Data::Dumper; -print "Content of session $session_id: ". Dumper( \%session); - -__END__ - -=head1 NAME - -rt-session-viewer - show the content of a user's session - -=head1 SYNOPSIS - - # show the content of a session - rt-session-viewer 2c21c8a2909c14eff12975dd2cc7b9a3 - -=head1 DESCRIPTION - -This script deserializes and print content of a session identified -by <session id>. May be useful for developers and for troubleshooting -problems. - -=cut diff --git a/rt/sbin/rt-session-viewer.in b/rt/sbin/rt-session-viewer.in index cdf7a77bc..5ace1aee2 100644 --- a/rt/sbin/rt-session-viewer.in +++ b/rt/sbin/rt-session-viewer.in @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <jesse@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/sbin/rt-setup-database.in b/rt/sbin/rt-setup-database.in index f1e35f5cc..edf3d4636 100644 --- a/rt/sbin/rt-setup-database.in +++ b/rt/sbin/rt-setup-database.in @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -83,13 +83,15 @@ $| = 1; # unbuffer all output. my %args = ( dba => '@DB_DBA@', + package => 'RT', ); GetOptions( \%args, 'action=s', 'force', 'debug', - 'dba=s', 'dba-password=s', 'prompt-for-dba-password', + 'dba=s', 'dba-password=s', 'prompt-for-dba-password', 'package=s', 'datafile=s', 'datadir=s', 'skip-create', 'root-password-file=s', + 'upgrade-from=s', 'upgrade-to=s', 'help|h', ); @@ -164,6 +166,7 @@ foreach my $key(qw(Type Host Name User Password)) { my $db_type = RT->Config->Get('DatabaseType') || ''; my $db_host = RT->Config->Get('DatabaseHost') || ''; +my $db_port = RT->Config->Get('DatabasePort') || ''; my $db_name = RT->Config->Get('DatabaseName') || ''; my $db_user = RT->Config->Get('DatabaseUser') || ''; my $db_pass = RT->Config->Get('DatabasePassword') || ''; @@ -191,8 +194,11 @@ if ($args{'skip-create'}) { } } +my $version_word_regex = join '|', RT::Handle->version_words; +my $version_dir = qr/^\d+\.\d+\.\d+(?:$version_word_regex)?\d*$/; + print "Working with:\n" - ."Type:\t$db_type\nHost:\t$db_host\nName:\t$db_name\n" + ."Type:\t$db_type\nHost:\t$db_host\nPort:\t$db_port\nName:\t$db_name\n" ."User:\t$db_user\nDBA:\t$dba_user" . ($args{'skip-create'} ? ' (No DBA)' : '') . "\n"; foreach my $action ( @actions ) { @@ -220,7 +226,7 @@ sub action_drop { unless ( $args{'force'} ) { print <<END; -About to drop $db_type database $db_name on $db_host. +About to drop $db_type database $db_name on $db_host (port '$db_port'). WARNING: This will erase all data in $db_name. END @@ -308,18 +314,17 @@ sub action_upgrade { return (0, "Couldn't read dir '$base_dir' with upgrade data") unless -d $base_dir || -r _; - my $version_word_regex = join '|', RT::Handle->version_words; my $upgrading_from = undef; do { if ( defined $upgrading_from ) { print "Doesn't match #.#.#: "; } else { - print "Enter RT version you're upgrading from: "; + print "Enter $args{package} version you're upgrading from: "; } - $upgrading_from = scalar <STDIN>; + $upgrading_from = $args{'upgrade-from'} || scalar <STDIN>; chomp $upgrading_from; $upgrading_from =~ s/\s+//g; - } while $upgrading_from !~ /^\d+\.\d+\.\d+(?:$version_word_regex)?\d*$/; + } while $upgrading_from !~ /$version_dir/; my $upgrading_to = $RT::VERSION; return (0, "The current version $upgrading_to is lower than $upgrading_from") @@ -347,14 +352,14 @@ sub action_upgrade { if ( defined $custom_upgrading_to ) { print "Doesn't match #.#.#: "; } else { - print "\nEnter RT version if you want to stop upgrade at some point,\n"; + print "\nEnter $args{package} version if you want to stop upgrade at some point,\n"; print " or leave it blank if you want apply above upgrades: "; } - $custom_upgrading_to = scalar <STDIN>; + $custom_upgrading_to = $args{'upgrade-to'} || scalar <STDIN>; chomp $custom_upgrading_to; $custom_upgrading_to =~ s/\s+//g; last unless $custom_upgrading_to; - } while $custom_upgrading_to !~ /^\d+\.\d+\.\d+(?:$version_word_regex)?\d*$/; + } while $custom_upgrading_to !~ /$version_dir/; if ( $custom_upgrading_to ) { return ( @@ -410,9 +415,12 @@ sub get_versions_from_to { my ($base_dir, $from, $to) = @_; opendir( my $dh, $base_dir ) or die "couldn't open dir: $!"; - my @versions = grep -d "$base_dir/$_" && /\d+\.\d+\.\d+/, readdir $dh; + my @versions = grep -d "$base_dir/$_" && /$version_dir/, readdir $dh; closedir $dh; + die "\nERROR: No upgrade data found in '$base_dir'! Perhaps you specified the wrong --datadir?\n" + unless @versions; + return grep defined $to ? RT::Handle::cmp_version($_, $to) <= 0 : 1, grep RT::Handle::cmp_version($_, $from) > 0, @@ -429,7 +437,7 @@ sub error { sub get_dba_password { print "In order to create or update your RT database," . " this script needs to connect to your " - . " $db_type instance on $db_host as $dba_user\n"; + . " $db_type instance on $db_host (port '$db_port') as $dba_user\n"; print "Please specify that user's database password below. If the user has no database\n"; print "password, just press return.\n\n"; print "Password: "; @@ -588,4 +596,14 @@ administrator privileges for 'init' and 'insert': rather than using the default administrative password for RT's "root" user, use the password in this file. +=item upgrade-from + +for 'upgrade': specifies the version to upgrade from, and do not prompt +for it if it appears to be a valid version. + +=item upgrade-to + +for 'upgrade': specifies the version to upgrade to, and do not prompt +for it if it appears to be a valid version. + =back diff --git a/rt/sbin/rt-setup-fulltext-index b/rt/sbin/rt-setup-fulltext-index deleted file mode 100755 index ef9b7d543..000000000 --- a/rt/sbin/rt-setup-fulltext-index +++ /dev/null @@ -1,714 +0,0 @@ -#!/usr/bin/perl -# BEGIN BPS TAGGED BLOCK {{{ -# -# COPYRIGHT: -# -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC -# <sales@bestpractical.com> -# -# (Except where explicitly superseded by other copyright notices) -# -# -# LICENSE: -# -# This work is made available to you under the terms of Version 2 of -# the GNU General Public License. A copy of that license should have -# been provided with this software, but in any event can be snarfed -# from www.gnu.org. -# -# This work is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301 or visit their web page on the internet at -# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. -# -# -# CONTRIBUTION SUBMISSION POLICY: -# -# (The following paragraph is not intended to limit the rights granted -# to you to modify and distribute this software under the terms of -# the GNU General Public License and is only of importance to you if -# you choose to contribute your changes and enhancements to the -# community by submitting them to Best Practical Solutions, LLC.) -# -# By intentionally submitting any modifications, corrections or -# derivatives to this work, or any other work intended for use with -# Request Tracker, to Best Practical Solutions, LLC, you confirm that -# you are the copyright holder for those contributions and you grant -# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, -# royalty-free, perpetual, license to use, copy, create derivative -# works based on those contributions, and sublicense and distribute -# those contributions and any derivatives thereof. -# -# END BPS TAGGED BLOCK }}} -use strict; -use warnings; -no warnings 'once'; - -# fix lib paths, some may be relative -BEGIN { - require File::Spec; - my @libs = ("/opt/rt3/lib", "/opt/rt3/local/lib"); - my $bin_path; - - for my $lib (@libs) { - unless ( File::Spec->file_name_is_absolute($lib) ) { - unless ($bin_path) { - if ( File::Spec->file_name_is_absolute(__FILE__) ) { - $bin_path = ( File::Spec->splitpath(__FILE__) )[1]; - } - else { - require FindBin; - no warnings "once"; - $bin_path = $FindBin::Bin; - } - } - $lib = File::Spec->catfile( $bin_path, File::Spec->updir, $lib ); - } - unshift @INC, $lib; - } -} - -BEGIN { - use RT; - RT::LoadConfig(); - RT::Init(); -}; -use RT::Interface::CLI (); - -my %DB = ( - type => scalar RT->Config->Get('DatabaseType'), - user => scalar RT->Config->Get('DatabaseUser'), - admin => 'freeside', - admin_password => undef, -); - -my %OPT = ( - help => 0, - ask => 1, - dryrun => 0, - attachments => 1, -); - -my %DEFAULT; -if ( $DB{'type'} eq 'Pg' ) { - %DEFAULT = ( - table => 'Attachments', - column => 'ContentIndex', - ); -} -elsif ( $DB{'type'} eq 'mysql' ) { - %DEFAULT = ( - table => 'AttachmentsIndex', - ); -} -elsif ( $DB{'type'} eq 'Oracle' ) { - %DEFAULT = ( - prefix => 'rt_fts_', - ); -} - -use Getopt::Long qw(GetOptions); -GetOptions( - 'h|help!' => \$OPT{'help'}, - 'ask!' => \$OPT{'ask'}, - 'dry-run!' => \$OPT{'dryrun'}, - 'attachments!' => \$OPT{'attachments'}, - - 'table=s' => \$OPT{'table'}, - 'column=s' => \$OPT{'column'}, - 'url=s' => \$OPT{'url'}, - 'maxmatches=i' => \$OPT{'maxmatches'}, - 'index-type=s' => \$OPT{'index-type'}, - - 'dba=s' => \$DB{'admin'}, - 'dba-password=s' => \$DB{'admin_password'}, -) or show_help(); - -if ( $OPT{'help'} || (!$DB{'admin'} && $DB{'type'} eq 'Oracle' ) ) { - show_help( !$OPT{'help'} ); -} - -my $dbh = $RT::Handle->dbh; -$dbh->{'RaiseError'} = 1; -$dbh->{'PrintError'} = 1; - -if ( $DB{'type'} eq 'mysql' ) { - check_sphinx(); - my $table = $OPT{'table'} || prompt( - message => "Enter name of a new MySQL table that will be used to connect to the\n" - . "Sphinx server:", - default => $DEFAULT{'table'}, - silent => !$OPT{'ask'}, - ); - my $url = $OPT{'url'} || prompt( - message => "Enter URL of the sphinx search server; this should be of the form\n" - . "sphinx://<server>:<port>/<index name>", - default => 'sphinx://localhost:3312/rt', - silent => !$OPT{'ask'}, - ); - my $maxmatches = $OPT{'maxmatches'} || prompt( - message => "Maximum number of matches to return; this is the maximum number of\n" - . "attachment records returned by the search, not the maximum number\n" - . "of tickets. Both your RT_SiteConfig.pm and your sphinx.conf must\n" - . "agree on this value. Larger values cause your Sphinx server to\n" - . "consume more memory and CPU time per query.", - default => 10000, - silent => !$OPT{'ask'}, - ); - - my $schema = <<END; -CREATE TABLE $table ( - id INTEGER UNSIGNED NOT NULL, - weight INTEGER NOT NULL, - query VARCHAR(3072) NOT NULL, - INDEX(query) -) ENGINE=SPHINX CONNECTION="$url" CHARACTER SET utf8 -END - - do_error_is_ok( dba_handle() => "DROP TABLE $table" ) - unless $OPT{'dryrun'}; - insert_schema( $schema ); - - print_rt_config( Table => $table, MaxMatches => $maxmatches ); - - require URI; - my $urlo = URI->new( $url ); - my ($host, $port) = split /:/, $urlo->authority; - my $index = $urlo->path; - $index =~ s{^/+}{}; - - my $var_path = $RT::VarPath; - - my %sphinx_conf = (); - $sphinx_conf{'host'} = RT->Config->Get('DatabaseHost'); - $sphinx_conf{'db'} = RT->Config->Get('DatabaseName'); - $sphinx_conf{'user'} = RT->Config->Get('DatabaseUser'); - $sphinx_conf{'pass'} = RT->Config->Get('DatabasePassword'); - - print <<END - -Below is a simple Sphinx configuration which can be used to index all -text/plain attachments in your database. This configuration is not -ideal; you should read the Sphinx documentation to understand how to -configure it to better suit your needs. - -source rt { - type = mysql - - sql_host = $sphinx_conf{'host'} - sql_db = $sphinx_conf{'db'} - sql_user = $sphinx_conf{'user'} - sql_pass = $sphinx_conf{'pass'} - - sql_query_pre = SET NAMES utf8 - sql_query = \\ - SELECT a.id, a.content FROM Attachments a \\ - JOIN Transactions txn ON a.TransactionId = txn.id AND txn.ObjectType = 'RT::Ticket' \\ - JOIN Tickets t ON txn.ObjectId = t.id \\ - WHERE a.ContentType = 'text/plain' AND t.Status != 'deleted' - - sql_query_info = SELECT * FROM Attachments WHERE id=\$id -} - -index $index { - source = rt - path = $var_path/sphinx/index - docinfo = extern - charset_type = utf-8 -} - -indexer { - mem_limit = 32M -} - -searchd { - port = $port - log = $var_path/sphinx/searchd.log - query_log = $var_path/sphinx/query.log - read_timeout = 5 - max_children = 30 - pid_file = $var_path/sphinx/searchd.pid - max_matches = $maxmatches - seamless_rotate = 1 - preopen_indexes = 0 - unlink_old = 1 -} - -END - -} -elsif ( $DB{'type'} eq 'Pg' ) { - check_tsvalue(); - my $table = $OPT{'table'} || prompt( - message => "Enter the name of a DB table that will be used to store the Pg tsvector.\n" - . "You may either use the existing Attachments table, or create a new\n" - . "table.", - default => $DEFAULT{'table'}, - silent => !$OPT{'ask'}, - ); - my $column = $OPT{'column'} || prompt( - message => 'Enter the name of a column that will be used to store the Pg tsvector:', - default => $DEFAULT{'column'}, - silent => !$OPT{'ask'}, - ); - - my $schema; - my $drop; - if ( lc($table) eq 'attachments' ) { - $drop = "ALTER TABLE $table DROP COLUMN $column"; - $schema = "ALTER TABLE $table ADD COLUMN $column tsvector"; - } else { - $drop = "DROP TABLE $table"; - $schema = "CREATE TABLE $table ( " - ."id INTEGER NOT NULL," - ."$column tsvector )"; - } - - my $index_type = lc($OPT{'index-type'} || ''); - while ( $index_type ne 'gist' and $index_type ne 'gin' ) { - $index_type = lc prompt( - message => "You may choose between GiST or GIN indexes; the former is several times\n" - . "slower to search, but takes less space on disk and is faster to update.", - default => 'GiST', - silent => !$OPT{'ask'}, - ); - } - - do_error_is_ok( dba_handle() => $drop ) - unless $OPT{'dryrun'}; - insert_schema( $schema ); - insert_schema("CREATE INDEX ${column}_idx ON $table USING $index_type($column)"); - - print_rt_config( Table => $table, Column => $column ); -} -elsif ( $DB{'type'} eq 'Oracle' ) { - { - my $dbah = dba_handle(); - do_print_error( $dbah => 'GRANT CTXAPP TO '. $DB{'user'} ); - do_print_error( $dbah => 'GRANT EXECUTE ON CTXSYS.CTX_DDL TO '. $DB{'user'} ); - } - - my %PREFERENCES = ( - datastore => { - type => 'DIRECT_DATASTORE', - }, - filter => { - type => 'AUTO_FILTER', -# attributes => { -# timeout => 120, # seconds -# timeout_type => 'HEURISTIC', # or 'FIXED' -# }, - }, - lexer => { - type => 'WORLD_LEXER', - }, - word_list => { - type => 'BASIC_WORDLIST', - attributes => { - stemmer => 'AUTO', - fuzzy_match => 'AUTO', -# fuzzy_score => undef, -# fuzzy_numresults => undef, -# substring_index => undef, -# prefix_index => undef, -# prefix_length_min => undef, -# prefix_length_max => undef, -# wlidcard_maxterms => undef, - }, - }, - 'section_group' => { - type => 'NULL_SECTION_GROUP', - }, - - storage => { - type => 'BASIC_STORAGE', - attributes => { - R_TABLE_CLAUSE => 'lob (data) store as (cache)', - I_INDEX_CLAUSE => 'compress 2', - }, - }, - ); - - my @params = (); - push @params, ora_create_datastore( %{ $PREFERENCES{'datastore'} } ); - push @params, ora_create_filter( %{ $PREFERENCES{'filter'} } ); - push @params, ora_create_lexer( %{ $PREFERENCES{'lexer'} } ); - push @params, ora_create_word_list( %{ $PREFERENCES{'word_list'} } ); - push @params, ora_create_stop_list(); - push @params, ora_create_section_group( %{ $PREFERENCES{'section_group'} } ); - push @params, ora_create_storage( %{ $PREFERENCES{'storage'} } ); - - my $index_params = join "\n", @params; - my $index_name = $DEFAULT{prefix} .'index'; - do_error_is_ok( $dbh => "DROP INDEX $index_name" ) - unless $OPT{'dryrun'}; - $dbh->do( - "CREATE INDEX $index_name ON Attachments(Content) - indextype is ctxsys.context parameters(' - $index_params - ')", - ) unless $OPT{'dryrun'}; - - print_rt_config( IndexName => $index_name ); -} -else { - die "Full-text indexes on $DB{type} are not yet supported"; -} - -sub check_tsvalue { - my $dbh = $RT::Handle->dbh; - my $fts = ($dbh->selectrow_array(<<EOQ))[0]; -SELECT 1 FROM information_schema.routines WHERE routine_name = 'plainto_tsquery' -EOQ - unless ($fts) { - print STDERR <<EOT; - -Your PostgreSQL server does not include full-text support. You will -need to upgrade to PostgreSQL version 8.3 or higher to use full-text -indexing. - -EOT - exit 1; - } -} - -sub check_sphinx { - return if $RT::Handle->CheckSphinxSE; - - print STDERR <<EOT; - -Your MySQL server has not been compiled with the Sphinx storage engine -(sphinxse). You will need to recompile MySQL according to the -instructions in Sphinx's documentation at -http://sphinxsearch.com/docs/current.html#sphinxse-installing - -EOT - exit 1; -} - -sub ora_create_datastore { - return sprintf 'datastore %s', ora_create_preference( - @_, - name => 'datastore', - ); -} - -sub ora_create_filter { - my $res = ''; - $res .= sprintf "format column %s\n", ora_create_format_column(); - $res .= sprintf 'filter %s', ora_create_preference( - @_, - name => 'filter', - ); - return $res; -} - -sub ora_create_lexer { - return sprintf 'lexer %s', ora_create_preference( - @_, - name => 'lexer', - ); -} - -sub ora_create_word_list { - return sprintf 'wordlist %s', ora_create_preference( - @_, - name => 'word_list', - ); -} - -sub ora_create_stop_list { - my $file = shift || 'etc/stopwords/en.txt'; - return '' unless -e $file; - - my $name = $DEFAULT{'prefix'} .'stop_list'; - unless ($OPT{'dryrun'}) { - do_error_is_ok( $dbh => 'begin ctx_ddl.drop_stoplist(?); end;', $name ); - - $dbh->do( - 'begin ctx_ddl.create_stoplist(?, ?); end;', - undef, $name, 'BASIC_STOPLIST' - ); - - open( my $fh, '<:utf8', $file ) - or die "couldn't open file '$file': $!"; - while ( my $word = <$fh> ) { - chomp $word; - $dbh->do( - 'begin ctx_ddl.add_stopword(?, ?); end;', - undef, $name, $word - ); - } - close $fh; - } - return sprintf 'stoplist %s', $name; -} - -sub ora_create_section_group { - my %args = @_; - my $name = $DEFAULT{'prefix'} .'section_group'; - unless ($OPT{'dryrun'}) { - do_error_is_ok( $dbh => 'begin ctx_ddl.drop_section_group(?); end;', $name ); - $dbh->do( - 'begin ctx_ddl.create_section_group(?, ?); end;', - undef, $name, $args{'type'} - ); - } - return sprintf 'section group %s', $name; -} - -sub ora_create_storage { - return sprintf 'storage %s', ora_create_preference( - @_, - name => 'storage', - ); -} - -sub ora_create_format_column { - my $column_name = 'ContentOracleFormat'; - return $column_name if $OPT{'dryrun'}; - unless ( - $dbh->column_info( - undef, undef, uc('Attachments'), uc( $column_name ) - )->fetchrow_array - ) { - $dbh->do(qq{ - ALTER TABLE Attachments ADD $column_name VARCHAR2(10) - }); - } - - my $detect_format = qq{ - CREATE OR REPLACE FUNCTION $DEFAULT{prefix}detect_format_simple( - parent IN NUMBER, - type IN VARCHAR2, - encoding IN VARCHAR2, - fname IN VARCHAR2 - ) - RETURN VARCHAR2 - AS - format VARCHAR2(10); - BEGIN - format := CASE - }; - unless ( $OPT{'attachments'} ) { - $detect_format .= qq{ - WHEN fname IS NOT NULL THEN 'ignore' - }; - } - $detect_format .= qq{ - WHEN type = 'text' THEN 'text' - WHEN type = 'text/rtf' THEN 'ignore' - WHEN type LIKE 'text/%' THEN 'text' - WHEN type LIKE 'message/%' THEN 'text' - ELSE 'ignore' - END; - RETURN format; - END; - }; - ora_create_procedure( $detect_format ); - - $dbh->do(qq{ - UPDATE Attachments - SET $column_name = $DEFAULT{prefix}detect_format_simple( - Parent, - ContentType, ContentEncoding, - Filename - ) - WHERE $column_name IS NULL - }); - $dbh->do(qq{ - CREATE OR REPLACE TRIGGER $DEFAULT{prefix}set_format - BEFORE INSERT - ON Attachments - FOR EACH ROW - BEGIN - :new.$column_name := $DEFAULT{prefix}detect_format_simple( - :new.Parent, - :new.ContentType, :new.ContentEncoding, - :new.Filename - ); - END; - }); - return $column_name; -} - -sub ora_create_preference { - my %info = @_; - my $name = $DEFAULT{'prefix'} . $info{'name'}; - return $name if $OPT{'dryrun'}; - do_error_is_ok( $dbh => 'begin ctx_ddl.drop_preference(?); end;', $name ); - $dbh->do( - 'begin ctx_ddl.create_preference(?, ?); end;', - undef, $name, $info{'type'} - ); - return $name unless $info{'attributes'}; - - while ( my ($attr, $value) = each %{ $info{'attributes'} } ) { - $dbh->do( - 'begin ctx_ddl.set_attribute(?, ?, ?); end;', - undef, $name, $attr, $value - ); - } - - return $name; -} - -sub ora_create_procedure { - my $text = shift; - - return if $OPT{'dryrun'}; - my $status = $dbh->do($text, { RaiseError => 0 }); - - # Statement succeeded - return if $status; - - if ( 6550 != $dbh->err ) { - # Utter failure - die $dbh->errstr; - } - else { - my $msg = $dbh->func( 'plsql_errstr' ); - die $dbh->errstr if !defined $msg; - die $msg if $msg; - } -} - -sub dba_handle { - if ( $DB{'type'} eq 'Oracle' ) { - $ENV{'NLS_LANG'} = "AMERICAN_AMERICA.AL32UTF8"; - $ENV{'NLS_NCHAR'} = "AL32UTF8"; - } - my $dsn = do { my $h = new RT::Handle; $h->BuildDSN; $h->DSN }; - my $dbh = DBI->connect( - $dsn, $DB{admin}, $DB{admin_password}, - { RaiseError => 1, PrintError => 1 }, - ); - unless ( $dbh ) { - die "Failed to connect to $dsn as user '$DB{admin}': ". $DBI::errstr; - } - return $dbh; -} - -sub do_error_is_ok { - my $dbh = shift; - local $dbh->{'RaiseError'} = 0; - local $dbh->{'PrintError'} = 0; - return $dbh->do(shift, undef, @_); -} - -sub do_print_error { - my $dbh = shift; - local $dbh->{'RaiseError'} = 0; - local $dbh->{'PrintError'} = 1; - return $dbh->do(shift, undef, @_); -} - -sub prompt { - my %args = ( @_ ); - return $args{'default'} if $args{'silent'}; - - local $| = 1; - print $args{'message'}; - if ( $args{'default'} ) { - print "\n[". $args{'default'} .']: '; - } else { - print ":\n"; - } - - my $res = <STDIN>; - chomp $res; - print "\n"; - return $args{'default'} if !$res && $args{'default'}; - return $res; -} - -sub verbose { print @_, "\n" if $OPT{verbose} || $OPT{verbose}; 1 } -sub debug { print @_, "\n" if $OPT{debug}; 1 } -sub error { $RT::Logger->error( @_ ); verbose(@_); 1 } -sub warning { $RT::Logger->warning( @_ ); verbose(@_); 1 } - -sub show_help { - my $error = shift; - RT::Interface::CLI->ShowHelp( - ExitValue => $error, - Sections => 'NAME|DESCRIPTION', - ); -} - -sub print_rt_config { - my %args = @_; - my $config = <<END; - -You can now configure RT to use the newly-created full-text index by -adding the following to your RT_SiteConfig.pm: - -Set( %FullTextSearch, - Enable => 1, - Indexed => 1, -END - - $config .= sprintf(" %-10s => '$args{$_}',\n",$_) - foreach grep defined $args{$_}, keys %args; - $config .= ");\n"; - - print $config; -} - -sub insert_schema { - my $dbh = dba_handle(); - my $message = "Going to run the following in the DB:"; - my $schema = shift; - print "$message\n"; - my $disp = $schema; - $disp =~ s/^/ /mg; - print "$disp\n\n"; - return if $OPT{'dryrun'}; - - my $res = $dbh->do( $schema ); - unless ( $res ) { - die "Couldn't run DDL query: ". $dbh->errstr; - } -} - -=head1 NAME - -rt-setup-fulltext-index - Create indexes for full text search - -=head1 DESCRIPTION - -This script creates the appropriate tables, columns, functions, and / or -views necessary for full-text searching for your database type. It will -drop any existing indexes in the process. - -Please read F<docs/full_text_indexing.pod> for complete documentation on -full-text indexing for your database type. - -If you have a non-standard database administrator user or password, you -may use the C<--dba> and C<--dba-password> parameters to set them -explicitly: - - rt-setup-fulltext-index --dba sysdba --dba-password 'secret' - -To test what will happen without running any DDL, pass the C<--dryrun> -flag. - -The Oracle index determines which content-types it will index at -creation time. By default, textual message bodies and textual uploaded -attachments (attachments with filenames) are indexed; to ignore textual -attachments, pass the C<--no-attachments> flag when the index is -created. - - -=head1 AUTHOR - -Ruslan Zakirov E<lt>ruz@bestpractical.comE<gt>, -Alex Vandiver E<lt>alexmv@bestpractical.comE<gt> - -=cut - diff --git a/rt/sbin/rt-setup-fulltext-index.in b/rt/sbin/rt-setup-fulltext-index.in index eab720352..ade728f8f 100644 --- a/rt/sbin/rt-setup-fulltext-index.in +++ b/rt/sbin/rt-setup-fulltext-index.in @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/sbin/rt-shredder.in b/rt/sbin/rt-shredder.in index e7910e523..a903728ce 100755 --- a/rt/sbin/rt-shredder.in +++ b/rt/sbin/rt-shredder.in @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -135,7 +135,10 @@ BEGIN { } -use RT::Shredder (); +use RT -init; + +require RT::Shredder; + use Getopt::Long qw(GetOptions); use File::Spec (); @@ -146,7 +149,6 @@ our %plugins = RT::Shredder::Plugin->List; our %opt; parse_args(); -RT::Shredder::Init( %opt ); my $shredder = RT::Shredder->new; { diff --git a/rt/sbin/rt-test-dependencies.in b/rt/sbin/rt-test-dependencies.in index df1ef135f..868105431 100644 --- a/rt/sbin/rt-test-dependencies.in +++ b/rt/sbin/rt-test-dependencies.in @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -295,6 +295,7 @@ Test::WWW::Mechanize::PSGI Plack::Middleware::Test::StashWarnings 0.06 Test::LongString Test::NoWarnings +Locale::PO . $deps{'FASTCGI'} = [ text_to_hash( << '.') ]; diff --git a/rt/sbin/rt-validate-aliases.in b/rt/sbin/rt-validate-aliases.in index 5dbfaa459..97252ae19 100644 --- a/rt/sbin/rt-validate-aliases.in +++ b/rt/sbin/rt-validate-aliases.in @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/sbin/rt-validator.in b/rt/sbin/rt-validator.in index d90280169..128e60af0 100644 --- a/rt/sbin/rt-validator.in +++ b/rt/sbin/rt-validator.in @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) diff --git a/rt/sbin/standalone_httpd b/rt/sbin/standalone_httpd deleted file mode 100755 index 5bc8d0c8b..000000000 --- a/rt/sbin/standalone_httpd +++ /dev/null @@ -1,284 +0,0 @@ -#!/usr/bin/perl -w -# BEGIN BPS TAGGED BLOCK {{{ -# -# COPYRIGHT: -# -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC -# <sales@bestpractical.com> -# -# (Except where explicitly superseded by other copyright notices) -# -# -# LICENSE: -# -# This work is made available to you under the terms of Version 2 of -# the GNU General Public License. A copy of that license should have -# been provided with this software, but in any event can be snarfed -# from www.gnu.org. -# -# This work is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301 or visit their web page on the internet at -# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. -# -# -# CONTRIBUTION SUBMISSION POLICY: -# -# (The following paragraph is not intended to limit the rights granted -# to you to modify and distribute this software under the terms of -# the GNU General Public License and is only of importance to you if -# you choose to contribute your changes and enhancements to the -# community by submitting them to Best Practical Solutions, LLC.) -# -# By intentionally submitting any modifications, corrections or -# derivatives to this work, or any other work intended for use with -# Request Tracker, to Best Practical Solutions, LLC, you confirm that -# you are the copyright holder for those contributions and you grant -# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, -# royalty-free, perpetual, license to use, copy, create derivative -# works based on those contributions, and sublicense and distribute -# those contributions and any derivatives thereof. -# -# END BPS TAGGED BLOCK }}} -use warnings; -use strict; - -# fix lib paths, some may be relative -BEGIN { - die <<EOT if ${^TAINT}; -RT does not run under Perl's "taint mode". Remove -T from the command -line, or remove the PerlTaintCheck parameter from your mod_perl -configuration. -EOT - - require File::Spec; - my @libs = ("/opt/rt3/lib", "/opt/rt3/local/lib"); - my $bin_path; - - for my $lib (@libs) { - unless ( File::Spec->file_name_is_absolute($lib) ) { - unless ($bin_path) { - if ( File::Spec->file_name_is_absolute(__FILE__) ) { - $bin_path = ( File::Spec->splitpath(__FILE__) )[1]; - } - else { - require FindBin; - no warnings "once"; - $bin_path = $FindBin::Bin; - } - } - $lib = File::Spec->catfile( $bin_path, File::Spec->updir, $lib ); - } - unshift @INC, $lib; - } - -} - -use Getopt::Long; -no warnings 'once'; - -if (grep { m/help/ } @ARGV) { - require Pod::Usage; - print Pod::Usage::pod2usage( { verbose => 2 } ); - exit; -} - -require RT; -RT->LoadConfig(); -RT->InitPluginPaths(); -RT->InitLogging(); -require Module::Refresh if RT->Config->Get('DevelMode'); - -require RT::Handle; -my ($integrity, $state, $msg) = RT::Handle->CheckIntegrity; - -unless ( $integrity ) { - print STDERR <<EOF; - -RT couldn't connect to the database where tickets are stored. -If this is a new installation of RT, you should visit the URL below -to configure RT and initialize your database. - -If this is an existing RT installation, this may indicate a database -connectivity problem. - -The error RT got back when trying to connect to your database was: - -$msg - -EOF - - require RT::Installer; - # don't enter install mode if the file exists but is unwritable - if (-e RT::Installer->ConfigFile && !-w _) { - die 'Since your configuration exists (' - . RT::Installer->ConfigFile - . ") but is not writable, I'm refusing to do anything.\n"; - } - - RT->Config->Set( 'LexiconLanguages' => '*' ); - RT::I18N->Init; - - RT->InstallMode(1); -} else { - RT->Init(); - - my ($status, $msg) = RT::Handle->CheckCompatibility( $RT::Handle->dbh, 'post'); - unless ( $status ) { - print STDERR $msg, "\n\n"; - exit -1; - } -} - -# we must disconnect DB before fork -if ($RT::Handle) { - $RT::Handle->dbh(undef); - undef $RT::Handle; -} - -require RT::Interface::Web::Handler; -my $app = RT::Interface::Web::Handler->PSGIApp; - -if ($ENV{RT_TESTING}) { - my $screen_logger = $RT::Logger->remove('screen'); - require Log::Dispatch::Perl; - $RT::Logger->add( - Log::Dispatch::Perl->new( - name => 'rttest', - min_level => $screen_logger->min_level, - action => { - error => 'warn', - critical => 'warn' - } - ) - ); - require Plack::Middleware::Test::StashWarnings; - $app = Plack::Middleware::Test::StashWarnings->wrap($app); -} - -# when used as a psgi file -if (caller) { - return $app; -} - - -# load appropriate server - -require Plack::Runner; - -my $is_fastcgi = $0 =~ m/fcgi$/; -my $r = Plack::Runner->new( $0 =~ /standalone/ ? ( server => 'Standalone' ) : - $is_fastcgi ? ( server => 'FCGI' ) - : (), - env => 'deployment' ); - -# figure out the port -my $port; - -# handle "rt-server 8888" for back-compat, but complain about it -if ($ARGV[0] && $ARGV[0] =~ m/^\d+$/) { - warn "Deprecated: please run $0 --port $ARGV[0] instead\n"; - unshift @ARGV, '--port'; -} - -my @args = @ARGV; - -use List::MoreUtils 'last_index'; -my $last_index = last_index { $_ eq '--port' } @args; - -my $explicit_port; - -if ( $last_index != -1 && $args[$last_index+1] =~ /^\d+$/ ) { - $explicit_port = $args[$last_index+1]; - $port = $explicit_port; - - # inform the rest of the system what port we manually chose - my $old_app = $app; - $app = sub { - my $env = shift; - - $env->{'rt.explicit_port'} = $port; - - $old_app->($env, @_); - }; -} -else { - # default to the configured WebPort and inform Plack::Runner - $port = RT->Config->Get('WebPort') || '8080'; - push @args, '--port', $port; -} - -push @args, '--server', 'Standalone' if RT->InstallMode; -push @args, '--server', 'Starlet' unless $r->{server} || grep { m/--server/ } @args; - -$r->parse_options(@args); - -delete $r->{options} if $is_fastcgi; ### mangle_host_port_socket ruins everything - -unless ($r->{env} eq 'development') { - push @{$r->{options}}, server_ready => sub { - my($args) = @_; - my $name = $args->{server_software} || ref($args); # $args is $server - my $host = $args->{host} || 0; - my $proto = $args->{proto} || 'http'; - print STDERR "$name: Accepting connections at $proto://$host:$args->{port}/\n"; - }; -} -eval { $r->run($app) }; -if (my $err = $@) { - handle_startup_error($err); -} - -exit 0; - -sub handle_startup_error { - my $err = shift; - if ( $err =~ /listen/ ) { - handle_bind_error(); - } else { - die - "Something went wrong while trying to run RT's standalone web server:\n\t" - . $err; - } -} - - -sub handle_bind_error { - - print STDERR <<EOF; -WARNING: RT couldn't start up a web server on port @{[$port]}. -This is often the case if the port is already in use or you're running @{[$0]} -as someone other than your system's "root" user. You may also specify a -temporary port with: $0 --port <port> -EOF - - if ($explicit_port) { - print STDERR - "Please check your system configuration or choose another port\n\n"; - } -} - -__END__ - -=head1 NAME - -rt-server - RT standalone server - -=head1 SYNOPSIS - - # runs prefork server listening on port 8080, requires Starlet - rt-server --port 8080 - - # runs server listening on port 8080 - rt-server --server Standalone --port 8080 - # or - standalone_httpd --port 8080 - - # runs other PSGI server on port 8080 - rt-server --server Starman --port 8080 diff --git a/rt/sbin/standalone_httpd.in b/rt/sbin/standalone_httpd.in index 632ba0ba6..0d11f0124 100644 --- a/rt/sbin/standalone_httpd.in +++ b/rt/sbin/standalone_httpd.in @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -127,7 +127,7 @@ EOF RT->InstallMode(1); } else { - RT->Init(); + RT->Init( Heavy => 1 ); my ($status, $msg) = RT::Handle->CheckCompatibility( $RT::Handle->dbh, 'post'); unless ( $status ) { diff --git a/rt/share/html/Admin/Articles/Classes/CustomFields.html b/rt/share/html/Admin/Articles/Classes/CustomFields.html index 65705b9a4..f8a5bd69b 100644 --- a/rt/share/html/Admin/Articles/Classes/CustomFields.html +++ b/rt/share/html/Admin/Articles/Classes/CustomFields.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Articles/Classes/GroupRights.html b/rt/share/html/Admin/Articles/Classes/GroupRights.html index 9fdd60d55..433e3d518 100644 --- a/rt/share/html/Admin/Articles/Classes/GroupRights.html +++ b/rt/share/html/Admin/Articles/Classes/GroupRights.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Articles/Classes/Modify.html b/rt/share/html/Admin/Articles/Classes/Modify.html index ef71ac399..f96094b78 100644 --- a/rt/share/html/Admin/Articles/Classes/Modify.html +++ b/rt/share/html/Admin/Articles/Classes/Modify.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Articles/Classes/Objects.html b/rt/share/html/Admin/Articles/Classes/Objects.html index b7c393774..5d5118fa9 100644 --- a/rt/share/html/Admin/Articles/Classes/Objects.html +++ b/rt/share/html/Admin/Articles/Classes/Objects.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Articles/Classes/Topics.html b/rt/share/html/Admin/Articles/Classes/Topics.html index 88b602ed3..525bf45b4 100644 --- a/rt/share/html/Admin/Articles/Classes/Topics.html +++ b/rt/share/html/Admin/Articles/Classes/Topics.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Articles/Classes/UserRights.html b/rt/share/html/Admin/Articles/Classes/UserRights.html index fe614ba9f..9f26fdcca 100644 --- a/rt/share/html/Admin/Articles/Classes/UserRights.html +++ b/rt/share/html/Admin/Articles/Classes/UserRights.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Articles/Classes/index.html b/rt/share/html/Admin/Articles/Classes/index.html index 5d478b3b9..1dc975622 100644 --- a/rt/share/html/Admin/Articles/Classes/index.html +++ b/rt/share/html/Admin/Articles/Classes/index.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Articles/Elements/Topics b/rt/share/html/Admin/Articles/Elements/Topics index c6a383996..f30f69e38 100644 --- a/rt/share/html/Admin/Articles/Elements/Topics +++ b/rt/share/html/Admin/Articles/Elements/Topics @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Articles/index.html b/rt/share/html/Admin/Articles/index.html index b2fca6f66..171af476d 100644 --- a/rt/share/html/Admin/Articles/index.html +++ b/rt/share/html/Admin/Articles/index.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/CustomFields/GroupRights.html b/rt/share/html/Admin/CustomFields/GroupRights.html index e58268fa4..b63619f55 100644 --- a/rt/share/html/Admin/CustomFields/GroupRights.html +++ b/rt/share/html/Admin/CustomFields/GroupRights.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/CustomFields/Modify.html b/rt/share/html/Admin/CustomFields/Modify.html index 8628cd383..015f4f350 100644 --- a/rt/share/html/Admin/CustomFields/Modify.html +++ b/rt/share/html/Admin/CustomFields/Modify.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -345,7 +345,7 @@ $m->callback(CallbackName => 'ValidationPatterns', Values => \@CFvalidations); <%ARGS> $id => undef $TypeComposite => undef -$LookupType => undef +$LookupType => RT::Ticket->CustomFieldLookupType $MaxValues => undef $SortOrder => undef $Description => undef diff --git a/rt/share/html/Admin/CustomFields/Objects.html b/rt/share/html/Admin/CustomFields/Objects.html index 26183acc1..f28997675 100644 --- a/rt/share/html/Admin/CustomFields/Objects.html +++ b/rt/share/html/Admin/CustomFields/Objects.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/CustomFields/UserRights.html b/rt/share/html/Admin/CustomFields/UserRights.html index d4692986c..bc2d800c4 100644 --- a/rt/share/html/Admin/CustomFields/UserRights.html +++ b/rt/share/html/Admin/CustomFields/UserRights.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/CustomFields/index.html b/rt/share/html/Admin/CustomFields/index.html index 24264fd23..78d9a92a9 100644 --- a/rt/share/html/Admin/CustomFields/index.html +++ b/rt/share/html/Admin/CustomFields/index.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/AddCustomFieldValue b/rt/share/html/Admin/Elements/AddCustomFieldValue index ac570db2c..ec1a34bc8 100755 --- a/rt/share/html/Admin/Elements/AddCustomFieldValue +++ b/rt/share/html/Admin/Elements/AddCustomFieldValue @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/ConfigureMyRT b/rt/share/html/Admin/Elements/ConfigureMyRT index 91e71d291..4be6803f8 100644 --- a/rt/share/html/Admin/Elements/ConfigureMyRT +++ b/rt/share/html/Admin/Elements/ConfigureMyRT @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/CreateUserCalled b/rt/share/html/Admin/Elements/CreateUserCalled index f0394ea14..f5ef9da8a 100755 --- a/rt/share/html/Admin/Elements/CreateUserCalled +++ b/rt/share/html/Admin/Elements/CreateUserCalled @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/EditCustomField b/rt/share/html/Admin/Elements/EditCustomField index caf5ce838..4c5e98fb6 100755 --- a/rt/share/html/Admin/Elements/EditCustomField +++ b/rt/share/html/Admin/Elements/EditCustomField @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/EditCustomFieldValues b/rt/share/html/Admin/Elements/EditCustomFieldValues index 32715805a..5a81ec7db 100755 --- a/rt/share/html/Admin/Elements/EditCustomFieldValues +++ b/rt/share/html/Admin/Elements/EditCustomFieldValues @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/EditCustomFieldValuesSource b/rt/share/html/Admin/Elements/EditCustomFieldValuesSource index 2b3051442..3aecf7cf6 100644 --- a/rt/share/html/Admin/Elements/EditCustomFieldValuesSource +++ b/rt/share/html/Admin/Elements/EditCustomFieldValuesSource @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/EditCustomFields b/rt/share/html/Admin/Elements/EditCustomFields index 7e63e5836..d3cd8e125 100755 --- a/rt/share/html/Admin/Elements/EditCustomFields +++ b/rt/share/html/Admin/Elements/EditCustomFields @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/EditQueueWatcherGroup b/rt/share/html/Admin/Elements/EditQueueWatcherGroup index 56c6490d5..767bc857c 100644 --- a/rt/share/html/Admin/Elements/EditQueueWatcherGroup +++ b/rt/share/html/Admin/Elements/EditQueueWatcherGroup @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/EditQueueWatchers b/rt/share/html/Admin/Elements/EditQueueWatchers index d7954820b..fb9d1d5f2 100755 --- a/rt/share/html/Admin/Elements/EditQueueWatchers +++ b/rt/share/html/Admin/Elements/EditQueueWatchers @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/EditRights b/rt/share/html/Admin/Elements/EditRights index 1522543f7..5d1e62f40 100644 --- a/rt/share/html/Admin/Elements/EditRights +++ b/rt/share/html/Admin/Elements/EditRights @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/EditRightsCategoryTabs b/rt/share/html/Admin/Elements/EditRightsCategoryTabs index 60d0a4412..61e30c313 100644 --- a/rt/share/html/Admin/Elements/EditRightsCategoryTabs +++ b/rt/share/html/Admin/Elements/EditRightsCategoryTabs @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -70,7 +70,8 @@ if ( blessed($Context) and $Context->can('RightCategories') ) { my %right_categories = %{$Context->RightCategories}; for my $right (keys %available_rights) { - push @{$categories{$right_categories{$right}}}, $right; + my $category = $right_categories{$right} || 'Miscellaneous'; # loc + push @{$categories{$category}}, $right; } } @@ -94,7 +95,12 @@ my %category_desc = ( 'Status' => loc('Status changes'), ); -my %catsort = ( General => 1, Staff => 2, Admin => 3, Status => 4 ); +my %catsort = ( General => 1, Staff => 2, Admin => 3, Status => 4, Miscellaneous => 999 ); +my $i = 5; +for my $category ( sort keys %categories ) { + next if $catsort{$category}; + $catsort{$category} = $i++; +} $acldesc ||= join '-', ($Principal ? $Principal->PrincipalId : 'addprincipal'), ref($Context), $Context->Id; @@ -102,7 +108,7 @@ $acldesc ||= join '-', ($Principal ? $Principal->PrincipalId : 'addprincipal'), <div class="category-tabs"> <ul> % for my $category (sort { $catsort{$a} <=> $catsort{$b} } keys %categories) { - <li><a href="#<% "$id-$category" %>"><% $category_desc{$category} || loc('Miscellaneous') %></a></li> + <li><a href="#<% "$id-$category" %>"><% $category_desc{$category} || loc($category) %></a></li> % } </ul> % for my $category (sort { $catsort{$a} <=> $catsort{$b} } keys %categories) { diff --git a/rt/share/html/Admin/Elements/EditScrip b/rt/share/html/Admin/Elements/EditScrip index bd1bde71d..3e2227c73 100755 --- a/rt/share/html/Admin/Elements/EditScrip +++ b/rt/share/html/Admin/Elements/EditScrip @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/EditScrips b/rt/share/html/Admin/Elements/EditScrips index 25cafb42f..c92fc5563 100755 --- a/rt/share/html/Admin/Elements/EditScrips +++ b/rt/share/html/Admin/Elements/EditScrips @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/EditTemplates b/rt/share/html/Admin/Elements/EditTemplates index 28fc59c49..e713e9d29 100755 --- a/rt/share/html/Admin/Elements/EditTemplates +++ b/rt/share/html/Admin/Elements/EditTemplates @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/EditUserComments b/rt/share/html/Admin/Elements/EditUserComments index 1a163d0d8..ac4b91a9d 100755 --- a/rt/share/html/Admin/Elements/EditUserComments +++ b/rt/share/html/Admin/Elements/EditUserComments @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/Header b/rt/share/html/Admin/Elements/Header index 7169bda94..b55052173 100755 --- a/rt/share/html/Admin/Elements/Header +++ b/rt/share/html/Admin/Elements/Header @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/ListGlobalCustomFields b/rt/share/html/Admin/Elements/ListGlobalCustomFields index ccec9986f..05ee51966 100755 --- a/rt/share/html/Admin/Elements/ListGlobalCustomFields +++ b/rt/share/html/Admin/Elements/ListGlobalCustomFields @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/ListGlobalScrips b/rt/share/html/Admin/Elements/ListGlobalScrips index 042628c1c..89491d3a7 100755 --- a/rt/share/html/Admin/Elements/ListGlobalScrips +++ b/rt/share/html/Admin/Elements/ListGlobalScrips @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/ModifyTemplate b/rt/share/html/Admin/Elements/ModifyTemplate index f5bb866de..d12dbb436 100755 --- a/rt/share/html/Admin/Elements/ModifyTemplate +++ b/rt/share/html/Admin/Elements/ModifyTemplate @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/PickCustomFields b/rt/share/html/Admin/Elements/PickCustomFields index 7ed29993c..bb9ba8cc8 100644 --- a/rt/share/html/Admin/Elements/PickCustomFields +++ b/rt/share/html/Admin/Elements/PickCustomFields @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/PickObjects b/rt/share/html/Admin/Elements/PickObjects index 6fccd49fa..d8f1aac66 100644 --- a/rt/share/html/Admin/Elements/PickObjects +++ b/rt/share/html/Admin/Elements/PickObjects @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/Portal b/rt/share/html/Admin/Elements/Portal index 52257aebe..b0b41f28a 100644 --- a/rt/share/html/Admin/Elements/Portal +++ b/rt/share/html/Admin/Elements/Portal @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/QueueRightsForUser b/rt/share/html/Admin/Elements/QueueRightsForUser index a00f84ff7..bab16853d 100755 --- a/rt/share/html/Admin/Elements/QueueRightsForUser +++ b/rt/share/html/Admin/Elements/QueueRightsForUser @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/SelectCustomField b/rt/share/html/Admin/Elements/SelectCustomField index 70b7be61f..9f2c24b66 100644 --- a/rt/share/html/Admin/Elements/SelectCustomField +++ b/rt/share/html/Admin/Elements/SelectCustomField @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/SelectCustomFieldLookupType b/rt/share/html/Admin/Elements/SelectCustomFieldLookupType index 7caa4eaef..7a66ff19c 100644 --- a/rt/share/html/Admin/Elements/SelectCustomFieldLookupType +++ b/rt/share/html/Admin/Elements/SelectCustomFieldLookupType @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/SelectCustomFieldRenderType b/rt/share/html/Admin/Elements/SelectCustomFieldRenderType index 6484def34..0ef6b53ea 100644 --- a/rt/share/html/Admin/Elements/SelectCustomFieldRenderType +++ b/rt/share/html/Admin/Elements/SelectCustomFieldRenderType @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -56,11 +56,6 @@ $Default ||= $cf->DefaultRenderType($TypeComposite); my @types = $cf->RenderTypes($TypeComposite); -# XXX: We currently don't support cascaded select CFs when -# rendering as a list, so don't offer it for now. -if ( $BasedOn ) { - @types = grep { not /List/ } @types; -} </%INIT> <%ARGS> $Default => undef diff --git a/rt/share/html/Admin/Elements/SelectCustomFieldType b/rt/share/html/Admin/Elements/SelectCustomFieldType index bf4cce1cb..a61b0bfa0 100755 --- a/rt/share/html/Admin/Elements/SelectCustomFieldType +++ b/rt/share/html/Admin/Elements/SelectCustomFieldType @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/SelectGroups b/rt/share/html/Admin/Elements/SelectGroups index 2661a02fc..e74bede72 100755 --- a/rt/share/html/Admin/Elements/SelectGroups +++ b/rt/share/html/Admin/Elements/SelectGroups @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/SelectModifyGroup b/rt/share/html/Admin/Elements/SelectModifyGroup index 8e8c7c9af..9aa6419a7 100755 --- a/rt/share/html/Admin/Elements/SelectModifyGroup +++ b/rt/share/html/Admin/Elements/SelectModifyGroup @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/SelectModifyQueue b/rt/share/html/Admin/Elements/SelectModifyQueue index 08fd8e901..92f4a7dad 100755 --- a/rt/share/html/Admin/Elements/SelectModifyQueue +++ b/rt/share/html/Admin/Elements/SelectModifyQueue @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/SelectModifyUser b/rt/share/html/Admin/Elements/SelectModifyUser index 7365f5a6e..0d4b130c0 100755 --- a/rt/share/html/Admin/Elements/SelectModifyUser +++ b/rt/share/html/Admin/Elements/SelectModifyUser @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/SelectNewGroupMembers b/rt/share/html/Admin/Elements/SelectNewGroupMembers index a3a649291..72f649c64 100755 --- a/rt/share/html/Admin/Elements/SelectNewGroupMembers +++ b/rt/share/html/Admin/Elements/SelectNewGroupMembers @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -57,7 +57,7 @@ jQuery(function(){ jQuery(event.target).val(ui.item.value); jQuery(event.target).closest("form").submit(); } - }); + }).addClass("autocompletes-user"); }); </script> % } diff --git a/rt/share/html/Admin/Elements/SelectRights b/rt/share/html/Admin/Elements/SelectRights index 161c09122..7994c14b4 100755 --- a/rt/share/html/Admin/Elements/SelectRights +++ b/rt/share/html/Admin/Elements/SelectRights @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/SelectScrip b/rt/share/html/Admin/Elements/SelectScrip index e13726d13..ffac81cf3 100755 --- a/rt/share/html/Admin/Elements/SelectScrip +++ b/rt/share/html/Admin/Elements/SelectScrip @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/SelectScripAction b/rt/share/html/Admin/Elements/SelectScripAction index a3f4431b5..33f6c1801 100755 --- a/rt/share/html/Admin/Elements/SelectScripAction +++ b/rt/share/html/Admin/Elements/SelectScripAction @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/SelectScripCondition b/rt/share/html/Admin/Elements/SelectScripCondition index a962e6eeb..e895c9425 100755 --- a/rt/share/html/Admin/Elements/SelectScripCondition +++ b/rt/share/html/Admin/Elements/SelectScripCondition @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/SelectSingleOrMultiple b/rt/share/html/Admin/Elements/SelectSingleOrMultiple index ae2639f6c..11cb0a7f1 100755 --- a/rt/share/html/Admin/Elements/SelectSingleOrMultiple +++ b/rt/share/html/Admin/Elements/SelectSingleOrMultiple @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/SelectStage b/rt/share/html/Admin/Elements/SelectStage index 78624eea3..1adb7c2cf 100644 --- a/rt/share/html/Admin/Elements/SelectStage +++ b/rt/share/html/Admin/Elements/SelectStage @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/SelectTemplate b/rt/share/html/Admin/Elements/SelectTemplate index 5da3baace..67e661b5b 100755 --- a/rt/share/html/Admin/Elements/SelectTemplate +++ b/rt/share/html/Admin/Elements/SelectTemplate @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/SelectUsers b/rt/share/html/Admin/Elements/SelectUsers index 7089362ff..2562b7a82 100755 --- a/rt/share/html/Admin/Elements/SelectUsers +++ b/rt/share/html/Admin/Elements/SelectUsers @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Elements/ShowKeyInfo b/rt/share/html/Admin/Elements/ShowKeyInfo index 71b58cfed..56c1d770d 100644 --- a/rt/share/html/Admin/Elements/ShowKeyInfo +++ b/rt/share/html/Admin/Elements/ShowKeyInfo @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Global/CustomFields/Class-Article.html b/rt/share/html/Admin/Global/CustomFields/Class-Article.html index 3f8a52c65..f7401bae4 100644 --- a/rt/share/html/Admin/Global/CustomFields/Class-Article.html +++ b/rt/share/html/Admin/Global/CustomFields/Class-Article.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Global/CustomFields/Groups.html b/rt/share/html/Admin/Global/CustomFields/Groups.html index 8466ff21e..64e331059 100644 --- a/rt/share/html/Admin/Global/CustomFields/Groups.html +++ b/rt/share/html/Admin/Global/CustomFields/Groups.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Global/CustomFields/Queue-Tickets.html b/rt/share/html/Admin/Global/CustomFields/Queue-Tickets.html index 4bdf702fc..5ab984405 100755 --- a/rt/share/html/Admin/Global/CustomFields/Queue-Tickets.html +++ b/rt/share/html/Admin/Global/CustomFields/Queue-Tickets.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Global/CustomFields/Queue-Transactions.html b/rt/share/html/Admin/Global/CustomFields/Queue-Transactions.html index 45c8de050..c198054f1 100755 --- a/rt/share/html/Admin/Global/CustomFields/Queue-Transactions.html +++ b/rt/share/html/Admin/Global/CustomFields/Queue-Transactions.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Global/CustomFields/Queues.html b/rt/share/html/Admin/Global/CustomFields/Queues.html index 6581bd3ed..04a264f3d 100644 --- a/rt/share/html/Admin/Global/CustomFields/Queues.html +++ b/rt/share/html/Admin/Global/CustomFields/Queues.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Global/CustomFields/Users.html b/rt/share/html/Admin/Global/CustomFields/Users.html index bb065db62..588818baf 100644 --- a/rt/share/html/Admin/Global/CustomFields/Users.html +++ b/rt/share/html/Admin/Global/CustomFields/Users.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Global/CustomFields/index.html b/rt/share/html/Admin/Global/CustomFields/index.html index 1a1406a0c..9034baf16 100644 --- a/rt/share/html/Admin/Global/CustomFields/index.html +++ b/rt/share/html/Admin/Global/CustomFields/index.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Global/GroupRights.html b/rt/share/html/Admin/Global/GroupRights.html index cccd894b1..055f1e033 100755 --- a/rt/share/html/Admin/Global/GroupRights.html +++ b/rt/share/html/Admin/Global/GroupRights.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Global/MyRT.html b/rt/share/html/Admin/Global/MyRT.html index 9b3cb96ee..d31aa444f 100644 --- a/rt/share/html/Admin/Global/MyRT.html +++ b/rt/share/html/Admin/Global/MyRT.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Global/Scrip.html b/rt/share/html/Admin/Global/Scrip.html index a730b8d0e..d03d52fd2 100755 --- a/rt/share/html/Admin/Global/Scrip.html +++ b/rt/share/html/Admin/Global/Scrip.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Global/Scrips.html b/rt/share/html/Admin/Global/Scrips.html index b9fd279ff..feccea569 100755 --- a/rt/share/html/Admin/Global/Scrips.html +++ b/rt/share/html/Admin/Global/Scrips.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Global/Template.html b/rt/share/html/Admin/Global/Template.html index 27b2a96c2..fad2d86e4 100755 --- a/rt/share/html/Admin/Global/Template.html +++ b/rt/share/html/Admin/Global/Template.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Global/Templates.html b/rt/share/html/Admin/Global/Templates.html index 9ef9f835e..64d6bd6d8 100755 --- a/rt/share/html/Admin/Global/Templates.html +++ b/rt/share/html/Admin/Global/Templates.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Global/Topics.html b/rt/share/html/Admin/Global/Topics.html index 9ad584b50..4b5aa6414 100644 --- a/rt/share/html/Admin/Global/Topics.html +++ b/rt/share/html/Admin/Global/Topics.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Global/UserRights.html b/rt/share/html/Admin/Global/UserRights.html index 55babf0b0..45d2bfc70 100755 --- a/rt/share/html/Admin/Global/UserRights.html +++ b/rt/share/html/Admin/Global/UserRights.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Global/index.html b/rt/share/html/Admin/Global/index.html index e382203fc..e01cff623 100755 --- a/rt/share/html/Admin/Global/index.html +++ b/rt/share/html/Admin/Global/index.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Groups/GroupRights.html b/rt/share/html/Admin/Groups/GroupRights.html index b3f0426f7..8e7f90827 100755 --- a/rt/share/html/Admin/Groups/GroupRights.html +++ b/rt/share/html/Admin/Groups/GroupRights.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Groups/History.html b/rt/share/html/Admin/Groups/History.html index 91a4fcce1..ba6ac813d 100644 --- a/rt/share/html/Admin/Groups/History.html +++ b/rt/share/html/Admin/Groups/History.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Groups/Members.html b/rt/share/html/Admin/Groups/Members.html index 24d575e7a..aca3633e6 100755 --- a/rt/share/html/Admin/Groups/Members.html +++ b/rt/share/html/Admin/Groups/Members.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Groups/Modify.html b/rt/share/html/Admin/Groups/Modify.html index b3bc13faa..94431d09d 100755 --- a/rt/share/html/Admin/Groups/Modify.html +++ b/rt/share/html/Admin/Groups/Modify.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Groups/UserRights.html b/rt/share/html/Admin/Groups/UserRights.html index e2c4b9c91..bcd2b0008 100755 --- a/rt/share/html/Admin/Groups/UserRights.html +++ b/rt/share/html/Admin/Groups/UserRights.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Groups/index.html b/rt/share/html/Admin/Groups/index.html index b86571f1a..a70904645 100755 --- a/rt/share/html/Admin/Groups/index.html +++ b/rt/share/html/Admin/Groups/index.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Queues/CustomField.html b/rt/share/html/Admin/Queues/CustomField.html index 3524c5b45..b1e0b9e6f 100755 --- a/rt/share/html/Admin/Queues/CustomField.html +++ b/rt/share/html/Admin/Queues/CustomField.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Queues/CustomFields.html b/rt/share/html/Admin/Queues/CustomFields.html index 7d1e60198..b5386900b 100755 --- a/rt/share/html/Admin/Queues/CustomFields.html +++ b/rt/share/html/Admin/Queues/CustomFields.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Queues/GroupRights.html b/rt/share/html/Admin/Queues/GroupRights.html index 72c0f2eff..60fb84399 100755 --- a/rt/share/html/Admin/Queues/GroupRights.html +++ b/rt/share/html/Admin/Queues/GroupRights.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Queues/History.html b/rt/share/html/Admin/Queues/History.html index 3a725b09a..7df45649a 100644 --- a/rt/share/html/Admin/Queues/History.html +++ b/rt/share/html/Admin/Queues/History.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Queues/Modify.html b/rt/share/html/Admin/Queues/Modify.html index 49736a45a..5ef308dae 100755 --- a/rt/share/html/Admin/Queues/Modify.html +++ b/rt/share/html/Admin/Queues/Modify.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Queues/People.html b/rt/share/html/Admin/Queues/People.html index e7cdd47e1..e3a9d0c20 100755 --- a/rt/share/html/Admin/Queues/People.html +++ b/rt/share/html/Admin/Queues/People.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Queues/Scrip.html b/rt/share/html/Admin/Queues/Scrip.html index fd487a157..4181c5184 100755 --- a/rt/share/html/Admin/Queues/Scrip.html +++ b/rt/share/html/Admin/Queues/Scrip.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Queues/Scrips.html b/rt/share/html/Admin/Queues/Scrips.html index 326d23fe0..8b1220d60 100755 --- a/rt/share/html/Admin/Queues/Scrips.html +++ b/rt/share/html/Admin/Queues/Scrips.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Queues/Template.html b/rt/share/html/Admin/Queues/Template.html index 50c29dc24..dfcee30fe 100755 --- a/rt/share/html/Admin/Queues/Template.html +++ b/rt/share/html/Admin/Queues/Template.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Queues/Templates.html b/rt/share/html/Admin/Queues/Templates.html index 1d1f19dc7..8713e20dc 100755 --- a/rt/share/html/Admin/Queues/Templates.html +++ b/rt/share/html/Admin/Queues/Templates.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Queues/UserRights.html b/rt/share/html/Admin/Queues/UserRights.html index ec908672f..957eed47b 100755 --- a/rt/share/html/Admin/Queues/UserRights.html +++ b/rt/share/html/Admin/Queues/UserRights.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Queues/index.html b/rt/share/html/Admin/Queues/index.html index 7f267021b..4ef183ee1 100755 --- a/rt/share/html/Admin/Queues/index.html +++ b/rt/share/html/Admin/Queues/index.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -58,6 +58,7 @@ <& /Elements/CollectionList, OrderBy => 'Name', Order => 'ASC', + Rows => 50, %ARGS, Format => $Format, Collection => $queues, diff --git a/rt/share/html/Admin/Tools/Configuration.html b/rt/share/html/Admin/Tools/Configuration.html index bedbba54b..43e9c21b1 100644 --- a/rt/share/html/Admin/Tools/Configuration.html +++ b/rt/share/html/Admin/Tools/Configuration.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Tools/Queries.html b/rt/share/html/Admin/Tools/Queries.html index 6304ffbf5..c9f6c2daa 100644 --- a/rt/share/html/Admin/Tools/Queries.html +++ b/rt/share/html/Admin/Tools/Queries.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Tools/Shredder/Dumps/dhandler b/rt/share/html/Admin/Tools/Shredder/Dumps/dhandler index a070c2342..bc09f2511 100644 --- a/rt/share/html/Admin/Tools/Shredder/Dumps/dhandler +++ b/rt/share/html/Admin/Tools/Shredder/Dumps/dhandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Tools/Shredder/Elements/DumpFileLink b/rt/share/html/Admin/Tools/Shredder/Elements/DumpFileLink index c43e81048..af720eb7d 100644 --- a/rt/share/html/Admin/Tools/Shredder/Elements/DumpFileLink +++ b/rt/share/html/Admin/Tools/Shredder/Elements/DumpFileLink @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Tools/Shredder/Elements/Error/NoRights b/rt/share/html/Admin/Tools/Shredder/Elements/Error/NoRights index 93319c491..af11bd7d6 100644 --- a/rt/share/html/Admin/Tools/Shredder/Elements/Error/NoRights +++ b/rt/share/html/Admin/Tools/Shredder/Elements/Error/NoRights @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Tools/Shredder/Elements/Error/NoStorage b/rt/share/html/Admin/Tools/Shredder/Elements/Error/NoStorage index 6197d395d..b337aa28f 100644 --- a/rt/share/html/Admin/Tools/Shredder/Elements/Error/NoStorage +++ b/rt/share/html/Admin/Tools/Shredder/Elements/Error/NoStorage @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Tools/Shredder/Elements/Object/RT--Attachment b/rt/share/html/Admin/Tools/Shredder/Elements/Object/RT--Attachment index cc6dd7dab..6ebdb4138 100644 --- a/rt/share/html/Admin/Tools/Shredder/Elements/Object/RT--Attachment +++ b/rt/share/html/Admin/Tools/Shredder/Elements/Object/RT--Attachment @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Tools/Shredder/Elements/Object/RT--Ticket b/rt/share/html/Admin/Tools/Shredder/Elements/Object/RT--Ticket index 1786959b2..9dcdeaddc 100644 --- a/rt/share/html/Admin/Tools/Shredder/Elements/Object/RT--Ticket +++ b/rt/share/html/Admin/Tools/Shredder/Elements/Object/RT--Ticket @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Tools/Shredder/Elements/Object/RT--User b/rt/share/html/Admin/Tools/Shredder/Elements/Object/RT--User index e8808e5cd..6cb7d1f11 100644 --- a/rt/share/html/Admin/Tools/Shredder/Elements/Object/RT--User +++ b/rt/share/html/Admin/Tools/Shredder/Elements/Object/RT--User @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Tools/Shredder/Elements/ObjectCheckBox b/rt/share/html/Admin/Tools/Shredder/Elements/ObjectCheckBox index fa7165dc6..20d0e02aa 100644 --- a/rt/share/html/Admin/Tools/Shredder/Elements/ObjectCheckBox +++ b/rt/share/html/Admin/Tools/Shredder/Elements/ObjectCheckBox @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Tools/Shredder/Elements/PluginArguments b/rt/share/html/Admin/Tools/Shredder/Elements/PluginArguments index 8456a8dd7..412f941b7 100644 --- a/rt/share/html/Admin/Tools/Shredder/Elements/PluginArguments +++ b/rt/share/html/Admin/Tools/Shredder/Elements/PluginArguments @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Tools/Shredder/Elements/PluginHelp b/rt/share/html/Admin/Tools/Shredder/Elements/PluginHelp index 3f064b0f6..6a8539e29 100644 --- a/rt/share/html/Admin/Tools/Shredder/Elements/PluginHelp +++ b/rt/share/html/Admin/Tools/Shredder/Elements/PluginHelp @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Tools/Shredder/Elements/SelectObjects b/rt/share/html/Admin/Tools/Shredder/Elements/SelectObjects index 0521075c0..f9f44aba0 100644 --- a/rt/share/html/Admin/Tools/Shredder/Elements/SelectObjects +++ b/rt/share/html/Admin/Tools/Shredder/Elements/SelectObjects @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Tools/Shredder/Elements/SelectPlugin b/rt/share/html/Admin/Tools/Shredder/Elements/SelectPlugin index b9d6fe6d6..28b7cbb72 100644 --- a/rt/share/html/Admin/Tools/Shredder/Elements/SelectPlugin +++ b/rt/share/html/Admin/Tools/Shredder/Elements/SelectPlugin @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Tools/Shredder/autohandler b/rt/share/html/Admin/Tools/Shredder/autohandler index 49c42340c..d8e0aa658 100644 --- a/rt/share/html/Admin/Tools/Shredder/autohandler +++ b/rt/share/html/Admin/Tools/Shredder/autohandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Tools/Shredder/index.html b/rt/share/html/Admin/Tools/Shredder/index.html index 01e4d167f..f5c5dff1b 100644 --- a/rt/share/html/Admin/Tools/Shredder/index.html +++ b/rt/share/html/Admin/Tools/Shredder/index.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Tools/Theme.html b/rt/share/html/Admin/Tools/Theme.html index a3f910edb..ac297e9ee 100644 --- a/rt/share/html/Admin/Tools/Theme.html +++ b/rt/share/html/Admin/Tools/Theme.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -131,14 +131,24 @@ jQuery(function($) { .text(v[0])); }); - $("style#sitecss").text($('#user_css').val()); + function update_sitecss(text) { + if (!text) + text = $('#user_css').val(); + + // IE 8 doesn't let us update the innerHTML of <style> tags (with jQuery.text()) + // see: http://stackoverflow.com/questions/2692770/style-style-textcss-appendtohead-does-not-work-in-ie/2692861#2692861 + $("style#sitecss").remove(); + $("<style id='sitecss' type='text/css' media='all'>" + text + "</style>").appendTo('head'); + } + + update_sitecss(); $('#try').click(function() { - $("style#sitecss").text($('#user_css').val()); + update_sitecss(); }); $('#reset').click(function() { setTimeout(function() { - $("style#sitecss").text($('#user_css').val()); + update_sitecss(); }, 1000); }); @@ -174,7 +184,7 @@ jQuery(function($) { } } $('#user_css').val(css); - $("style#sitecss").text(css); + update_sitecss(css); } $('#color-picker').farbtastic(function(color){ change_color(color, this.hsl[2] > <% $text_threshold %> ? '#000' : '#fff') }); diff --git a/rt/share/html/Admin/Tools/index.html b/rt/share/html/Admin/Tools/index.html index c14847ebd..bee491f74 100644 --- a/rt/share/html/Admin/Tools/index.html +++ b/rt/share/html/Admin/Tools/index.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Users/CustomFields.html b/rt/share/html/Admin/Users/CustomFields.html index cca0606a8..b57cfa522 100644 --- a/rt/share/html/Admin/Users/CustomFields.html +++ b/rt/share/html/Admin/Users/CustomFields.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Users/GnuPG.html b/rt/share/html/Admin/Users/GnuPG.html index fbf1a3cca..71cf22b54 100644 --- a/rt/share/html/Admin/Users/GnuPG.html +++ b/rt/share/html/Admin/Users/GnuPG.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Users/History.html b/rt/share/html/Admin/Users/History.html index 2b91b6631..d6e4aa3e8 100644 --- a/rt/share/html/Admin/Users/History.html +++ b/rt/share/html/Admin/Users/History.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Users/Memberships.html b/rt/share/html/Admin/Users/Memberships.html index cff33fa1c..ba88905ce 100644 --- a/rt/share/html/Admin/Users/Memberships.html +++ b/rt/share/html/Admin/Users/Memberships.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Users/Modify.html b/rt/share/html/Admin/Users/Modify.html index d66955660..814e7f996 100755 --- a/rt/share/html/Admin/Users/Modify.html +++ b/rt/share/html/Admin/Users/Modify.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Users/MyRT.html b/rt/share/html/Admin/Users/MyRT.html index f9055d3ad..1836b43df 100644 --- a/rt/share/html/Admin/Users/MyRT.html +++ b/rt/share/html/Admin/Users/MyRT.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/Users/index.html b/rt/share/html/Admin/Users/index.html index de9a55d36..31e1c122d 100755 --- a/rt/share/html/Admin/Users/index.html +++ b/rt/share/html/Admin/Users/index.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -70,7 +70,7 @@ jQuery(function(){ form.find('input[name=UserOp]').val('='); form.submit(); } - }); + }).addClass("autocompletes-user"); }); </script> </form> diff --git a/rt/share/html/Admin/autohandler b/rt/share/html/Admin/autohandler index faf7237c4..73aa47dfc 100644 --- a/rt/share/html/Admin/autohandler +++ b/rt/share/html/Admin/autohandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Admin/index.html b/rt/share/html/Admin/index.html index 09d0908db..ac29709d0 100755 --- a/rt/share/html/Admin/index.html +++ b/rt/share/html/Admin/index.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Approvals/Display.html b/rt/share/html/Approvals/Display.html index 562487357..b639f41a5 100755 --- a/rt/share/html/Approvals/Display.html +++ b/rt/share/html/Approvals/Display.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Approvals/Elements/Approve b/rt/share/html/Approvals/Elements/Approve index 4df5ff1b7..e9a3762bd 100755 --- a/rt/share/html/Approvals/Elements/Approve +++ b/rt/share/html/Approvals/Elements/Approve @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Approvals/Elements/PendingMyApproval b/rt/share/html/Approvals/Elements/PendingMyApproval index 475cb428b..9b34b1f81 100755 --- a/rt/share/html/Approvals/Elements/PendingMyApproval +++ b/rt/share/html/Approvals/Elements/PendingMyApproval @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Approvals/Elements/ShowDependency b/rt/share/html/Approvals/Elements/ShowDependency index 70d22eb94..c7e31769d 100755 --- a/rt/share/html/Approvals/Elements/ShowDependency +++ b/rt/share/html/Approvals/Elements/ShowDependency @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Approvals/autohandler b/rt/share/html/Approvals/autohandler index 8a6df139a..c98152837 100644 --- a/rt/share/html/Approvals/autohandler +++ b/rt/share/html/Approvals/autohandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Approvals/index.html b/rt/share/html/Approvals/index.html index 09392c910..97f360ac0 100755 --- a/rt/share/html/Approvals/index.html +++ b/rt/share/html/Approvals/index.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -64,6 +64,13 @@ foreach my $arg ( keys %ARGS ) { my $ticket = LoadTicket($1); + my $skip_update = 0; + $m->callback( CallbackName => 'BeforeApproval', + skip_update => \$skip_update, + Ticket => $ticket, + actions => \@actions); + next if $skip_update; + if ( $ARGS{ "Approval-" . $ticket->Id . "-Notes" } ) { my $notes = MIME::Entity->build( Data => [ $ARGS{ "Approval-" . $ticket->Id . "-Notes" } ] diff --git a/rt/share/html/Articles/Article/Delete.html b/rt/share/html/Articles/Article/Delete.html index fc695c6cb..22dc30348 100644 --- a/rt/share/html/Articles/Article/Delete.html +++ b/rt/share/html/Articles/Article/Delete.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Article/Display.html b/rt/share/html/Articles/Article/Display.html index 1b455b9b3..77a1e433c 100644 --- a/rt/share/html/Articles/Article/Display.html +++ b/rt/share/html/Articles/Article/Display.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Article/Edit.html b/rt/share/html/Articles/Article/Edit.html index 2d27b03f8..dd8f94582 100644 --- a/rt/share/html/Articles/Article/Edit.html +++ b/rt/share/html/Articles/Article/Edit.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Article/Elements/EditBasics b/rt/share/html/Articles/Article/Elements/EditBasics index ab12b394a..705cb0d19 100644 --- a/rt/share/html/Articles/Article/Elements/EditBasics +++ b/rt/share/html/Articles/Article/Elements/EditBasics @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Article/Elements/EditCustomFields b/rt/share/html/Articles/Article/Elements/EditCustomFields index 1eee87c1a..792f2220e 100644 --- a/rt/share/html/Articles/Article/Elements/EditCustomFields +++ b/rt/share/html/Articles/Article/Elements/EditCustomFields @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Article/Elements/EditLinks b/rt/share/html/Articles/Article/Elements/EditLinks index 1d86eb5be..57d733362 100644 --- a/rt/share/html/Articles/Article/Elements/EditLinks +++ b/rt/share/html/Articles/Article/Elements/EditLinks @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Article/Elements/EditTopics b/rt/share/html/Articles/Article/Elements/EditTopics index e5f9fade3..531030160 100644 --- a/rt/share/html/Articles/Article/Elements/EditTopics +++ b/rt/share/html/Articles/Article/Elements/EditTopics @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Article/Elements/LinkEntryInstructions b/rt/share/html/Articles/Article/Elements/LinkEntryInstructions index 8e6cc4eb5..23512634b 100644 --- a/rt/share/html/Articles/Article/Elements/LinkEntryInstructions +++ b/rt/share/html/Articles/Article/Elements/LinkEntryInstructions @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Article/Elements/Preformatted b/rt/share/html/Articles/Article/Elements/Preformatted index d4ab9f949..0b4ddaaaa 100644 --- a/rt/share/html/Articles/Article/Elements/Preformatted +++ b/rt/share/html/Articles/Article/Elements/Preformatted @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Article/Elements/SearchByCustomField b/rt/share/html/Articles/Article/Elements/SearchByCustomField index b86698660..188995d63 100644 --- a/rt/share/html/Articles/Article/Elements/SearchByCustomField +++ b/rt/share/html/Articles/Article/Elements/SearchByCustomField @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Article/Elements/SelectSavedSearches b/rt/share/html/Articles/Article/Elements/SelectSavedSearches index 8bf070adb..57ab8d19a 100644 --- a/rt/share/html/Articles/Article/Elements/SelectSavedSearches +++ b/rt/share/html/Articles/Article/Elements/SelectSavedSearches @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Article/Elements/SelectSearchPrivacy b/rt/share/html/Articles/Article/Elements/SelectSearchPrivacy index 01bd592ec..8fa382270 100644 --- a/rt/share/html/Articles/Article/Elements/SelectSearchPrivacy +++ b/rt/share/html/Articles/Article/Elements/SelectSearchPrivacy @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Article/Elements/ShowHistory b/rt/share/html/Articles/Article/Elements/ShowHistory index a419f2a72..d48bc0b5c 100644 --- a/rt/share/html/Articles/Article/Elements/ShowHistory +++ b/rt/share/html/Articles/Article/Elements/ShowHistory @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Article/Elements/ShowLinks b/rt/share/html/Articles/Article/Elements/ShowLinks index f90289022..8dddfc7fd 100644 --- a/rt/share/html/Articles/Article/Elements/ShowLinks +++ b/rt/share/html/Articles/Article/Elements/ShowLinks @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Article/Elements/ShowSavedSearches b/rt/share/html/Articles/Article/Elements/ShowSavedSearches index b9485e27d..8da873e61 100644 --- a/rt/share/html/Articles/Article/Elements/ShowSavedSearches +++ b/rt/share/html/Articles/Article/Elements/ShowSavedSearches @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Article/Elements/ShowSearchCriteria b/rt/share/html/Articles/Article/Elements/ShowSearchCriteria index 6430691c6..cf2884592 100644 --- a/rt/share/html/Articles/Article/Elements/ShowSearchCriteria +++ b/rt/share/html/Articles/Article/Elements/ShowSearchCriteria @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Article/Elements/ShowTopics b/rt/share/html/Articles/Article/Elements/ShowTopics index 2c805a7c0..cf62afa80 100644 --- a/rt/share/html/Articles/Article/Elements/ShowTopics +++ b/rt/share/html/Articles/Article/Elements/ShowTopics @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Article/ExtractFromTicket.html b/rt/share/html/Articles/Article/ExtractFromTicket.html index a7b15d6fc..9d4939034 100644 --- a/rt/share/html/Articles/Article/ExtractFromTicket.html +++ b/rt/share/html/Articles/Article/ExtractFromTicket.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Article/ExtractIntoClass.html b/rt/share/html/Articles/Article/ExtractIntoClass.html index b64a5a9fb..e2ddfcde4 100644 --- a/rt/share/html/Articles/Article/ExtractIntoClass.html +++ b/rt/share/html/Articles/Article/ExtractIntoClass.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -55,7 +55,7 @@ % $Classes->LimitToEnabled(); % while (my $Class = $Classes->Next) { <li><a href="ExtractIntoTopic.html?Ticket=<%$Ticket%>&Class=<%$Class->Id%>" onclick="document.getElementById('topics-'+<% $Class->Id |n,j%>).style.display = (document.getElementById('topics-'+<% $Class->Id |n,j%>).style.display == 'block') ? 'none' : 'block'; return false;"><%$Class->Name%></a>: -<%$Class->Description%> +<%$Class->Description || ''%> <div id="topics-<%$Class->Id%>" style="display: none"> <form action="ExtractFromTicket.html"> <input type="hidden" name="Ticket" value="<% $Ticket %>" /> diff --git a/rt/share/html/Articles/Article/ExtractIntoTopic.html b/rt/share/html/Articles/Article/ExtractIntoTopic.html index 51c1fa12e..a90def932 100644 --- a/rt/share/html/Articles/Article/ExtractIntoTopic.html +++ b/rt/share/html/Articles/Article/ExtractIntoTopic.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Article/History.html b/rt/share/html/Articles/Article/History.html index 449fd4d28..8fc9d2854 100644 --- a/rt/share/html/Articles/Article/History.html +++ b/rt/share/html/Articles/Article/History.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Article/PreCreate.html b/rt/share/html/Articles/Article/PreCreate.html index d1060e68a..2b11ac089 100644 --- a/rt/share/html/Articles/Article/PreCreate.html +++ b/rt/share/html/Articles/Article/PreCreate.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -46,7 +46,7 @@ %# %# END BPS TAGGED BLOCK }}} <& /Elements/Header, Title => loc('Create an article in class...') &> -<& /Elements/Tabs, Title => loc('Create an article in class...') &> +<& /Elements/Tabs &> <ul> % my $Classes = RT::Classes->new($session{'CurrentUser'}); % $Classes->LimitToEnabled(); diff --git a/rt/share/html/Articles/Article/Search.html b/rt/share/html/Articles/Article/Search.html index a8c7d8034..14c4538b7 100644 --- a/rt/share/html/Articles/Article/Search.html +++ b/rt/share/html/Articles/Article/Search.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Elements/BeforeMessageBox b/rt/share/html/Articles/Elements/BeforeMessageBox index 751f9d60e..4339ca1f3 100644 --- a/rt/share/html/Articles/Elements/BeforeMessageBox +++ b/rt/share/html/Articles/Elements/BeforeMessageBox @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Elements/CheckSkipCreate b/rt/share/html/Articles/Elements/CheckSkipCreate index 32b7dfab5..3663a5e08 100644 --- a/rt/share/html/Articles/Elements/CheckSkipCreate +++ b/rt/share/html/Articles/Elements/CheckSkipCreate @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Elements/CreateArticle b/rt/share/html/Articles/Elements/CreateArticle index fd9a546a2..95258318d 100644 --- a/rt/share/html/Articles/Elements/CreateArticle +++ b/rt/share/html/Articles/Elements/CreateArticle @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Elements/GotoArticle b/rt/share/html/Articles/Elements/GotoArticle index d15d48943..4e6f2fa70 100644 --- a/rt/share/html/Articles/Elements/GotoArticle +++ b/rt/share/html/Articles/Elements/GotoArticle @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Elements/IncludeArticle b/rt/share/html/Articles/Elements/IncludeArticle index 25b68e724..11abdb0dc 100644 --- a/rt/share/html/Articles/Elements/IncludeArticle +++ b/rt/share/html/Articles/Elements/IncludeArticle @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Elements/NewestArticles b/rt/share/html/Articles/Elements/NewestArticles index a379063b8..5b44a9928 100644 --- a/rt/share/html/Articles/Elements/NewestArticles +++ b/rt/share/html/Articles/Elements/NewestArticles @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Elements/QuickSearch b/rt/share/html/Articles/Elements/QuickSearch index f531f67c2..31c77472b 100644 --- a/rt/share/html/Articles/Elements/QuickSearch +++ b/rt/share/html/Articles/Elements/QuickSearch @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Elements/SelectClass b/rt/share/html/Articles/Elements/SelectClass index 3bc970059..4d084b2a7 100644 --- a/rt/share/html/Articles/Elements/SelectClass +++ b/rt/share/html/Articles/Elements/SelectClass @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Elements/ShowTopic b/rt/share/html/Articles/Elements/ShowTopic index 2ed578cd7..6d786efff 100644 --- a/rt/share/html/Articles/Elements/ShowTopic +++ b/rt/share/html/Articles/Elements/ShowTopic @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Elements/ShowTopicLink b/rt/share/html/Articles/Elements/ShowTopicLink index decaa902e..1487bd297 100644 --- a/rt/share/html/Articles/Elements/ShowTopicLink +++ b/rt/share/html/Articles/Elements/ShowTopicLink @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Elements/UpdatedArticles b/rt/share/html/Articles/Elements/UpdatedArticles index 777bc48c7..647086ef9 100644 --- a/rt/share/html/Articles/Elements/UpdatedArticles +++ b/rt/share/html/Articles/Elements/UpdatedArticles @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/Topics.html b/rt/share/html/Articles/Topics.html index da731abff..e6cdc85de 100644 --- a/rt/share/html/Articles/Topics.html +++ b/rt/share/html/Articles/Topics.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Articles/index.html b/rt/share/html/Articles/index.html index 958c286e6..f50d2e0fa 100644 --- a/rt/share/html/Articles/index.html +++ b/rt/share/html/Articles/index.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Dashboards/Elements/DashboardsForObject b/rt/share/html/Dashboards/Elements/DashboardsForObject index 966a03f18..3e1131072 100644 --- a/rt/share/html/Dashboards/Elements/DashboardsForObject +++ b/rt/share/html/Dashboards/Elements/DashboardsForObject @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Dashboards/Elements/Deleted b/rt/share/html/Dashboards/Elements/Deleted index 09480b9a1..d253f85be 100644 --- a/rt/share/html/Dashboards/Elements/Deleted +++ b/rt/share/html/Dashboards/Elements/Deleted @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Dashboards/Elements/HiddenSearches b/rt/share/html/Dashboards/Elements/HiddenSearches index d5c041634..6c21f0893 100644 --- a/rt/share/html/Dashboards/Elements/HiddenSearches +++ b/rt/share/html/Dashboards/Elements/HiddenSearches @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Dashboards/Elements/ListOfDashboards b/rt/share/html/Dashboards/Elements/ListOfDashboards index eba8d502a..ac222842d 100644 --- a/rt/share/html/Dashboards/Elements/ListOfDashboards +++ b/rt/share/html/Dashboards/Elements/ListOfDashboards @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Dashboards/Elements/SelectPrivacy b/rt/share/html/Dashboards/Elements/SelectPrivacy index 1c59937d0..b95a06082 100644 --- a/rt/share/html/Dashboards/Elements/SelectPrivacy +++ b/rt/share/html/Dashboards/Elements/SelectPrivacy @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Dashboards/Elements/ShowDashboards b/rt/share/html/Dashboards/Elements/ShowDashboards index a1d41bb24..e04e149bb 100644 --- a/rt/share/html/Dashboards/Elements/ShowDashboards +++ b/rt/share/html/Dashboards/Elements/ShowDashboards @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Dashboards/Elements/ShowPortlet/component b/rt/share/html/Dashboards/Elements/ShowPortlet/component index 6d3112910..81614a24b 100644 --- a/rt/share/html/Dashboards/Elements/ShowPortlet/component +++ b/rt/share/html/Dashboards/Elements/ShowPortlet/component @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Dashboards/Elements/ShowPortlet/dashboard b/rt/share/html/Dashboards/Elements/ShowPortlet/dashboard index f0af23a9f..c9de6dfbd 100644 --- a/rt/share/html/Dashboards/Elements/ShowPortlet/dashboard +++ b/rt/share/html/Dashboards/Elements/ShowPortlet/dashboard @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Dashboards/Elements/ShowPortlet/search b/rt/share/html/Dashboards/Elements/ShowPortlet/search index 8fc42eefb..416476c86 100644 --- a/rt/share/html/Dashboards/Elements/ShowPortlet/search +++ b/rt/share/html/Dashboards/Elements/ShowPortlet/search @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Dashboards/Modify.html b/rt/share/html/Dashboards/Modify.html index e680cd10c..001dd4a35 100755 --- a/rt/share/html/Dashboards/Modify.html +++ b/rt/share/html/Dashboards/Modify.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Dashboards/Queries.html b/rt/share/html/Dashboards/Queries.html index 2b0a73e15..61f6195e5 100644 --- a/rt/share/html/Dashboards/Queries.html +++ b/rt/share/html/Dashboards/Queries.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Dashboards/Render.html b/rt/share/html/Dashboards/Render.html index a99bf7485..dfb836917 100644 --- a/rt/share/html/Dashboards/Render.html +++ b/rt/share/html/Dashboards/Render.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -84,11 +84,13 @@ % my $edit = RT->Config->Get('WebPath') . '/Dashboards/Modify.html?id='.$id; % my $subscription = RT->Config->Get('WebPath') . '/Dashboards/Subscription.html?id='.$id; <p><&|/l, $edit, $subscription &>You <a href="[_1]">may edit this dashboard</a> and <a href="[_2]">your subscription</a> to it in RT.</&></p> -% } -%# Matches the closing div in /Elements/Footer that it expects -%# from PageLayout (which we don't use here) -<div> +%# We disable autohandlers when mailing (!$Preview) so /Elements/Footer isn't +%# run for us. Tidy up the end of the HTML. We don't use /Elements/Tabs (and +%# hence PageLayout) so we don't need to close any other tags. + </body> +</html> +% } <%INIT> diff --git a/rt/share/html/Dashboards/Subscription.html b/rt/share/html/Dashboards/Subscription.html index 02800d82f..df612d2f8 100644 --- a/rt/share/html/Dashboards/Subscription.html +++ b/rt/share/html/Dashboards/Subscription.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Dashboards/dhandler b/rt/share/html/Dashboards/dhandler index 97a1ad16d..744d2018b 100644 --- a/rt/share/html/Dashboards/dhandler +++ b/rt/share/html/Dashboards/dhandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Dashboards/index.html b/rt/share/html/Dashboards/index.html index 6930277c7..b9aea36e3 100644 --- a/rt/share/html/Dashboards/index.html +++ b/rt/share/html/Dashboards/index.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Download/CustomFieldValue/dhandler b/rt/share/html/Download/CustomFieldValue/dhandler index a9190491f..f41ed5008 100644 --- a/rt/share/html/Download/CustomFieldValue/dhandler +++ b/rt/share/html/Download/CustomFieldValue/dhandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/BevelBoxRaisedEnd b/rt/share/html/Elements/BevelBoxRaisedEnd index eb97f32fb..01b72b75a 100755 --- a/rt/share/html/Elements/BevelBoxRaisedEnd +++ b/rt/share/html/Elements/BevelBoxRaisedEnd @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/BevelBoxRaisedStart b/rt/share/html/Elements/BevelBoxRaisedStart index e87c84af5..37b787a05 100755 --- a/rt/share/html/Elements/BevelBoxRaisedStart +++ b/rt/share/html/Elements/BevelBoxRaisedStart @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/CSRF b/rt/share/html/Elements/CSRF index b62b321d9..d8c00145c 100644 --- a/rt/share/html/Elements/CSRF +++ b/rt/share/html/Elements/CSRF @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/Callback b/rt/share/html/Elements/Callback index f9508abea..9e0e90524 100755 --- a/rt/share/html/Elements/Callback +++ b/rt/share/html/Elements/Callback @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/Checkbox b/rt/share/html/Elements/Checkbox index dd82a245b..19ca36345 100755 --- a/rt/share/html/Elements/Checkbox +++ b/rt/share/html/Elements/Checkbox @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/CollectionAsTable/Header b/rt/share/html/Elements/CollectionAsTable/Header index ffb7441f0..c9116ade6 100644 --- a/rt/share/html/Elements/CollectionAsTable/Header +++ b/rt/share/html/Elements/CollectionAsTable/Header @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/CollectionAsTable/ParseFormat b/rt/share/html/Elements/CollectionAsTable/ParseFormat index e00370487..e56e9ce0f 100644 --- a/rt/share/html/Elements/CollectionAsTable/ParseFormat +++ b/rt/share/html/Elements/CollectionAsTable/ParseFormat @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -59,6 +59,7 @@ while ($Format =~ /($RE{delimited}{-delim=>qq{\'"}}|[{}\w.]+)/go) { if ($col =~ /^$RE{quoted}$/o) { substr($col,0,1) = ""; substr($col,-1,1) = ""; + $col =~ s/\\(.)/$1/g; } my $colref = { }; diff --git a/rt/share/html/Elements/CollectionAsTable/Row b/rt/share/html/Elements/CollectionAsTable/Row index bbcfd2227..efe046d81 100644 --- a/rt/share/html/Elements/CollectionAsTable/Row +++ b/rt/share/html/Elements/CollectionAsTable/Row @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/CollectionList b/rt/share/html/Elements/CollectionList index b47c7aabd..44f762410 100644 --- a/rt/share/html/Elements/CollectionList +++ b/rt/share/html/Elements/CollectionList @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -68,9 +68,10 @@ if ( $Rows ) { # collection is ordered or not if ( @OrderBy && ($AllowSorting || !$Collection->{'order_by'}) ) { if ( $OrderBy[0] =~ /\|/ ) { - @OrderBy = grep length($_), split /\|/, $OrderBy[0]; + @OrderBy = split /\|/, $OrderBy[0]; @Order = split /\|/,$Order[0]; } + @OrderBy = grep length, @OrderBy; $Collection->OrderByCols( map { { FIELD => $OrderBy[$_], ORDER => $Order[$_] } } ( 0 .. $#OrderBy ) diff --git a/rt/share/html/Elements/CollectionListPaging b/rt/share/html/Elements/CollectionListPaging index 8e6aebde7..4a0b45b58 100644 --- a/rt/share/html/Elements/CollectionListPaging +++ b/rt/share/html/Elements/CollectionListPaging @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/ColumnMap b/rt/share/html/Elements/ColumnMap index 12a61453c..30d4b3a0a 100644 --- a/rt/share/html/Elements/ColumnMap +++ b/rt/share/html/Elements/ColumnMap @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -111,9 +111,9 @@ my $COLUMN_MAP = { # Display custom field contents, separated by newlines. # For Image custom fields we also show a thumbnail here. - my $values = $cf->ValuesForObject( $_[0] ); return if $values->Count == 0; + my @values; # it is guaranteed to be the same type for all fields, right? my $v = $values->First; @@ -160,7 +160,7 @@ my $COLUMN_MAP = { my $arg = $DECODED_ARGS->{ $name }; my $checked = ''; if ( $arg && ref $arg ) { - $checked = 'checked="checked"' if grep $_ == $id, @$arg; + $checked = 'checked="checked"' if grep $_ == $id, grep { defined and length } @$arg; } elsif ( $arg ) { $checked = 'checked="checked"' if $arg == $id; diff --git a/rt/share/html/Elements/CreateTicket b/rt/share/html/Elements/CreateTicket index ed15cd76b..9e7427c2e 100755 --- a/rt/share/html/Elements/CreateTicket +++ b/rt/share/html/Elements/CreateTicket @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/Dashboards b/rt/share/html/Elements/Dashboards index e271bf1c8..26796f52f 100644 --- a/rt/share/html/Elements/Dashboards +++ b/rt/share/html/Elements/Dashboards @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/EditCustomField b/rt/share/html/Elements/EditCustomField index e8de7afb1..9b7f29a40 100644 --- a/rt/share/html/Elements/EditCustomField +++ b/rt/share/html/Elements/EditCustomField @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/EditCustomFieldAutocomplete b/rt/share/html/Elements/EditCustomFieldAutocomplete index 32a3b9fa0..7bfe91114 100644 --- a/rt/share/html/Elements/EditCustomFieldAutocomplete +++ b/rt/share/html/Elements/EditCustomFieldAutocomplete @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/EditCustomFieldBinary b/rt/share/html/Elements/EditCustomFieldBinary index c74bfd0bc..591082790 100644 --- a/rt/share/html/Elements/EditCustomFieldBinary +++ b/rt/share/html/Elements/EditCustomFieldBinary @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -47,7 +47,7 @@ %# END BPS TAGGED BLOCK }}} % while ( $Values and my $value = $Values->Next ) { %# XXX - let user download the file(s) here? -<input type="checkbox" class="checkbox" name="<%$NamePrefix%><%$CustomField->Id%>-DeleteValueIds" class="CF-<%$CustomField->id%>-Edit" value="<% $value->Id %>" /><a href="<%RT->Config->Get('WebPath')%>/Download/CustomFieldValue/<% $value->Id %>/<% $value->Content |un %>"><% $value->Content %></a><br /> +<input type="checkbox" name="<%$NamePrefix%><%$CustomField->Id%>-DeleteValueIds" class="checkbox CF-<%$CustomField->id%>-Edit" value="<% $value->Id %>" /><a href="<%RT->Config->Get('WebPath')%>/Download/CustomFieldValue/<% $value->Id %>/<% $value->Content |un %>"><% $value->Content %></a><br /> % } % if (!$MaxValues || !$Values || $Values->Count < $MaxValues) { <input type="file" name="<% $NamePrefix %><% $CustomField->Id %>-Upload" class="CF-<%$CustomField->id%>-Edit" /> diff --git a/rt/share/html/Elements/EditCustomFieldCombobox b/rt/share/html/Elements/EditCustomFieldCombobox index f382a4084..a23ed008b 100644 --- a/rt/share/html/Elements/EditCustomFieldCombobox +++ b/rt/share/html/Elements/EditCustomFieldCombobox @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/EditCustomFieldDate b/rt/share/html/Elements/EditCustomFieldDate index 9e190be5d..f62f04704 100644 --- a/rt/share/html/Elements/EditCustomFieldDate +++ b/rt/share/html/Elements/EditCustomFieldDate @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/EditCustomFieldDateTime b/rt/share/html/Elements/EditCustomFieldDateTime index 3d94855f7..25d1ce160 100644 --- a/rt/share/html/Elements/EditCustomFieldDateTime +++ b/rt/share/html/Elements/EditCustomFieldDateTime @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/EditCustomFieldFreeform b/rt/share/html/Elements/EditCustomFieldFreeform index b6810b6ec..67248738b 100644 --- a/rt/share/html/Elements/EditCustomFieldFreeform +++ b/rt/share/html/Elements/EditCustomFieldFreeform @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/EditCustomFieldIPAddress b/rt/share/html/Elements/EditCustomFieldIPAddress index 9fcc264ef..ba8378a7c 100644 --- a/rt/share/html/Elements/EditCustomFieldIPAddress +++ b/rt/share/html/Elements/EditCustomFieldIPAddress @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/EditCustomFieldIPAddressRange b/rt/share/html/Elements/EditCustomFieldIPAddressRange index 9fcc264ef..ba8378a7c 100644 --- a/rt/share/html/Elements/EditCustomFieldIPAddressRange +++ b/rt/share/html/Elements/EditCustomFieldIPAddressRange @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/EditCustomFieldImage b/rt/share/html/Elements/EditCustomFieldImage index 9316fbc71..3f64d38c1 100644 --- a/rt/share/html/Elements/EditCustomFieldImage +++ b/rt/share/html/Elements/EditCustomFieldImage @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/EditCustomFieldSelect b/rt/share/html/Elements/EditCustomFieldSelect index 8668bc427..87400ab2e 100644 --- a/rt/share/html/Elements/EditCustomFieldSelect +++ b/rt/share/html/Elements/EditCustomFieldSelect @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -66,50 +66,74 @@ <script type="text/javascript" src="<%RT->Config->Get('WebPath')%>/NoAuth/js/cascaded.js"></script> <script type="text/javascript"><!-- jQuery( function () { - var basedon = document.getElementById(<% $NamePrefix . $CustomField->BasedOnObj->id . "-Values" |n,j%>); - if (basedon != null) { - var oldchange = basedon.onchange; - basedon.onchange = function () { + var basedon = jQuery('[name^=<% $NamePrefix . $CustomField->BasedOnObj->id %>-Value][type!=hidden]:input:not(.hidden)'); + basedon.each( function() { + var oldchange = jQuery(this).onchange; + jQuery(this).change( function () { + var vals; + if ( jQuery(this).is('select') ) { + vals = basedon.first().val(); + } + else { + vals = []; + jQuery(basedon).each( function() { + if ( jQuery(this).is(':checked') ) { + vals.push(jQuery(this).val()); + } + }); + } filter_cascade( <% "$id-Values" |n,j%>, - basedon.value, + vals, 1 ); if (oldchange != null) oldchange(); - }; - basedon.onchange(); + }); + }); + + if ( basedon.is('select') ) { + basedon.change(); + } + else { + basedon.first().change(); } }); --></script> % } -% if (@category) { -%# this hidden select is to supply a full list of values, -%# see filter_cascade() in js/cascaded.js - <select name="<%$id%>-Values-Complete" id="<%$id%>-Values-Complete" class="hidden" disabled="disabled"> - <option value=""<% !$selected && qq[ selected="selected"] |n %>><&|/l&>(no value)</&></option> -% $m->out($out); - </select> -% } % if ( $RenderType eq 'List' ) { <fieldset class="cfedit"> +<div name="<%$id%>-Values" id="<%$id%>-Values"> % if ( $checktype eq 'radio' ) { - <input type="<% $checktype %>" name="<% $name %>" id="<% $name %>-none" value="" <% keys %default ? '' : ' checked="checked"' |n%> /> + <div class="none"> + <input class="none" type="<% $checktype %>" name="<% $name %>" id="<% $name %>-none" value="" <% keys %default ? '' : ' checked="checked"' |n%> /> <label for="<% $name %>-none"><&|/l&>(no value)</&></label><br /> + </div> % } % my $CFVs = $CustomField->Values; % while ( my $value = $CFVs->Next ) { % my $content = $value->Name; % my $labelid = "$name-". $value->id; +<div name="<% $value->Category %>"> <input type="<% $checktype %>" name="<% $name %>" id="<% $labelid %>" value="<% $content %>" <% $default{ lc $content }? ' checked="checked"' : '' |n%> /> <label for="<% $labelid %>"><% $content %></label><br /> +</div> % } +</div> </fieldset> % } else { +% if (@category) { +%# this hidden select is to supply a full list of values, +%# see filter_cascade() in js/cascaded.js + <select name="<%$id%>-Values-Complete" id="<%$id%>-Values-Complete" class="hidden" disabled="disabled"> + <option value=""<% !$selected && qq[ selected="selected"] |n %>><&|/l&>(no value)</&></option> +% $m->out($out); + </select> +% } <select name="<%$id%>-Values" id="<%$id%>-Values" class="CF-<%$CustomField->id%>-Edit" -% if ( $Rows && ( $Multiple || !@category ) ) { +% if ( $Rows && ( $Multiple || !@category || $RenderType eq 'Select box') ) { size="<% $Rows %>" % } <% $Multiple && qq[multiple="multiple"] |n %> > diff --git a/rt/share/html/Elements/EditCustomFieldText b/rt/share/html/Elements/EditCustomFieldText index c169740d5..866460472 100644 --- a/rt/share/html/Elements/EditCustomFieldText +++ b/rt/share/html/Elements/EditCustomFieldText @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/EditCustomFieldWikitext b/rt/share/html/Elements/EditCustomFieldWikitext index ac2de26a7..1a36ae333 100644 --- a/rt/share/html/Elements/EditCustomFieldWikitext +++ b/rt/share/html/Elements/EditCustomFieldWikitext @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/EditLinks b/rt/share/html/Elements/EditLinks index 6a3f4b6b5..28cc940c6 100755 --- a/rt/share/html/Elements/EditLinks +++ b/rt/share/html/Elements/EditLinks @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/EditPassword b/rt/share/html/Elements/EditPassword index d7f48bf40..aaf1780a0 100644 --- a/rt/share/html/Elements/EditPassword +++ b/rt/share/html/Elements/EditPassword @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/EditTimeValue b/rt/share/html/Elements/EditTimeValue index fc8781322..f1126ec17 100644 --- a/rt/share/html/Elements/EditTimeValue +++ b/rt/share/html/Elements/EditTimeValue @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/EmailInput b/rt/share/html/Elements/EmailInput index 2830a721d..1f561e983 100644 --- a/rt/share/html/Elements/EmailInput +++ b/rt/share/html/Elements/EmailInput @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/Error b/rt/share/html/Elements/Error index 838432069..b2042610e 100755 --- a/rt/share/html/Elements/Error +++ b/rt/share/html/Elements/Error @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/Footer b/rt/share/html/Elements/Footer index 15e96c9b2..940e71ccf 100755 --- a/rt/share/html/Elements/Footer +++ b/rt/share/html/Elements/Footer @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/Framekiller b/rt/share/html/Elements/Framekiller index 8d04b7f30..9b9f9efb5 100644 --- a/rt/share/html/Elements/Framekiller +++ b/rt/share/html/Elements/Framekiller @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/GnuPG/KeyIssues b/rt/share/html/Elements/GnuPG/KeyIssues index f19e02684..07d6455be 100644 --- a/rt/share/html/Elements/GnuPG/KeyIssues +++ b/rt/share/html/Elements/GnuPG/KeyIssues @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/GnuPG/SelectKeyForEncryption b/rt/share/html/Elements/GnuPG/SelectKeyForEncryption index 6d287176c..d6126317d 100644 --- a/rt/share/html/Elements/GnuPG/SelectKeyForEncryption +++ b/rt/share/html/Elements/GnuPG/SelectKeyForEncryption @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/GnuPG/SelectKeyForSigning b/rt/share/html/Elements/GnuPG/SelectKeyForSigning index a930a3ecd..d684896d6 100644 --- a/rt/share/html/Elements/GnuPG/SelectKeyForSigning +++ b/rt/share/html/Elements/GnuPG/SelectKeyForSigning @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/GnuPG/SignEncryptWidget b/rt/share/html/Elements/GnuPG/SignEncryptWidget index 7e0aa2d1b..cec3f3a84 100644 --- a/rt/share/html/Elements/GnuPG/SignEncryptWidget +++ b/rt/share/html/Elements/GnuPG/SignEncryptWidget @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/GotoTicket b/rt/share/html/Elements/GotoTicket index a602d8843..ec6e5c6d2 100755 --- a/rt/share/html/Elements/GotoTicket +++ b/rt/share/html/Elements/GotoTicket @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/Header b/rt/share/html/Elements/Header index d97e626a1..5e08fe384 100755 --- a/rt/share/html/Elements/Header +++ b/rt/share/html/Elements/Header @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/HeaderJavascript b/rt/share/html/Elements/HeaderJavascript index bfb4a8cbb..3e5e9eca3 100644 --- a/rt/share/html/Elements/HeaderJavascript +++ b/rt/share/html/Elements/HeaderJavascript @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -67,7 +67,7 @@ $onload => undef % } % if ( $RichText and RT->Config->Get('MessageBoxRichText', $session{'CurrentUser'})) { - jQuery().ready(function () { ReplaceAllTextareas(<%$DECODED_ARGS->{'CKeditorEncoded'} || 0 |n,j%>) }); + jQuery().ready(function () { ReplaceAllTextareas() }); % } --></script> <%ARGS> diff --git a/rt/share/html/Elements/ListActions b/rt/share/html/Elements/ListActions index 805bd2ef2..37f7ce57a 100755 --- a/rt/share/html/Elements/ListActions +++ b/rt/share/html/Elements/ListActions @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/ListMenu b/rt/share/html/Elements/ListMenu index 34ef1c705..4e5602989 100644 --- a/rt/share/html/Elements/ListMenu +++ b/rt/share/html/Elements/ListMenu @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/Login b/rt/share/html/Elements/Login index c1b358880..5564df26f 100755 --- a/rt/share/html/Elements/Login +++ b/rt/share/html/Elements/Login @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/LoginRedirectWarning b/rt/share/html/Elements/LoginRedirectWarning index d6156894c..9233d3e00 100644 --- a/rt/share/html/Elements/LoginRedirectWarning +++ b/rt/share/html/Elements/LoginRedirectWarning @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/Logo b/rt/share/html/Elements/Logo index a00f6bdfa..ff2dae6e7 100644 --- a/rt/share/html/Elements/Logo +++ b/rt/share/html/Elements/Logo @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/MakeClicky b/rt/share/html/Elements/MakeClicky index dabe3bb33..e22e75fbb 100644 --- a/rt/share/html/Elements/MakeClicky +++ b/rt/share/html/Elements/MakeClicky @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -76,12 +76,12 @@ my %actions = ( my @types = ( { name => "httpurl", - regex => qr/$RE{URI}{HTTP}{-keep}{-scheme => 'https?'}(?:#\S+)?/, + regex => qr/$RE{URI}{HTTP}{-keep}{-scheme => 'https?'}(?:#[^\s<]+)?(?<![.?!,;:])/, action => "url", }, { name => "httpurl_overwrite", - regex => qr/$RE{URI}{HTTP}{-keep}{-scheme => 'https?'}(?:#\S+)?/, + regex => qr/$RE{URI}{HTTP}{-keep}{-scheme => 'https?'}(?:#[^\s<]+)?(?<![.?!,;:])/, action => "url_overwrite", }, ); diff --git a/rt/share/html/Elements/Menu b/rt/share/html/Elements/Menu index b2a2fb638..c1b12076d 100755 --- a/rt/share/html/Elements/Menu +++ b/rt/share/html/Elements/Menu @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/MessageBox b/rt/share/html/Elements/MessageBox index 6f55b2704..09fedad7e 100755 --- a/rt/share/html/Elements/MessageBox +++ b/rt/share/html/Elements/MessageBox @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -50,6 +50,9 @@ % $m->callback( %ARGS, SignatureRef => \$signature ); <% $Default || '' %><% $message %><% $signature %></textarea> % $m->callback( %ARGS, CallbackName => 'AfterTextArea' ); +% if (RT->Config->Get('MessageBoxRichText', $session{'CurrentUser'})) { +<input type="text" style="display:none" name="<% $Name %>Type" id="<% $Name %>Type" value="<% $m->request_args->{$Name."Type"}||'' %>" /> +% } <%INIT> my $message = ''; diff --git a/rt/share/html/Elements/MyAdminQueues b/rt/share/html/Elements/MyAdminQueues index 880ef3c8c..168d01c5e 100644 --- a/rt/share/html/Elements/MyAdminQueues +++ b/rt/share/html/Elements/MyAdminQueues @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/MyRT b/rt/share/html/Elements/MyRT index 9abfe955c..c59ec1c32 100644 --- a/rt/share/html/Elements/MyRT +++ b/rt/share/html/Elements/MyRT @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/MyReminders b/rt/share/html/Elements/MyReminders index 62eae563b..c9f789cb9 100755 --- a/rt/share/html/Elements/MyReminders +++ b/rt/share/html/Elements/MyReminders @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/MyRequests b/rt/share/html/Elements/MyRequests index 4c0445437..19608a366 100755 --- a/rt/share/html/Elements/MyRequests +++ b/rt/share/html/Elements/MyRequests @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/MySupportQueues b/rt/share/html/Elements/MySupportQueues index 6537ea12e..97e609178 100644 --- a/rt/share/html/Elements/MySupportQueues +++ b/rt/share/html/Elements/MySupportQueues @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/MyTickets b/rt/share/html/Elements/MyTickets index e27450be5..6d56e6646 100755 --- a/rt/share/html/Elements/MyTickets +++ b/rt/share/html/Elements/MyTickets @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/PageLayout b/rt/share/html/Elements/PageLayout index c8ca0905e..e04142621 100755 --- a/rt/share/html/Elements/PageLayout +++ b/rt/share/html/Elements/PageLayout @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/PersonalQuickbar b/rt/share/html/Elements/PersonalQuickbar index feab1fe1a..2a8c86e41 100644 --- a/rt/share/html/Elements/PersonalQuickbar +++ b/rt/share/html/Elements/PersonalQuickbar @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/QueriesAsComment b/rt/share/html/Elements/QueriesAsComment index f8f67044b..33e2211e2 100644 --- a/rt/share/html/Elements/QueriesAsComment +++ b/rt/share/html/Elements/QueriesAsComment @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/QueryString b/rt/share/html/Elements/QueryString index bb5cf9102..5672f19a0 100644 --- a/rt/share/html/Elements/QueryString +++ b/rt/share/html/Elements/QueryString @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/QueueSummaryByLifecycle b/rt/share/html/Elements/QueueSummaryByLifecycle index 44d6b5a8f..57373085b 100644 --- a/rt/share/html/Elements/QueueSummaryByLifecycle +++ b/rt/share/html/Elements/QueueSummaryByLifecycle @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -75,7 +75,7 @@ for my $queue (@queues) { % for my $status (@cur_statuses) { <td align="right"> - <a href="<% $link_status->($queue, $status) %>"><% $data->{$queue->{id}}->{$status } || '-' %></a> + <a href="<% $link_status->($queue, $status) %>"><% $data->{$queue->{id}}->{lc $status} || '-' %></a> </td> % } </tr> diff --git a/rt/share/html/Elements/QueueSummaryByStatus b/rt/share/html/Elements/QueueSummaryByStatus index 2a8dc5396..40b2131c2 100644 --- a/rt/share/html/Elements/QueueSummaryByStatus +++ b/rt/share/html/Elements/QueueSummaryByStatus @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -72,7 +72,7 @@ for my $queue (@queues) { if ( $lifecycle->IsValid( $status ) ) { </%perl> <td align="right"> - <a href="<% $link_status->($queue, $status) %>"><% $data->{$queue->{id}}->{$status } || '-' %></a> + <a href="<% $link_status->($queue, $status) %>"><% $data->{$queue->{id}}->{lc $status} || '-' %></a> </td> % } else { <td align="right">-</td> diff --git a/rt/share/html/Elements/QuickCreate b/rt/share/html/Elements/QuickCreate index 4925168c1..425694cd7 100644 --- a/rt/share/html/Elements/QuickCreate +++ b/rt/share/html/Elements/QuickCreate @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/Quicksearch b/rt/share/html/Elements/Quicksearch index 77814edbc..1639733d2 100755 --- a/rt/share/html/Elements/Quicksearch +++ b/rt/share/html/Elements/Quicksearch @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/RT__Article/ColumnMap b/rt/share/html/Elements/RT__Article/ColumnMap index e900e1975..497c8afe6 100644 --- a/rt/share/html/Elements/RT__Article/ColumnMap +++ b/rt/share/html/Elements/RT__Article/ColumnMap @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/RT__Class/ColumnMap b/rt/share/html/Elements/RT__Class/ColumnMap index 114e333a5..4920e90d0 100644 --- a/rt/share/html/Elements/RT__Class/ColumnMap +++ b/rt/share/html/Elements/RT__Class/ColumnMap @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/RT__CustomField/ColumnMap b/rt/share/html/Elements/RT__CustomField/ColumnMap index 9df091d01..fea3f5527 100644 --- a/rt/share/html/Elements/RT__CustomField/ColumnMap +++ b/rt/share/html/Elements/RT__CustomField/ColumnMap @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -104,7 +104,7 @@ my $COLUMN_MAP = { $res .= ', ' if $res; my $id = ''; - $id = $record->Name if $record->can('Name'); + $id = $record->Name if $record->_Accessible('Name','read'); $id ||= "#". $record->id; $res .= $id; diff --git a/rt/share/html/Elements/RT__Dashboard/ColumnMap b/rt/share/html/Elements/RT__Dashboard/ColumnMap index 2d971635a..73df7f496 100644 --- a/rt/share/html/Elements/RT__Dashboard/ColumnMap +++ b/rt/share/html/Elements/RT__Dashboard/ColumnMap @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/RT__Group/ColumnMap b/rt/share/html/Elements/RT__Group/ColumnMap index 3c22debf8..29ab57307 100644 --- a/rt/share/html/Elements/RT__Group/ColumnMap +++ b/rt/share/html/Elements/RT__Group/ColumnMap @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/RT__Queue/ColumnMap b/rt/share/html/Elements/RT__Queue/ColumnMap index 47a673e66..a153177da 100644 --- a/rt/share/html/Elements/RT__Queue/ColumnMap +++ b/rt/share/html/Elements/RT__Queue/ColumnMap @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/RT__SavedSearch/ColumnMap b/rt/share/html/Elements/RT__SavedSearch/ColumnMap index 296787bb1..9edf435c1 100644 --- a/rt/share/html/Elements/RT__SavedSearch/ColumnMap +++ b/rt/share/html/Elements/RT__SavedSearch/ColumnMap @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/RT__Scrip/ColumnMap b/rt/share/html/Elements/RT__Scrip/ColumnMap index 976d76205..d417cef39 100644 --- a/rt/share/html/Elements/RT__Scrip/ColumnMap +++ b/rt/share/html/Elements/RT__Scrip/ColumnMap @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/RT__Template/ColumnMap b/rt/share/html/Elements/RT__Template/ColumnMap index 5da71b146..61da591d6 100644 --- a/rt/share/html/Elements/RT__Template/ColumnMap +++ b/rt/share/html/Elements/RT__Template/ColumnMap @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/RT__Ticket/ColumnMap b/rt/share/html/Elements/RT__Ticket/ColumnMap index dd1fd3902..7309b5d66 100644 --- a/rt/share/html/Elements/RT__Ticket/ColumnMap +++ b/rt/share/html/Elements/RT__Ticket/ColumnMap @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -68,7 +68,7 @@ my $LinkCallback = sub { \'<a href="', $_->$mode_uri->Resolver->HREF, \'">', - ( $_->$mode_uri->IsLocal ? $_->$local_type : $_->$mode ), + ( $_->$mode_uri->IsLocal && $_->$local_type ? $_->$local_type : $_->$mode_uri->Resolver->AsString ), \'</a><br />', } @{ $_[0]->Links($other_mode,$type)->ItemsArrayRef } } diff --git a/rt/share/html/Elements/RT__User/ColumnMap b/rt/share/html/Elements/RT__User/ColumnMap index 7a6eb25d1..d6d7d6583 100644 --- a/rt/share/html/Elements/RT__User/ColumnMap +++ b/rt/share/html/Elements/RT__User/ColumnMap @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -142,6 +142,11 @@ my $COLUMN_MAP = { attribute => 'Lang', value => sub { return $_[0]->Lang() }, }, + FreeformContactInfo => { + title => 'Extra Info', #loc + attribute => 'FreeformContactInfo', + value => sub { return $_[0]->FreeformContactInfo() }, + }, }; </%ONCE> diff --git a/rt/share/html/Elements/Refresh b/rt/share/html/Elements/Refresh index 432bc8041..d3484ec1f 100755 --- a/rt/share/html/Elements/Refresh +++ b/rt/share/html/Elements/Refresh @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/RefreshHomepage b/rt/share/html/Elements/RefreshHomepage index 5729f4042..4a9c72cf8 100644 --- a/rt/share/html/Elements/RefreshHomepage +++ b/rt/share/html/Elements/RefreshHomepage @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/SavedSearches b/rt/share/html/Elements/SavedSearches index 20e9903b5..db990010f 100644 --- a/rt/share/html/Elements/SavedSearches +++ b/rt/share/html/Elements/SavedSearches @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/ScrubHTML b/rt/share/html/Elements/ScrubHTML index ecc3fbb5f..1e9a49c83 100644 --- a/rt/share/html/Elements/ScrubHTML +++ b/rt/share/html/Elements/ScrubHTML @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/Section b/rt/share/html/Elements/Section index 4655f78ee..0d9fa715d 100755 --- a/rt/share/html/Elements/Section +++ b/rt/share/html/Elements/Section @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/SelectAttachmentField b/rt/share/html/Elements/SelectAttachmentField index a74a46a76..d6a38ea60 100755 --- a/rt/share/html/Elements/SelectAttachmentField +++ b/rt/share/html/Elements/SelectAttachmentField @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/SelectBoolean b/rt/share/html/Elements/SelectBoolean index c328ae23c..a34775ebe 100755 --- a/rt/share/html/Elements/SelectBoolean +++ b/rt/share/html/Elements/SelectBoolean @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/SelectCustomFieldOperator b/rt/share/html/Elements/SelectCustomFieldOperator index 48538adaa..9fadd0e4f 100755 --- a/rt/share/html/Elements/SelectCustomFieldOperator +++ b/rt/share/html/Elements/SelectCustomFieldOperator @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/SelectCustomFieldValue b/rt/share/html/Elements/SelectCustomFieldValue index 3e1bdbe60..21887b810 100755 --- a/rt/share/html/Elements/SelectCustomFieldValue +++ b/rt/share/html/Elements/SelectCustomFieldValue @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -56,7 +56,20 @@ % } </select> % } -% else { +% elsif ( $CustomField->Type eq 'Autocomplete' ) { +<input type="text" id="CF-<% $CustomField->id %>" name="<% $Name %>" size="20" /> +<script type="text/javascript"> +% my @options; +% my $values = $CustomField->Values; +% while (my $value = $values->Next) { +% push @options, { +% value => $value->Name, +% label => $value->Description ? $value->Name . ' (' . $value->Description . ')' : $value->Name, +% }; +% } +jQuery('#'+'CF-' + <% $CustomField->id %>).autocomplete({ source: <% JSON::to_json(\@options) |n %> }); +</script> +% } else { <input name="<%$Name%>" size="20" /> % } <%args> diff --git a/rt/share/html/Elements/SelectDate b/rt/share/html/Elements/SelectDate index ed8c9e46a..98656c15d 100755 --- a/rt/share/html/Elements/SelectDate +++ b/rt/share/html/Elements/SelectDate @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/SelectDateRelation b/rt/share/html/Elements/SelectDateRelation index 1fe424a3d..fe1ab6bdd 100755 --- a/rt/share/html/Elements/SelectDateRelation +++ b/rt/share/html/Elements/SelectDateRelation @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/SelectDateType b/rt/share/html/Elements/SelectDateType index 92ae2fce5..a37b3f127 100755 --- a/rt/share/html/Elements/SelectDateType +++ b/rt/share/html/Elements/SelectDateType @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/SelectEqualityOperator b/rt/share/html/Elements/SelectEqualityOperator index 4cb56ca57..8e35bab56 100755 --- a/rt/share/html/Elements/SelectEqualityOperator +++ b/rt/share/html/Elements/SelectEqualityOperator @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/SelectGroups b/rt/share/html/Elements/SelectGroups index f9910a205..bf7989b69 100755 --- a/rt/share/html/Elements/SelectGroups +++ b/rt/share/html/Elements/SelectGroups @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/SelectIPRelation b/rt/share/html/Elements/SelectIPRelation index 19c9a1f69..b129820f5 100644 --- a/rt/share/html/Elements/SelectIPRelation +++ b/rt/share/html/Elements/SelectIPRelation @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/SelectLang b/rt/share/html/Elements/SelectLang index 41e56e651..45d6b01cc 100755 --- a/rt/share/html/Elements/SelectLang +++ b/rt/share/html/Elements/SelectLang @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/SelectLinkType b/rt/share/html/Elements/SelectLinkType index 240a5d61d..c53e20fbd 100755 --- a/rt/share/html/Elements/SelectLinkType +++ b/rt/share/html/Elements/SelectLinkType @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/SelectMatch b/rt/share/html/Elements/SelectMatch index edabefb56..7d3c28cae 100755 --- a/rt/share/html/Elements/SelectMatch +++ b/rt/share/html/Elements/SelectMatch @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/SelectNewTicketQueue b/rt/share/html/Elements/SelectNewTicketQueue index 2afe34ba1..dd966ed6d 100755 --- a/rt/share/html/Elements/SelectNewTicketQueue +++ b/rt/share/html/Elements/SelectNewTicketQueue @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/SelectOwner b/rt/share/html/Elements/SelectOwner index 9a351dfee..9327de20a 100755 --- a/rt/share/html/Elements/SelectOwner +++ b/rt/share/html/Elements/SelectOwner @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/SelectOwnerAutocomplete b/rt/share/html/Elements/SelectOwnerAutocomplete index d5aad4d25..a78a6ad0d 100644 --- a/rt/share/html/Elements/SelectOwnerAutocomplete +++ b/rt/share/html/Elements/SelectOwnerAutocomplete @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/SelectOwnerDropdown b/rt/share/html/Elements/SelectOwnerDropdown index a051d57f2..415049ad6 100644 --- a/rt/share/html/Elements/SelectOwnerDropdown +++ b/rt/share/html/Elements/SelectOwnerDropdown @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/SelectPriority b/rt/share/html/Elements/SelectPriority index c49182816..10cfc3ea2 100644 --- a/rt/share/html/Elements/SelectPriority +++ b/rt/share/html/Elements/SelectPriority @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/SelectQueue b/rt/share/html/Elements/SelectQueue index e5b053b05..7276af09a 100755 --- a/rt/share/html/Elements/SelectQueue +++ b/rt/share/html/Elements/SelectQueue @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -107,7 +107,21 @@ if ( defined $session{$cache_key} && if ( not defined $session{$cache_key} and not $Lite ) { my $q = RT::Queues->new($session{'CurrentUser'}); $q->UnLimit; - + + if ( $Default ) { + my $d = RT::Queue->new($session{'CurrentUser'}); + $d->Load($Default); + unless ( $d->CurrentUserHasRight('SeeQueue') ) { + if ( $d->id ) { + push @{$session{$cache_key}{queues}}, { + Id => $d->id, + Name => '#' . $d->id, + Description => '#' . $d->id, + }; + } + } + } + while (my $queue = $q->Next) { if ($ShowAllQueues || $queue->CurrentUserHasRight($CheckQueueRight)) { push @{$session{$cache_key}{queues}}, { diff --git a/rt/share/html/Elements/SelectResultsPerPage b/rt/share/html/Elements/SelectResultsPerPage index c39ea37f3..145d19482 100755 --- a/rt/share/html/Elements/SelectResultsPerPage +++ b/rt/share/html/Elements/SelectResultsPerPage @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/SelectSortOrder b/rt/share/html/Elements/SelectSortOrder index 33d03b6f5..7611349fe 100755 --- a/rt/share/html/Elements/SelectSortOrder +++ b/rt/share/html/Elements/SelectSortOrder @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/SelectStatus b/rt/share/html/Elements/SelectStatus index 7e3e0cc67..b9f463321 100755 --- a/rt/share/html/Elements/SelectStatus +++ b/rt/share/html/Elements/SelectStatus @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -55,7 +55,7 @@ <optgroup label="<% $lifecycle %>"> % } % foreach my $status (@{$statuses_by_lifecycle{$lifecycle}}) { -% next if ($SkipDeleted && $status eq 'deleted'); +% next if ($SkipDeleted && lc $status eq 'deleted'); % my $selected = defined $Default && $status eq $Default ? 'selected="selected"' : ''; <option value="<% $status %>" <% $selected |n %>><% loc($status) %></option> % } diff --git a/rt/share/html/Elements/SelectTicketSortBy b/rt/share/html/Elements/SelectTicketSortBy index 7fc294099..18a0cc093 100755 --- a/rt/share/html/Elements/SelectTicketSortBy +++ b/rt/share/html/Elements/SelectTicketSortBy @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/SelectTicketTypes b/rt/share/html/Elements/SelectTicketTypes index 4f4cf2c01..fe7f62d0a 100755 --- a/rt/share/html/Elements/SelectTicketTypes +++ b/rt/share/html/Elements/SelectTicketTypes @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/SelectTimeUnits b/rt/share/html/Elements/SelectTimeUnits index f6e7c9bd0..e548af43b 100755 --- a/rt/share/html/Elements/SelectTimeUnits +++ b/rt/share/html/Elements/SelectTimeUnits @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/SelectTimezone b/rt/share/html/Elements/SelectTimezone index 5f5bd5a38..003fd9acc 100644 --- a/rt/share/html/Elements/SelectTimezone +++ b/rt/share/html/Elements/SelectTimezone @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/SelectUsers b/rt/share/html/Elements/SelectUsers index 311e3e1b9..ae3c96400 100755 --- a/rt/share/html/Elements/SelectUsers +++ b/rt/share/html/Elements/SelectUsers @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/SelectWatcherType b/rt/share/html/Elements/SelectWatcherType index dc9f02015..174a77a43 100755 --- a/rt/share/html/Elements/SelectWatcherType +++ b/rt/share/html/Elements/SelectWatcherType @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/SetupSessionCookie b/rt/share/html/Elements/SetupSessionCookie index 7cfcf9557..d042d6d72 100755 --- a/rt/share/html/Elements/SetupSessionCookie +++ b/rt/share/html/Elements/SetupSessionCookie @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/ShowCustomFieldBinary b/rt/share/html/Elements/ShowCustomFieldBinary index 306f46314..78e44e807 100644 --- a/rt/share/html/Elements/ShowCustomFieldBinary +++ b/rt/share/html/Elements/ShowCustomFieldBinary @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/ShowCustomFieldDate b/rt/share/html/Elements/ShowCustomFieldDate index 4cfb96596..ad7ae4f50 100644 --- a/rt/share/html/Elements/ShowCustomFieldDate +++ b/rt/share/html/Elements/ShowCustomFieldDate @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/ShowCustomFieldDateTime b/rt/share/html/Elements/ShowCustomFieldDateTime index 61a430d7d..006cc788d 100644 --- a/rt/share/html/Elements/ShowCustomFieldDateTime +++ b/rt/share/html/Elements/ShowCustomFieldDateTime @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/ShowCustomFieldImage b/rt/share/html/Elements/ShowCustomFieldImage index 07796966c..c36106283 100644 --- a/rt/share/html/Elements/ShowCustomFieldImage +++ b/rt/share/html/Elements/ShowCustomFieldImage @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/ShowCustomFieldText b/rt/share/html/Elements/ShowCustomFieldText index 0e061ee6d..13455e608 100644 --- a/rt/share/html/Elements/ShowCustomFieldText +++ b/rt/share/html/Elements/ShowCustomFieldText @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/ShowCustomFieldWikitext b/rt/share/html/Elements/ShowCustomFieldWikitext index 31391ee5c..5f32d479e 100644 --- a/rt/share/html/Elements/ShowCustomFieldWikitext +++ b/rt/share/html/Elements/ShowCustomFieldWikitext @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/ShowCustomFields b/rt/share/html/Elements/ShowCustomFields index 6a6fb9c79..3fe51c109 100644 --- a/rt/share/html/Elements/ShowCustomFields +++ b/rt/share/html/Elements/ShowCustomFields @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/ShowLink b/rt/share/html/Elements/ShowLink index 1f8568ae9..cccc3d824 100644 --- a/rt/share/html/Elements/ShowLink +++ b/rt/share/html/Elements/ShowLink @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/ShowLinks b/rt/share/html/Elements/ShowLinks index c06c6f7ef..16fc56d29 100755 --- a/rt/share/html/Elements/ShowLinks +++ b/rt/share/html/Elements/ShowLinks @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/ShowMemberships b/rt/share/html/Elements/ShowMemberships index 0dbe67c80..f8c20cd20 100644 --- a/rt/share/html/Elements/ShowMemberships +++ b/rt/share/html/Elements/ShowMemberships @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/ShowRelationLabel b/rt/share/html/Elements/ShowRelationLabel index b486b7fed..9635a120c 100644 --- a/rt/share/html/Elements/ShowRelationLabel +++ b/rt/share/html/Elements/ShowRelationLabel @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/ShowReminders b/rt/share/html/Elements/ShowReminders index ca5b33835..18945c10e 100644 --- a/rt/share/html/Elements/ShowReminders +++ b/rt/share/html/Elements/ShowReminders @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/ShowSearch b/rt/share/html/Elements/ShowSearch index 8bdbd8aae..e08b9eaa6 100644 --- a/rt/share/html/Elements/ShowSearch +++ b/rt/share/html/Elements/ShowSearch @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -125,10 +125,7 @@ foreach ( $SearchArg, $ProcessedSearchArg ) { $_->{'Format'} =~ s/__(Web(?:Path|Base|BaseURL))__/scalar RT->Config->Get($1)/ge; # extract-message-catalog would "$1", so we avoid quotes for loc calls $_->{'Format'} =~ s/__loc\(["']?(\w+)["']?\)__/my $f = "$1"; loc($f)/ge; - if ( $_->{'Query'} =~ /__Bookmarked__/ ) { - $_->{'Rows'} = 999; - } - elsif ( $_->{'Query'} =~ /__Bookmarks__/ ) { + if ( $_->{'Query'} =~ /__Bookmarks__/ ) { $_->{'Rows'} = 999; # DEPRECATED: will be here for a while up to 3.10/4.0 diff --git a/rt/share/html/Elements/ShowUser b/rt/share/html/Elements/ShowUser index 678a45cd8..dd79f2eed 100644 --- a/rt/share/html/Elements/ShowUser +++ b/rt/share/html/Elements/ShowUser @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/ShowUserConcise b/rt/share/html/Elements/ShowUserConcise index a68ba4fee..aeabae0c2 100644 --- a/rt/share/html/Elements/ShowUserConcise +++ b/rt/share/html/Elements/ShowUserConcise @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/ShowUserEmailFrequency b/rt/share/html/Elements/ShowUserEmailFrequency index b18961dd4..6229e9571 100644 --- a/rt/share/html/Elements/ShowUserEmailFrequency +++ b/rt/share/html/Elements/ShowUserEmailFrequency @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/ShowUserVerbose b/rt/share/html/Elements/ShowUserVerbose index f805b575a..3276228bf 100644 --- a/rt/share/html/Elements/ShowUserVerbose +++ b/rt/share/html/Elements/ShowUserVerbose @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/SimpleSearch b/rt/share/html/Elements/SimpleSearch index 6d9bce84c..bd8a87642 100755 --- a/rt/share/html/Elements/SimpleSearch +++ b/rt/share/html/Elements/SimpleSearch @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/Submit b/rt/share/html/Elements/Submit index d1bf0a53b..04bc98aa3 100755 --- a/rt/share/html/Elements/Submit +++ b/rt/share/html/Elements/Submit @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/Tabs b/rt/share/html/Elements/Tabs index a82cdd1be..6eae81d39 100755 --- a/rt/share/html/Elements/Tabs +++ b/rt/share/html/Elements/Tabs @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -56,7 +56,7 @@ $request_path =~ s!/{2,}!/!g; my $query_string = sub { my %args = @_; my $u = URI->new(); - $u->query_form(%args); + $u->query_form(map { $_ => $args{$_} } sort keys %args); return $u->query; }; @@ -660,8 +660,10 @@ my $build_main_nav = sub { if ( $item_map->{$id}->{next} ) { $search->child( next => title => loc('Next') . ' >', class => "nav", path => "/Ticket/Display.html?id=" . $item_map->{$id}->{next}); - $search->child( last => - title => loc('Last') . ' >>', class => "nav", path => "/Ticket/Display.html?id=" . $item_map->{last}); + if ( $item_map->{last} ) { + $search->child( last => + title => loc('Last') . ' >>', class => "nav", path => "/Ticket/Display.html?id=" . $item_map->{last}); + } } } } diff --git a/rt/share/html/Elements/TicketList b/rt/share/html/Elements/TicketList index 498759572..62fc9d09d 100644 --- a/rt/share/html/Elements/TicketList +++ b/rt/share/html/Elements/TicketList @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/TitleBox b/rt/share/html/Elements/TitleBox index bbb55ebcd..c2c94cd9b 100644 --- a/rt/share/html/Elements/TitleBox +++ b/rt/share/html/Elements/TitleBox @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/TitleBoxEnd b/rt/share/html/Elements/TitleBoxEnd index f1ac68250..646256c6c 100644 --- a/rt/share/html/Elements/TitleBoxEnd +++ b/rt/share/html/Elements/TitleBoxEnd @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/TitleBoxStart b/rt/share/html/Elements/TitleBoxStart index cb746c491..405ecbd9a 100644 --- a/rt/share/html/Elements/TitleBoxStart +++ b/rt/share/html/Elements/TitleBoxStart @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/ValidateCustomFields b/rt/share/html/Elements/ValidateCustomFields index 7b0469bde..713885f6f 100644 --- a/rt/share/html/Elements/ValidateCustomFields +++ b/rt/share/html/Elements/ValidateCustomFields @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Elements/WidgetBar b/rt/share/html/Elements/WidgetBar index cf59bfc78..b9daab398 100644 --- a/rt/share/html/Elements/WidgetBar +++ b/rt/share/html/Elements/WidgetBar @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Helpers/Autocomplete/CustomFieldValues b/rt/share/html/Helpers/Autocomplete/CustomFieldValues index 5bb0c90b2..eec346ebb 100644 --- a/rt/share/html/Helpers/Autocomplete/CustomFieldValues +++ b/rt/share/html/Helpers/Autocomplete/CustomFieldValues @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Helpers/Autocomplete/Groups b/rt/share/html/Helpers/Autocomplete/Groups index b6a6f1af5..a7de30a6d 100644 --- a/rt/share/html/Helpers/Autocomplete/Groups +++ b/rt/share/html/Helpers/Autocomplete/Groups @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -83,6 +83,6 @@ foreach (split /\s*,\s*/, $exclude) { my @suggestions; while ( my $group = $groups->Next ) { - push @suggestions, $group->Name; + push @suggestions, { label => $group->Name, value => $group->Name, id => $group->id }; } </%INIT> diff --git a/rt/share/html/Helpers/Autocomplete/Owners b/rt/share/html/Helpers/Autocomplete/Owners index 93a571c82..e3ac81eca 100644 --- a/rt/share/html/Helpers/Autocomplete/Owners +++ b/rt/share/html/Helpers/Autocomplete/Owners @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Helpers/Autocomplete/Users b/rt/share/html/Helpers/Autocomplete/Users index 349442a4f..8f7425f2f 100644 --- a/rt/share/html/Helpers/Autocomplete/Users +++ b/rt/share/html/Helpers/Autocomplete/Users @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -139,7 +139,7 @@ while ( my $user = $users->Next ) { my $formatted = $m->scomp('/Elements/ShowUser', User => $user, NoEscape => 1); $formatted =~ s/\n//g; - my $suggestion = { label => $formatted, value => $user->$return }; + my $suggestion = { label => $formatted, value => $user->$return, id => $user->id }; $m->callback( CallbackName => "ModifySuggestion", suggestion => $suggestion, user => $user ); push @suggestions, $suggestion; } diff --git a/rt/share/html/Helpers/Autocomplete/autohandler b/rt/share/html/Helpers/Autocomplete/autohandler index 73d99669d..c76636fc0 100644 --- a/rt/share/html/Helpers/Autocomplete/autohandler +++ b/rt/share/html/Helpers/Autocomplete/autohandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Helpers/TicketHistory b/rt/share/html/Helpers/TicketHistory index 92c0f85c0..97864d412 100644 --- a/rt/share/html/Helpers/TicketHistory +++ b/rt/share/html/Helpers/TicketHistory @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Helpers/Toggle/ShowRequestor b/rt/share/html/Helpers/Toggle/ShowRequestor index c708e9948..a2b3ed248 100644 --- a/rt/share/html/Helpers/Toggle/ShowRequestor +++ b/rt/share/html/Helpers/Toggle/ShowRequestor @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Helpers/Toggle/TicketBookmark b/rt/share/html/Helpers/Toggle/TicketBookmark index 741bbcfe0..08a3f8756 100644 --- a/rt/share/html/Helpers/Toggle/TicketBookmark +++ b/rt/share/html/Helpers/Toggle/TicketBookmark @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Helpers/autohandler b/rt/share/html/Helpers/autohandler index fd683a449..59a04c87e 100644 --- a/rt/share/html/Helpers/autohandler +++ b/rt/share/html/Helpers/autohandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Install/Basics.html b/rt/share/html/Install/Basics.html index 8fe1a582d..67f2cc8ec 100644 --- a/rt/share/html/Install/Basics.html +++ b/rt/share/html/Install/Basics.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Install/DatabaseDetails.html b/rt/share/html/Install/DatabaseDetails.html index 30a495dc2..78672db5c 100644 --- a/rt/share/html/Install/DatabaseDetails.html +++ b/rt/share/html/Install/DatabaseDetails.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -143,7 +143,17 @@ if ( $Run ) { $dbh = DBI->connect( RT::Handle->DSN, $ARGS{DatabaseAdmin}, $ARGS{DatabaseAdminPassword}, { RaiseError => 0, PrintError => 0 }, ); - + + if ( $dbh and $db_type eq "Oracle") { + # The database _existing_ is itself insufficient for Oracle -- we need to check for the RT user + my $sth = $dbh->prepare('SELECT username FROM dba_users WHERE username = ?'); + $sth->execute( $ARGS{DatabaseUser} ); + undef $dbh unless $sth->fetchrow_array; + + push @errors, loc("Oracle users cannot have empty passwords") + unless $ARGS{DatabasePassword}; + } + if ( $dbh ) { # check if table Users exists eval { diff --git a/rt/share/html/Install/DatabaseType.html b/rt/share/html/Install/DatabaseType.html index 1a6e5e009..d2017d1e6 100644 --- a/rt/share/html/Install/DatabaseType.html +++ b/rt/share/html/Install/DatabaseType.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Install/Elements/Errors b/rt/share/html/Install/Elements/Errors index 0a171b729..14d7e6b30 100644 --- a/rt/share/html/Install/Elements/Errors +++ b/rt/share/html/Install/Elements/Errors @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Install/Elements/Wrapper b/rt/share/html/Install/Elements/Wrapper index e1cbd9f5e..53d2b9d40 100644 --- a/rt/share/html/Install/Elements/Wrapper +++ b/rt/share/html/Install/Elements/Wrapper @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Install/Finish.html b/rt/share/html/Install/Finish.html index 9d53152dc..9f84457e8 100644 --- a/rt/share/html/Install/Finish.html +++ b/rt/share/html/Install/Finish.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Install/Global.html b/rt/share/html/Install/Global.html index 9ef4f695a..620a6c43a 100644 --- a/rt/share/html/Install/Global.html +++ b/rt/share/html/Install/Global.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Install/Initialize.html b/rt/share/html/Install/Initialize.html index 468662b1e..a6e905fca 100644 --- a/rt/share/html/Install/Initialize.html +++ b/rt/share/html/Install/Initialize.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Install/Sendmail.html b/rt/share/html/Install/Sendmail.html index 24749e210..fd835b46f 100644 --- a/rt/share/html/Install/Sendmail.html +++ b/rt/share/html/Install/Sendmail.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Install/autohandler b/rt/share/html/Install/autohandler index 436303e16..b4c802281 100644 --- a/rt/share/html/Install/autohandler +++ b/rt/share/html/Install/autohandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Install/index.html b/rt/share/html/Install/index.html index da3b7e423..a6aff83a5 100644 --- a/rt/share/html/Install/index.html +++ b/rt/share/html/Install/index.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/Helpers/CustomLogo/dhandler b/rt/share/html/NoAuth/Helpers/CustomLogo/dhandler index 3575451d8..8bbc9d65d 100644 --- a/rt/share/html/NoAuth/Helpers/CustomLogo/dhandler +++ b/rt/share/html/NoAuth/Helpers/CustomLogo/dhandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/Login.html b/rt/share/html/NoAuth/Login.html index 7c649bbb6..d880e25f8 100755 --- a/rt/share/html/NoAuth/Login.html +++ b/rt/share/html/NoAuth/Login.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/Logout.html b/rt/share/html/NoAuth/Logout.html index 7c9e0cb76..409526964 100755 --- a/rt/share/html/NoAuth/Logout.html +++ b/rt/share/html/NoAuth/Logout.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/Reminder.html b/rt/share/html/NoAuth/Reminder.html index a54e0fbb3..03f87afa7 100755 --- a/rt/share/html/NoAuth/Reminder.html +++ b/rt/share/html/NoAuth/Reminder.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/RichText/autohandler b/rt/share/html/NoAuth/RichText/autohandler index c1ffaf451..ee4397edd 100644 --- a/rt/share/html/NoAuth/RichText/autohandler +++ b/rt/share/html/NoAuth/RichText/autohandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/RichText/dhandler b/rt/share/html/NoAuth/RichText/dhandler index 230cf5fb7..1cc15ed3c 100644 --- a/rt/share/html/NoAuth/RichText/dhandler +++ b/rt/share/html/NoAuth/RichText/dhandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/aileron/InHeader b/rt/share/html/NoAuth/css/aileron/InHeader index 4d0c88d6c..b1f7787ff 100644 --- a/rt/share/html/NoAuth/css/aileron/InHeader +++ b/rt/share/html/NoAuth/css/aileron/InHeader @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/aileron/base.css b/rt/share/html/NoAuth/css/aileron/base.css index a44ec369d..dc3472f1e 100644 --- a/rt/share/html/NoAuth/css/aileron/base.css +++ b/rt/share/html/NoAuth/css/aileron/base.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/aileron/boxes.css b/rt/share/html/NoAuth/css/aileron/boxes.css index a6c580997..267b2cfc6 100644 --- a/rt/share/html/NoAuth/css/aileron/boxes.css +++ b/rt/share/html/NoAuth/css/aileron/boxes.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/aileron/forms.css b/rt/share/html/NoAuth/css/aileron/forms.css index e0bba5191..4e626d26e 100644 --- a/rt/share/html/NoAuth/css/aileron/forms.css +++ b/rt/share/html/NoAuth/css/aileron/forms.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/aileron/images/dhandler b/rt/share/html/NoAuth/css/aileron/images/dhandler index ab1c4e4a5..441935390 100644 --- a/rt/share/html/NoAuth/css/aileron/images/dhandler +++ b/rt/share/html/NoAuth/css/aileron/images/dhandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/aileron/layout.css b/rt/share/html/NoAuth/css/aileron/layout.css index 93e3784c2..541cdaf7d 100644 --- a/rt/share/html/NoAuth/css/aileron/layout.css +++ b/rt/share/html/NoAuth/css/aileron/layout.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/aileron/login.css b/rt/share/html/NoAuth/css/aileron/login.css index d68d1e66f..f0a7d487c 100644 --- a/rt/share/html/NoAuth/css/aileron/login.css +++ b/rt/share/html/NoAuth/css/aileron/login.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/aileron/main.css b/rt/share/html/NoAuth/css/aileron/main.css index 87ccba512..90463e1fc 100644 --- a/rt/share/html/NoAuth/css/aileron/main.css +++ b/rt/share/html/NoAuth/css/aileron/main.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/aileron/misc.css b/rt/share/html/NoAuth/css/aileron/misc.css index bb88b1636..b879a8edc 100644 --- a/rt/share/html/NoAuth/css/aileron/misc.css +++ b/rt/share/html/NoAuth/css/aileron/misc.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/aileron/msie.css b/rt/share/html/NoAuth/css/aileron/msie.css index 414a2fde5..05e96c391 100644 --- a/rt/share/html/NoAuth/css/aileron/msie.css +++ b/rt/share/html/NoAuth/css/aileron/msie.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/aileron/msie6.css b/rt/share/html/NoAuth/css/aileron/msie6.css index e50fa4e25..6a5eb3252 100644 --- a/rt/share/html/NoAuth/css/aileron/msie6.css +++ b/rt/share/html/NoAuth/css/aileron/msie6.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -45,6 +45,8 @@ %# those contributions and any derivatives thereof. %# %# END BPS TAGGED BLOCK }}} +@import "../base/msie6.css"; + div#body { top: 0em; } @@ -84,3 +86,25 @@ div#body { #page-navigation ul { width: auto; } + +.ticket-transaction div.metadata span.actions { + right: 1.2em; +} + +div.titlebox, +#ticket-create-metadata, +#ticket-update-metadata, +#ticket-create-message, +#ticket-update-message { + position: relative; +} + +#Ticket-Create-details { + float: left; + position: relative; +} + +div.submit .extra-buttons { + float: none; +} + diff --git a/rt/share/html/NoAuth/css/aileron/nav.css b/rt/share/html/NoAuth/css/aileron/nav.css index 9f6eb5e0e..161d24921 100644 --- a/rt/share/html/NoAuth/css/aileron/nav.css +++ b/rt/share/html/NoAuth/css/aileron/nav.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/aileron/ticket-lists.css b/rt/share/html/NoAuth/css/aileron/ticket-lists.css index b3faf6d20..4ec9ae7e5 100644 --- a/rt/share/html/NoAuth/css/aileron/ticket-lists.css +++ b/rt/share/html/NoAuth/css/aileron/ticket-lists.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -186,6 +186,8 @@ padding-bottom: 1em; .chart-wrapper .collection-as-table { width: auto; font-size: 1em; + /* Firefox needs this to let the table flow below the chart on narrow screens */ + clear: right; } .chart-wrapper .collection-as-table th.collection-as-table { diff --git a/rt/share/html/NoAuth/css/aileron/ticket-search.css b/rt/share/html/NoAuth/css/aileron/ticket-search.css index 5b0aa83fc..ea92e69e5 100644 --- a/rt/share/html/NoAuth/css/aileron/ticket-search.css +++ b/rt/share/html/NoAuth/css/aileron/ticket-search.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/aileron/ticket.css b/rt/share/html/NoAuth/css/aileron/ticket.css index ebc34f297..0d60f6ada 100644 --- a/rt/share/html/NoAuth/css/aileron/ticket.css +++ b/rt/share/html/NoAuth/css/aileron/ticket.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/autohandler b/rt/share/html/NoAuth/css/autohandler index 1ef0e2e3a..c0647ad30 100644 --- a/rt/share/html/NoAuth/css/autohandler +++ b/rt/share/html/NoAuth/css/autohandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/ballard/InHeader b/rt/share/html/NoAuth/css/ballard/InHeader index 8043cead9..1c6a39c0a 100644 --- a/rt/share/html/NoAuth/css/ballard/InHeader +++ b/rt/share/html/NoAuth/css/ballard/InHeader @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -50,5 +50,5 @@ <![endif]--> <!--[if lt IE 7]> -<link rel="stylesheet" href="<%RT->Config->Get('WebPath')%>/NoAuth/css/web2/msie6.css" type="text/css" media="all" /> +<link rel="stylesheet" href="<%RT->Config->Get('WebPath')%>/NoAuth/css/ballard/msie6.css" type="text/css" media="all" /> <![endif]--> diff --git a/rt/share/html/NoAuth/css/ballard/base.css b/rt/share/html/NoAuth/css/ballard/base.css index a44ec369d..dc3472f1e 100644 --- a/rt/share/html/NoAuth/css/ballard/base.css +++ b/rt/share/html/NoAuth/css/ballard/base.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/ballard/boxes.css b/rt/share/html/NoAuth/css/ballard/boxes.css index 7589ea4b8..6c61c2d80 100644 --- a/rt/share/html/NoAuth/css/ballard/boxes.css +++ b/rt/share/html/NoAuth/css/ballard/boxes.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/ballard/images/dhandler b/rt/share/html/NoAuth/css/ballard/images/dhandler index ab1c4e4a5..441935390 100644 --- a/rt/share/html/NoAuth/css/ballard/images/dhandler +++ b/rt/share/html/NoAuth/css/ballard/images/dhandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/ballard/layout.css b/rt/share/html/NoAuth/css/ballard/layout.css index 5e2593823..c7d18f02c 100644 --- a/rt/share/html/NoAuth/css/ballard/layout.css +++ b/rt/share/html/NoAuth/css/ballard/layout.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/ballard/main.css b/rt/share/html/NoAuth/css/ballard/main.css index ea6e75858..3c3241feb 100644 --- a/rt/share/html/NoAuth/css/ballard/main.css +++ b/rt/share/html/NoAuth/css/ballard/main.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/ballard/misc.css b/rt/share/html/NoAuth/css/ballard/misc.css index 48db9a7be..f177bb724 100644 --- a/rt/share/html/NoAuth/css/ballard/misc.css +++ b/rt/share/html/NoAuth/css/ballard/misc.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/ballard/msie.css b/rt/share/html/NoAuth/css/ballard/msie.css index 1b9589168..de5e62664 100644 --- a/rt/share/html/NoAuth/css/ballard/msie.css +++ b/rt/share/html/NoAuth/css/ballard/msie.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/ballard/msie6.css b/rt/share/html/NoAuth/css/ballard/msie6.css index 5b9b639fa..dc55b60a3 100644 --- a/rt/share/html/NoAuth/css/ballard/msie6.css +++ b/rt/share/html/NoAuth/css/ballard/msie6.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -45,6 +45,8 @@ %# those contributions and any derivatives thereof. %# %# END BPS TAGGED BLOCK }}} +@import "../base/msie6.css"; + .topaction .select-queue { margin-top: 0; } @@ -86,3 +88,11 @@ div#page-navigation ul#page-menu { width: expression(this.width > 401 ? 400 : true); } +#page-navigation { + width: 100%; +} + +.ticket-transaction div.metadata span.actions { + right: 1.1em; +} + diff --git a/rt/share/html/NoAuth/css/ballard/nav.css b/rt/share/html/NoAuth/css/ballard/nav.css index 89a4eae93..482eaac59 100644 --- a/rt/share/html/NoAuth/css/ballard/nav.css +++ b/rt/share/html/NoAuth/css/ballard/nav.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -59,7 +59,6 @@ top: 6.2em; left: 0em; z-index: 9997; - background-color: none; padding-top: 1em; padding-right: 0.5em; padding-left: 0.5em; diff --git a/rt/share/html/NoAuth/css/ballard/ticket-lists.css b/rt/share/html/NoAuth/css/ballard/ticket-lists.css index e104dddf4..ba05a07a0 100644 --- a/rt/share/html/NoAuth/css/ballard/ticket-lists.css +++ b/rt/share/html/NoAuth/css/ballard/ticket-lists.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -172,7 +172,6 @@ padding-bottom: 1em; } .chart.image { - margin-top: -1em; padding-right: 2em; float: left; clear: both; @@ -186,6 +185,8 @@ padding-bottom: 1em; .chart-wrapper .collection-as-table { width: auto; font-size: 1em; + /* Firefox needs this to let the table flow below the chart on narrow screens */ + clear: right; } .chart-wrapper .collection-as-table th.collection-as-table { diff --git a/rt/share/html/NoAuth/css/ballard/ticket-search.css b/rt/share/html/NoAuth/css/ballard/ticket-search.css index 0be4cff37..09165fa77 100644 --- a/rt/share/html/NoAuth/css/ballard/ticket-search.css +++ b/rt/share/html/NoAuth/css/ballard/ticket-search.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/ballard/ticket.css b/rt/share/html/NoAuth/css/ballard/ticket.css index 56771da0b..8b6d09ba4 100644 --- a/rt/share/html/NoAuth/css/ballard/ticket.css +++ b/rt/share/html/NoAuth/css/ballard/ticket.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/base/admin.css b/rt/share/html/NoAuth/css/base/admin.css index 493e3b47b..459786fb0 100644 --- a/rt/share/html/NoAuth/css/base/admin.css +++ b/rt/share/html/NoAuth/css/base/admin.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/base/articles.css b/rt/share/html/NoAuth/css/base/articles.css index a20533800..1f05041af 100644 --- a/rt/share/html/NoAuth/css/base/articles.css +++ b/rt/share/html/NoAuth/css/base/articles.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/base/collection.css b/rt/share/html/NoAuth/css/base/collection.css index cb4fdd866..ed053abff 100644 --- a/rt/share/html/NoAuth/css/base/collection.css +++ b/rt/share/html/NoAuth/css/base/collection.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/base/farbtastic.css b/rt/share/html/NoAuth/css/base/farbtastic.css index 8d9e8e08e..d0601ecdd 100644 --- a/rt/share/html/NoAuth/css/base/farbtastic.css +++ b/rt/share/html/NoAuth/css/base/farbtastic.css @@ -1,50 +1,3 @@ -%# BEGIN BPS TAGGED BLOCK {{{ -%# -%# COPYRIGHT: -%# -%# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC -%# <sales@bestpractical.com> -%# -%# (Except where explicitly superseded by other copyright notices) -%# -%# -%# LICENSE: -%# -%# This work is made available to you under the terms of Version 2 of -%# the GNU General Public License. A copy of that license should have -%# been provided with this software, but in any event can be snarfed -%# from www.gnu.org. -%# -%# This work is distributed in the hope that it will be useful, but -%# WITHOUT ANY WARRANTY; without even the implied warranty of -%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -%# General Public License for more details. -%# -%# You should have received a copy of the GNU General Public License -%# along with this program; if not, write to the Free Software -%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -%# 02110-1301 or visit their web page on the internet at -%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. -%# -%# -%# CONTRIBUTION SUBMISSION POLICY: -%# -%# (The following paragraph is not intended to limit the rights granted -%# to you to modify and distribute this software under the terms of -%# the GNU General Public License and is only of importance to you if -%# you choose to contribute your changes and enhancements to the -%# community by submitting them to Best Practical Solutions, LLC.) -%# -%# By intentionally submitting any modifications, corrections or -%# derivatives to this work, or any other work intended for use with -%# Request Tracker, to Best Practical Solutions, LLC, you confirm that -%# you are the copyright holder for those contributions and you grant -%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, -%# royalty-free, perpetual, license to use, copy, create derivative -%# works based on those contributions, and sublicense and distribute -%# those contributions and any derivatives thereof. -%# -%# END BPS TAGGED BLOCK }}} /** * Farbtastic Color Picker 1.2 * © 2008 Steven Wittens diff --git a/rt/share/html/NoAuth/css/base/forms.css b/rt/share/html/NoAuth/css/base/forms.css index 6a7548203..d6bc91729 100644 --- a/rt/share/html/NoAuth/css/base/forms.css +++ b/rt/share/html/NoAuth/css/base/forms.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/base/history-folding.css b/rt/share/html/NoAuth/css/base/history-folding.css index 1e7da59d8..e48eb1215 100644 --- a/rt/share/html/NoAuth/css/base/history-folding.css +++ b/rt/share/html/NoAuth/css/base/history-folding.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/base/jquery-ui.css b/rt/share/html/NoAuth/css/base/jquery-ui.css index a33047579..93ec275a4 100644 --- a/rt/share/html/NoAuth/css/base/jquery-ui.css +++ b/rt/share/html/NoAuth/css/base/jquery-ui.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/base/login.css b/rt/share/html/NoAuth/css/base/login.css index 12de00f8c..e95e8f7ee 100644 --- a/rt/share/html/NoAuth/css/base/login.css +++ b/rt/share/html/NoAuth/css/base/login.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/base/main.css b/rt/share/html/NoAuth/css/base/main.css index 7657db779..4eb890825 100644 --- a/rt/share/html/NoAuth/css/base/main.css +++ b/rt/share/html/NoAuth/css/base/main.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/base/misc.css b/rt/share/html/NoAuth/css/base/misc.css index ddea4c464..a9b887fe1 100644 --- a/rt/share/html/NoAuth/css/base/misc.css +++ b/rt/share/html/NoAuth/css/base/misc.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -111,3 +111,7 @@ fieldset.cfedit { font-family: arial,helvetica,sans-serif !important; } +textarea.messagebox, #cke_Content, #cke_UpdateContent { + -moz-box-sizing: border-box; + box-sizing: border-box; +} diff --git a/rt/share/html/NoAuth/css/base/nav.css b/rt/share/html/NoAuth/css/base/nav.css index 15f7c597f..c921722c5 100644 --- a/rt/share/html/NoAuth/css/base/nav.css +++ b/rt/share/html/NoAuth/css/base/nav.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/base/portlets.css b/rt/share/html/NoAuth/css/base/portlets.css index 1a11500ec..f104b6a02 100644 --- a/rt/share/html/NoAuth/css/base/portlets.css +++ b/rt/share/html/NoAuth/css/base/portlets.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/base/rights-editor.css b/rt/share/html/NoAuth/css/base/rights-editor.css index e54ac79f4..8e40f07e3 100644 --- a/rt/share/html/NoAuth/css/base/rights-editor.css +++ b/rt/share/html/NoAuth/css/base/rights-editor.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/base/theme-editor.css b/rt/share/html/NoAuth/css/base/theme-editor.css index 950995031..3d12dcfff 100644 --- a/rt/share/html/NoAuth/css/base/theme-editor.css +++ b/rt/share/html/NoAuth/css/base/theme-editor.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/base/ticket-form.css b/rt/share/html/NoAuth/css/base/ticket-form.css index b31b5ae7f..14673622d 100644 --- a/rt/share/html/NoAuth/css/base/ticket-form.css +++ b/rt/share/html/NoAuth/css/base/ticket-form.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/base/ticket.css b/rt/share/html/NoAuth/css/base/ticket.css index 6e15a9de0..6a43a1db1 100644 --- a/rt/share/html/NoAuth/css/base/ticket.css +++ b/rt/share/html/NoAuth/css/base/ticket.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/base/tools.css b/rt/share/html/NoAuth/css/base/tools.css index 526cac2b3..1dd6cb9d5 100644 --- a/rt/share/html/NoAuth/css/base/tools.css +++ b/rt/share/html/NoAuth/css/base/tools.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/dhandler b/rt/share/html/NoAuth/css/dhandler index 81e6a8d3a..756b9b36e 100644 --- a/rt/share/html/NoAuth/css/dhandler +++ b/rt/share/html/NoAuth/css/dhandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/print.css b/rt/share/html/NoAuth/css/print.css index ecd702168..96250845f 100644 --- a/rt/share/html/NoAuth/css/print.css +++ b/rt/share/html/NoAuth/css/print.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/web2/InHeader b/rt/share/html/NoAuth/css/web2/InHeader index fd3af82ca..a6e1d2f32 100644 --- a/rt/share/html/NoAuth/css/web2/InHeader +++ b/rt/share/html/NoAuth/css/web2/InHeader @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/web2/base.css b/rt/share/html/NoAuth/css/web2/base.css index a44ec369d..dc3472f1e 100644 --- a/rt/share/html/NoAuth/css/web2/base.css +++ b/rt/share/html/NoAuth/css/web2/base.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/web2/boxes.css b/rt/share/html/NoAuth/css/web2/boxes.css index 3ca25869e..645e83bfe 100644 --- a/rt/share/html/NoAuth/css/web2/boxes.css +++ b/rt/share/html/NoAuth/css/web2/boxes.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/web2/images/dhandler b/rt/share/html/NoAuth/css/web2/images/dhandler index ab1c4e4a5..441935390 100644 --- a/rt/share/html/NoAuth/css/web2/images/dhandler +++ b/rt/share/html/NoAuth/css/web2/images/dhandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/web2/layout.css b/rt/share/html/NoAuth/css/web2/layout.css index 026037695..0567db671 100644 --- a/rt/share/html/NoAuth/css/web2/layout.css +++ b/rt/share/html/NoAuth/css/web2/layout.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/web2/main.css b/rt/share/html/NoAuth/css/web2/main.css index ea6e75858..3c3241feb 100644 --- a/rt/share/html/NoAuth/css/web2/main.css +++ b/rt/share/html/NoAuth/css/web2/main.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/web2/misc.css b/rt/share/html/NoAuth/css/web2/misc.css index 48db9a7be..f177bb724 100644 --- a/rt/share/html/NoAuth/css/web2/misc.css +++ b/rt/share/html/NoAuth/css/web2/misc.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/web2/msie.css b/rt/share/html/NoAuth/css/web2/msie.css index 249ff22d4..63e36ae95 100644 --- a/rt/share/html/NoAuth/css/web2/msie.css +++ b/rt/share/html/NoAuth/css/web2/msie.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/web2/msie6.css b/rt/share/html/NoAuth/css/web2/msie6.css index 40851f09b..cbe175414 100644 --- a/rt/share/html/NoAuth/css/web2/msie6.css +++ b/rt/share/html/NoAuth/css/web2/msie6.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -45,6 +45,8 @@ %# those contributions and any derivatives thereof. %# %# END BPS TAGGED BLOCK }}} +@import "../base/msie6.css"; + .topaction .select-queue { margin-top: 0; } @@ -94,3 +96,6 @@ div#page-navigation { background-image: url(<%RT->Config->Get('WebPath')%>/NoAuth/css/images/arrows-grey.gif); } +.ticket-transaction div.metadata span.actions { + right: 1.1em; +} diff --git a/rt/share/html/NoAuth/css/web2/nav.css b/rt/share/html/NoAuth/css/web2/nav.css index 9e00eee09..3783a1dc4 100644 --- a/rt/share/html/NoAuth/css/web2/nav.css +++ b/rt/share/html/NoAuth/css/web2/nav.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/web2/ticket-lists.css b/rt/share/html/NoAuth/css/web2/ticket-lists.css index e104dddf4..ba05a07a0 100644 --- a/rt/share/html/NoAuth/css/web2/ticket-lists.css +++ b/rt/share/html/NoAuth/css/web2/ticket-lists.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -172,7 +172,6 @@ padding-bottom: 1em; } .chart.image { - margin-top: -1em; padding-right: 2em; float: left; clear: both; @@ -186,6 +185,8 @@ padding-bottom: 1em; .chart-wrapper .collection-as-table { width: auto; font-size: 1em; + /* Firefox needs this to let the table flow below the chart on narrow screens */ + clear: right; } .chart-wrapper .collection-as-table th.collection-as-table { diff --git a/rt/share/html/NoAuth/css/web2/ticket-search.css b/rt/share/html/NoAuth/css/web2/ticket-search.css index 94dc9c223..725a812e7 100644 --- a/rt/share/html/NoAuth/css/web2/ticket-search.css +++ b/rt/share/html/NoAuth/css/web2/ticket-search.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/css/web2/ticket.css b/rt/share/html/NoAuth/css/web2/ticket.css index c67b780fd..d3902169a 100644 --- a/rt/share/html/NoAuth/css/web2/ticket.css +++ b/rt/share/html/NoAuth/css/web2/ticket.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/iCal/dhandler b/rt/share/html/NoAuth/iCal/dhandler index 338db8b0f..35da94080 100644 --- a/rt/share/html/NoAuth/iCal/dhandler +++ b/rt/share/html/NoAuth/iCal/dhandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/images/autohandler b/rt/share/html/NoAuth/images/autohandler index e7e6e31b9..d7e8e6abd 100644 --- a/rt/share/html/NoAuth/images/autohandler +++ b/rt/share/html/NoAuth/images/autohandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/js/autohandler b/rt/share/html/NoAuth/js/autohandler index b994580d3..29444400f 100644 --- a/rt/share/html/NoAuth/js/autohandler +++ b/rt/share/html/NoAuth/js/autohandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/js/cascaded.js b/rt/share/html/NoAuth/js/cascaded.js index 349d18187..b72a33f67 100644 --- a/rt/share/html/NoAuth/js/cascaded.js +++ b/rt/share/html/NoAuth/js/cascaded.js @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -45,50 +45,98 @@ %# those contributions and any derivatives thereof. %# %# END BPS TAGGED BLOCK }}} -function filter_cascade (id, val) { +function filter_cascade (id, vals) { + var element = document.getElementById(id); + if (!element) { return }; + + if ( element.tagName == 'SELECT' ) { + return filter_cascade_select.apply(this, arguments); + } + else { + if ( !( vals instanceof Array ) ) { + vals = [vals]; + } + + if ( arguments.length == 3 && (vals.length == 0 || (vals.length == 1 && vals[0] == '')) ) { + // no category, and the category is from a hierchical cf; + // leave it empty + jQuery(element).find('div').hide(); + } + else { + jQuery(element).find('div').hide().find('input').attr('disabled', 'disabled'); + jQuery(element).find('div[name=]').show().find('input').attr('disabled', ''); + jQuery(element).find('div.none').show().find('input').attr('disabled',''); + for ( var j = 0; j < vals.length; j++ ) { + jQuery(element).find('div[name^=' + vals[j] + ']').show().find('input').attr('disabled', ''); + } + } + } +} + +function filter_cascade_select (id, vals) { var select = document.getElementById(id); var complete_select = document.getElementById(id + "-Complete" ); + if ( !( vals instanceof Array ) ) { + vals = [vals]; + } if (!select) { return }; var i; var children = select.childNodes; if ( complete_select ) { - while (select.hasChildNodes()){ - select.removeChild(select.firstChild); - } + jQuery(select).children().remove(); var complete_children = complete_select.childNodes; - if ( val == '' && arguments.length == 3 ) { - // no category, and the category is from a hierchical cf; - // leave this set of options empty - } else if ( val == '' ) { - // no category, let's clone all node - for (i in complete_children) { - if ( complete_children[i].cloneNode ) { - new_option = complete_children[i].cloneNode(true); - select.appendChild(new_option); - } + var cloned_labels = {}; + var cloned_empty_label; + for ( var j = 0; j < vals.length; j++ ) { + var val = vals[j]; + if ( val == '' && arguments.length == 3 ) { + // no category, and the category is from a hierchical cf; + // leave this set of options empty + } else if ( val == '' ) { + // no category, let's clone all node + jQuery(select).append(jQuery(complete_children).clone()); + break; } - } - else { - for (i in complete_children) { - if (!complete_children[i].label || - (complete_children[i].hasAttribute && - !complete_children[i].hasAttribute('label') ) || - complete_children[i].label.substr(0, val.length) == val ) { - if ( complete_children[i].cloneNode ) { - new_option = complete_children[i].cloneNode(true); - select.appendChild(new_option); + else { + var labels_to_clone = {}; + for (i = 0; i < complete_children.length; i++) { + if (!complete_children[i].label || + (complete_children[i].hasAttribute && + !complete_children[i].hasAttribute('label') ) ) { + if ( cloned_empty_label ) { + continue; + } } + else if ( complete_children[i].label.substr(0, val.length) == val ) { + if ( cloned_labels[complete_children[i].label] ) { + continue; + } + labels_to_clone[complete_children[i].label] = true; + } + else { + continue; + } + + jQuery(select).append(jQuery(complete_children[i]).clone()); + } + + if ( !cloned_empty_label ) + cloned_empty_label = true; + + for ( label in labels_to_clone ) { + if ( !cloned_labels[label] ) + cloned_labels[label] = true; } } } } else { // for back compatibility - for (i in children) { + for (i = 0; i < children.length; i++) { if (!children[i].label) { continue }; if ( val == '' && arguments.length == 3 ) { hide(children[i]); diff --git a/rt/share/html/NoAuth/js/combobox.js b/rt/share/html/NoAuth/js/combobox.js index 51dded95e..27fa3881e 100644 --- a/rt/share/html/NoAuth/js/combobox.js +++ b/rt/share/html/NoAuth/js/combobox.js @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/js/dhandler b/rt/share/html/NoAuth/js/dhandler index 5e0ef1570..8059cd75c 100644 --- a/rt/share/html/NoAuth/js/dhandler +++ b/rt/share/html/NoAuth/js/dhandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/js/history-folding.js b/rt/share/html/NoAuth/js/history-folding.js index 629ec739a..c4e441878 100644 --- a/rt/share/html/NoAuth/js/history-folding.js +++ b/rt/share/html/NoAuth/js/history-folding.js @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/js/jquery-ui-patch-datepicker.js b/rt/share/html/NoAuth/js/jquery-ui-patch-datepicker.js index b9e5a7789..4b2183293 100644 --- a/rt/share/html/NoAuth/js/jquery-ui-patch-datepicker.js +++ b/rt/share/html/NoAuth/js/jquery-ui-patch-datepicker.js @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/js/jquery_noconflict.js b/rt/share/html/NoAuth/js/jquery_noconflict.js index 87fe06cb3..b71b1cdd8 100644 --- a/rt/share/html/NoAuth/js/jquery_noconflict.js +++ b/rt/share/html/NoAuth/js/jquery_noconflict.js @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/js/late.js b/rt/share/html/NoAuth/js/late.js index 37ba9513e..763f2c15d 100644 --- a/rt/share/html/NoAuth/js/late.js +++ b/rt/share/html/NoAuth/js/late.js @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/js/titlebox-state.js b/rt/share/html/NoAuth/js/titlebox-state.js index 6e410939b..b8399a8dd 100644 --- a/rt/share/html/NoAuth/js/titlebox-state.js +++ b/rt/share/html/NoAuth/js/titlebox-state.js @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/NoAuth/js/userautocomplete.js b/rt/share/html/NoAuth/js/userautocomplete.js index 3c3f5fe07..b2b0f765a 100644 --- a/rt/share/html/NoAuth/js/userautocomplete.js +++ b/rt/share/html/NoAuth/js/userautocomplete.js @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -105,6 +105,22 @@ jQuery(function() { if (queryargs.length) options.source += "?" + queryargs.join("&"); - jQuery(input).autocomplete(options); + jQuery(input) + .addClass('autocompletes-user') + .autocomplete(options) + .data("autocomplete") + ._renderItem = function(ul, item) { + var rendered = jQuery("<a/>"); + + if (item.html == null) + rendered.text( item.label ); + else + rendered.html( item.html ); + + return jQuery("<li/>") + .data( "item.autocomplete", item ) + .append( rendered ) + .appendTo( ul ); + }; } }); diff --git a/rt/share/html/NoAuth/js/util.js b/rt/share/html/NoAuth/js/util.js index a267940ae..cc6e27535 100644 --- a/rt/share/html/NoAuth/js/util.js +++ b/rt/share/html/NoAuth/js/util.js @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -273,7 +273,7 @@ function textToHTML(value) { .replace(/\n/g, "\n<br />"); }; -function ReplaceAllTextareas(encoded) { +function ReplaceAllTextareas() { var sAgent = navigator.userAgent.toLowerCase(); if (!CKEDITOR.env.isCompatible || sAgent.indexOf('iphone') != -1 || @@ -288,23 +288,12 @@ function ReplaceAllTextareas(encoded) { var textArea = allTextAreas[i]; if (jQuery(textArea).hasClass("messagebox")) { // Turn the original plain text content into HTML - if (encoded == 0) { + var type = jQuery("#"+textArea.name+"Type"); + if (type.val() != "text/html") textArea.value = textToHTML(textArea.value); - } - // For this javascript - var CKeditorEncoded = document.createElement('input'); - CKeditorEncoded.setAttribute('type', 'hidden'); - CKeditorEncoded.setAttribute('name', 'CKeditorEncoded'); - CKeditorEncoded.setAttribute('value', '1'); - textArea.parentNode.appendChild(CKeditorEncoded); - - // For fckeditor - var typeField = document.createElement('input'); - typeField.setAttribute('type', 'hidden'); - typeField.setAttribute('name', textArea.name + 'Type'); - typeField.setAttribute('value', 'text/html'); - textArea.parentNode.appendChild(typeField); + // Set the type + type.val("text/html"); CKEDITOR.replace(textArea.name,{width:'100%',height:<% RT->Config->Get('MessageBoxRichTextHeight') |n,j%>}); CKEDITOR.basePath = <%RT->Config->Get('WebPath')|n,j%>+"/NoAuth/RichText/"; @@ -336,6 +325,16 @@ function update_addprincipal_title(title) { // when a value is selected from the autocompleter function addprincipal_onselect(ev, ui) { + + // if principal link exists, we shall go there instead + var principal_link = jQuery(ev.target).closest('form').find('ul.ui-tabs-nav a[href="#acl-' + ui.item.id + '"]:first'); + if (principal_link.size()) { + jQuery(this).val('').blur(); + update_addprincipal_title( '' ); // reset title to blank for #acl-AddPrincipal + principal_link.click(); + return false; + } + // pass the item's value along as the title since the input's value // isn't actually updated yet toggle_addprincipal_validity(this, true, ui.item.value); diff --git a/rt/share/html/NoAuth/rss/dhandler b/rt/share/html/NoAuth/rss/dhandler index b8057e730..4bc69aba4 100644 --- a/rt/share/html/NoAuth/rss/dhandler +++ b/rt/share/html/NoAuth/rss/dhandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Prefs/MyRT.html b/rt/share/html/Prefs/MyRT.html index 61a7e6c51..a595ccf78 100644 --- a/rt/share/html/Prefs/MyRT.html +++ b/rt/share/html/Prefs/MyRT.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Prefs/Other.html b/rt/share/html/Prefs/Other.html index 9a04cc2aa..15f5dfd30 100644 --- a/rt/share/html/Prefs/Other.html +++ b/rt/share/html/Prefs/Other.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Prefs/Quicksearch.html b/rt/share/html/Prefs/Quicksearch.html index cb4292a25..a6791b840 100644 --- a/rt/share/html/Prefs/Quicksearch.html +++ b/rt/share/html/Prefs/Quicksearch.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Prefs/Search.html b/rt/share/html/Prefs/Search.html index 9e62f68dd..bb52a6212 100644 --- a/rt/share/html/Prefs/Search.html +++ b/rt/share/html/Prefs/Search.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Prefs/SearchOptions.html b/rt/share/html/Prefs/SearchOptions.html index 67067ffd6..029e13f21 100644 --- a/rt/share/html/Prefs/SearchOptions.html +++ b/rt/share/html/Prefs/SearchOptions.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/REST/1.0/Forms/attachment/default b/rt/share/html/REST/1.0/Forms/attachment/default index 80039cee2..8c6cf3ec8 100644 --- a/rt/share/html/REST/1.0/Forms/attachment/default +++ b/rt/share/html/REST/1.0/Forms/attachment/default @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/REST/1.0/Forms/group/customfields b/rt/share/html/REST/1.0/Forms/group/customfields index 1dba6ccd8..5fb4730b0 100644 --- a/rt/share/html/REST/1.0/Forms/group/customfields +++ b/rt/share/html/REST/1.0/Forms/group/customfields @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/REST/1.0/Forms/group/default b/rt/share/html/REST/1.0/Forms/group/default index 8867bf938..ffbd9dbf3 100644 --- a/rt/share/html/REST/1.0/Forms/group/default +++ b/rt/share/html/REST/1.0/Forms/group/default @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -156,7 +156,7 @@ if (%data == 0) { } else { my ($get, $set, $key, $val, $n, $s); - + my $updated; foreach $key (keys %data) { $val = $data{$key}; $key = lc $key; @@ -192,9 +192,12 @@ else { $k = $changes; } } + else { + $updated ||= 1; + } } - push(@comments, "# Group $id updated.") unless $n == 0; + push(@comments, "# Group $id updated.") if $updated; } DONE: diff --git a/rt/share/html/REST/1.0/Forms/group/ns b/rt/share/html/REST/1.0/Forms/group/ns index 907324de5..c993db8b6 100644 --- a/rt/share/html/REST/1.0/Forms/group/ns +++ b/rt/share/html/REST/1.0/Forms/group/ns @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/REST/1.0/Forms/queue/customfields b/rt/share/html/REST/1.0/Forms/queue/customfields index 9ebabb065..79ab07531 100644 --- a/rt/share/html/REST/1.0/Forms/queue/customfields +++ b/rt/share/html/REST/1.0/Forms/queue/customfields @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/REST/1.0/Forms/queue/default b/rt/share/html/REST/1.0/Forms/queue/default index 58bb89953..48e4fba7f 100755 --- a/rt/share/html/REST/1.0/Forms/queue/default +++ b/rt/share/html/REST/1.0/Forms/queue/default @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -146,7 +146,7 @@ if ( keys %data == 0) { } else { my ($get, $set, $key, $val, $n, $s); - + my $updated; foreach $key (keys %data) { $val = $data{$key}; $key = lc $key; @@ -175,9 +175,12 @@ else { $k = $changes; } } + else { + $updated ||= 1; + } } - push(@comments, "# Queue $id updated.") unless $n == 0; + push(@comments, "# Queue $id updated.") if $updated; } DONE: diff --git a/rt/share/html/REST/1.0/Forms/queue/ns b/rt/share/html/REST/1.0/Forms/queue/ns index 3ea6bf261..5a3e09f8a 100755 --- a/rt/share/html/REST/1.0/Forms/queue/ns +++ b/rt/share/html/REST/1.0/Forms/queue/ns @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/REST/1.0/Forms/queue/ticketcustomfields b/rt/share/html/REST/1.0/Forms/queue/ticketcustomfields index c38f3beb3..038f1881d 100644 --- a/rt/share/html/REST/1.0/Forms/queue/ticketcustomfields +++ b/rt/share/html/REST/1.0/Forms/queue/ticketcustomfields @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/REST/1.0/Forms/ticket/attachments b/rt/share/html/REST/1.0/Forms/ticket/attachments index ba3a24825..43df839af 100755 --- a/rt/share/html/REST/1.0/Forms/ticket/attachments +++ b/rt/share/html/REST/1.0/Forms/ticket/attachments @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/REST/1.0/Forms/ticket/comment b/rt/share/html/REST/1.0/Forms/ticket/comment index b50135fec..934cbfb68 100755 --- a/rt/share/html/REST/1.0/Forms/ticket/comment +++ b/rt/share/html/REST/1.0/Forms/ticket/comment @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -53,10 +53,7 @@ $id </%ARGS> <%INIT> use MIME::Entity; -use LWP::MediaTypes; use RT::Interface::REST; -use File::Temp qw(tempfile); -my @tmp_files; $RT::Logger->debug("Got ticket id=$id for comment"); $RT::Logger->debug("Got args @{[keys(%changes)]}."); @@ -89,44 +86,23 @@ if (!$changes{Text} && @atts == 0) { goto OUTPUT; } -my $cgi = $m->cgi_object; my $ent = MIME::Entity->build( Type => "multipart/mixed", 'X-RT-Interface' => 'REST', ); -$ent->attach(Data => $changes{Text}) if $changes{Text}; +$ent->attach( + 'Content-Type' => $changes{'Content-Type'} || 'text/plain', + Data => $changes{Text}, +) if $changes{Text}; -my $i = 1; -foreach my $att (@atts) { - local $/=undef; - my $file = $att; - $file =~ s#^.*[\\/]##; - my $fh = $cgi->upload("attachment_$i"); - if ($fh) { - my $buf; - my ($w, $tmp) = tempfile(); - my $info = $cgi->uploadInfo($fh); - push @tmp_files, $tmp; - - while (sysread($fh, $buf, 8192)) { - syswrite($w, $buf); - } - - $ent->attach( - Path => $tmp, - Type => $info->{'Content-Type'} || guess_media_type($tmp), - Filename => $file, - Disposition => "attachment" - ); - } - else { +{ + my ($status, $msg) = process_attachments($ent, @atts); + unless ( $status ) { $e = 1; - $c = "# No attachment for $att."; + $c = "# $msg"; goto OUTPUT; } - - $i++; } unless ($ticket->CurrentUserHasRight('ModifyTicket') || @@ -154,6 +130,5 @@ if ($changes{Status}) { OUTPUT: -unlink @tmp_files; return [ $c, $o, $k, $e ]; </%INIT> diff --git a/rt/share/html/REST/1.0/Forms/ticket/default b/rt/share/html/REST/1.0/Forms/ticket/default index 0bced1e99..2a0c7efa4 100755 --- a/rt/share/html/REST/1.0/Forms/ticket/default +++ b/rt/share/html/REST/1.0/Forms/ticket/default @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -67,7 +67,7 @@ my @dates = qw(Created Starts Started Due Resolved Told LastUpdated); my @people = qw(Requestors Cc AdminCc); my @create = qw(Queue Requestor Subject Cc AdminCc Owner Status Priority InitialPriority FinalPriority TimeEstimated TimeWorked - TimeLeft Starts Started Due Resolved); + TimeLeft Starts Started Due Resolved Content-Type); my @simple = qw(Subject Status Priority Disabled TimeEstimated TimeWorked TimeLeft InitialPriority FinalPriority); my %dates = map {lc $_ => $_} @dates; @@ -82,7 +82,7 @@ if ($id ne 'new') { return [ "# Ticket $id does not exist.", [], {}, 1 ]; } elsif ( %data ) { - if ( $data{status} && $data{status} eq 'deleted' && ! grep { $_ ne 'id' && $_ ne 'status' } keys %data ) { + if ( $data{status} && lc $data{status} eq 'deleted' && ! grep { $_ ne 'id' && $_ ne 'status' } keys %data ) { if ( !$ticket->CurrentUserHasRight('DeleteTicket') ) { return [ "# You are not allowed to delete ticket $id.", [], {}, 1 ]; } @@ -110,7 +110,7 @@ else { return [ "# Required: id, Queue", [ qw(id Queue Requestor Subject Cc AdminCc Owner Status Priority - InitialPriority FinalPriority TimeEstimated Starts Due Text) ], + InitialPriority FinalPriority TimeEstimated Starts Due Attachment Text) ], { id => "ticket/new", Queue => $queue->Name, @@ -126,6 +126,7 @@ else { TimeEstimated => 0, Starts => $starts->ISO, Due => $due->ISO, + Attachment => '', Text => "", }, 0 @@ -134,7 +135,7 @@ else { else { # We'll create a new ticket, and fall through to set fields that # can't be set in the call to Create(). - my (%v, $text); + my (%v, $text, @atts); foreach my $k (keys %data) { # flexibly parse any dates @@ -167,6 +168,9 @@ else { elsif (lc $k eq 'text') { $text = delete $data{$k}; } + elsif (lc $k eq 'attachment') { + push @atts, @{ vsplit(delete $data{$k}) }; + } elsif ( $k !~ /^(?:id|requestors)$/i ) { $e = 1; push @$o, $k; @@ -183,14 +187,24 @@ else { # people fields allow multiple values $v{$_} = vsplit($v{$_}) foreach ( grep $create{lc $_}, @people ); - if ($text) { + if ($text || @atts) { $v{MIMEObj} = MIME::Entity->build( + Type => "multipart/mixed", From => $session{CurrentUser}->EmailAddress, Subject => $v{Subject}, - Data => $text, 'X-RT-Interface' => 'REST', ); + $v{MIMEObj}->attach( + Data => $text, + 'Content-Type' => $v{'Content-Type'} || 'text/plain', + ) if $text; + my ($status, $msg) = process_attachments($v{'MIMEObj'}, @atts); + unless ($status) { + push(@comments, "# $msg"); + goto DONE; + } + $v{MIMEObj}->make_singlepart; } my($tid,$trid,$terr) = $ticket->Create(%v); @@ -279,6 +293,7 @@ if (!keys(%data)) { } else { my ($get, $set, $key, $val, $n, $s); + my $updated; foreach $key (keys %data) { $val = $data{$key}; @@ -416,14 +431,14 @@ else { $s =~ s/\\'/'/g; push @new, $s; } - elsif ( $a =~ /^q{/ ) { + elsif ( $a =~ /^q\{/ ) { my $s = $a; - while ( $a !~ /}$/ ) { + while ( $a !~ /\}$/ ) { ( $a, $b ) = split /\s*,\s*/, $b, 2; $s .= ',' . $a; } - $s =~ s/^q{//; - $s =~ s/}//; + $s =~ s/^q\{//; + $s =~ s/\}//; push @new, $s; } else { @@ -454,7 +469,7 @@ else { } } } - elsif ($key ne 'id' && $key ne 'type' && $key ne 'creator') { + elsif ($key ne 'id' && $key ne 'type' && $key ne 'creator' && $key ne 'content-type' ) { $n = 0; $s = "Unknown field."; } @@ -469,8 +484,11 @@ else { $k = $changes; } } + else { + $updated ||= 1; + } } - push(@comments, "# Ticket ".$ticket->id." updated.") unless $n == 0; + push(@comments, "# Ticket ".$ticket->id." updated.") if $updated; } DONE: diff --git a/rt/share/html/REST/1.0/Forms/ticket/history b/rt/share/html/REST/1.0/Forms/ticket/history index ec4f08150..debfcc85c 100755 --- a/rt/share/html/REST/1.0/Forms/ticket/history +++ b/rt/share/html/REST/1.0/Forms/ticket/history @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/REST/1.0/Forms/ticket/links b/rt/share/html/REST/1.0/Forms/ticket/links index 32e072457..45b14d015 100755 --- a/rt/share/html/REST/1.0/Forms/ticket/links +++ b/rt/share/html/REST/1.0/Forms/ticket/links @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/REST/1.0/Forms/ticket/merge b/rt/share/html/REST/1.0/Forms/ticket/merge index db25bdfe2..fdc224423 100755 --- a/rt/share/html/REST/1.0/Forms/ticket/merge +++ b/rt/share/html/REST/1.0/Forms/ticket/merge @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/REST/1.0/Forms/ticket/take b/rt/share/html/REST/1.0/Forms/ticket/take index e30cd84b6..b5a536270 100755 --- a/rt/share/html/REST/1.0/Forms/ticket/take +++ b/rt/share/html/REST/1.0/Forms/ticket/take @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/REST/1.0/Forms/transaction/default b/rt/share/html/REST/1.0/Forms/transaction/default index 2cc10d1aa..adcf3438f 100644 --- a/rt/share/html/REST/1.0/Forms/transaction/default +++ b/rt/share/html/REST/1.0/Forms/transaction/default @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/REST/1.0/Forms/user/default b/rt/share/html/REST/1.0/Forms/user/default index c11263693..046154768 100755 --- a/rt/share/html/REST/1.0/Forms/user/default +++ b/rt/share/html/REST/1.0/Forms/user/default @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -136,7 +136,7 @@ if (keys %data == 0) { } else { my ($get, $set, $key, $val, $n, $s); - + my $updated; foreach $key (keys %data) { $val = $data{$key}; $key = lc $key; @@ -177,9 +177,12 @@ else { $k = $changes; } } + else { + $updated ||= 1; + } } - push(@comments, "# User $id updated.") unless $n == 0; + push(@comments, "# User $id updated.") if $updated; } DONE: diff --git a/rt/share/html/REST/1.0/Forms/user/ns b/rt/share/html/REST/1.0/Forms/user/ns index 161372493..84a668503 100755 --- a/rt/share/html/REST/1.0/Forms/user/ns +++ b/rt/share/html/REST/1.0/Forms/user/ns @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/REST/1.0/NoAuth/mail-gateway b/rt/share/html/REST/1.0/NoAuth/mail-gateway index dec5ce71f..cd4271417 100755 --- a/rt/share/html/REST/1.0/NoAuth/mail-gateway +++ b/rt/share/html/REST/1.0/NoAuth/mail-gateway @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/REST/1.0/autohandler b/rt/share/html/REST/1.0/autohandler index b50bf6aac..03f70e052 100755 --- a/rt/share/html/REST/1.0/autohandler +++ b/rt/share/html/REST/1.0/autohandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/REST/1.0/dhandler b/rt/share/html/REST/1.0/dhandler index 49a28c636..7ade8fa53 100755 --- a/rt/share/html/REST/1.0/dhandler +++ b/rt/share/html/REST/1.0/dhandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/REST/1.0/logout b/rt/share/html/REST/1.0/logout index 4ce4d8294..4dbb098bd 100755 --- a/rt/share/html/REST/1.0/logout +++ b/rt/share/html/REST/1.0/logout @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/REST/1.0/search/dhandler b/rt/share/html/REST/1.0/search/dhandler index 677a632f6..c247bd3ed 100755 --- a/rt/share/html/REST/1.0/search/dhandler +++ b/rt/share/html/REST/1.0/search/dhandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/REST/1.0/search/ticket b/rt/share/html/REST/1.0/search/ticket index a0e65d070..f7b8f4c5a 100755 --- a/rt/share/html/REST/1.0/search/ticket +++ b/rt/share/html/REST/1.0/search/ticket @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/REST/1.0/ticket/comment b/rt/share/html/REST/1.0/ticket/comment index 475e3a88d..4c058b6ab 100755 --- a/rt/share/html/REST/1.0/ticket/comment +++ b/rt/share/html/REST/1.0/ticket/comment @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -52,10 +52,7 @@ $content </%ARGS> <%INIT> use MIME::Entity; -use LWP::MediaTypes; use RT::Interface::REST; -use File::Temp qw(tempfile); -my @tmp_files; my $ticket = RT::Ticket->new($session{CurrentUser}); my $object = $r->path_info; @@ -113,37 +110,13 @@ my $ent = MIME::Entity->build( ); $ent->attach(Data => $k->{Text}) if $k->{Text}; -my $i = 1; -foreach my $att (@atts) { - local $/=undef; - my $file = $att; - $file =~ s#^.*[\\/]##; - - my $fh = $cgi->upload("attachment_$i"); - if ($fh) { - my $buf; - my ($w, $tmp) = tempfile(); - push @tmp_files, $tmp; - my $info = $cgi->uploadInfo(); - - while (sysread($fh, $buf, 8192)) { - syswrite($w, $buf); - } - - $ent->attach( - Path => $tmp, - Type => $info->{'Content-Type'} || guess_media_type($tmp), - Filename => $file, - Disposition => "attachment" - ); - } - else { +{ + my ($res, $msg) = process_attachments($ent, @atts); + unless ( $res ) { $status = "400 Bad Request"; - $output = "No attachment for $att.\n"; + $output = "$msg\n"; goto OUTPUT; } - - $i++; } $ticket->Load($object); @@ -177,7 +150,6 @@ if ($k->{Status}) { OUTPUT: -unlink @tmp_files; </%INIT> RT/<% $RT::VERSION %> <% $status %> diff --git a/rt/share/html/REST/1.0/ticket/link b/rt/share/html/REST/1.0/ticket/link index 0b8b50692..023dc81db 100755 --- a/rt/share/html/REST/1.0/ticket/link +++ b/rt/share/html/REST/1.0/ticket/link @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/REST/1.0/ticket/merge b/rt/share/html/REST/1.0/ticket/merge index 98cbaf7e4..ea96f6185 100755 --- a/rt/share/html/REST/1.0/ticket/merge +++ b/rt/share/html/REST/1.0/ticket/merge @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Search/Article.html b/rt/share/html/Search/Article.html index 619c4d869..dc4ad0a9f 100644 --- a/rt/share/html/Search/Article.html +++ b/rt/share/html/Search/Article.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Search/Build.html b/rt/share/html/Search/Build.html index ad680beee..9594771f0 100644 --- a/rt/share/html/Search/Build.html +++ b/rt/share/html/Search/Build.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -190,7 +190,7 @@ my @new_values = (); # Try to find if we're adding a clause foreach my $arg ( keys %ARGS ) { - next unless $arg =~ m/^ValueOf([\w\.]+|'CF.{.*?}')$/ + next unless $arg =~ m/^ValueOf([\w\.]+|'\w*CF\.\{.*?\}')$/ && ( ref $ARGS{$arg} eq "ARRAY" ? grep $_ ne '', @{ $ARGS{$arg} } : $ARGS{$arg} ne '' ); @@ -234,10 +234,10 @@ foreach my $arg ( keys %ARGS ) { $value = "'$value'"; } - if ($keyword =~ /^'CF\.{(.*)}'/) { - my $cf = $1; + if ($keyword =~ /^'(\w*CF)\.\{(.*)\}'/) { + my ($field, $cf) = ($1, $2); $cf =~ s/(['\\])/\\$1/g; - $keyword = "'CF.{$cf}'"; + $keyword = "'$field.{$cf}'"; } my $clause = { diff --git a/rt/share/html/Search/Bulk.html b/rt/share/html/Search/Bulk.html index 9fbbc4790..a215eac8e 100755 --- a/rt/share/html/Search/Bulk.html +++ b/rt/share/html/Search/Bulk.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -279,7 +279,6 @@ while ( my $ticket = $Tickets->Next ) { #Iterate through each ticket we've been handed my @linkresults; -my %queues; $Tickets->RedoSearch(); @@ -306,7 +305,6 @@ unless ( $ARGS{'AddMoreAttach'} ) { #Update the links $ARGS{'id'} = $Ticket->id; - $queues{ $Ticket->QueueObj->Id }++; my @updateresults = ProcessUpdateMessage( TicketObj => $Ticket, @@ -417,7 +415,7 @@ unless ( $ARGS{'AddMoreAttach'} ) { my $TxnCFs = RT::CustomFields->new( $session{CurrentUser} ); $TxnCFs->LimitToLookupType( RT::Transaction->CustomFieldLookupType ); -$TxnCFs->LimitToGlobalOrObjectId( sort keys %queues ); +$TxnCFs->LimitToGlobalOrObjectId( keys %$seen_queues ); </%INIT> <%args> diff --git a/rt/share/html/Search/Chart b/rt/share/html/Search/Chart index 5d1ec6447..4be28abd6 100644 --- a/rt/share/html/Search/Chart +++ b/rt/share/html/Search/Chart @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Search/Chart.html b/rt/share/html/Search/Chart.html index 6ec578945..952f09cf4 100644 --- a/rt/share/html/Search/Chart.html +++ b/rt/share/html/Search/Chart.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -51,11 +51,13 @@ $ChartStyle => 'bars' $Description => undef </%args> <%init> +$m->callback( ARGSRef => \%ARGS, CallbackName => 'Initial' ); + $ARGS{Query} ||= 'id > 0'; # FIXME: should be factored with RT::Report::Tickets::Label :( my $PrimaryGroupByLabel; -if ( $PrimaryGroupBy =~ /^(?:CF|CustomField)\.{(.*)}$/ ) { +if ( $PrimaryGroupBy =~ /^(?:CF|CustomField)\.\{(.*)\}$/ ) { my $cf = $1; if ( $cf =~ /\D/ ) { $PrimaryGroupByLabel = loc( "custom field '[_1]'", $cf ); @@ -97,8 +99,8 @@ my %query; ); for(@session_fields) { - $query{$_} = $current->{$_} unless defined $query{$_}; $query{$_} = $DECODED_ARGS->{$_} unless defined $query{$_}; + $query{$_} = $current->{$_} unless defined $query{$_}; } if ($DECODED_ARGS->{'SavedSearchLoadSubmit'}) { @@ -111,12 +113,18 @@ my %query; } +$m->callback( ARGSRef => \%ARGS, QueryArgsRef => \%query ); </%init> <& /Elements/Header, Title => $title &> <& /Elements/Tabs, QueryArgs => \%query &> <& /Elements/ListActions, actions => \@actions &> + +% $m->callback( ARGSRef => \%ARGS, CallbackName => 'BeforeChart' ); + <& /Search/Elements/Chart, %ARGS &> +% $m->callback( ARGSRef => \%ARGS, CallbackName => 'AfterChart' ); + <div class="chart-meta"> <div class="chart-type"> <&| /Widgets/TitleBox, title => loc('Chart Properties')&> diff --git a/rt/share/html/Search/Edit.html b/rt/share/html/Search/Edit.html index 3c0ec684f..238989f49 100755 --- a/rt/share/html/Search/Edit.html +++ b/rt/share/html/Search/Edit.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Search/Elements/Article b/rt/share/html/Search/Elements/Article index 73404b925..ca12d586e 100644 --- a/rt/share/html/Search/Elements/Article +++ b/rt/share/html/Search/Elements/Article @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Search/Elements/BuildFormatString b/rt/share/html/Search/Elements/BuildFormatString index 6bc12f438..14e3a7105 100644 --- a/rt/share/html/Search/Elements/BuildFormatString +++ b/rt/share/html/Search/Elements/BuildFormatString @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -129,22 +129,11 @@ $m->callback( Fields => \@fields, ARGSRef => \%ARGS ); my ( @seen); $Format ||= RT->Config->Get('DefaultSearchResultFormat'); -my @format = split( /,\s*/, $Format ); +my @format = $m->comp('/Elements/CollectionAsTable/ParseFormat', Format => $Format); foreach my $field (@format) { - my %column = (); - $field =~ s/'(.*)'/$1/; - my ( $prefix, $suffix ); - if ( $field =~ m/(.*)__(.*)__(.*)/ ) { - $prefix = $1; - $suffix = $3; - $field = $2; - } - $field = "<blank>" if !$field; - $column{Prefix} = $prefix; - $column{Suffix} = $suffix; - $field =~ s/\s*(.*)\s*/$1/; - $column{Column} = $field; - push @seen, \%column; + # "title" is for columns like NEWLINE, which doesn't have "attribute" + $field->{Column} = $field->{attribute} || $field->{title} || '<blank>'; + push @seen, $field; } if ( $RemoveCol ) { @@ -237,12 +226,18 @@ elsif ( $ColDown ) { my @format_string; foreach my $field (@seen) { next unless $field; - my $row = "'"; - $row .= $field->{'Prefix'} if defined $field->{'Prefix'}; - $row .= "__$field->{'Column'}__" - unless ( $field->{'Column'} eq "<blank>" ); - $row .= $field->{'Suffix'} if defined $field->{'Suffix'}; - $row .= "'"; + my $row = ""; + if ( $field->{'output'} ) { + $row = join '', @{$field->{'output'}}; + } + else { + $row .= $field->{'Prefix'} if defined $field->{'Prefix'}; + $row .= "__$field->{'Column'}__" + unless ( $field->{'Column'} eq "<blank>" ); + $row .= $field->{'Suffix'} if defined $field->{'Suffix'}; + } + $row =~ s!([\\'])!\\$1!g; + $row = "'$row'"; push( @format_string, $row ); } diff --git a/rt/share/html/Search/Elements/Chart b/rt/share/html/Search/Elements/Chart index 734390031..05a0422b1 100644 --- a/rt/share/html/Search/Elements/Chart +++ b/rt/share/html/Search/Elements/Chart @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Search/Elements/ConditionRow b/rt/share/html/Search/Elements/ConditionRow index 1741326ce..046b3b1ea 100644 --- a/rt/share/html/Search/Elements/ConditionRow +++ b/rt/share/html/Search/Elements/ConditionRow @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Search/Elements/DisplayOptions b/rt/share/html/Search/Elements/DisplayOptions index fb4a6af1c..47224a911 100644 --- a/rt/share/html/Search/Elements/DisplayOptions +++ b/rt/share/html/Search/Elements/DisplayOptions @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Search/Elements/EditFormat b/rt/share/html/Search/Elements/EditFormat index c3491fcfa..58de19780 100644 --- a/rt/share/html/Search/Elements/EditFormat +++ b/rt/share/html/Search/Elements/EditFormat @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Search/Elements/EditQuery b/rt/share/html/Search/Elements/EditQuery index 6fef3a994..5d312002e 100644 --- a/rt/share/html/Search/Elements/EditQuery +++ b/rt/share/html/Search/Elements/EditQuery @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Search/Elements/EditSearches b/rt/share/html/Search/Elements/EditSearches index 372a20fb8..ae8d45c67 100644 --- a/rt/share/html/Search/Elements/EditSearches +++ b/rt/share/html/Search/Elements/EditSearches @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Search/Elements/EditSort b/rt/share/html/Search/Elements/EditSort index 842384b90..087c81c8b 100644 --- a/rt/share/html/Search/Elements/EditSort +++ b/rt/share/html/Search/Elements/EditSort @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Search/Elements/Graph b/rt/share/html/Search/Elements/Graph index a9c7ba311..b4cfde05e 100644 --- a/rt/share/html/Search/Elements/Graph +++ b/rt/share/html/Search/Elements/Graph @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Search/Elements/NewListActions b/rt/share/html/Search/Elements/NewListActions index 41e581ea3..071b91f6e 100644 --- a/rt/share/html/Search/Elements/NewListActions +++ b/rt/share/html/Search/Elements/NewListActions @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Search/Elements/PickBasics b/rt/share/html/Search/Elements/PickBasics index 534b51d59..f02348140 100644 --- a/rt/share/html/Search/Elements/PickBasics +++ b/rt/share/html/Search/Elements/PickBasics @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Search/Elements/PickCFs b/rt/share/html/Search/Elements/PickCFs index 5d16b9c35..1c9f2a918 100644 --- a/rt/share/html/Search/Elements/PickCFs +++ b/rt/share/html/Search/Elements/PickCFs @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -49,14 +49,6 @@ <& ConditionRow, Condition => $_ &> % } <%INIT> -my $CustomFields = RT::CustomFields->new( $session{'CurrentUser'}); -foreach my $id (keys %queues) { - # Gotta load up the $queue object, since queues get stored by name now. - my $queue = RT::Queue->new($session{'CurrentUser'}); - $queue->Load($id); - $CustomFields->LimitToQueue($queue->Id) if $queue->Id; -} -$CustomFields->LimitToGlobal; $m->callback( CallbackName => 'MassageCustomFields', CustomFields => $CustomFields, @@ -66,7 +58,7 @@ $m->callback( my @lines; while ( my $CustomField = $CustomFields->Next ) { my %line; - $line{'Name'} = "'CF.{" . $CustomField->Name . "}'"; + $line{'Name'} = "'$TicketSQLField.{" . $CustomField->Name . "}'"; $line{'Field'} = $CustomField->Name; # Op @@ -120,4 +112,6 @@ $m->callback( Conditions => \@lines, Queues => \%queues ); <%ARGS> %queues => () +$CustomFields +$TicketSQLField => 'CF' </%ARGS> diff --git a/rt/share/html/Search/Elements/PickCriteria b/rt/share/html/Search/Elements/PickCriteria index f821da292..797aa6c40 100644 --- a/rt/share/html/Search/Elements/PickCriteria +++ b/rt/share/html/Search/Elements/PickCriteria @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -50,10 +50,11 @@ <table width="100%" cellspacing="0" cellpadding="0" border="0"> - +% $m->callback( %ARGS, CallbackName => "BeforeBasics" ); <& PickBasics &> <& PickCustomerFields &> -<& PickCFs, queues => \%queues &> +<& PickTicketCFs, queues => \%queues &> +% $m->callback( %ARGS, CallbackName => "AfterCFs" ); <tr class="separator"><td colspan="3"><hr /></td></tr> <tr> diff --git a/rt/share/html/Search/Elements/ResultsRSSView b/rt/share/html/Search/Elements/ResultsRSSView index a6d634ddd..d08771124 100644 --- a/rt/share/html/Search/Elements/ResultsRSSView +++ b/rt/share/html/Search/Elements/ResultsRSSView @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Search/Elements/SearchPrivacy b/rt/share/html/Search/Elements/SearchPrivacy index 31ad2046d..d8e40c815 100644 --- a/rt/share/html/Search/Elements/SearchPrivacy +++ b/rt/share/html/Search/Elements/SearchPrivacy @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Search/Elements/SearchesForObject b/rt/share/html/Search/Elements/SearchesForObject index db5fc8f76..34894918c 100644 --- a/rt/share/html/Search/Elements/SearchesForObject +++ b/rt/share/html/Search/Elements/SearchesForObject @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Search/Elements/SelectAndOr b/rt/share/html/Search/Elements/SelectAndOr index fe164d778..fa176ddc3 100644 --- a/rt/share/html/Search/Elements/SelectAndOr +++ b/rt/share/html/Search/Elements/SelectAndOr @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Search/Elements/SelectChartType b/rt/share/html/Search/Elements/SelectChartType index 77af786e2..1e8f2eca9 100644 --- a/rt/share/html/Search/Elements/SelectChartType +++ b/rt/share/html/Search/Elements/SelectChartType @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Search/Elements/SelectGroup b/rt/share/html/Search/Elements/SelectGroup index 42a9c3792..6392ac4e4 100644 --- a/rt/share/html/Search/Elements/SelectGroup +++ b/rt/share/html/Search/Elements/SelectGroup @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Search/Elements/SelectGroupBy b/rt/share/html/Search/Elements/SelectGroupBy index 8b436c854..08a4ec36d 100644 --- a/rt/share/html/Search/Elements/SelectGroupBy +++ b/rt/share/html/Search/Elements/SelectGroupBy @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Search/Elements/SelectLinks b/rt/share/html/Search/Elements/SelectLinks index 78e24451f..fae3379ec 100644 --- a/rt/share/html/Search/Elements/SelectLinks +++ b/rt/share/html/Search/Elements/SelectLinks @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Search/Elements/SelectPersonType b/rt/share/html/Search/Elements/SelectPersonType index 70df7ba26..a59571563 100644 --- a/rt/share/html/Search/Elements/SelectPersonType +++ b/rt/share/html/Search/Elements/SelectPersonType @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Search/Elements/SelectSearchObject b/rt/share/html/Search/Elements/SelectSearchObject index 24014fcd5..b9e0d1944 100644 --- a/rt/share/html/Search/Elements/SelectSearchObject +++ b/rt/share/html/Search/Elements/SelectSearchObject @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Search/Elements/SelectSearchesForObjects b/rt/share/html/Search/Elements/SelectSearchesForObjects index 13603d6bd..1fa1e2783 100644 --- a/rt/share/html/Search/Elements/SelectSearchesForObjects +++ b/rt/share/html/Search/Elements/SelectSearchesForObjects @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Search/Graph.html b/rt/share/html/Search/Graph.html index 8ad557012..8b08e7d68 100644 --- a/rt/share/html/Search/Graph.html +++ b/rt/share/html/Search/Graph.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Search/Results.html b/rt/share/html/Search/Results.html index 13fa3c04f..601786f10 100755 --- a/rt/share/html/Search/Results.html +++ b/rt/share/html/Search/Results.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -52,6 +52,13 @@ % $m->callback( ARGSRef => \%ARGS, CallbackName => 'BeforeResults' ); +% unless ($ok) { +% $msg =~ s{ at .*? line .*}{}s; +<&| /Widgets/TitleBox, title => loc("Error"), class => "error" &> +<&|/l_unsafe, "<i>".$m->interp->apply_escapes($msg, "h")."</i>" &>There was an error parsing your search query: [_1]. Your RT admin can find more information in the error logs.</&> +</&> +% } else { + <& /Elements/CollectionList, Query => $Query, TotalFound => $ticketcount, @@ -65,6 +72,7 @@ BaseURL => $BaseURL &> +% } % $m->callback( ARGSRef => \%ARGS, CallbackName => 'AfterResults' ); % my %hiddens = (Query => $Query, Format => $Format, Rows => $Rows, OrderBy => $OrderBy, Order => $Order, HideResults => $HideResults, Page => $Page, SavedChartSearchId => $SavedChartSearchId ); diff --git a/rt/share/html/Search/Results.rdf b/rt/share/html/Search/Results.rdf index b8057e730..4bc69aba4 100644 --- a/rt/share/html/Search/Results.rdf +++ b/rt/share/html/Search/Results.rdf @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Search/Results.tsv b/rt/share/html/Search/Results.tsv index 0fa0fcd97..6d8253e78 100644 --- a/rt/share/html/Search/Results.tsv +++ b/rt/share/html/Search/Results.tsv @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Search/Simple.html b/rt/share/html/Search/Simple.html index cb56c83ea..ab3bc4760 100644 --- a/rt/share/html/Search/Simple.html +++ b/rt/share/html/Search/Simple.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -60,7 +60,7 @@ % my @strong = qw(<strong> </strong>); -<p><&|/l_unsafe, @strong &>Search for tickets by entering [_1]id[_2] numbers, subject words [_1]"in quotes"[_2], [_1]queues[_2] by name, Owners by [_1]username[_2], Requestors by [_1]email address[_2], and ticket [_1]statuses[_2].</&></p> +<p><&|/l_unsafe, @strong &>Search for tickets by entering [_1]id[_2] numbers, subject words [_1]"in quotes"[_2], [_1]queues[_2] by name, Owners by [_1]username[_2], Requestors by [_1]email address[_2], and ticket [_1]statuses[_2]. Searching for [_1]@domainname.com[_2] will return tickets with requestors from that domain.</&></p> <p><&|/l&>Any word not recognized by RT is searched for in ticket subjects.</&></p> diff --git a/rt/share/html/SelfService/Article/Display.html b/rt/share/html/SelfService/Article/Display.html index 93e8bcbc3..1d7a8045c 100644 --- a/rt/share/html/SelfService/Article/Display.html +++ b/rt/share/html/SelfService/Article/Display.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/SelfService/Article/Search.html b/rt/share/html/SelfService/Article/Search.html index 7e178d37f..f7692694c 100644 --- a/rt/share/html/SelfService/Article/Search.html +++ b/rt/share/html/SelfService/Article/Search.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/SelfService/Article/autohandler b/rt/share/html/SelfService/Article/autohandler index 3bb2c2b38..8b2c12a99 100644 --- a/rt/share/html/SelfService/Article/autohandler +++ b/rt/share/html/SelfService/Article/autohandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/SelfService/Attachment/dhandler b/rt/share/html/SelfService/Attachment/dhandler index 01b7bba76..0078d5b1a 100755 --- a/rt/share/html/SelfService/Attachment/dhandler +++ b/rt/share/html/SelfService/Attachment/dhandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/SelfService/Closed.html b/rt/share/html/SelfService/Closed.html index 13ca3a876..01b275b02 100755 --- a/rt/share/html/SelfService/Closed.html +++ b/rt/share/html/SelfService/Closed.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/SelfService/Create.html b/rt/share/html/SelfService/Create.html index 76126ae18..189595fc9 100755 --- a/rt/share/html/SelfService/Create.html +++ b/rt/share/html/SelfService/Create.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/SelfService/CreateTicketInQueue.html b/rt/share/html/SelfService/CreateTicketInQueue.html index 39020973e..e7df9473c 100755 --- a/rt/share/html/SelfService/CreateTicketInQueue.html +++ b/rt/share/html/SelfService/CreateTicketInQueue.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/SelfService/Display.html b/rt/share/html/SelfService/Display.html index 857ebfa98..9f51e3359 100755 --- a/rt/share/html/SelfService/Display.html +++ b/rt/share/html/SelfService/Display.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -50,6 +50,7 @@ % $m->callback(CallbackName => 'BeforeActionList', %ARGS, Actions => \@results, ARGSRef => \%ARGS, Ticket => $Ticket ); <& /Elements/ListActions, actions => \@results &> +<& /Ticket/Elements/ShowUpdateStatus, Ticket => $Ticket &> <table width="100%" class="ticketsummary" > <tr> @@ -177,16 +178,22 @@ if ( defined ($id[0]) && $id[0] eq 'new' ) { $m->abort(); } - if (@results) { - # We've done something, so we need to clear the decks to avoid - # resubmission on refresh. - # But we need to store Actions somewhere too, so we don't lose them. - my $key = Digest::MD5::md5_hex(rand(1024)); - push @{ $session{"Actions"}->{$key} ||= [] }, @results; - $session{'i'}++; - RT::Interface::Web::Redirect( RT->Config->Get('WebURL') ."SelfService/Display.html?id=". $Ticket->id."&results=".$key); + if ( $ARGS{'MarkAsSeen'} ) { + $Ticket->SetAttribute( + Name => 'User-'. $Ticket->CurrentUser->id .'-SeenUpTo', + Content => $Ticket->LastUpdated, + ); + push @results, loc('Marked all messages as seen'); } + # This code does automatic redirection if any updates happen. + MaybeRedirectForResults( + Actions => \@results, + Path => '/SelfService/Display.html', + Anchor => $ARGS{'Anchor'}, + Arguments => { id => $Ticket->id }, + ); + my $Transactions = $Ticket->Transactions; my $attachments = diff --git a/rt/share/html/SelfService/Elements/GotoTicket b/rt/share/html/SelfService/Elements/GotoTicket index 8d8dae07b..daabef4a2 100755 --- a/rt/share/html/SelfService/Elements/GotoTicket +++ b/rt/share/html/SelfService/Elements/GotoTicket @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/SelfService/Elements/Header b/rt/share/html/SelfService/Elements/Header index 1aad1a791..dbc1fd113 100755 --- a/rt/share/html/SelfService/Elements/Header +++ b/rt/share/html/SelfService/Elements/Header @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/SelfService/Elements/MyRequests b/rt/share/html/SelfService/Elements/MyRequests index b6f8f8979..94b6a8853 100755 --- a/rt/share/html/SelfService/Elements/MyRequests +++ b/rt/share/html/SelfService/Elements/MyRequests @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/SelfService/Elements/SearchArticle b/rt/share/html/SelfService/Elements/SearchArticle index 1d0087695..749d083a2 100644 --- a/rt/share/html/SelfService/Elements/SearchArticle +++ b/rt/share/html/SelfService/Elements/SearchArticle @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/SelfService/Error.html b/rt/share/html/SelfService/Error.html index 0ee0b5d64..048b1dc27 100755 --- a/rt/share/html/SelfService/Error.html +++ b/rt/share/html/SelfService/Error.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/SelfService/Prefs.html b/rt/share/html/SelfService/Prefs.html index 6478ef206..602096c71 100755 --- a/rt/share/html/SelfService/Prefs.html +++ b/rt/share/html/SelfService/Prefs.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/SelfService/Update.html b/rt/share/html/SelfService/Update.html index cc5e496db..664cd3d4f 100755 --- a/rt/share/html/SelfService/Update.html +++ b/rt/share/html/SelfService/Update.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/SelfService/index.html b/rt/share/html/SelfService/index.html index ab43ab950..c30bf883a 100755 --- a/rt/share/html/SelfService/index.html +++ b/rt/share/html/SelfService/index.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Attachment/WithHeaders/dhandler b/rt/share/html/Ticket/Attachment/WithHeaders/dhandler index d9a94f270..17e70b36b 100644 --- a/rt/share/html/Ticket/Attachment/WithHeaders/dhandler +++ b/rt/share/html/Ticket/Attachment/WithHeaders/dhandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Attachment/dhandler b/rt/share/html/Ticket/Attachment/dhandler index 6dde34c37..9394fbc3f 100755 --- a/rt/share/html/Ticket/Attachment/dhandler +++ b/rt/share/html/Ticket/Attachment/dhandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Create.html b/rt/share/html/Ticket/Create.html index 6d84b036d..697db546b 100755 --- a/rt/share/html/Ticket/Create.html +++ b/rt/share/html/Ticket/Create.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -337,8 +337,14 @@ if ($CloneTicket) { while ( my $cf_value = $cf_values->Next ) { push @cf_values, $cf_value->Content; } - $clone->{"Object-RT::Ticket--CustomField-$cf_id-Value"} = join "\n", - @cf_values; + + if ( @cf_values > 1 && $cf->Type eq 'Select' ) { + $clone->{"Object-RT::Ticket--CustomField-$cf_id-Value"} = \@cf_values; + } + else { + $clone->{"Object-RT::Ticket--CustomField-$cf_id-Value"} = join "\n", + @cf_values; + } } # Pass customer links along (even though cloning of parent links diff --git a/rt/share/html/Ticket/Display.html b/rt/share/html/Ticket/Display.html index 0ff9e0b47..50df5982d 100755 --- a/rt/share/html/Ticket/Display.html +++ b/rt/share/html/Ticket/Display.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -242,6 +242,6 @@ if (defined $session{'tickets'} and ($ARGS{'Query'} or $session{'CurrentSearchHa $link_rel{first} = "Ticket/Display.html?id=" . $item_map->{first} if $item_map->{$TicketObj->Id}{prev}; $link_rel{prev} = "Ticket/Display.html?id=" . $item_map->{$TicketObj->Id}{prev} if $item_map->{$TicketObj->Id}{prev}; $link_rel{next} = "Ticket/Display.html?id=" . $item_map->{$TicketObj->Id}{next} if $item_map->{$TicketObj->Id}{next}; - $link_rel{last} = "Ticket/Display.html?id=" . $item_map->{last} if $item_map->{$TicketObj->Id}{next}; + $link_rel{last} = "Ticket/Display.html?id=" . $item_map->{last} if $item_map->{$TicketObj->Id}{next} && $item_map->{last}; } </%INIT> diff --git a/rt/share/html/Ticket/Elements/AddAttachments b/rt/share/html/Ticket/Elements/AddAttachments index d00a021af..9458bbb32 100644 --- a/rt/share/html/Ticket/Elements/AddAttachments +++ b/rt/share/html/Ticket/Elements/AddAttachments @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -49,7 +49,7 @@ <tr><td class="label"><&|/l&>Attached file</&>:</td> <td> <&|/l&>Check box to delete</&><br /> -% foreach my $attach_name (keys %{$session{'Attachments'}}) { +% foreach my $attach_name (sort keys %{$session{'Attachments'}}) { <input type="checkbox" class="checkbox" name="DeleteAttach-<%$attach_name%>" value="1" /><%$attach_name%><br /> % } # end of foreach </td> diff --git a/rt/share/html/Ticket/Elements/AddWatchers b/rt/share/html/Ticket/Elements/AddWatchers index 8e11ba28d..70fba86d1 100755 --- a/rt/share/html/Ticket/Elements/AddWatchers +++ b/rt/share/html/Ticket/Elements/AddWatchers @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/Bookmark b/rt/share/html/Ticket/Elements/Bookmark index b74da799f..e4bae8162 100644 --- a/rt/share/html/Ticket/Elements/Bookmark +++ b/rt/share/html/Ticket/Elements/Bookmark @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/BulkLinks b/rt/share/html/Ticket/Elements/BulkLinks index 3d9abeefe..1303b103d 100755 --- a/rt/share/html/Ticket/Elements/BulkLinks +++ b/rt/share/html/Ticket/Elements/BulkLinks @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/ClickToShowHistory b/rt/share/html/Ticket/Elements/ClickToShowHistory index b570fe683..fafffae5e 100644 --- a/rt/share/html/Ticket/Elements/ClickToShowHistory +++ b/rt/share/html/Ticket/Elements/ClickToShowHistory @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/EditBasics b/rt/share/html/Ticket/Elements/EditBasics index e7a16620f..9f597838c 100755 --- a/rt/share/html/Ticket/Elements/EditBasics +++ b/rt/share/html/Ticket/Elements/EditBasics @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -54,9 +54,10 @@ $InTable => 0 <%INIT> my $WillResolveObj = $TicketObj->WillResolveObj if defined $TicketObj; unless ( @fields ) { + my $subject = $defaults{'Subject'} || $TicketObj->Subject; @fields = ( { name => 'Subject', - html => '<input name="Subject" value="'.$m->interp->apply_escapes( $defaults{'Subject'} || $TicketObj->Subject, 'h' ).'" />', + html => '<input name="Subject" value="'.(defined($subject) ? $m->interp->apply_escapes( $subject, 'h' ) : '').'" />', }, { name => 'Status', comp => '/Elements/SelectStatus', diff --git a/rt/share/html/Ticket/Elements/EditCustomFields b/rt/share/html/Ticket/Elements/EditCustomFields index 237dcbf37..2eba6c81d 100755 --- a/rt/share/html/Ticket/Elements/EditCustomFields +++ b/rt/share/html/Ticket/Elements/EditCustomFields @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/EditDates b/rt/share/html/Ticket/Elements/EditDates index d0474fedb..0bb7693b8 100755 --- a/rt/share/html/Ticket/Elements/EditDates +++ b/rt/share/html/Ticket/Elements/EditDates @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/EditPeople b/rt/share/html/Ticket/Elements/EditPeople index adc48b7cd..9110aedd8 100755 --- a/rt/share/html/Ticket/Elements/EditPeople +++ b/rt/share/html/Ticket/Elements/EditPeople @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/EditTransactionCustomFields b/rt/share/html/Ticket/Elements/EditTransactionCustomFields index 961c7e16d..a52ecc349 100644 --- a/rt/share/html/Ticket/Elements/EditTransactionCustomFields +++ b/rt/share/html/Ticket/Elements/EditTransactionCustomFields @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/EditWatchers b/rt/share/html/Ticket/Elements/EditWatchers index 3bc6cd725..d87c6135b 100755 --- a/rt/share/html/Ticket/Elements/EditWatchers +++ b/rt/share/html/Ticket/Elements/EditWatchers @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/FindAttachments b/rt/share/html/Ticket/Elements/FindAttachments index 546b4b818..d69da612d 100644 --- a/rt/share/html/Ticket/Elements/FindAttachments +++ b/rt/share/html/Ticket/Elements/FindAttachments @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/FindTransactions b/rt/share/html/Ticket/Elements/FindTransactions index e0f13b9d4..ea6de3506 100644 --- a/rt/share/html/Ticket/Elements/FindTransactions +++ b/rt/share/html/Ticket/Elements/FindTransactions @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/FoldStanzaJS b/rt/share/html/Ticket/Elements/FoldStanzaJS index 581c963d9..8fa5c5f0f 100644 --- a/rt/share/html/Ticket/Elements/FoldStanzaJS +++ b/rt/share/html/Ticket/Elements/FoldStanzaJS @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/LoadTextAttachments b/rt/share/html/Ticket/Elements/LoadTextAttachments index 9321030b9..b36dd6178 100644 --- a/rt/share/html/Ticket/Elements/LoadTextAttachments +++ b/rt/share/html/Ticket/Elements/LoadTextAttachments @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/PreviewScrips b/rt/share/html/Ticket/Elements/PreviewScrips index e9e2fc963..3526f31a7 100755 --- a/rt/share/html/Ticket/Elements/PreviewScrips +++ b/rt/share/html/Ticket/Elements/PreviewScrips @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/Reminders b/rt/share/html/Ticket/Elements/Reminders index 37b360bd2..2896df970 100644 --- a/rt/share/html/Ticket/Elements/Reminders +++ b/rt/share/html/Ticket/Elements/Reminders @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -112,11 +112,11 @@ my $visible = 0; % } % } -% if ($Ticket->Status ne "deleted") { +% if (lc $Ticket->Status ne "deleted") { <&|/l&>New reminder:</&> <& SELF:NewReminder, Ticket => $Ticket &> % } -% return($Ticket->Status ne "deleted" or $visible); +% return(lc $Ticket->Status ne "deleted" or $visible); <%method NewReminder> <%args> $Ticket diff --git a/rt/share/html/Ticket/Elements/ShowAttachments b/rt/share/html/Ticket/Elements/ShowAttachments index c487fee51..0a03b9647 100755 --- a/rt/share/html/Ticket/Elements/ShowAttachments +++ b/rt/share/html/Ticket/Elements/ShowAttachments @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/ShowBasics b/rt/share/html/Ticket/Elements/ShowBasics index f329d5061..6d0006209 100755 --- a/rt/share/html/Ticket/Elements/ShowBasics +++ b/rt/share/html/Ticket/Elements/ShowBasics @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/ShowCustomFields b/rt/share/html/Ticket/Elements/ShowCustomFields index ad8f825cf..07c776901 100755 --- a/rt/share/html/Ticket/Elements/ShowCustomFields +++ b/rt/share/html/Ticket/Elements/ShowCustomFields @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/ShowDates b/rt/share/html/Ticket/Elements/ShowDates index 0d7591a65..586c5ee0b 100755 --- a/rt/share/html/Ticket/Elements/ShowDates +++ b/rt/share/html/Ticket/Elements/ShowDates @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/ShowDependencies b/rt/share/html/Ticket/Elements/ShowDependencies index 08056cb32..d7b189f44 100755 --- a/rt/share/html/Ticket/Elements/ShowDependencies +++ b/rt/share/html/Ticket/Elements/ShowDependencies @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/ShowGnuPGStatus b/rt/share/html/Ticket/Elements/ShowGnuPGStatus index d246954b9..4e66ea472 100644 --- a/rt/share/html/Ticket/Elements/ShowGnuPGStatus +++ b/rt/share/html/Ticket/Elements/ShowGnuPGStatus @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/ShowGroupMembers b/rt/share/html/Ticket/Elements/ShowGroupMembers index 046a4339d..66b5ff956 100644 --- a/rt/share/html/Ticket/Elements/ShowGroupMembers +++ b/rt/share/html/Ticket/Elements/ShowGroupMembers @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/ShowHistory b/rt/share/html/Ticket/Elements/ShowHistory index 610038d6f..eed513a4d 100755 --- a/rt/share/html/Ticket/Elements/ShowHistory +++ b/rt/share/html/Ticket/Elements/ShowHistory @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/ShowMembers b/rt/share/html/Ticket/Elements/ShowMembers index 7a217d7e5..3f805ef20 100755 --- a/rt/share/html/Ticket/Elements/ShowMembers +++ b/rt/share/html/Ticket/Elements/ShowMembers @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/ShowMessageHeaders b/rt/share/html/Ticket/Elements/ShowMessageHeaders index 1ae67171c..57280a227 100755 --- a/rt/share/html/Ticket/Elements/ShowMessageHeaders +++ b/rt/share/html/Ticket/Elements/ShowMessageHeaders @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/ShowMessageStanza b/rt/share/html/Ticket/Elements/ShowMessageStanza index 716bdfbf0..eddc916ed 100755 --- a/rt/share/html/Ticket/Elements/ShowMessageStanza +++ b/rt/share/html/Ticket/Elements/ShowMessageStanza @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/ShowParents b/rt/share/html/Ticket/Elements/ShowParents index ed7a0d4d3..9a6b4f90a 100644 --- a/rt/share/html/Ticket/Elements/ShowParents +++ b/rt/share/html/Ticket/Elements/ShowParents @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/ShowPeople b/rt/share/html/Ticket/Elements/ShowPeople index 23faf9bb4..4b1588430 100755 --- a/rt/share/html/Ticket/Elements/ShowPeople +++ b/rt/share/html/Ticket/Elements/ShowPeople @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/ShowPriority b/rt/share/html/Ticket/Elements/ShowPriority index 906538ad3..0dced0bc0 100644 --- a/rt/share/html/Ticket/Elements/ShowPriority +++ b/rt/share/html/Ticket/Elements/ShowPriority @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/ShowQueue b/rt/share/html/Ticket/Elements/ShowQueue index 118108f6d..5aefe9c4e 100644 --- a/rt/share/html/Ticket/Elements/ShowQueue +++ b/rt/share/html/Ticket/Elements/ShowQueue @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/ShowRequestor b/rt/share/html/Ticket/Elements/ShowRequestor index a82a24007..1323012dc 100755 --- a/rt/share/html/Ticket/Elements/ShowRequestor +++ b/rt/share/html/Ticket/Elements/ShowRequestor @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/ShowRequestorExtraInfo b/rt/share/html/Ticket/Elements/ShowRequestorExtraInfo index 0418a0011..f7ca458cd 100644 --- a/rt/share/html/Ticket/Elements/ShowRequestorExtraInfo +++ b/rt/share/html/Ticket/Elements/ShowRequestorExtraInfo @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/ShowRequestorTickets b/rt/share/html/Ticket/Elements/ShowRequestorTickets index b9f984a60..7bd17f183 100644 --- a/rt/share/html/Ticket/Elements/ShowRequestorTickets +++ b/rt/share/html/Ticket/Elements/ShowRequestorTickets @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/ShowRequestorTicketsActive b/rt/share/html/Ticket/Elements/ShowRequestorTicketsActive index 9aee04098..e398455fe 100644 --- a/rt/share/html/Ticket/Elements/ShowRequestorTicketsActive +++ b/rt/share/html/Ticket/Elements/ShowRequestorTicketsActive @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/ShowRequestorTicketsAll b/rt/share/html/Ticket/Elements/ShowRequestorTicketsAll index ac31d9943..098519172 100644 --- a/rt/share/html/Ticket/Elements/ShowRequestorTicketsAll +++ b/rt/share/html/Ticket/Elements/ShowRequestorTicketsAll @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/ShowRequestorTicketsInactive b/rt/share/html/Ticket/Elements/ShowRequestorTicketsInactive index b8d5a0184..ff21e08b7 100644 --- a/rt/share/html/Ticket/Elements/ShowRequestorTicketsInactive +++ b/rt/share/html/Ticket/Elements/ShowRequestorTicketsInactive @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/ShowSimplifiedRecipients b/rt/share/html/Ticket/Elements/ShowSimplifiedRecipients index a27375aa1..ad8053e1e 100644 --- a/rt/share/html/Ticket/Elements/ShowSimplifiedRecipients +++ b/rt/share/html/Ticket/Elements/ShowSimplifiedRecipients @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/ShowSummary b/rt/share/html/Ticket/Elements/ShowSummary index 797f6edc7..0cfa0d403 100755 --- a/rt/share/html/Ticket/Elements/ShowSummary +++ b/rt/share/html/Ticket/Elements/ShowSummary @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -66,7 +66,7 @@ &><& /Ticket/Elements/ShowCustomers, Ticket => $Ticket &></&> <&| /Widgets/TitleBox, title => loc('People'), - (($can_modify || $can_modify_owner) ? (title_href => RT->Config->Get('WebPath')."/Ticket/ModifyPeople.html?id=".$Ticket->Id) : ()), + (($can_modify || $can_modify_owner || $can_modify_people) ? (title_href => RT->Config->Get('WebPath')."/Ticket/ModifyPeople.html?id=".$Ticket->Id) : ()), class => 'ticket-info-people', &><& /Ticket/Elements/ShowPeople, Ticket => $Ticket &></&> <& /Ticket/Elements/ShowAttachments, Ticket => $Ticket, Attachments => $Attachments &> @@ -115,4 +115,6 @@ my $can_modify_cf = $Ticket->CurrentUserHasRight('ModifyCustomField'); my $can_modify_owner = $Ticket->CurrentUserHasRight('OwnTicket') || $Ticket->CurrentUserHasRight('TakeTicket') || $Ticket->CurrentUserHasRight('StealTicket'); +my $can_modify_people = $Ticket->CurrentUserHasRight('Watch') + || $Ticket->CurrentUserHasRight('WatchAsAdminCc'); </%INIT> diff --git a/rt/share/html/Ticket/Elements/ShowTime b/rt/share/html/Ticket/Elements/ShowTime index a62668f46..a29f81f96 100644 --- a/rt/share/html/Ticket/Elements/ShowTime +++ b/rt/share/html/Ticket/Elements/ShowTime @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/ShowTransaction b/rt/share/html/Ticket/Elements/ShowTransaction index 2c217b438..a9c751fff 100755 --- a/rt/share/html/Ticket/Elements/ShowTransaction +++ b/rt/share/html/Ticket/Elements/ShowTransaction @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/ShowTransactionAttachments b/rt/share/html/Ticket/Elements/ShowTransactionAttachments index bf9aad054..4e9fd60de 100644 --- a/rt/share/html/Ticket/Elements/ShowTransactionAttachments +++ b/rt/share/html/Ticket/Elements/ShowTransactionAttachments @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -216,8 +216,17 @@ my $render_attachment = sub { ticket => $Ticket, ); - require HTML::Quoted; - $content = HTML::Quoted->extract($content) unless length $name; + unless (length $name) { + eval { + require HTML::Quoted; + $content = HTML::Quoted->extract($content) + }; + if ($@) { + RT->Logger->error( + "HTML::Quoted couldn't process attachment #@{[$message->id]}: $@." + . " This is a bug, please report it to rt-bugs\@bestpractical.com."); + } + } $m->comp( 'ShowMessageStanza', @@ -235,8 +244,18 @@ my $render_attachment = sub { # It's a text type we don't have special handling for else { unless ( length $name ) { - eval { require Text::Quoted; $content = Text::Quoted::extract($content); }; - if ($@) { $RT::Logger->warning( "Text::Quoted failed: $@" ) } + eval { + require Text::Quoted; + # XXX: Deprecate ->can check in 4.2 and simply bump version requirement. + Text::Quoted::set_quote_characters(undef) # only use > + if Text::Quoted->can("set_quote_characters"); + $content = Text::Quoted::extract($content); + }; + if ($@) { + RT->Logger->error( + "Text::Quoted couldn't process attachment #@{[$message->id]}: $@." + . " This is a bug, please report it to rt-bugs\@bestpractical.com."); + } } $m->comp( diff --git a/rt/share/html/Ticket/Elements/ShowUpdateStatus b/rt/share/html/Ticket/Elements/ShowUpdateStatus index e9f534159..21713a43a 100644 --- a/rt/share/html/Ticket/Elements/ShowUpdateStatus +++ b/rt/share/html/Ticket/Elements/ShowUpdateStatus @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -49,8 +49,8 @@ <&| /Widgets/TitleBox, title => loc('New messages'), title_href => "#txn-". $txn->id &> <&|/l&>There are unread messages on this ticket.</&> <&|/l, - RT->Config->Get('WebPath') ."/Ticket/Display.html?id=". $Ticket->id. "#txn-".$txn->id, - RT->Config->Get('WebPath') ."/Ticket/Display.html?id=". $Ticket->id ."&MarkAsSeen=1&Anchor=txn-" . $txn->id + RT->Config->Get('WebPath') ."/$DisplayPath/Display.html?id=". $Ticket->id. "#txn-".$txn->id, + RT->Config->Get('WebPath') ."/$DisplayPath/Display.html?id=". $Ticket->id ."&MarkAsSeen=1&Anchor=txn-" . $txn->id &>You can <a href="[_1]">jump to the first unread message</a> or <a href="[_2]">jump to the first unread message and mark all messages as seen</a>.</&> </&> </div> @@ -60,4 +60,6 @@ $Ticket <%INIT> return unless (RT->Config->Get( 'ShowUnreadMessageNotifications', $session{'CurrentUser'})); my $txn = $Ticket->SeenUpTo or return; + +my $DisplayPath = $session{'CurrentUser'}->Privileged ? 'Ticket' : 'SelfService'; </%INIT> diff --git a/rt/share/html/Ticket/Elements/ShowUserEntry b/rt/share/html/Ticket/Elements/ShowUserEntry index 857998108..0760f3eed 100644 --- a/rt/share/html/Ticket/Elements/ShowUserEntry +++ b/rt/share/html/Ticket/Elements/ShowUserEntry @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Elements/UpdateCc b/rt/share/html/Ticket/Elements/UpdateCc index 2435fc496..0656f4e81 100644 --- a/rt/share/html/Ticket/Elements/UpdateCc +++ b/rt/share/html/Ticket/Elements/UpdateCc @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Forward.html b/rt/share/html/Ticket/Forward.html index 2c20daf5d..62fb34671 100644 --- a/rt/share/html/Ticket/Forward.html +++ b/rt/share/html/Ticket/Forward.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/GnuPG.html b/rt/share/html/Ticket/GnuPG.html index f3a29f6d2..aa629c717 100644 --- a/rt/share/html/Ticket/GnuPG.html +++ b/rt/share/html/Ticket/GnuPG.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Graphs/Elements/EditGraphProperties b/rt/share/html/Ticket/Graphs/Elements/EditGraphProperties index df402bc58..b2963006f 100644 --- a/rt/share/html/Ticket/Graphs/Elements/EditGraphProperties +++ b/rt/share/html/Ticket/Graphs/Elements/EditGraphProperties @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Graphs/Elements/ShowGraph b/rt/share/html/Ticket/Graphs/Elements/ShowGraph index 5dc5e1425..1eae4b6ae 100644 --- a/rt/share/html/Ticket/Graphs/Elements/ShowGraph +++ b/rt/share/html/Ticket/Graphs/Elements/ShowGraph @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Graphs/Elements/ShowLegends b/rt/share/html/Ticket/Graphs/Elements/ShowLegends index cd19aa634..36572ec08 100644 --- a/rt/share/html/Ticket/Graphs/Elements/ShowLegends +++ b/rt/share/html/Ticket/Graphs/Elements/ShowLegends @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Graphs/dhandler b/rt/share/html/Ticket/Graphs/dhandler index b3c751bee..021e03d0a 100644 --- a/rt/share/html/Ticket/Graphs/dhandler +++ b/rt/share/html/Ticket/Graphs/dhandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Graphs/index.html b/rt/share/html/Ticket/Graphs/index.html index f0f32606a..e79252129 100644 --- a/rt/share/html/Ticket/Graphs/index.html +++ b/rt/share/html/Ticket/Graphs/index.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/History.html b/rt/share/html/Ticket/History.html index 8972fcda3..32e5993fe 100755 --- a/rt/share/html/Ticket/History.html +++ b/rt/share/html/Ticket/History.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Modify.html b/rt/share/html/Ticket/Modify.html index 4b24b89a9..8884c19ee 100755 --- a/rt/share/html/Ticket/Modify.html +++ b/rt/share/html/Ticket/Modify.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/ModifyAll.html b/rt/share/html/Ticket/ModifyAll.html index d36076cf2..6fb79e4fe 100755 --- a/rt/share/html/Ticket/ModifyAll.html +++ b/rt/share/html/Ticket/ModifyAll.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/ModifyDates.html b/rt/share/html/Ticket/ModifyDates.html index 82c3ca807..1d05f87ad 100755 --- a/rt/share/html/Ticket/ModifyDates.html +++ b/rt/share/html/Ticket/ModifyDates.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/ModifyLinks.html b/rt/share/html/Ticket/ModifyLinks.html index 72b636fc5..c29d8766f 100755 --- a/rt/share/html/Ticket/ModifyLinks.html +++ b/rt/share/html/Ticket/ModifyLinks.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/ModifyPeople.html b/rt/share/html/Ticket/ModifyPeople.html index 9bfbae76c..cdf25806a 100755 --- a/rt/share/html/Ticket/ModifyPeople.html +++ b/rt/share/html/Ticket/ModifyPeople.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Reminders.html b/rt/share/html/Ticket/Reminders.html index 5a7ebcdea..8da163fa7 100755 --- a/rt/share/html/Ticket/Reminders.html +++ b/rt/share/html/Ticket/Reminders.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/ShowEmailRecord.html b/rt/share/html/Ticket/ShowEmailRecord.html index bb754db34..69a5ad064 100644 --- a/rt/share/html/Ticket/ShowEmailRecord.html +++ b/rt/share/html/Ticket/ShowEmailRecord.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Ticket/Update.html b/rt/share/html/Ticket/Update.html index 26a37e80a..ae6b70095 100755 --- a/rt/share/html/Ticket/Update.html +++ b/rt/share/html/Ticket/Update.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -221,8 +221,12 @@ changeStatus(); </table> </&> +% $m->callback( %ARGS, CallbackName => 'BeforeSubmit', Ticket => $TicketObj ); + <& /Elements/Submit, Label => loc('Update Ticket'), Name => 'SubmitTicket', id => 'SubmitTicket' &> +% $m->callback( %ARGS, CallbackName => 'BeforeScrips', Ticket => $TicketObj ); + % if ($TicketObj->CurrentUserHasRight('ShowOutgoingEmail')) { <&|/Widgets/TitleBox, title => loc('Scrips and Recipients'), id => 'previewscrips', rolledup => RT->Config->Get('SimplifiedRecipients', $session{'CurrentUser'}) &> <& /Ticket/Elements/PreviewScrips, TicketObj => $TicketObj, %ARGS &> @@ -230,12 +234,17 @@ changeStatus(); % } </div> +% $m->callback( %ARGS, CallbackName => 'AfterScrips', Ticket => $TicketObj ); + % if (my $recips = $m->notes("DryRun-Recipients-".$TicketObj->Id)) { <input type="hidden" name="TxnRecipients" value="<% join ",",sort keys %{$recips} %>" /> % } </form> <hr class="clear" /> + +% $m->callback( %ARGS, CallbackName => 'AfterForm', Ticket => $TicketObj ); + <%INIT> my $CanRespond = 0; my $CanComment = 0; diff --git a/rt/share/html/Ticket/autohandler b/rt/share/html/Ticket/autohandler index 6fa9998ea..468808a77 100644 --- a/rt/share/html/Ticket/autohandler +++ b/rt/share/html/Ticket/autohandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Tools/MyDay.html b/rt/share/html/Tools/MyDay.html index f86250f27..e21851f11 100644 --- a/rt/share/html/Tools/MyDay.html +++ b/rt/share/html/Tools/MyDay.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Tools/MyReminders.html b/rt/share/html/Tools/MyReminders.html index 4e5d753f1..8884c483e 100644 --- a/rt/share/html/Tools/MyReminders.html +++ b/rt/share/html/Tools/MyReminders.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Tools/Offline.html b/rt/share/html/Tools/Offline.html index 48cf9b637..507ca17e2 100644 --- a/rt/share/html/Tools/Offline.html +++ b/rt/share/html/Tools/Offline.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Tools/index.html b/rt/share/html/Tools/index.html index 6d50d3810..72ae91b1c 100644 --- a/rt/share/html/Tools/index.html +++ b/rt/share/html/Tools/index.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/User/Prefs.html b/rt/share/html/User/Prefs.html index 178093a43..967f4004d 100755 --- a/rt/share/html/User/Prefs.html +++ b/rt/share/html/User/Prefs.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Widgets/BulkEdit b/rt/share/html/Widgets/BulkEdit index a1bd36ab6..6a4655710 100644 --- a/rt/share/html/Widgets/BulkEdit +++ b/rt/share/html/Widgets/BulkEdit @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Widgets/BulkProcess b/rt/share/html/Widgets/BulkProcess index feefab3a8..92d249e84 100644 --- a/rt/share/html/Widgets/BulkProcess +++ b/rt/share/html/Widgets/BulkProcess @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Widgets/ComboBox b/rt/share/html/Widgets/ComboBox index 2f9be26d4..4d2a03fa5 100644 --- a/rt/share/html/Widgets/ComboBox +++ b/rt/share/html/Widgets/ComboBox @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Widgets/FinalizeWidgetArguments b/rt/share/html/Widgets/FinalizeWidgetArguments index 0f015abbb..5bb390547 100644 --- a/rt/share/html/Widgets/FinalizeWidgetArguments +++ b/rt/share/html/Widgets/FinalizeWidgetArguments @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Widgets/Form/Boolean b/rt/share/html/Widgets/Form/Boolean index 7c7ddf749..2a362a3cd 100644 --- a/rt/share/html/Widgets/Form/Boolean +++ b/rt/share/html/Widgets/Form/Boolean @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Widgets/Form/Integer b/rt/share/html/Widgets/Form/Integer index 3bbea652a..99e544904 100644 --- a/rt/share/html/Widgets/Form/Integer +++ b/rt/share/html/Widgets/Form/Integer @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Widgets/Form/Select b/rt/share/html/Widgets/Form/Select index 46ffb4083..08a7bdab2 100644 --- a/rt/share/html/Widgets/Form/Select +++ b/rt/share/html/Widgets/Form/Select @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Widgets/Form/String b/rt/share/html/Widgets/Form/String index 2cbcaff2d..c222819d8 100644 --- a/rt/share/html/Widgets/Form/String +++ b/rt/share/html/Widgets/Form/String @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Widgets/SavedSearch b/rt/share/html/Widgets/SavedSearch index 08ad33824..3cb0f35a7 100644 --- a/rt/share/html/Widgets/SavedSearch +++ b/rt/share/html/Widgets/SavedSearch @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Widgets/SelectionBox b/rt/share/html/Widgets/SelectionBox index 8d0e3f4cc..675c9783f 100644 --- a/rt/share/html/Widgets/SelectionBox +++ b/rt/share/html/Widgets/SelectionBox @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Widgets/TitleBox b/rt/share/html/Widgets/TitleBox index 44f9e8386..abe088d09 100644 --- a/rt/share/html/Widgets/TitleBox +++ b/rt/share/html/Widgets/TitleBox @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Widgets/TitleBoxEnd b/rt/share/html/Widgets/TitleBoxEnd index 41278e43a..d4618bb2e 100755 --- a/rt/share/html/Widgets/TitleBoxEnd +++ b/rt/share/html/Widgets/TitleBoxEnd @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/Widgets/TitleBoxStart b/rt/share/html/Widgets/TitleBoxStart index 21c84df8f..f6655edad 100755 --- a/rt/share/html/Widgets/TitleBoxStart +++ b/rt/share/html/Widgets/TitleBoxStart @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/autohandler b/rt/share/html/autohandler index 4687e0dcf..180127b3f 100755 --- a/rt/share/html/autohandler +++ b/rt/share/html/autohandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/dhandler b/rt/share/html/dhandler index 02ffe2c86..830c08814 100644 --- a/rt/share/html/dhandler +++ b/rt/share/html/dhandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/index.html b/rt/share/html/index.html index 5b1edd662..702c75bed 100755 --- a/rt/share/html/index.html +++ b/rt/share/html/index.html @@ -30,7 +30,7 @@ If you need commercial support, please contact us at sales@bestpractical.com. %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/l b/rt/share/html/l index 7fd8ce473..814d69b91 100755 --- a/rt/share/html/l +++ b/rt/share/html/l @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/l_unsafe b/rt/share/html/l_unsafe index 79b1d8842..524c9a2ea 100644 --- a/rt/share/html/l_unsafe +++ b/rt/share/html/l_unsafe @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/m/_elements/footer b/rt/share/html/m/_elements/footer index 662544e45..10f3fba4e 100644 --- a/rt/share/html/m/_elements/footer +++ b/rt/share/html/m/_elements/footer @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) @@ -48,7 +48,7 @@ <& /Elements/Logo, ShowName => 1, OnlyCustom => 1 &> <div id="bpscredits"> <div id="copyright"> -<&|/l_unsafe, '', '', '2013', '<a href="http://www.bestpractical.com?rt='.$RT::VERSION.'">Best Practical Solutions, LLC</a>', &>[_1] RT [_2] Copyright 1996-[_3] [_4].</&> +<&|/l_unsafe, '', '', '2014', '<a href="http://www.bestpractical.com?rt='.$RT::VERSION.'">Best Practical Solutions, LLC</a>', &>[_1] RT [_2] Copyright 1996-[_3] [_4].</&> </div> </div> </body> diff --git a/rt/share/html/m/_elements/full_site_link b/rt/share/html/m/_elements/full_site_link index db23422d2..5769c4ee8 100644 --- a/rt/share/html/m/_elements/full_site_link +++ b/rt/share/html/m/_elements/full_site_link @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/m/_elements/header b/rt/share/html/m/_elements/header index ca08ec314..0d284e3f1 100644 --- a/rt/share/html/m/_elements/header +++ b/rt/share/html/m/_elements/header @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/m/_elements/login b/rt/share/html/m/_elements/login index f6213d0ca..64effcbd3 100644 --- a/rt/share/html/m/_elements/login +++ b/rt/share/html/m/_elements/login @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/m/_elements/menu b/rt/share/html/m/_elements/menu index 94d72b103..a6181a218 100644 --- a/rt/share/html/m/_elements/menu +++ b/rt/share/html/m/_elements/menu @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/m/_elements/raw_style b/rt/share/html/m/_elements/raw_style index 9157bc595..636884984 100644 --- a/rt/share/html/m/_elements/raw_style +++ b/rt/share/html/m/_elements/raw_style @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/m/_elements/ticket_list b/rt/share/html/m/_elements/ticket_list index 3c2932188..501494c8e 100644 --- a/rt/share/html/m/_elements/ticket_list +++ b/rt/share/html/m/_elements/ticket_list @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/m/_elements/ticket_menu b/rt/share/html/m/_elements/ticket_menu index fed142e25..8e51b5055 100644 --- a/rt/share/html/m/_elements/ticket_menu +++ b/rt/share/html/m/_elements/ticket_menu @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/m/_elements/wrapper b/rt/share/html/m/_elements/wrapper index b8b433625..c8d2d011e 100644 --- a/rt/share/html/m/_elements/wrapper +++ b/rt/share/html/m/_elements/wrapper @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/m/dhandler b/rt/share/html/m/dhandler index 7b2179f1e..ca5f3528f 100644 --- a/rt/share/html/m/dhandler +++ b/rt/share/html/m/dhandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/m/index.html b/rt/share/html/m/index.html index d0312a4ec..b8e9bbf90 100644 --- a/rt/share/html/m/index.html +++ b/rt/share/html/m/index.html @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/m/logout b/rt/share/html/m/logout index 23a741fa7..b92e7d8b3 100644 --- a/rt/share/html/m/logout +++ b/rt/share/html/m/logout @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/m/style.css b/rt/share/html/m/style.css index 4c553bbc8..243d32d74 100644 --- a/rt/share/html/m/style.css +++ b/rt/share/html/m/style.css @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/m/ticket/autohandler b/rt/share/html/m/ticket/autohandler index 30cdc0621..9bcd56e53 100644 --- a/rt/share/html/m/ticket/autohandler +++ b/rt/share/html/m/ticket/autohandler @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/m/ticket/create b/rt/share/html/m/ticket/create index 9fd04e436..7fbfc7a82 100644 --- a/rt/share/html/m/ticket/create +++ b/rt/share/html/m/ticket/create @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/m/ticket/history b/rt/share/html/m/ticket/history index dcc25692b..4293e2f1d 100644 --- a/rt/share/html/m/ticket/history +++ b/rt/share/html/m/ticket/history @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/m/ticket/reply b/rt/share/html/m/ticket/reply index d3b0f6f0d..4db5401aa 100644 --- a/rt/share/html/m/ticket/reply +++ b/rt/share/html/m/ticket/reply @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/m/ticket/select_create_queue b/rt/share/html/m/ticket/select_create_queue index e9bc3b2ce..63c49f2ca 100644 --- a/rt/share/html/m/ticket/select_create_queue +++ b/rt/share/html/m/ticket/select_create_queue @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/m/ticket/show b/rt/share/html/m/ticket/show index ead23a75e..360ef405f 100644 --- a/rt/share/html/m/ticket/show +++ b/rt/share/html/m/ticket/show @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/share/html/m/tickets/search b/rt/share/html/m/tickets/search index f10607b3b..e0bc84dda 100644 --- a/rt/share/html/m/tickets/search +++ b/rt/share/html/m/tickets/search @@ -2,7 +2,7 @@ %# %# COPYRIGHT: %# -%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC %# <sales@bestpractical.com> %# %# (Except where explicitly superseded by other copyright notices) diff --git a/rt/t/api/action-createtickets.t b/rt/t/api/action-createtickets.t index c37e2ed12..ceed4231c 100644 --- a/rt/t/api/action-createtickets.t +++ b/rt/t/api/action-createtickets.t @@ -105,7 +105,7 @@ is ($dependson->FirstCustomFieldValue('GlobalCF'), 'A Value', 'global custom field was set'); is ($dependson->FirstCustomFieldValue('QueueCF'), 'Another Value', 'queue custom field was set'); -unlike ($dependson->Subject, qr/{/, "The subject doesn't have braces in it. that means we're interpreting expressions"); +unlike ($dependson->Subject, qr/\{/, "The subject doesn't have braces in it. that means we're interpreting expressions"); is ($t->ReferredToBy->Count,1, "It's only referred to by one other ticket"); is ($t->ReferredToBy->First->BaseObj->Id,$t->DependsOn->First->TargetObj->Id, "The same ticket that depends on it refers to it."); use RT::Action::CreateTickets; diff --git a/rt/t/api/date.t b/rt/t/api/date.t index 728a4a2bc..cc1c694cc 100644 --- a/rt/t/api/date.t +++ b/rt/t/api/date.t @@ -94,7 +94,7 @@ my $current_user; '1970-01-01T00:00:00Z', "W3CDTF format with defaults"); is($date->Get(Format =>'RFC2822'), - 'Thu, 1 Jan 1970 00:00:00 +0000', + 'Thu, 01 Jan 1970 00:00:00 +0000', "RFC2822 format with defaults"); is($date->Get(Format =>'LocalizedDateTime'), 'Thu, Jan 1, 1970 12:00:00 AM', @@ -107,7 +107,7 @@ my $current_user; '1970-01-01', "W3CDTF format without time part"); is($date->RFC2822(Time => 0), - 'Thu, 1 Jan 1970', + 'Thu, 01 Jan 1970', "RFC2822 format without time part"); is($date->LocalizedDateTime(Time => 0), 'Thu, Jan 1, 1970', @@ -137,7 +137,7 @@ my $current_user; "RFC2822 format without date part and seconds"); is($date->RFC2822(DayOfWeek => 0), - '1 Jan 1970 00:00:00 +0000', + '01 Jan 1970 00:00:00 +0000', "RFC2822 format without 'day of week' part"); is($date->RFC2822(DayOfWeek => 0, Date => 0), '00:00:00 +0000', @@ -163,7 +163,7 @@ my $current_user; '1970-01-01', "'Date' method, W3CDTF format"); is($date->Date(Format => 'RFC2822'), - 'Thu, 1 Jan 1970', + 'Thu, 01 Jan 1970', "'Date' method, RFC2822 format"); is($date->Date(Time => 1), '1970-01-01', @@ -195,7 +195,7 @@ my $current_user; '1970-01-01T00:00:00Z', "'DateTime' method, W3CDTF format"); is($date->DateTime(Format =>'RFC2822'), - 'Thu, 1 Jan 1970 00:00:00 +0000', + 'Thu, 01 Jan 1970 00:00:00 +0000', "'DateTime' method, RFC2822 format"); is($date->DateTime(Date => 0, Time => 0), '1970-01-01 00:00:00', @@ -209,14 +209,14 @@ my $current_user; $date->Set( Format => 'ISO', Timezone => 'utc', Value => '2005-01-01 15:10:00' ); is($date->ISO( Timezone => 'user' ), '2005-01-01 18:10:00', "ISO"); is($date->W3CDTF( Timezone => 'user' ), '2005-01-01T18:10:00+03:00', "W3C DTF"); - is($date->RFC2822( Timezone => 'user' ), 'Sat, 1 Jan 2005 18:10:00 +0300', "RFC2822"); + is($date->RFC2822( Timezone => 'user' ), 'Sat, 01 Jan 2005 18:10:00 +0300', "RFC2822"); # DST $date = RT::Date->new( $current_user ); $date->Set( Format => 'ISO', Timezone => 'utc', Value => '2005-07-01 15:10:00' ); is($date->ISO( Timezone => 'user' ), '2005-07-01 19:10:00', "ISO"); is($date->W3CDTF( Timezone => 'user' ), '2005-07-01T19:10:00+04:00', "W3C DTF"); - is($date->RFC2822( Timezone => 'user' ), 'Fri, 1 Jul 2005 19:10:00 +0400', "RFC2822"); + is($date->RFC2822( Timezone => 'user' ), 'Fri, 01 Jul 2005 19:10:00 +0400', "RFC2822"); } { # negative timezone @@ -225,14 +225,14 @@ my $current_user; $date->Set( Format => 'ISO', Timezone => 'utc', Value => '2005-01-01 15:10:00' ); is($date->ISO( Timezone => 'user' ), '2005-01-01 10:10:00', "ISO"); is($date->W3CDTF( Timezone => 'user' ), '2005-01-01T10:10:00-05:00', "W3C DTF"); - is($date->RFC2822( Timezone => 'user' ), 'Sat, 1 Jan 2005 10:10:00 -0500', "RFC2822"); + is($date->RFC2822( Timezone => 'user' ), 'Sat, 01 Jan 2005 10:10:00 -0500', "RFC2822"); # DST $date = RT::Date->new( $current_user ); $date->Set( Format => 'ISO', Timezone => 'utc', Value => '2005-07-01 15:10:00' ); is($date->ISO( Timezone => 'user' ), '2005-07-01 11:10:00', "ISO"); is($date->W3CDTF( Timezone => 'user' ), '2005-07-01T11:10:00-04:00', "W3C DTF"); - is($date->RFC2822( Timezone => 'user' ), 'Fri, 1 Jul 2005 11:10:00 -0400', "RFC2822"); + is($date->RFC2822( Timezone => 'user' ), 'Fri, 01 Jul 2005 11:10:00 -0400', "RFC2822"); } warning_like @@ -306,8 +306,6 @@ my $year = (localtime(time))[5] + 1900; { # set+datemanip format(Time::ParseDate) my $date = RT::Date->new(RT->SystemUser); - $date->Set(Format => 'unknown', Value => 'weird date'); - is($date->Unix, 0, "date was wrong"); RT->Config->Set( Timezone => 'Europe/Moscow' ); $date->Set(Format => 'datemanip', Value => '2005-11-28 15:10:00'); @@ -325,7 +323,9 @@ my $year = (localtime(time))[5] + 1900; { # set+unknown format(Time::ParseDate) my $date = RT::Date->new(RT->SystemUser); - $date->Set(Format => 'unknown', Value => 'weird date'); + warnings_like { + $date->Set(Format => 'unknown', Value => 'weird date'); + } qr{Couldn't parse date 'weird date' by Time::ParseDate}; is($date->Unix, 0, "date was wrong"); RT->Config->Set( Timezone => 'Europe/Moscow' ); @@ -456,12 +456,12 @@ my $year = (localtime(time))[5] + 1900; RT->Config->Set( DateTimeFormat => 'RFC2822' ); $date->Unix(1); - is($date->AsString, 'Thu, 1 Jan 1970 00:00:01 +0000', "correct string"); + is($date->AsString, 'Thu, 01 Jan 1970 00:00:01 +0000', "correct string"); RT->Config->Set( DateTimeFormat => { Format => 'RFC2822', Seconds => 0 } ); $date->Unix(1); - is($date->AsString, 'Thu, 1 Jan 1970 00:00 +0000', "correct string"); - is($date->AsString(Seconds => 1), 'Thu, 1 Jan 1970 00:00:01 +0000', "correct string"); + is($date->AsString, 'Thu, 01 Jan 1970 00:00 +0000', "correct string"); + is($date->AsString(Seconds => 1), 'Thu, 01 Jan 1970 00:00:01 +0000', "correct string"); } { # DurationAsString diff --git a/rt/t/api/group.t b/rt/t/api/group.t index 2c1ca73cf..d55fc5c4a 100644 --- a/rt/t/api/group.t +++ b/rt/t/api/group.t @@ -20,11 +20,19 @@ ok($ng->LoadUserDefinedGroup('TestGroup'), "Loaded testgroup"); is($ng->id , $group->id, "Loaded the right group"); -ok (($id,$msg) = $ng->AddMember('1'), "Added a member to the group"); +my @users = (undef); +for my $number (1..3) { + my $user = RT::User->new(RT->SystemUser); + $user->Create( Name => "User $number" ); + push @users, $user->id; +} + + +ok (($id,$msg) = $ng->AddMember( $users[1] ), "Added a member to the group"); ok($id, $msg); -ok (($id,$msg) = $ng->AddMember('2' ), "Added a member to the group"); +ok (($id,$msg) = $ng->AddMember( $users[2] ), "Added a member to the group"); ok($id, $msg); -ok (($id,$msg) = $ng->AddMember('3' ), "Added a member to the group"); +ok (($id,$msg) = $ng->AddMember( $users[3] ), "Added a member to the group"); ok($id, $msg); # Group 1 now has members 1, 2 ,3 @@ -34,7 +42,7 @@ ok (my ($id_2, $msg_2) = $group_2->CreateUserDefinedGroup( Name => 'TestGroup2', isnt ($id_2 , 0, "Created group 2 ok- $msg_2 "); ok (($id,$msg) = $group_2->AddMember($ng->PrincipalId), "Made TestGroup a member of testgroup2"); ok($id, $msg); -ok (($id,$msg) = $group_2->AddMember('1' ), "Added member RT_System to the group TestGroup2"); +ok (($id,$msg) = $group_2->AddMember( $users[1] ), "Added member User 1 to the group TestGroup2"); ok($id, $msg); # Group 2 how has 1, g1->{1, 2,3} @@ -48,12 +56,12 @@ ok($id, $msg); # g3 now has g2->{1, g1->{1,2,3}} my $principal_1 = RT::Principal->new(RT->SystemUser); -$principal_1->Load('1'); +$principal_1->Load( $users[1] ); my $principal_2 = RT::Principal->new(RT->SystemUser); -$principal_2->Load('2'); +$principal_2->Load( $users[2] ); -ok (($id,$msg) = $group_3->AddMember('1' ), "Added member RT_System to the group TestGroup2"); +ok (($id,$msg) = $group_3->AddMember( $users[1] ), "Added member User 1 to the group TestGroup2"); ok($id, $msg); # g3 now has 1, g2->{1, g1->{1,2,3}} diff --git a/rt/t/api/rights.t b/rt/t/api/rights.t index 107fb2b35..5cf3a0008 100644 --- a/rt/t/api/rights.t +++ b/rt/t/api/rights.t @@ -1,17 +1,14 @@ -use RT::Test nodata => 1, tests => 30; +use RT::Test nodata => 1, tests => 38; use strict; use warnings; +use Test::Warn; + +sub reset_rights { RT::Test->set_rights } + # clear all global right -{ - my $acl = RT::ACL->new(RT->SystemUser); - $acl->Limit( FIELD => 'RightName', OPERATOR => '!=', VALUE => 'SuperUser' ); - $acl->LimitToObject( $RT::System ); - while( my $ace = $acl->Next ) { - $ace->Delete; - } -} +reset_rights; my $queue = RT::Test->load_or_create_queue( Name => 'Regression' ); ok $queue && $queue->id, 'loaded or created queue'; @@ -146,3 +143,38 @@ my $ticket2; "user is not AdminCc and can't modify ticket2 (same question different answer)" ); } + +my $queue2 = RT::Test->load_or_create_queue( Name => 'Rights' ); +ok $queue2 && $queue2->id, 'loaded or created queue'; + +my $user2 = RT::Test->load_or_create_user( + Name => 'user2', Password => 'password', +); +ok $user2 && $user2->id, 'Created user: ' . $user2->Name . ' with id ' . $user2->Id; + +warning_like { + ok( !$user2->HasRight( Right => 'Foo', Object => $queue2 ), + "HasRight false for invalid right Foo" + ); +} qr/Invalid right\. Couldn't canonicalize right 'Foo'/, + 'Got warning on invalid right'; + + +note "Right name canonicalization"; +{ + reset_rights; + my ($ok, $msg) = $user->PrincipalObj->GrantRight( + Right => "showticket", + Object => RT->System, + ); + ok $ok, "Granted showticket: $msg"; + ok $user->HasRight( Right => "ShowTicket", Object => RT->System ), "HasRight ShowTicket"; + + reset_rights; + ($ok, $msg) = $user->PrincipalObj->GrantRight( + Right => "ShowTicket", + Object => RT->System, + ); + ok $ok, "Granted ShowTicket: $msg"; + ok $user->HasRight( Right => "showticket", Object => RT->System ), "HasRight showticket"; +} diff --git a/rt/t/api/rights_show_ticket.t b/rt/t/api/rights_show_ticket.t index c8107fe07..b7bec70de 100644 --- a/rt/t/api/rights_show_ticket.t +++ b/rt/t/api/rights_show_ticket.t @@ -207,7 +207,6 @@ diag "Testing with UseSQLForACLChecks => $option"; } sub have_no_rights { - $SIG{'INT'} = $SIG{'TERM'} = sub { print STDERR Carp::longmess('boo'); exit 1 }; local $Test::Builder::Level = $Test::Builder::Level + 1; foreach my $u ( @_ ) { foreach my $q ( diff --git a/rt/t/api/searchbuilder.t b/rt/t/api/searchbuilder.t index 8562bfc2b..84568718d 100644 --- a/rt/t/api/searchbuilder.t +++ b/rt/t/api/searchbuilder.t @@ -2,7 +2,7 @@ use strict; use warnings; use RT; -use RT::Test tests => 11; +use RT::Test tests => 19; { @@ -37,3 +37,27 @@ is_deeply(\@items_ids, \@sorted_ids, "ItemsArrayRef sorts alphabetically by name } +#20767: CleanSlate doesn't clear RT::SearchBuilder's flags for handling Disabled columns +{ + my $items; + + ok(my $queues = RT::Queues->new(RT->SystemUser), 'Created a queues object'); + ok( $queues->UnLimit(),'Unlimited the result set of the queues object'); + + # sanity check + is( $queues->{'handled_disabled_column'} => undef, 'handled_disabled_column IS NOT set' ); + is( $queues->{'find_disabled_rows'} => undef, 'find_disabled_rows IS NOT set ' ); + + $queues->LimitToDeleted; + + # sanity check + ok( $queues->{'handled_disabled_column'}, 'handled_disabled_column IS set' ); + ok( $queues->{'find_disabled_rows'}, 'find_disabled_rows IS set ' ); + + $queues->CleanSlate; + + # these fail without the overloaded CleanSlate method + is( $queues->{'handled_disabled_column'} => undef, 'handled_disabled_column IS NOT set' ); + is( $queues->{'find_disabled_rows'} => undef, 'find_disabled_rows IS NOT set ' ); +} + diff --git a/rt/t/fts/indexed_mysql.t b/rt/t/fts/indexed_mysql.t index c124ff8f8..a54382ff8 100644 --- a/rt/t/fts/indexed_mysql.t +++ b/rt/t/fts/indexed_mysql.t @@ -41,7 +41,7 @@ sub setup_indexing { mkdir $tmp; my $sphinx_conf = $output; - $sphinx_conf =~ s/.*?source rt {/source rt {/ms; + $sphinx_conf =~ s/.*?source rt \{/source rt {/ms; $sphinx_conf =~ s{\Q$RT::VarPath\E/sphinx/}{$tmp/}g; $sphinx{'config'} = File::Spec->catfile( $tmp, 'sphinx.conf' ); diff --git a/rt/t/fts/indexed_oracle.t b/rt/t/fts/indexed_oracle.t index 98db30439..a5b15bd82 100644 --- a/rt/t/fts/indexed_oracle.t +++ b/rt/t/fts/indexed_oracle.t @@ -6,7 +6,7 @@ use RT::Test tests => undef; plan skip_all => 'Not Oracle' unless RT->Config->Get('DatabaseType') eq 'Oracle'; plan tests => 13; -RT->Config->Set( FullTextSearch => Enable => 1, Indexed => 1 ); +RT->Config->Set( FullTextSearch => Enable => 1, Indexed => 1, IndexName => 'rt_fts_index' ); setup_indexing(); diff --git a/rt/t/mail/dashboards.t b/rt/t/mail/dashboards.t index edd455300..6bf4ba520 100644 --- a/rt/t/mail/dashboards.t +++ b/rt/t/mail/dashboards.t @@ -1,7 +1,7 @@ use strict; use warnings; -use RT::Test tests => 181; +use RT::Test tests => undef; use Test::Warn; use RT::Dashboard::Mailer; @@ -102,15 +102,13 @@ sub produces_dashboard_mail_ok { # {{{ my $mail = parse_mail( $mails[0] ); is($mail->head->get('Subject'), $subject); is($mail->head->get('From'), "root\n"); + is($mail->head->get('Content-Transfer-Encoding'), "base64\n"); is($mail->head->get('X-RT-Dashboard-Id'), "$dashboard_id\n"); is($mail->head->get('X-RT-Dashboard-Subscription-Id'), "$subscription_id\n"); - SKIP: { - skip 'Weird MIME failure', 2; - my $body = $mail->stringify_body; - like($body, qr{My dashboards}); - like($body, qr{<a href="http://[^/]+/Dashboards/\d+/Testing!">Testing!</a>}); - }; + my $body = $mail->bodyhandle->as_string; + like($body, qr{My dashboards}); + like($body, qr{<a href="http://[^/]+/Dashboards/\d+/Testing!">Testing!</a>}); } # }}} sub produces_no_dashboard_mail_ok { # {{{ @@ -202,12 +200,9 @@ 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"); -SKIP: { - skip 'Weird MIME failure', 2; - my $body = $mail->stringify_body; - unlike($body, qr{My dashboards}); - unlike($body, qr{Testing!}); -}; +my $body = $mail->bodyhandle->as_string; +unlike($body, qr{My dashboards}); +unlike($body, qr{Testing!}); delete_dashboard($dashboard_id); @@ -368,3 +363,4 @@ produces_no_dashboard_mail_ok( Time => $bad_time, ); +done_testing; diff --git a/rt/t/mail/digest-attributes.t b/rt/t/mail/digest-attributes.t index badd59b87..54c1c803f 100644 --- a/rt/t/mail/digest-attributes.t +++ b/rt/t/mail/digest-attributes.t @@ -136,14 +136,14 @@ is( $c_susp, 1, "correct number of suspended messages" ); # the first time get the content email_digest_like( '--mode daily --print', qr/in the last day/ ); # The second time run it for real so we make sure that we get RT to mark the txn as sent -email_digest_like( '--mode daily', qr/maildaily\@/ ); +email_digest_like( '--mode daily --verbose', qr/maildaily\@/ ); # now we should have nothing to do, so no content. email_digest_like( '--mode daily --print', '' ); # the first time get the content email_digest_like( '--mode weekly --print', qr/in the last seven days/ ); # The second time run it for real so we make sure that we get RT to mark the txn as sent -email_digest_like( '--mode weekly', qr/mailweekly\@/ ); +email_digest_like( '--mode weekly --verbose', qr/mailweekly\@/ ); # now we should have nothing to do, so no content. email_digest_like( '--mode weekly --print', '' ); diff --git a/rt/t/mail/disposition-outgoing.t b/rt/t/mail/disposition-outgoing.t index 06295a09c..cbfe43b74 100644 --- a/rt/t/mail/disposition-outgoing.t +++ b/rt/t/mail/disposition-outgoing.t @@ -50,7 +50,7 @@ a fake patch $mail =~ s/^Content-disposition: .+?\n(?=\n)//ism; my $rt = send_and_receive($mail); - like $rt, qr/Content-Disposition:\s*inline.+?filename\.patch/is, 'found default (inline) disposition'; + like $rt, qr/Content-Disposition:\s*attachment.+?filename\.patch/is, 'found default (attachment) disposition'; } sub send_and_receive { diff --git a/rt/t/mail/gnupg-reverification.t b/rt/t/mail/gnupg-reverification.t index 939bf3333..deef1ec24 100644 --- a/rt/t/mail/gnupg-reverification.t +++ b/rt/t/mail/gnupg-reverification.t @@ -1,7 +1,7 @@ use strict; use warnings; -use RT::Test::GnuPG tests => 216, gnupg_options => { passphrase => 'rt-test' }; +use RT::Test::GnuPG tests => 232, gnupg_options => { passphrase => 'rt-test' }; diag "load Everyone group"; my $everyone; @@ -62,10 +62,12 @@ foreach my $file ( @files ) { $m->content_like(qr/This is .*ID:$eid/ims, "$eid: content is there and message is decrypted"); $m->next_warning_like(qr/public key not found/); + $m->next_warning_like(qr/above error may result from an unconfigured RT\/GPG/); # some mails contain multiple signatures if ($eid == 5 || $eid == 17 || $eid == 18) { $m->next_warning_like(qr/public key not found/); + $m->next_warning_like(qr/above error may result from an unconfigured RT\/GPG/); } $m->no_leftover_warnings_ok; diff --git a/rt/t/mail/mime_decoding.t b/rt/t/mail/mime_decoding.t index 4b3e3c075..fbf884932 100644 --- a/rt/t/mail/mime_decoding.t +++ b/rt/t/mail/mime_decoding.t @@ -1,6 +1,6 @@ use strict; use warnings; -use RT::Test nodb => 1, tests => 13; +use RT::Test nodb => 1, tests => 14; use_ok('RT::I18N'); @@ -34,6 +34,16 @@ diag q{'=' char in a trailing part after an encoded part}; ); } +diag q{adding quotes around mime words containing specials when word is already quoted}; +{ + my $str = <<"END"; +Content-Disposition: attachment; filename="=?iso-8859-1?Q?foobar,_?= + =?iso-8859-1?Q?barfoo.docx?=" +END + my $decoded = 'Content-Disposition: attachment; filename="foobar, barfoo.docx"'; + is( RT::I18N::DecodeMIMEWordsToUTF8($str), $decoded, "No added quotes" ); +} + diag q{regression test for #5248 from rt3.fsck.com}; { my $str = qq{Subject: =?ISO-8859-1?Q?Re=3A_=5BXXXXXX=23269=5D_=5BComment=5D_Frag?=} diff --git a/rt/t/shredder/utils.pl b/rt/t/shredder/utils.pl index 7be951370..a3d0cf59a 100644 --- a/rt/t/shredder/utils.pl +++ b/rt/t/shredder/utils.pl @@ -8,8 +8,14 @@ require RT::Test; BEGIN { ### after: push @INC, qw(@RT_LIB_PATH@); + + use RT; + RT->LoadConfig; + RT->InitPluginPaths; + RT->InitClasses; } -use RT::Shredder; + +require RT::Shredder; =head1 DESCRIPTION @@ -282,8 +288,7 @@ sub dump_sqlite my $old_fhkn = $dbh->{'FetchHashKeyName'}; $dbh->{'FetchHashKeyName'} = 'NAME_lc'; - my $sth = $dbh->table_info( '', '%', '%', 'TABLE' ) || die $DBI::err; - my @tables = keys %{$sth->fetchall_hashref( 'table_name' )}; + my @tables = $RT::Handle->_TableNames( $dbh ); my $res = {}; foreach my $t( @tables ) { diff --git a/rt/t/ticket/search_by_links.t b/rt/t/ticket/search_by_links.t index d25d3002e..265771846 100644 --- a/rt/t/ticket/search_by_links.t +++ b/rt/t/ticket/search_by_links.t @@ -2,7 +2,7 @@ use strict; use warnings; -use RT::Test nodata => 1, tests => 98; +use RT::Test nodata => 1, tests => 100; use RT::Ticket; my $q = RT::Test->load_or_create_queue( Name => 'Regression' ); @@ -71,6 +71,14 @@ $total += @tickets; } run_tests(); +# make sure search by id is on LocalXXX columns +{ + my $tickets = RT::Tickets->new( RT->SystemUser ); + $tickets->FromSQL('MemberOf = '. $tickets[0]->id); + like $tickets->BuildSelectQuery, qr/LocalBase/; + like $tickets->BuildSelectQuery, qr/LocalTarget/; +} + # another set with tests of combinations searches @tickets = RT::Test->create_tickets( { Queue => $q->id }, diff --git a/rt/t/ticket/search_by_watcher.t b/rt/t/ticket/search_by_watcher.t index a6800bbb4..4fbc2617b 100644 --- a/rt/t/ticket/search_by_watcher.t +++ b/rt/t/ticket/search_by_watcher.t @@ -2,7 +2,7 @@ use strict; use warnings; -use RT::Test nodata => 1, tests => 2108; +use RT::Test nodata => 1, tests => undef; use RT::Ticket; my $q = RT::Test->load_or_create_queue( Name => 'Regression' ); @@ -101,40 +101,41 @@ sub run_auto_tests { run_test( $query, %checks ); } } } -# XXX: It -# @queries = ( -# '? AND ? AND ?' => sub { $_[0] and $_[1] and $_[2] }, -# '(? OR ?) AND ?' => sub { return (($_[0] or $_[1]) and $_[2]) }, -# '? OR (? AND ?)' => sub { $_[0] or ($_[1] and $_[2]) }, -# '(? AND ?) OR ?' => sub { ($_[0] and $_[1]) or $_[2] }, -# '? AND (? OR ?)' => sub { $_[0] and ($_[1] or $_[2]) }, -# '? OR ? OR ?' => sub { $_[0] or $_[1] or $_[2] }, -# ); -# while ( my ($template, $t_cb) = splice @queries, 0, 2 ) { -# my @atmp = @conditions; -# while ( my ($a, $a_cb) = splice @atmp, 0, 2 ) { -# my @btmp = @conditions; -# while ( my ($b, $b_cb) = splice @btmp, 0, 2 ) { -# next if $a eq $b; -# my @ctmp = @conditions; -# while ( my ($c, $c_cb) = splice @ctmp, 0, 2 ) { -# next if $a eq $c; -# next if $b eq $c; -# -# my %checks = (); -# foreach my $ticket ( @tickets ) { -# my $s = $ticket->Subject; -# $checks{ $s } = $t_cb->( scalar $a_cb->($s), scalar $b_cb->($s), scalar $c_cb->($s) ); -# } -# -# my $query = $template; -# foreach my $tmp ($a, $b, $c) { -# $query =~ s/\?/$tmp/; -# } -# -# run_test( $query, %checks ); -# } } } -# } + return unless $ENV{'RT_TEST_HEAVY'}; + + @queries = ( + '? AND ? AND ?' => sub { $_[0] and $_[1] and $_[2] }, + '(? OR ?) AND ?' => sub { return (($_[0] or $_[1]) and $_[2]) }, + '? OR (? AND ?)' => sub { $_[0] or ($_[1] and $_[2]) }, + '(? AND ?) OR ?' => sub { ($_[0] and $_[1]) or $_[2] }, + '? AND (? OR ?)' => sub { $_[0] and ($_[1] or $_[2]) }, + '? OR ? OR ?' => sub { $_[0] or $_[1] or $_[2] }, + ); + while ( my ($template, $t_cb) = splice @queries, 0, 2 ) { + my @atmp = @conditions; + while ( my ($a, $a_cb) = splice @atmp, 0, 2 ) { + my @btmp = @conditions; + while ( my ($b, $b_cb) = splice @btmp, 0, 2 ) { + next if $a eq $b; + my @ctmp = @conditions; + while ( my ($c, $c_cb) = splice @ctmp, 0, 2 ) { + next if $a eq $c; + next if $b eq $c; + + my %checks = (); + foreach my $ticket ( @tickets ) { + my $s = $ticket->Subject; + $checks{ $s } = $t_cb->( scalar $a_cb->($s), scalar $b_cb->($s), scalar $c_cb->($s) ); + } + + my $query = $template; + foreach my $tmp ($a, $b, $c) { + $query =~ s/\?/$tmp/; + } + + run_test( $query, %checks ); + } } } + } } @@ -266,4 +267,4 @@ my $nobody = RT::Nobody(); } @tickets = (); - +done_testing(); diff --git a/rt/t/web/articles-links.t b/rt/t/web/articles-links.t index 713dc05e4..eb6de51b3 100644 --- a/rt/t/web/articles-links.t +++ b/rt/t/web/articles-links.t @@ -37,7 +37,7 @@ $m->content_contains('instance of ticket #17421', 'got the name of the article i # delete RT::Article's Name method on the server so we'll need to AUTOLOAD it my $clone = $m->clone; $clone->get_ok('/delete-article-name-method.html'); -like($clone->content, qr/{deleted}/); +like($clone->content, qr/\{deleted\}/); $m->form_name('TicketUpdate'); $m->click('SubmitTicket'); diff --git a/rt/t/web/case-sensitivity.t b/rt/t/web/case-sensitivity.t index f9c61b519..5f40ef690 100644 --- a/rt/t/web/case-sensitivity.t +++ b/rt/t/web/case-sensitivity.t @@ -22,7 +22,7 @@ $m->login; require JSON; is_deeply( JSON::from_json( $m->content ), - [{"value" => "root\@localhost","label" => "Enoch Root"}] + [{"value" => "root\@localhost","label" => "Enoch Root", id=>$root_id}] ); } diff --git a/rt/t/web/cf_date.t b/rt/t/web/cf_date.t index 4ea93e4de..e69833c13 100644 --- a/rt/t/web/cf_date.t +++ b/rt/t/web/cf_date.t @@ -2,7 +2,7 @@ use strict; use warnings; -use RT::Test tests => 35; +use RT::Test tests => undef; my ( $baseurl, $m ) = RT::Test->started_ok; ok $m->login, 'logged in as root'; @@ -183,4 +183,10 @@ diag 'check invalid inputs'; $m->content_contains('test cf date:', 'has no cf date field on the page' ); $m->content_lacks('foodate', 'invalid dates not set' ); + + my @warnings = $m->get_warnings; + chomp @warnings; + is_deeply( @warnings, q{Couldn't parse date 'foodate' by Time::ParseDate} ); } + +done_testing; diff --git a/rt/t/web/cf_datetime.t b/rt/t/web/cf_datetime.t index 8cc099d1c..4580c4a4f 100644 --- a/rt/t/web/cf_datetime.t +++ b/rt/t/web/cf_datetime.t @@ -2,7 +2,7 @@ use strict; use warnings; -use RT::Test tests => 51; +use RT::Test tests => undef; RT->Config->Set( 'Timezone' => 'EST5EDT' ); # -04:00 my ($baseurl, $m) = RT::Test->started_ok; @@ -209,6 +209,10 @@ diag 'check invalid inputs'; $m->content_contains('test cf datetime:', 'has cf datetime field on the page'); $m->content_lacks('foodate', 'invalid dates not set'); + + my @warnings = $m->get_warnings; + chomp @warnings; + is_deeply( @warnings, q{Couldn't parse date 'foodate' by Time::ParseDate} ); } sub is_results_number { @@ -232,3 +236,4 @@ sub is_results_number { # to make $m->DESTROY happy undef $m; +done_testing; diff --git a/rt/t/web/charting.t b/rt/t/web/charting.t index 32d95d99b..e19ec41ae 100644 --- a/rt/t/web/charting.t +++ b/rt/t/web/charting.t @@ -76,3 +76,20 @@ $m->content_like(qr{<img src="/Search/Chart\?}, "Found image"); $m->get_ok( "/Search/Chart?Query=id>0&PrimaryGroupBy=Requestor.Phone" ); is( $m->content_type, "image/png" ); ok( length($m->content), "Has content" ); + +diag "Confirm subnav links use Query param before saved search in session."; + +$m->get_ok( "/Search/Chart.html?Query=id>0" ); +my $advanced = $m->find_link( text => 'Advanced' )->URI->equery; +like( $advanced, qr{Query=id%3E0}, + 'Advanced link has Query param with id search' + ); + +# Load the session with another search. +$m->get_ok( "/Search/Results.html?Query=Queue='General'" ); + +$m->get_ok( "/Search/Chart.html?Query=id>0" ); +$advanced = $m->find_link( text => 'Advanced' )->URI->equery; +like( $advanced, qr{Query=id%3E0}, + 'Advanced link still has Query param with id search' + ); diff --git a/rt/t/web/command_line.t b/rt/t/web/command_line.t index 7c444f49d..a5c52d261 100644 --- a/rt/t/web/command_line.t +++ b/rt/t/web/command_line.t @@ -164,106 +164,106 @@ expect_like(qr/Queue: EditedQueue$$/, 'Verified lack of change'); # Test reading and setting custom fields without spaces expect_send("show ticket/$ticket_id -f CF-myCF$$", 'Checking initial value'); -expect_like(qr/CF\.{myCF$$}:/i, 'Verified initial empty value (CF-x syntax)'); +expect_like(qr/\QCF.{myCF$$}\E:/i, 'Verified initial empty value (CF-x syntax)'); expect_send("show ticket/$ticket_id -f CF.{myCF$$}", 'Checking initial value'); -expect_like(qr/CF\.{myCF$$}:/i, 'Verified initial empty value (CF.{x} syntax)'); +expect_like(qr/\QCF.{myCF$$}\E:/i, 'Verified initial empty value (CF.{x} syntax)'); expect_send("edit ticket/$ticket_id set 'CF-myCF$$=VALUE' ", 'Changing CF...'); expect_like(qr/Ticket $ticket_id updated/, 'Changed cf'); expect_send("show ticket/$ticket_id -f CF-myCF$$", 'Checking new value'); -expect_like(qr/CF\.{myCF$$}: VALUE/i, 'Verified change'); +expect_like(qr/\QCF.{myCF$$}\E: VALUE/i, 'Verified change'); # Test setting 0 as value of the custom field expect_send("edit ticket/$ticket_id set 'CF-myCF$$=0' ", 'Changing CF...'); expect_like(qr/Ticket $ticket_id updated/, 'Changed cf'); expect_send("show ticket/$ticket_id -f CF-myCF$$", 'Checking new value'); -expect_like(qr/CF\.{myCF$$}: 0/i, 'Verified change'); +expect_like(qr/\QCF.{myCF$$}\E: 0/i, 'Verified change'); expect_send("edit ticket/$ticket_id set 'CF.{myCF$$}=VALUE' ",'Changing CF...'); expect_like(qr/Ticket $ticket_id updated/, 'Changed cf'); expect_send("show ticket/$ticket_id -f CF.{myCF$$}", 'Checking new value'); -expect_like(qr/CF\.{myCF$$}: VALUE/i, 'Verified change'); +expect_like(qr/\QCF.{myCF$$}\E: VALUE/i, 'Verified change'); # Test setting 0 as value of the custom field expect_send("edit ticket/$ticket_id set 'CF.{myCF$$}=0' ", 'Changing CF...'); expect_like(qr/Ticket $ticket_id updated/, 'Changed cf'); expect_send("show ticket/$ticket_id -f CF.{myCF$$}", 'Checking new value'); -expect_like(qr/CF\.{myCF$$}: 0/i, 'Verified change'); +expect_like(qr/\QCF.{myCF$$}\E: 0/i, 'Verified change'); # Test reading and setting custom fields with spaces expect_send("show ticket/$ticket_id -f 'CF-my CF$$'", 'Checking initial value'); -expect_like(qr/CF\.{my CF$$}:/i, 'Verified change'); +expect_like(qr/\QCF.{my CF$$}\E:/i, 'Verified change'); expect_send("edit ticket/$ticket_id set 'CF-my CF$$=VALUE' ", 'Changing CF...'); expect_like(qr/Ticket $ticket_id updated/, 'Changed cf'); expect_send("show ticket/$ticket_id -f 'CF-my CF$$'", 'Checking new value'); -expect_like(qr/CF\.{my CF$$}: VALUE/i, 'Verified change'); +expect_like(qr/\QCF.{my CF$$}\E: VALUE/i, 'Verified change'); expect_send("ls -l 'id = $ticket_id' -f 'CF-my CF$$'", 'Checking new value'); -expect_like(qr/CF\.{my CF$$}: VALUE/i, 'Verified change'); +expect_like(qr/\QCF.{my CF$$}\E: VALUE/i, 'Verified change'); expect_send("show ticket/$ticket_id -f 'CF.{my CF$$}'", 'Checking initial value'); -expect_like(qr/CF\.{my CF$$}: VALUE/i, 'Verified change'); +expect_like(qr/\QCF.{my CF$$}\E: VALUE/i, 'Verified change'); expect_send("edit ticket/$ticket_id set 'CF.{my CF$$}=NEW' ", 'Changing CF...'); expect_send("show ticket/$ticket_id -f 'CF.{my CF$$}'", 'Checking new value'); -expect_like(qr/CF\.{my CF$$}: NEW/i, 'Verified change'); +expect_like(qr/\QCF.{my CF$$}\E: NEW/i, 'Verified change'); expect_send("ls -l 'id = $ticket_id' -f 'CF.{my CF$$}'", 'Checking new value'); -expect_like(qr/CF\.{my CF$$}: NEW/i, 'Verified change'); +expect_like(qr/\QCF.{my CF$$}\E: NEW/i, 'Verified change'); # Test reading and setting single value custom field with commas or quotes expect_send("show ticket/$ticket_id -f CF-myCF$$", 'Checking initial value'); -expect_like(qr/CF\.{myCF$$}:/i, 'Verified change'); +expect_like(qr/\QCF.{myCF$$}\E:/i, 'Verified change'); expect_send("edit ticket/$ticket_id set CF-myCF$$=1,2,3", 'Changing CF...'); expect_like(qr/Ticket $ticket_id updated/, 'Changed cf'); expect_send("show ticket/$ticket_id -f CF-myCF$$", 'Checking new value'); -expect_like(qr/CF\.{myCF$$}: 1,2,3/i, 'Verified change'); +expect_like(qr/\QCF.{myCF$$}\E: 1,2,3/i, 'Verified change'); expect_send("edit ticket/$ticket_id set CF-myCF$$=\"1's,2,3\"", 'Changing CF...'); expect_like(qr/Ticket $ticket_id updated/, 'Changed cf'); expect_send("show ticket/$ticket_id -f CF-myCF$$", 'Checking new value'); -expect_like(qr/CF\.{myCF$$}: 1's,2,3/i, 'Verified change'); +expect_like(qr/\QCF.{myCF$$}\E: 1's,2,3/i, 'Verified change'); # Test reading and setting custom fields with multiple values expect_send("show ticket/$ticket_id -f CF-MultipleCF$$", 'Checking initial value'); -expect_like(qr/CF\.{MultipleCF$$}:/i, 'Verified multiple cf change'); +expect_like(qr/\QCF.{MultipleCF$$}\E:/i, 'Verified multiple cf change'); expect_send("edit ticket/$ticket_id set CF.{MultipleCF$$}=1,2,3 ", 'Changing CF...'); expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf'); expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value'); -expect_like(qr/CF\.{MultipleCF$$}: 1,\s*2,\s*3/i, 'Verified multiple cf change'); +expect_like(qr/\QCF.{MultipleCF$$}\E: 1,\s*2,\s*3/i, 'Verified multiple cf change'); expect_send("edit ticket/$ticket_id set CF.{MultipleCF$$}=a,b,c ", 'Changing CF...'); expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf'); expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value'); -expect_like(qr/CF\.{MultipleCF$$}: a,\s*b,\s*c/i, 'Verified change'); +expect_like(qr/\QCF.{MultipleCF$$}\E: a,\s*b,\s*c/i, 'Verified change'); expect_send("edit ticket/$ticket_id del CF.{MultipleCF$$}=a", 'Changing CF...'); expect_like(qr/Ticket $ticket_id updated/, 'del multiple cf'); expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value'); -expect_like(qr/CF\.{MultipleCF$$}: b,\s*c/i, 'Verified multiple cf change'); +expect_like(qr/\QCF.{MultipleCF$$}\E: b,\s*c/i, 'Verified multiple cf change'); expect_send("edit ticket/$ticket_id add CF.{MultipleCF$$}=o", 'Changing CF...'); expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf'); expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value'); -expect_like(qr/CF\.{MultipleCF$$}: b,\s*c,\s*o/i, 'Verified multiple cf change'); +expect_like(qr/\QCF.{MultipleCF$$}\E: b,\s*c,\s*o/i, 'Verified multiple cf change'); expect_send("edit ticket/$ticket_id set CF.{MultipleCF$$}=\"'a,b,c'\" ", 'Changing CF...'); expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf'); expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value'); -expect_like(qr/CF\.{MultipleCF$$}: 'a,b,c'/i, 'Verified change'); +expect_like(qr/\QCF.{MultipleCF$$}\E: 'a,b,c'/i, 'Verified change'); expect_send("edit ticket/$ticket_id del CF.{MultipleCF$$}=a", 'Changing CF...'); expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf'); expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value'); -expect_like(qr/CF\.{MultipleCF$$}: 'a,b,c'/i, 'Verified change'); +expect_like(qr/\QCF.{MultipleCF$$}\E: 'a,b,c'/i, 'Verified change'); expect_send("edit ticket/$ticket_id set CF.{MultipleCF$$}=q{a,b,c}", 'Changing CF...'); expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf'); expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value'); -expect_like(qr/CF\.{MultipleCF$$}: 'a,b,c'/i, 'Verified change'); +expect_like(qr/\QCF.{MultipleCF$$}\E: 'a,b,c'/i, 'Verified change'); expect_send("edit ticket/$ticket_id del CF.{MultipleCF$$}=a", 'Changing CF...'); expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf'); expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value'); -expect_like(qr/CF\.{MultipleCF$$}: 'a,b,c'/i, 'Verified change'); +expect_like(qr/\QCF.{MultipleCF$$}\E: 'a,b,c'/i, 'Verified change'); expect_send("edit ticket/$ticket_id del CF.{MultipleCF$$}=\"'a,b,c'\"", 'Changing CF...'); expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf'); expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value'); -expect_like(qr/CF\.{MultipleCF$$}: \s*$/i, 'Verified change'); +expect_like(qr/\QCF.{MultipleCF$$}\E: \s*$/i, 'Verified change'); expect_send("edit ticket/$ticket_id set CF.{MultipleCF$$}=\"q{1,2's,3}\"", 'Changing CF...'); expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf'); expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value'); -expect_like(qr/CF\.{MultipleCF$$}: '1,2\\'s,3'/i, 'Verified change'); +expect_like(qr/\QCF.{MultipleCF$$}\E: '1,2\\'s,3'/i, 'Verified change'); # ... # change a ticket's ...[other properties]... diff --git a/rt/t/web/crypt-gnupg.t b/rt/t/web/crypt-gnupg.t index 1743a3a8e..85e090cbc 100644 --- a/rt/t/web/crypt-gnupg.t +++ b/rt/t/web/crypt-gnupg.t @@ -2,7 +2,7 @@ use strict; use warnings; use RT::Test::GnuPG - tests => 102, + tests => 104, gnupg_options => { passphrase => 'recipient', 'trust-model' => 'always', @@ -444,5 +444,7 @@ like($content, qr/KR-general\@example.com-K/, "KeyRequestors does not issue no-p like($content, qr/KR-nokey\@example.com \(no pubkey!\)-K/, "KeyRequestors DOES issue no-pubkey warning for nokey\@example.com"); $m->next_warning_like(qr/public key not found/); +$m->next_warning_like(qr/above error may result from an unconfigured RT\/GPG/); $m->next_warning_like(qr/public key not found/); +$m->next_warning_like(qr/above error may result from an unconfigured RT\/GPG/); $m->no_leftover_warnings_ok; diff --git a/rt/t/web/gnupg-select-keys-on-create.t b/rt/t/web/gnupg-select-keys-on-create.t index 893ae65c9..8c1ae448c 100644 --- a/rt/t/web/gnupg-select-keys-on-create.t +++ b/rt/t/web/gnupg-select-keys-on-create.t @@ -1,7 +1,7 @@ use strict; use warnings; -use RT::Test::GnuPG tests => 79, gnupg_options => { passphrase => 'rt-test' }; +use RT::Test::GnuPG tests => 83, gnupg_options => { passphrase => 'rt-test' }; use RT::Action::SendEmail; my $queue = RT::Test->load_or_create_queue( @@ -66,7 +66,11 @@ diag "check that things don't work if there is no key"; my @mail = RT::Test->fetch_caught_mails; ok !@mail, 'there are no outgoing emails'; - $m->next_warning_like(qr/public key not found/) for 1 .. 4; + for (1 .. 4) { + $m->next_warning_like(qr/public key not found/) ; + $m->next_warning_like(qr/above error may result from an unconfigured RT\/GPG/); + } + $m->no_leftover_warnings_ok; } diff --git a/rt/t/web/gnupg-select-keys-on-update.t b/rt/t/web/gnupg-select-keys-on-update.t index 1509d1df3..a5b01d3ae 100644 --- a/rt/t/web/gnupg-select-keys-on-update.t +++ b/rt/t/web/gnupg-select-keys-on-update.t @@ -1,7 +1,7 @@ use strict; use warnings; -use RT::Test::GnuPG tests => 86, gnupg_options => { passphrase => 'rt-test' }; +use RT::Test::GnuPG tests => 88, gnupg_options => { passphrase => 'rt-test' }; use RT::Action::SendEmail; @@ -82,7 +82,10 @@ diag "check that things don't work if there is no key"; my @mail = RT::Test->fetch_caught_mails; ok !@mail, 'there are no outgoing emails'; - $m->next_warning_like(qr/public key not found/) for 1 .. 2; + for (1 .. 2) { + $m->next_warning_like(qr/public key not found/); + $m->next_warning_like(qr/above error may result from an unconfigured RT\/GPG/); + } $m->no_leftover_warnings_ok; } diff --git a/rt/t/web/installer.t b/rt/t/web/installer.t index a34cdcb4b..79198a7e8 100644 --- a/rt/t/web/installer.t +++ b/rt/t/web/installer.t @@ -57,6 +57,7 @@ diag "Walking through install screens setting defaults"; $m->submit_form(with_fields => { DatabaseAdmin => $ENV{RT_DBA_USER}, DatabaseAdminPassword => $ENV{RT_DBA_PASSWORD}, + DatabasePassword => "rt_pass", }); } $m->content_contains('Connection succeeded'); diff --git a/rt/t/web/reminders.t b/rt/t/web/reminders.t index af7e2fb26..510235156 100644 --- a/rt/t/web/reminders.t +++ b/rt/t/web/reminders.t @@ -51,10 +51,10 @@ is($col->Count, 1, 'got a reminder'); my $reminder = $col->First; is($reminder->Subject, "baby's first reminder"); my $reminder_id = $reminder->id; -is($reminder->Status, 'new'); +is($reminder->Status, 'open'); -$ticket->SetStatus('new'); -is( $ticket->Status, 'new', 'changed back to new' ); +$ticket->SetStatus('open'); +is( $ticket->Status, 'open', 'changed back to new' ); $m->goto_ticket($ticket->id); $m->text_contains('New reminder:', "can create a new reminder"); @@ -72,7 +72,7 @@ DBIx::SearchBuilder::Record::Cachable->FlushCache; $reminder = RT::Ticket->new($user); $reminder->Load($reminder_id); is($reminder->Subject, 'changed the subject'); -is($reminder->Status, 'new'); +is($reminder->Status, 'open'); $m->goto_ticket($ticket->id); $m->form_name('UpdateReminders'); diff --git a/rt/t/web/rest_cfs_with_same_name.t b/rt/t/web/rest_cfs_with_same_name.t index 958f67177..9ab6e9a06 100644 --- a/rt/t/web/rest_cfs_with_same_name.t +++ b/rt/t/web/rest_cfs_with_same_name.t @@ -69,10 +69,10 @@ for my $queue_name (qw/foo bar/) { ] ); $text = $m->content; - like( $text, qr/^CF\.{test}: baz\s*$/m, 'cf value in rest show' ); + like( $text, qr/^CF\.\{test\}: baz\s*$/m, 'cf value in rest show' ); $text =~ s{.*}{}; # remove header - $text =~ s!CF\.{test}: baz!CF.{test}: newbaz!; + $text =~ s!CF\.\{test\}: baz!CF.{test}: newbaz!; $m->post( "$baseurl/REST/1.0/ticket/edit", [ diff --git a/rt/t/web/self_service.t b/rt/t/web/self_service.t index 49d9e37ee..adc90d776 100644 --- a/rt/t/web/self_service.t +++ b/rt/t/web/self_service.t @@ -1,13 +1,37 @@ use strict; use warnings; -use RT::Test tests => 9; + +use RT::Test + tests => 17, + config => 'Set( $ShowUnreadMessageNotifications, 1 );' +; my ($url, $m) = RT::Test->started_ok; -my ($ticket) = - RT::Test->create_ticket( Queue => 'General', Subject => 'test subject' ); +my $user_a = RT::Test->load_or_create_user( + Name => 'user_a', + Password => 'password', + EmailAddress => 'user_a@example.com', + Privileged => 0, +); +ok( $user_a && $user_a->id, 'loaded or created user' ); +ok( ! $user_a->Privileged, 'user is not privileged' ); + +# Load Cc group +my $Cc = RT::Group->new( RT->SystemUser ); +my($ok, $msg) = $Cc->LoadSystemRoleGroup( 'Cc' ); +ok($ok, $msg); +RT::Test->add_rights( { Principal => $Cc, Right => ['ShowTicket'] } ); + +my ($ticket) = RT::Test->create_ticket( + Queue => 'General', + Subject => 'test subject', + Cc => 'user_a@example.com', +); + +my @results = $ticket->Correspond( Content => 'sample correspondence' ); -$m->login(); +ok( $m->login('user_a' => 'password'), 'unprivileged user logged in' ); $m->get_ok( '/SelfService/Display.html?id=' . $ticket->id, 'got selfservice display page' ); @@ -16,4 +40,16 @@ my $title = '#' . $ticket->id . ': test subject'; $m->title_is( $title ); $m->content_contains( "<h1>$title</h1>", "contains <h1>$title</h1>" ); +# $ShowUnreadMessageNotifications tests: +$m->content_contains( "There are unread messages on this ticket." ); + +# mark the message as read +$m->follow_link_ok( + { text => 'jump to the first unread message and mark all messages as seen' }, + 'followed mark as seen link' +); + +$m->content_contains( "<h1>$title</h1>", "contains <h1>$title</h1>" ); +$m->content_lacks( "There are unread messages on this ticket." ); + # TODO need more SelfService tests diff --git a/rt/t/web/user_update.t b/rt/t/web/user_update.t index f55c773cd..c0e9e5264 100644 --- a/rt/t/web/user_update.t +++ b/rt/t/web/user_update.t @@ -35,7 +35,7 @@ $m->text_contains("Lang changed from 'en_us' to 'ja'"); $m->text_contains("実名", "Page content is japanese"); $m->submit_form_ok({ with_fields => { Lang => ''} }, "And set to the default"); -$m->text_contains("Langは「'ja'」から「''」に変更されました"); +$m->text_contains("Langは「'ja'」から「(値なし)」に変更されました"); $m->text_contains("Real Name", "Page content is english"); undef $m; |