TimeWorked-like custom fields, RT#11168
[freeside.git] / rt / share / html / Ticket / Display.html
1 %# BEGIN BPS TAGGED BLOCK {{{
2 %#
3 %# COPYRIGHT:
4 %#
5 %# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC
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 <& /Elements/Header, 
49     Title => loc("Ticket #[_1]: [_2]", $TicketObj->Id, $TicketObj->Subject),
50     LinkRel => \%link_rel &>
51 <& /Ticket/Elements/Tabs, 
52     Ticket => $TicketObj, 
53     current_tab => 'Ticket/Display.html?id='.$TicketObj->id,
54     Title => loc("Ticket #[_1]: [_2]", $TicketObj->Id, $TicketObj->Subject) &>
55
56 % $m->callback(CallbackName => 'BeforeActionList', %ARGS, Actions => \@Actions, ARGSRef => \%ARGS, Ticket => $TicketObj);
57
58 <& /Elements/ListActions, actions => \@Actions &>
59 <& Elements/ShowUpdateStatus, Ticket => $TicketObj &>
60
61 % $m->callback( %ARGS, Ticket => $TicketObj, CallbackName => 'BeforeShowSummary' );
62 <div class="summary">
63 <&| /Widgets/TitleBox, title => loc('Ticket metadata') &>
64 <& /Ticket/Elements/ShowSummary,  Ticket => $TicketObj, Attachments => $attachments &>
65 </&>
66 </div>
67 <br />
68
69 % $m->callback( Ticket => $TicketObj, %ARGS, CallbackName => 'BeforeShowHistory' );
70
71 <& /Ticket/Elements/ShowHistory , 
72       Ticket => $TicketObj, 
73       Tickets => $Tickets, 
74       Collapsed => $ARGS{'Collapsed'}, 
75       ShowHeaders => $ARGS{'ShowHeaders'},
76       Attachments => $attachments,
77       AttachmentContent => $attachment_content
78 &> 
79
80 % $m->callback( %ARGS,
81 %     Ticket       => $TicketObj,
82 %     current_tab  => 'Ticket/Display.html?id=' . $TicketObj->id,
83 %     CallbackName => 'AfterShowHistory',
84 % );
85
86 <%ARGS>
87 $id => undef
88 $TicketObj => undef
89 $ShowHeaders => 0
90 $Collapsed => undef
91 </%ARGS>
92
93 <%INIT>
94
95 $m->callback( TicketObj => $TicketObj, ARGSRef => \%ARGS, CallbackName => 'Initial' );
96
97 my (@Actions, $Tickets);  
98
99
100 unless ($id || $TicketObj) {
101     Abort('No ticket specified');
102 }
103
104 if ($ARGS{'id'} eq 'new') {
105     # {{{ Create a new ticket
106
107     my $Queue = new RT::Queue( $session{'CurrentUser'} );
108     $Queue->Load($ARGS{'Queue'});
109     unless ( $Queue->id ) {
110         Abort('Queue not found');
111     }
112
113     unless ( $Queue->CurrentUserHasRight('CreateTicket') ) {
114         Abort('You have no permission to create tickets in that queue.');
115     }
116
117     ($TicketObj, @Actions) = CreateTicket(
118         Attachments => delete $session{'Attachments'},
119         %ARGS,
120     );
121     unless ( $TicketObj->CurrentUserHasRight('ShowTicket') ) {
122         Abort("No permission to view newly created ticket #".$TicketObj->id.".");
123     }
124     # }}}
125 } else { 
126     $TicketObj ||= LoadTicket($ARGS{'id'});
127
128     $m->callback( CallbackName => 'BeforeProcessArguments',
129         TicketObj => $TicketObj, Tickets => $Tickets,
130         ActionsRef => \@Actions, ARGSRef => \%ARGS );
131     if ( defined $ARGS{'Action'} ) {
132         if ($ARGS{'Action'} =~ /^(Steal|Kill|Take|SetTold)$/) {
133             my $action = $1;
134             my ($res, $msg) = $TicketObj->$action();
135             push(@Actions, $msg);
136         }
137     }
138
139     $m->callback(CallbackName => 'ProcessArguments', 
140             Ticket => $TicketObj, 
141             ARGSRef => \%ARGS, 
142             Actions => \@Actions);
143     
144     $ARGS{UpdateAttachments} = $session{'Attachments'};
145     push @Actions,
146         ProcessUpdateMessage(
147         ARGSRef   => \%ARGS,
148         Actions   => \@Actions,
149         TicketObj => $TicketObj,
150         );
151     delete $session{'Attachments'};
152
153     #Process status updates
154     push @Actions, ProcessTicketWatchers(ARGSRef => \%ARGS, TicketObj => $TicketObj );
155     push @Actions, ProcessTicketBasics(  ARGSRef => \%ARGS, TicketObj => $TicketObj );
156     push @Actions, ProcessTicketLinks(   ARGSRef => \%ARGS, TicketObj => $TicketObj );
157     push @Actions, ProcessTicketDates(   ARGSRef => \%ARGS, TicketObj => $TicketObj );
158     push @Actions, ProcessTicketCustomFieldUpdates(ARGSRef => \%ARGS, TicketObj => $TicketObj );
159
160     # XXX: we shouldn't block actions here if user has no right to see the ticket,
161     # but we should allow him to see actions he has done
162     unless ($TicketObj->CurrentUserHasRight('ShowTicket')) {
163         Abort("No permission to view ticket");
164     }
165     if ( $ARGS{'MarkAsSeen'} ) {
166         $TicketObj->SetAttribute(
167             Name => 'User-'. $TicketObj->CurrentUser->id .'-SeenUpTo',
168             Content => $TicketObj->LastUpdated,
169         );
170         push @Actions, loc('Marked all messages as seen');
171     }
172 }
173
174 $m->callback(
175     CallbackName => 'BeforeDisplay',
176     TicketObj => \$TicketObj,
177     Tickets => \$Tickets,
178     Actions => \@Actions,
179     ARGSRef => \%ARGS,
180 );
181
182 # This code does automatic redirection if any updates happen. 
183
184 if (@Actions) {
185
186     # We've done something, so we need to clear the decks to avoid
187     # resubmission on refresh.
188     # But we need to store Actions somewhere too, so we don't lose them.
189     my $key = Digest::MD5::md5_hex( rand(1024) );
190     push @{ $session{"Actions"}->{$key} ||= [] }, @Actions;
191     $session{'i'}++;
192     my $url = RT->Config->Get('WebURL') . "Ticket/Display.html?id=" . $TicketObj->id . "&results=" . $key;
193     $url .= '#' . $ARGS{Anchor} if $ARGS{Anchor};
194     RT::Interface::Web::Redirect($url);
195 }
196
197 my $attachments = $m->comp('Elements/FindAttachments', Ticket => $TicketObj, Tickets => $Tickets);
198 my $attachment_content = $m->comp('Elements/LoadTextAttachments', Ticket => $TicketObj);
199
200 my %link_rel;
201 if (defined $session{'tickets'} and ($ARGS{'Query'} or $session{'CurrentSearchHash'}->{'Query'})) {
202     my $item_map = $session{'tickets'}->ItemMap;
203     $link_rel{first} = "Ticket/Display.html?id=" . $item_map->{first}                if $item_map->{$TicketObj->Id}{prev};
204     $link_rel{prev}  = "Ticket/Display.html?id=" . $item_map->{$TicketObj->Id}{prev} if $item_map->{$TicketObj->Id}{prev};
205     $link_rel{next}  = "Ticket/Display.html?id=" . $item_map->{$TicketObj->Id}{next} if $item_map->{$TicketObj->Id}{next};
206     $link_rel{last}  = "Ticket/Display.html?id=" . $item_map->{last}                 if $item_map->{$TicketObj->Id}{next};
207 }
208 </%INIT>