import rt 3.8.9
[freeside.git] / rt / share / html / REST / 1.0 / Forms / ticket / default
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 %# REST/1.0/Forms/ticket/default
49 %#
50 <%ARGS>
51 $id
52 $changes => {}
53 $fields => undef
54 $args => undef
55 </%ARGS>
56 <%INIT>
57 use MIME::Entity;
58 use RT::Interface::REST;
59
60 my $cf_spec = RT::Interface::REST->custom_field_spec(1);
61
62 my @comments;
63 my ($c, $o, $k, $e) = ("", [], {}, 0);
64 my %data   = %$changes;
65 my $ticket = new RT::Ticket $session{CurrentUser};
66 my @dates  = qw(Created Starts Started Due Resolved Told LastUpdated);
67 my @people = qw(Requestors Cc AdminCc);
68 my @create = qw(Queue Requestor Subject Cc AdminCc Owner Status Priority
69                 InitialPriority FinalPriority TimeEstimated TimeWorked
70                 TimeLeft Starts Started Due Resolved);
71 my @simple = qw(Subject Status Priority Disabled TimeEstimated TimeWorked
72                 TimeLeft InitialPriority FinalPriority);
73 my %dates  = map {lc $_ => $_} @dates;
74 my %people = map {lc $_ => $_} @people;
75 my %create = map {lc $_ => $_} @create;
76 my %simple = map {lc $_ => $_} @simple;
77
78 # Are we dealing with an existing ticket?
79 if ($id ne 'new') {
80     $ticket->Load($id);
81     if (!$ticket->Id) {
82         return [ "# Ticket $id does not exist.", [], {}, 1 ];
83     }
84     elsif (!$ticket->CurrentUserHasRight('ShowTicket') ||
85            (%data && !$ticket->CurrentUserHasRight('ModifyTicket')))
86     {
87         my $act = %data ? "modify" : "display";
88         return [ "# You are not allowed to $act ticket $id.", [], {}, 1 ];
89     }
90 }
91 else {
92     if (!keys(%data)) {
93         # GET ticket/new: Return a suitable default form.
94         # We get defaults from queue/1 (XXX: What if it isn't there?).
95         my $due = new RT::Date $session{CurrentUser};
96         my $queue = new RT::Queue $session{CurrentUser};
97         my $starts = new RT::Date $session{CurrentUser};
98         $queue->Load(1);
99         $due->SetToNow;
100         $due->AddDays($queue->DefaultDueIn) if $queue->DefaultDueIn;
101         $starts->SetToNow;
102
103         return [
104             "# Required: id, Queue",
105             [ qw(id Queue Requestor Subject Cc AdminCc Owner Status Priority
106                  InitialPriority FinalPriority TimeEstimated Starts Due Text) ],
107             {
108                 id               => "ticket/new",
109                 Queue            => $queue->Name,
110                 Requestor        => $session{CurrentUser}->Name,
111                 Subject          => "",
112                 Cc               => [],
113                 AdminCc          => [],
114                 Owner            => "",
115                 Status           => "new",
116                 Priority         => $queue->InitialPriority,
117                 InitialPriority  => $queue->InitialPriority,
118                 FinalPriority    => $queue->FinalPriority,
119                 TimeEstimated    => 0,
120                 Starts           => $starts->ISO,
121                 Due              => $due->ISO,
122                 Text             => "",
123             },
124             0
125         ];
126     }
127     else {
128         # We'll create a new ticket, and fall through to set fields that
129         # can't be set in the call to Create().
130         my (%v, $text);
131
132         foreach my $k (keys %data) {
133             # flexibly parse any dates
134             if ($dates{lc $k}) {
135                 my $time = new RT::Date $session{CurrentUser};
136                 $time->Set(Format => 'unknown', Value => $data{$k});
137                 $data{$k} = $time->ISO;
138             }
139
140             if (exists $create{lc $k}) {
141                 $v{$create{lc $k}} = delete $data{$k};
142             }
143             # Set custom field
144             elsif ($k =~ /^$cf_spec/) {
145                 my $cf = RT::CustomField->new( $RT::SystemUser );
146                 my $cfk = $1 || $2;
147                 unless($cf->LoadByName( Name => $cfk )) {
148                     push @comments, "# Invalid custom field name ($cfk)";
149                     delete $data{$k};
150                     next;
151                 }
152                 $v{"CustomField-".$cf->Id()} = delete $data{$k};
153             }
154             elsif (lc $k eq 'text') {
155                 $text = delete $data{$k};
156             }
157         }
158
159         # people fields allow multiple values
160         $v{$_} = vsplit($v{$_}) foreach ( grep $create{lc $_}, @people );
161
162         if ($text) {
163             $v{MIMEObj} =
164                 MIME::Entity->build(
165                     From => $session{CurrentUser}->EmailAddress,
166                     Subject => $v{Subject},
167                     Data => $text
168                 );
169         }
170
171         my($tid,$trid,$terr) = $ticket->Create(%v);    
172         unless ($tid) {
173             push(@comments, "# Could not create ticket.");
174             push(@comments, "# " . $terr);
175             goto DONE;
176         }
177
178         delete $data{id};
179         $id = $ticket->Id;
180         push(@comments, "# Ticket $id created.");
181         # see if the hash is empty
182         goto DONE if ! keys(%data);
183     }
184 }
185
186 # Now we know we're dealing with an existing ticket.
187 if (!keys(%data)) {
188     my ($time, $key, $val, @data);
189
190     push @data, [ id    => "ticket/".$ticket->Id   ];
191     push @data, [ Queue => $ticket->QueueObj->Name ] 
192         if (!%$fields || exists $fields->{lc 'Queue'});
193     push @data, [ Owner => $ticket->OwnerObj->Name ]
194         if (!%$fields || exists $fields->{lc 'Owner'});
195     push @data, [ Creator => $ticket->CreatorObj->Name ]
196         if (!%$fields || exists $fields->{lc 'Creator'});
197
198     foreach (qw(Subject Status Priority InitialPriority FinalPriority)) {
199         next unless (!%$fields || (exists $fields->{lc $_}));
200         push @data, [$_ => $ticket->$_ ];
201     }
202
203     foreach $key (@people) {
204         next unless (!%$fields || (exists $fields->{lc $key}));
205         push @data, [ $key => [ $ticket->$key->MemberEmailAddresses ] ];
206     }
207
208     $time = new RT::Date ($session{CurrentUser});
209     foreach $key (@dates) {
210         next unless (!%$fields || (exists $fields->{lc $key}));
211         $time->Set(Format => 'sql', Value => $ticket->$key);
212         push @data, [ $key => $time->AsString ];
213     }
214
215     $time = new RT::Date ($session{CurrentUser});
216     foreach $key (qw(TimeEstimated TimeWorked TimeLeft)) {
217         next unless (!%$fields || (exists $fields->{lc $key}));
218         $val = $ticket->$key || 0;
219         $val = "$val minutes" if $val;
220         push @data, [ $key => $val ];
221     }
222
223     # Display custom fields
224     my $CustomFields = $ticket->CustomFields;
225     while (my $cf = $CustomFields->Next()) {
226         next unless !%$fields
227                  || exists $fields->{"cf.{".lc($cf->Name)."}"}
228                  || exists $fields->{"cf-".lc $cf->Name};
229
230         my $vals = $ticket->CustomFieldValues($cf->Id());
231         my @out = ();
232         if ( $cf->SingleValue ) {
233             my $v = $vals->Next;
234             push @out, $v->Content if $v;
235         }
236         else {
237             while (my $v = $vals->Next()) {
238                 my $content = $v->Content;
239                 $content =~ s/'/\\'/g;
240                 if ( $v->Content =~ /,/ ) {
241                     push @out, q{'} . $content . q{'};
242                 }
243                 else {
244                     push @out, $content;
245                 }
246             }
247         }
248         push @data, [ ('CF.{' . $cf->Name . '}') => join ',', @out ];
249     }
250
251     my %k = map {@$_} @data;
252     $o = [ map {$_->[0]} @data ];
253     $k = \%k;
254 }
255 else {
256     my ($get, $set, $key, $val, $n, $s);
257
258     foreach $key (keys %data) {
259         $val = $data{$key};
260         $key = lc $key;
261         $n = 1;
262
263         if (ref $val eq 'ARRAY') {
264             unless ($key =~ /^(?:Requestors|Cc|AdminCc)$/i) {
265                 $n = 0;
266                 $s = "$key may have only one value.";
267                 goto SET;
268             }
269         }
270
271         if ($key =~ /^queue$/i) {
272             next if $val eq $ticket->QueueObj->Name;
273             ($n, $s) = $ticket->SetQueue($val);
274         }
275         elsif ($key =~ /^owner$/i) {
276             next if $val eq $ticket->OwnerObj->Name;
277             ($n, $s) = $ticket->SetOwner($val);
278         }
279         elsif (exists $simple{$key}) {
280             $key = $simple{$key};
281             $set = "Set$key";
282
283             next if (($val eq $ticket->$key)|| ($ticket->$key =~ /^\d+$/ && $val == $ticket->$key));
284             ($n, $s) = $ticket->$set("$val");
285         }
286         elsif (exists $dates{$key}) {
287             $key = $dates{$key};
288
289             # We try to detect whether it should update a field by checking
290             # whether its current value equals the entered value. Since the
291             # LastUpdated field is automatically updated as other columns are
292             # changed, it is not properly skipped. Users cannot update this
293             # field anyway.
294             next if $key eq 'LastUpdated';
295
296             $set = "Set$key";
297
298             my $time = new RT::Date $session{CurrentUser};
299             $time->Set(Format => 'sql', Value => $ticket->$key);
300             next if ($val =~ /^not set$/i || $val eq $time->AsString);
301
302             $time->Set(Format => 'unknown', Value => $val);
303             ($n, $s) = $ticket->$set($time->ISO);
304         }
305         elsif (exists $people{$key}) {
306             $key = $people{$key};
307             my ($p, @msgs);
308
309             my %new  = map {$_=>1} @{ vsplit($val) };
310             my %old  = map {$_=>1} $ticket->$key->MemberEmailAddresses;
311             my $type = $key eq 'Requestors' ? 'Requestor' : $key;
312
313             foreach $p (keys %old) {
314                 unless (exists $new{$p}) {
315                     ($s, $n) = $ticket->DeleteWatcher(Type => $type,
316                                                       Email => $p);
317                     push @msgs, [ $s, $n ];
318                 }
319             }
320             foreach $p (keys %new) {
321                 # XXX: This is a stupid test.
322                 unless ($p =~ /^[\w.+-]+\@([\w.-]+\.)*\w+.?$/) {
323                     $s = 0;
324                     $n = "$p is not a valid email address.";
325                     push @msgs, [ $s, $n ];
326                     next;
327                 }
328                 unless ($ticket->IsWatcher(Type => $type, Email => $p)) {
329                     ($s, $n) = $ticket->AddWatcher(Type => $type,
330                                                    Email => $p);
331                     push @msgs, [ $s, $n ];
332                 }
333             }
334
335             $n = 1;
336             if (@msgs = grep {$_->[0] == 0} @msgs) {
337                 $n = 0;
338                 $s = join "\n", map {"# ".$_->[1]} @msgs;
339                 $s =~ s/^# //;
340             }
341         }
342         # Set custom field
343         elsif ($key =~ /^$cf_spec/) {
344             my $cf = RT::CustomField->new( $RT::SystemUser );
345             $key = $1 || $2;
346             if (not $cf->LoadByName( Name => $key )) {
347                 $n = 0;
348                 $s = "Unknown custom field.";
349             }
350             else {
351                 my $vals = $ticket->CustomFieldValues($cf->id);
352
353                 if ( $cf->SingleValue ) {
354                     my $old = $vals->Next;
355                     if ( $old ) {
356                         if ( $val ne $old->Content ) {
357                             $old->Delete;
358                             ($n, $s) = $ticket->AddCustomFieldValue(
359                                  Field => $cf, Value => $val );
360                             $s =~ s/^# // if defined $s;
361                         }
362                     }
363                     else {
364                         ($n, $s) = $ticket->AddCustomFieldValue(
365                              Field => $cf, Value => $val );
366                         $s =~ s/^# // if defined $s;
367                     }
368                 }
369                 else {
370                     my @new;
371                     my ( $a, $b ) = split /\s*,\s*/, $val, 2;
372                     while ($a) {
373                         no warnings 'uninitialized';
374                         if ( $a =~ /^'/ ) {
375                             my $s = $a;
376                             while ( $a !~ /'$/ || ( $a !~ /(\\\\)+'$/
377                                             && $a =~ /(\\)+'$/ ) ) {
378                                 ( $a, $b ) = split /\s*,\s*/, $b, 2;
379                                 $s .= ',' . $a;
380                             }
381                             $s =~ s/^'//;
382                             $s =~ s/'$//;
383                             $s =~ s/\\'/'/g;
384                             push @new, $s;
385                         }
386                         elsif ( $a =~ /^q{/ ) {
387                             my $s = $a;
388                             while ( $a !~ /}$/ ) {
389                                 ( $a, $b ) = split /\s*,\s*/, $b, 2;
390                                 $s .= ',' . $a;
391                             }
392                             $s =~ s/^q{//;
393                             $s =~ s/}//;
394                             push @new, $s;
395                         }
396                         else {
397                             push @new, $a;
398                         }
399                         ( $a, $b ) = split /\s*,\s*/, $b, 2;
400                     }
401
402                     my %new;
403                     $new{$_}++ for @new;
404
405                     while (my $v = $vals->Next()) {
406                         my $c = $v->Content;
407                         if ( $new{$c} ) {
408                             $new{$c}--;
409                         }
410                         else {
411                             $v->Delete();
412                         }
413                     }
414                     for ( @new ) {
415                         while ( $new{$_} && $new{$_}-- ) {
416                             ($n, $s) = $ticket->AddCustomFieldValue(
417                                 Field => $cf, Value => $_ );
418                             $s =~ s/^# // if defined $s;
419                         }
420                     }
421                 }
422             }
423         }
424         elsif ($key ne 'id' && $key ne 'type' && $key ne 'creator') {
425             $n = 0;
426             $s = "Unknown field.";
427         }
428
429     SET:
430         if ($n == 0) {
431             $e = 1;
432             push @comments, "# $key: $s";
433             unless (@$o) {
434                 # move id forward
435                 @$o = ("id", grep { $_ ne 'id' } keys %$changes);
436                 $k = $changes;
437             }
438         }
439     }
440     push(@comments, "# Ticket ".$ticket->id." updated.") unless $n == 0;
441 }
442
443 DONE:
444 $c ||= join("\n", @comments) if @comments;
445 return [$c, $o, $k, $e];
446
447 </%INIT>