diff options
Diffstat (limited to 'rt/lib/RT/Interface/Web')
-rw-r--r-- | rt/lib/RT/Interface/Web/Handler.pm | 96 | ||||
-rw-r--r-- | rt/lib/RT/Interface/Web/Menu.pm | 14 | ||||
-rw-r--r-- | rt/lib/RT/Interface/Web/Middleware/StaticHeaders.pm | 80 | ||||
-rwxr-xr-x | rt/lib/RT/Interface/Web/QueryBuilder/Tree.pm | 7 | ||||
-rw-r--r-- | rt/lib/RT/Interface/Web/Request.pm | 3 | ||||
-rw-r--r-- | rt/lib/RT/Interface/Web/Session.pm | 30 |
6 files changed, 198 insertions, 32 deletions
diff --git a/rt/lib/RT/Interface/Web/Handler.pm b/rt/lib/RT/Interface/Web/Handler.pm index fc95aa10e..8667f014d 100644 --- a/rt/lib/RT/Interface/Web/Handler.pm +++ b/rt/lib/RT/Interface/Web/Handler.pm @@ -54,7 +54,6 @@ use CGI qw/-private_tempfiles/; use MIME::Entity; use Text::Wrapper; use CGI::Cookie; -use Time::ParseDate; use Time::HiRes; use HTML::Scrubber; use RT::Interface::Web; @@ -62,6 +61,9 @@ use RT::Interface::Web::Request; use File::Path qw( rmtree ); use File::Glob qw( bsd_glob ); use File::Spec::Unix; +use HTTP::Message::PSGI; +use HTTP::Request; +use HTTP::Response; sub DefaultHandlerArgs { ( comp_root => [ @@ -104,7 +106,6 @@ sub InitSessionDir { } -use UNIVERSAL::require; sub NewHandler { my $class = shift; $class->require or die $!; @@ -114,7 +115,7 @@ sub NewHandler { @_ ); - $handler->interp->set_escape( h => \&RT::Interface::Web::EscapeUTF8 ); + $handler->interp->set_escape( h => \&RT::Interface::Web::EscapeHTML ); $handler->interp->set_escape( u => \&RT::Interface::Web::EscapeURI ); $handler->interp->set_escape( j => \&RT::Interface::Web::EscapeJS ); return($handler); @@ -154,7 +155,7 @@ and is not recommended to change. =item Clean up state of RT::Action::SendEmail using 'CleanSlate' method -=item Flush tmp GnuPG key preferences +=item Flush tmp crypt key preferences =back @@ -181,10 +182,9 @@ sub CleanupRequest { require RT::Action::SendEmail; RT::Action::SendEmail->CleanSlate; - if (RT->Config->Get('GnuPG')->{'Enable'}) { - require RT::Crypt::GnuPG; - RT::Crypt::GnuPG::UseKeyForEncryption(); - RT::Crypt::GnuPG::UseKeyForSigning( undef ); + if (RT->Config->Get('Crypt')->{'Enable'}) { + RT::Crypt->UseKeyForEncryption(); + RT::Crypt->UseKeyForSigning( undef ); } %RT::Ticket::MERGE_CACHE = ( effective => {}, merged => {} ); @@ -248,6 +248,7 @@ MODPERL use RT::Interface::Web::Handler; use CGI::Emulate::PSGI; +use Plack::Builder; use Plack::Request; use Plack::Response; use Plack::Util; @@ -262,7 +263,7 @@ sub PSGIApp { $self->InitSessionDir; - return sub { + my $mason = sub { my $env = shift; { @@ -270,7 +271,14 @@ sub PSGIApp { return $self->_psgi_response_cb( $res->finalize ) if $res; } - RT::ConnectToDatabase() unless RT->InstallMode; + unless (RT->InstallMode) { + unless (eval { RT::ConnectToDatabase() }) { + my $res = Plack::Response->new(503); + $res->content_type("text/plain"); + $res->body("Database inaccessible; contact the RT administrator (".RT->Config->Get("OwnerEmail").")"); + return $self->_psgi_response_cb( $res->finalize, sub { $self->CleanupRequest } ); + } + } my $req = Plack::Request->new($env); @@ -307,7 +315,59 @@ sub PSGIApp { sub { $self->CleanupRequest() }); -}; + }; + + my $app = $self->StaticWrap($mason); + for my $plugin (RT->Config->Get("Plugins")) { + my $wrap = $plugin->can("PSGIWrap") + or next; + $app = $wrap->($plugin, $app); + } + return $app; +} + +sub StaticWrap { + my $self = shift; + my $app = shift; + my $builder = Plack::Builder->new; + + my $headers = RT::Interface::Web::GetStaticHeaders(Time => 'forever'); + + for my $static ( RT->Config->Get('StaticRoots') ) { + if ( ref $static && ref $static eq 'HASH' ) { + $builder->add_middleware( + '+RT::Interface::Web::Middleware::StaticHeaders', + path => $static->{'path'}, + headers => $headers, + ); + $builder->add_middleware( + 'Plack::Middleware::Static', + pass_through => 1, + %$static + ); + } + else { + $RT::Logger->error( + "Invalid config StaticRoots: item can only be a hashref" ); + } + } + + my $path = sub { s!^/static/!! }; + $builder->add_middleware( + '+RT::Interface::Web::Middleware::StaticHeaders', + path => $path, + headers => $headers, + ); + for my $root (RT::Interface::Web->StaticRoots) { + $builder->add_middleware( + 'Plack::Middleware::Static', + path => $path, + root => $root, + pass_through => 1, + ); + } + return $builder->to_app($app); +} sub _psgi_response_cb { my $self = shift; @@ -334,7 +394,19 @@ sub _psgi_response_cb { return $_[0]; }; }); - } +} + +sub GetStatic { + my $class = shift; + my $path = shift; + my $static = $class->StaticWrap( + # Anything the static wrap doesn't handle gets 404'd. + sub { [404, [], []] } + ); + my $response = HTTP::Response->from_psgi( + $static->( HTTP::Request->new(GET => $path)->to_psgi ) + ); + return $response; } 1; diff --git a/rt/lib/RT/Interface/Web/Menu.pm b/rt/lib/RT/Interface/Web/Menu.pm index 03ce8ac5a..8670b8acf 100644 --- a/rt/lib/RT/Interface/Web/Menu.pm +++ b/rt/lib/RT/Interface/Web/Menu.pm @@ -57,7 +57,7 @@ use URI; use Scalar::Util qw(weaken); __PACKAGE__->mk_accessors(qw( - key title description raw_html escape_title sort_order target class + key title description raw_html escape_title sort_order target class attributes )); =head1 NAME @@ -70,9 +70,9 @@ RT::Interface::Web::Menu - Handle the API for menu navigation Creates a new L<RT::Interface::Web::Menu> object. Possible keys in the I<PARAMHASH> are L</parent>, L</title>, L</description>, L</path>, -L</raw_html>, L<escape_title>, L</sort_order>, L</class>, L</target> and -L</active>. See the subroutines with the respective name below for -each option's use. +L</raw_html>, L<escape_title>, L</sort_order>, L</class>, L</target>, +L<attributes>, and L</active>. See the subroutines with the respective name +below for each option's use. =cut @@ -139,6 +139,12 @@ Get or set the frame or pseudo-target for this link. something like L<_blank> Gets or sets the CSS class the menu item should have in addition to the default classes. This is only used if L</raw_html> isn't specified. +=head2 attributes [HASHREF] + +Gets or sets a hashref of HTML attribute name-value pairs that the menu item +should have in addition to the attributes which have their own accessor, like +L</class> and L</target>. This is only used if L</raw_html> isn't specified. + =head2 path Gets or sets the URL that the menu's link goes to. If the link diff --git a/rt/lib/RT/Interface/Web/Middleware/StaticHeaders.pm b/rt/lib/RT/Interface/Web/Middleware/StaticHeaders.pm new file mode 100644 index 000000000..6d98d9ecd --- /dev/null +++ b/rt/lib/RT/Interface/Web/Middleware/StaticHeaders.pm @@ -0,0 +1,80 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2015 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 }}} + +package RT::Interface::Web::Middleware::StaticHeaders; + +use strict; +use warnings; +use base 'Plack::Middleware'; +use Plack::Util; + +use Plack::Util::Accessor qw(path headers); + +sub call { + my ( $self, $env ) = @_; + my $res = $self->app->($env); + my $path_match = $self->path; + my $path = $env->{'PATH_INFO'}; + for ($path) { + my $matched = 'CODE' eq ref $path_match ? + $path_match->($_, $env) + : $_ =~ $path_match; + return $res unless $matched; + return $self->response_cb( $res, + sub { + my $res = shift; + my $headers = $res->[1]; + Plack::Util::header_iter( $self->headers, sub { + Plack::Util::header_set($headers, @_); + } ); + } + ); + } +} + +1; diff --git a/rt/lib/RT/Interface/Web/QueryBuilder/Tree.pm b/rt/lib/RT/Interface/Web/QueryBuilder/Tree.pm index 1da160c8d..d7de61ccf 100755 --- a/rt/lib/RT/Interface/Web/QueryBuilder/Tree.pm +++ b/rt/lib/RT/Interface/Web/QueryBuilder/Tree.pm @@ -113,9 +113,7 @@ sub GetReferencedQueues { return unless $clause->{Key} eq 'Queue'; return unless $clause->{Op} eq '='; - my $value = $clause->{Value}; - $value =~ s/\\(.)/$1/g if $value =~ s/^'(.*)'$/$1/; - $queues->{ $value } = 1; + $queues->{ $clause->{RawValue} } = 1; } ); @@ -257,6 +255,7 @@ sub ParseSQL { $callback{'EntryAggregator'} = sub { $node->setNodeValue( $_[0] ) }; $callback{'Condition'} = sub { my ($key, $op, $value) = @_; + my $rawvalue = $value; my ($main_key) = split /[.]/, $key; @@ -281,7 +280,7 @@ sub ParseSQL { $key = "'$key'"; } - my $clause = { Key => $key, Op => $op, Value => $value }; + my $clause = { Key => $key, Op => $op, Value => $value, RawValue => $rawvalue }; $node->addChild( __PACKAGE__->new( $clause ) ); }; $callback{'Error'} = sub { push @results, @_ }; diff --git a/rt/lib/RT/Interface/Web/Request.pm b/rt/lib/RT/Interface/Web/Request.pm index 7a246a32b..61cfa70ff 100644 --- a/rt/lib/RT/Interface/Web/Request.pm +++ b/rt/lib/RT/Interface/Web/Request.pm @@ -51,7 +51,6 @@ package RT::Interface::Web::Request; use strict; use warnings; -our $VERSION = '0.30'; use HTML::Mason::PSGIHandler; use base qw(HTML::Mason::Request::PSGI); use Params::Validate qw(:all); @@ -65,8 +64,6 @@ sub new { =head2 callback -Method replaces deprecated component C<Element/Callback>. - Takes hash with optional C<CallbackPage>, C<CallbackName> and C<CallbackOnce> arguments, other arguments are passed throught to callback components. diff --git a/rt/lib/RT/Interface/Web/Session.pm b/rt/lib/RT/Interface/Web/Session.pm index d854130b6..c4cc93080 100644 --- a/rt/lib/RT/Interface/Web/Session.pm +++ b/rt/lib/RT/Interface/Web/Session.pm @@ -84,8 +84,7 @@ sub Class { my $class = RT->Config->Get('WebSessionClass') || $self->Backends->{RT->Config->Get('DatabaseType')} || 'Apache::Session::File'; - eval "require $class"; - die $@ if $@; + $class->require or die "Can't load $class: $@"; return $class; } @@ -98,8 +97,9 @@ sessions class names as values. sub Backends { return { - mysql => 'Apache::Session::MySQL', - Pg => 'Apache::Session::Postgres', + mysql => 'Apache::Session::MySQL', + Pg => 'Apache::Session::Postgres', + Oracle => 'Apache::Session::Oracle', }; } @@ -112,15 +112,27 @@ new session objects. sub Attributes { my $class = $_[0]->Class; - return !$class->isa('Apache::Session::File') ? { - Handle => $RT::Handle->dbh, - LockHandle => $RT::Handle->dbh, - Transaction => 1, - } : { + my $res; + if ( my %props = RT->Config->Get('WebSessionProperties') ) { + $res = \%props; + } + elsif ( $class->isa('Apache::Session::File') ) { + $res = { Directory => $RT::MasonSessionDir, LockDirectory => $RT::MasonSessionDir, Transaction => 1, }; + } + else { + $res = { + Handle => $RT::Handle->dbh, + LockHandle => $RT::Handle->dbh, + Transaction => 1, + }; + } + $res->{LongReadLen} = RT->Config->Get('MaxAttachmentSize') + if $class->isa('Apache::Session::Oracle'); + return $res; } =head3 Ids |