1 %# BEGIN BPS TAGGED BLOCK {{{
5 %# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC
6 %# <sales@bestpractical.com>
8 %# (Except where explicitly superseded by other copyright notices)
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
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.
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.
30 %# CONTRIBUTION SUBMISSION POLICY:
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.)
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.
47 %# END BPS TAGGED BLOCK }}}
49 Title => loc("Ticket #[_1]: [_2]", $TicketObj->Id, $TicketObj->Subject),
50 LinkRel => \%link_rel &>
51 <& /Ticket/Elements/Tabs,
53 current_tab => 'Ticket/Display.html?id='.$TicketObj->id,
54 Title => loc("Ticket #[_1]: [_2]", $TicketObj->Id, $TicketObj->Subject) &>
56 % $m->callback(CallbackName => 'BeforeActionList', %ARGS, Actions => \@Actions, ARGSRef => \%ARGS, Ticket => $TicketObj);
58 <& /Elements/ListActions, actions => \@Actions &>
59 <& Elements/ShowUpdateStatus, Ticket => $TicketObj &>
61 % $m->callback( %ARGS, Ticket => $TicketObj, CallbackName => 'BeforeShowSummary' );
63 <&| /Widgets/TitleBox, title => loc('Ticket metadata') &>
64 <& /Ticket/Elements/ShowSummary, Ticket => $TicketObj, Attachments => $attachments &>
69 % $m->callback( Ticket => $TicketObj, %ARGS, CallbackName => 'BeforeShowHistory' );
71 <& /Ticket/Elements/ShowHistory ,
74 Collapsed => $ARGS{'Collapsed'},
75 ShowHeaders => $ARGS{'ShowHeaders'},
76 Attachments => $attachments,
77 AttachmentContent => $attachment_content
80 % $m->callback( %ARGS,
81 % Ticket => $TicketObj,
82 % current_tab => 'Ticket/Display.html?id=' . $TicketObj->id,
83 % CallbackName => 'AfterShowHistory',
95 $m->callback( TicketObj => $TicketObj, ARGSRef => \%ARGS, CallbackName => 'Initial' );
97 my (@Actions, $Tickets);
100 unless ($id || $TicketObj) {
101 Abort('No ticket specified');
104 if ($ARGS{'id'} eq 'new') {
105 # {{{ Create a new ticket
107 # Massage customer IDs into member links.
108 my @cust_uris = map {
109 /^(\d+)$/ && "freeside://freeside/cust_main/$1"
110 } split(' ', $ARGS{'new-Customer'});
112 $ARGS{'new-MemberOf'} =
113 join(' ', $ARGS{'new-MemberOf'}, @cust_uris);
115 my $Queue = new RT::Queue( $session{'CurrentUser'} );
116 $Queue->Load($ARGS{'Queue'});
117 unless ( $Queue->id ) {
118 Abort('Queue not found');
121 unless ( $Queue->CurrentUserHasRight('CreateTicket') ) {
122 Abort('You have no permission to create tickets in that queue.');
125 ($TicketObj, @Actions) = CreateTicket(
126 Attachments => delete $session{'Attachments'},
129 unless ( $TicketObj->CurrentUserHasRight('ShowTicket') ) {
130 Abort("No permission to view newly created ticket #".$TicketObj->id.".");
134 $TicketObj ||= LoadTicket($ARGS{'id'});
136 $m->callback( CallbackName => 'BeforeProcessArguments',
137 TicketObj => $TicketObj, Tickets => $Tickets,
138 ActionsRef => \@Actions, ARGSRef => \%ARGS );
139 if ( defined $ARGS{'Action'} ) {
140 if ($ARGS{'Action'} =~ /^(Steal|Kill|Take|SetTold)$/) {
142 my ($res, $msg) = $TicketObj->$action();
143 push(@Actions, $msg);
147 $m->callback(CallbackName => 'ProcessArguments',
148 Ticket => $TicketObj,
150 Actions => \@Actions);
152 $ARGS{UpdateAttachments} = $session{'Attachments'};
154 ProcessUpdateMessage(
156 Actions => \@Actions,
157 TicketObj => $TicketObj,
159 delete $session{'Attachments'};
161 #Process status updates
162 push @Actions, ProcessTicketWatchers(ARGSRef => \%ARGS, TicketObj => $TicketObj );
163 push @Actions, ProcessTicketBasics( ARGSRef => \%ARGS, TicketObj => $TicketObj );
164 push @Actions, ProcessTicketLinks( ARGSRef => \%ARGS, TicketObj => $TicketObj );
165 push @Actions, ProcessTicketDates( ARGSRef => \%ARGS, TicketObj => $TicketObj );
166 push @Actions, ProcessTicketCustomFieldUpdates(ARGSRef => \%ARGS, TicketObj => $TicketObj );
167 # If this fails due to required fields being empty, it will set
168 # notes('RedirectToBasics').
169 push @Actions, ProcessTicketStatus( ARGSRef => \%ARGS, TicketObj => $TicketObj );
171 # XXX: we shouldn't block actions here if user has no right to see the
172 # ticket, but we should allow him to see actions he has done
173 unless ($TicketObj->CurrentUserHasRight('ShowTicket')) {
174 Abort("No permission to view ticket");
176 if ( $ARGS{'MarkAsSeen'} ) {
177 $TicketObj->SetAttribute(
178 Name => 'User-'. $TicketObj->CurrentUser->id .'-SeenUpTo',
179 Content => $TicketObj->LastUpdated,
181 push @Actions, loc('Marked all messages as seen');
186 CallbackName => 'BeforeDisplay',
187 TicketObj => \$TicketObj,
188 Tickets => \$Tickets,
189 Actions => \@Actions,
193 # This code does automatic redirection if any updates happen.
197 # We've done something, so we need to clear the decks to avoid
198 # resubmission on refresh.
199 # But we need to store Actions somewhere too, so we don't lose them.
200 my $key = Digest::MD5::md5_hex( rand(1024) );
201 push @{ $session{"Actions"}->{$key} ||= [] }, @Actions;
203 my $url = RT->Config->Get('WebURL');
204 if ( $m->notes('RedirectToBasics') ) {
205 $url .= 'Ticket/Modify.html';
208 $url .= 'Ticket/Display.html';
210 $url .= '?id=' . $TicketObj->id . "&results=" . $key;
211 $url .= '#' . $ARGS{Anchor} if $ARGS{Anchor};
212 RT::Interface::Web::Redirect($url);
215 my $attachments = $m->comp('Elements/FindAttachments', Ticket => $TicketObj, Tickets => $Tickets);
216 my $attachment_content = $m->comp('Elements/LoadTextAttachments', Ticket => $TicketObj);
219 if (defined $session{'tickets'} and ($ARGS{'Query'} or $session{'CurrentSearchHash'}->{'Query'})) {
220 my $item_map = $session{'tickets'}->ItemMap;
221 $link_rel{first} = "Ticket/Display.html?id=" . $item_map->{first} if $item_map->{$TicketObj->Id}{prev};
222 $link_rel{prev} = "Ticket/Display.html?id=" . $item_map->{$TicketObj->Id}{prev} if $item_map->{$TicketObj->Id}{prev};
223 $link_rel{next} = "Ticket/Display.html?id=" . $item_map->{$TicketObj->Id}{next} if $item_map->{$TicketObj->Id}{next};
224 $link_rel{last} = "Ticket/Display.html?id=" . $item_map->{last} if $item_map->{$TicketObj->Id}{next};