Putting 4.2.0 on top of 4.0.17
[usit-rt.git] / lib / RT / Interface / Web / Request.pm
CommitLineData
84fb5b46
MKG
1# BEGIN BPS TAGGED BLOCK {{{
2#
3# COPYRIGHT:
4#
403d7b0b 5# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
84fb5b46
MKG
6# <sales@bestpractical.com>
7#
8# (Except where explicitly superseded by other copyright notices)
9#
10#
11# LICENSE:
12#
13# This work is made available to you under the terms of Version 2 of
14# the GNU General Public License. A copy of that license should have
15# been provided with this software, but in any event can be snarfed
16# from www.gnu.org.
17#
18# This work is distributed in the hope that it will be useful, but
19# WITHOUT ANY WARRANTY; without even the implied warranty of
20# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21# General Public License for more details.
22#
23# You should have received a copy of the GNU General Public License
24# along with this program; if not, write to the Free Software
25# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26# 02110-1301 or visit their web page on the internet at
27# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
28#
29#
30# CONTRIBUTION SUBMISSION POLICY:
31#
32# (The following paragraph is not intended to limit the rights granted
33# to you to modify and distribute this software under the terms of
34# the GNU General Public License and is only of importance to you if
35# you choose to contribute your changes and enhancements to the
36# community by submitting them to Best Practical Solutions, LLC.)
37#
38# By intentionally submitting any modifications, corrections or
39# derivatives to this work, or any other work intended for use with
40# Request Tracker, to Best Practical Solutions, LLC, you confirm that
41# you are the copyright holder for those contributions and you grant
42# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
43# royalty-free, perpetual, license to use, copy, create derivative
44# works based on those contributions, and sublicense and distribute
45# those contributions and any derivatives thereof.
46#
47# END BPS TAGGED BLOCK }}}
48
49package RT::Interface::Web::Request;
50
51use strict;
52use warnings;
53
84fb5b46
MKG
54use HTML::Mason::PSGIHandler;
55use base qw(HTML::Mason::Request::PSGI);
56use Params::Validate qw(:all);
57
58sub new {
59 my $class = shift;
60 $class->valid_params( %{ $class->valid_params },cgi_request => { type => OBJECT, optional => 1 } );
61 return $class->SUPER::new(@_);
62}
63
64
65=head2 callback
66
84fb5b46
MKG
67Takes hash with optional C<CallbackPage>, C<CallbackName>
68and C<CallbackOnce> arguments, other arguments are passed
69throught to callback components.
70
71=over 4
72
73=item CallbackPage
74
75Page path relative to the root, leading slash is mandatory.
76By default is equal to path of the caller component.
77
78=item CallbackName
79
80Name of the callback. C<Default> is used unless specified.
81
82=item CallbackOnce
83
84By default is false, otherwise runs callbacks only once per
85process of the server. Such callbacks can be used to fill
86structures.
87
88=back
89
90Searches for callback components in
91F<< /Callbacks/<any dir>/CallbackPage/CallbackName >>, for
92example F</Callbacks/MyExtension/autohandler/Default> would
93be called as default callback for F</autohandler>.
94
95=cut
96
97{
98my %cache = ();
99my %called = ();
100sub callback {
101 my ($self, %args) = @_;
102
103 my $name = delete $args{'CallbackName'} || 'Default';
104 my $page = delete $args{'CallbackPage'} || $self->callers(0)->path;
105 unless ( $page ) {
106 $RT::Logger->error("Couldn't get a page name for callbacks");
107 return;
108 }
109
110 my $CacheKey = "$page--$name";
111 return 1 if delete $args{'CallbackOnce'} && $called{ $CacheKey };
112 $called{ $CacheKey } = 1;
113
114 my $callbacks = $cache{ $CacheKey };
115 unless ( $callbacks ) {
116 $callbacks = [];
117 my $path = "/Callbacks/*$page/$name";
118 my @roots = RT::Interface::Web->ComponentRoots;
119 my %seen;
120 @$callbacks = (
121 grep defined && length,
122 # Skip backup files, files without a leading package name,
123 # and files we've already seen
124 grep !$seen{$_}++ && !m{/\.} && !m{~$} && m{^/Callbacks/[^/]+\Q$page/$name\E$},
125 map { sort $self->interp->resolver->glob_path($path, $_) }
126 @roots
127 );
128 foreach my $comp (keys %seen) {
129 next unless $seen{$comp} > 1;
130 $RT::Logger->error("Found more than one occurrence of the $comp callback. This may cause only one of the callbacks to run. Look for the duplicate Callback in your @roots");
131 }
132
133 $cache{ $CacheKey } = $callbacks unless RT->Config->Get('DevelMode');
134 }
135
136 my @rv;
137 foreach my $cb ( @$callbacks ) {
138 push @rv, scalar $self->comp( $cb, %args );
139 }
140 return @rv;
141}
403d7b0b
MKG
142
143sub clear_callback_cache {
144 %cache = %called = ();
145}
84fb5b46
MKG
146}
147
148=head2 request_path
149
150Returns path of the request.
151
152Very close to C<< $m->request_comp->path >>, but if called in a dhandler returns
153path of the request without dhandler name, but with dhandler arguments instead.
154
155=cut
156
157sub request_path {
158 my $self = shift;
159
160 my $path = $self->request_comp->path;
161 # disabled dhandlers, not RT case, but anyway
162 return $path unless my $dh_name = $self->dhandler_name;
163 # not a dhandler
164 return $path unless substr($path, -length("/$dh_name")) eq "/$dh_name";
165 substr($path, -length $dh_name) = $self->dhandler_arg;
166 return $path;
167}
168
403d7b0b
MKG
169=head2 abort
170
171Logs any recorded SQL statements for this request before calling the standard
172abort.
173
174=cut
175
176sub abort {
177 my $self = shift;
178 RT::Interface::Web::LogRecordedSQLStatements(
179 RequestData => {
180 Path => $self->request_path,
181 },
182 );
183 return $self->SUPER::abort(@_);
184}
185
84fb5b46 1861;