rt 4.2.16
[freeside.git] / rt / share / html / REST / 1.0 / Forms / ticket / default
index b82cb5e..ab97059 100755 (executable)
@@ -1,40 +1,40 @@
 %# BEGIN BPS TAGGED BLOCK {{{
-%# 
+%#
 %# COPYRIGHT:
-%# 
-%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC
-%#                                          <jesse@bestpractical.com>
-%# 
+%#
+%# This software is Copyright (c) 1996-2019 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
@@ -43,7 +43,7 @@
 %# 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 }}}
 %# REST/1.0/Forms/ticket/default
 %#
@@ -62,12 +62,12 @@ my $cf_spec = RT::Interface::REST->custom_field_spec(1);
 my @comments;
 my ($c, $o, $k, $e) = ("", [], {}, 0);
 my %data   = %$changes;
-my $ticket = new RT::Ticket $session{CurrentUser};
+my $ticket = RT::Ticket->new($session{CurrentUser});
 my @dates  = qw(Created Starts Started Due Resolved Told LastUpdated);
 my @people = qw(Requestors Cc AdminCc);
 my @create = qw(Queue Requestor Subject Cc AdminCc Owner Status Priority
                 InitialPriority FinalPriority TimeEstimated TimeWorked
-                TimeLeft Starts Started Due Resolved);
+                TimeLeft Starts Started Due Resolved Content-Type);
 my @simple = qw(Subject Status Priority Disabled TimeEstimated TimeWorked
                 TimeLeft InitialPriority FinalPriority);
 my %dates  = map {lc $_ => $_} @dates;
@@ -81,29 +81,40 @@ if ($id ne 'new') {
     if (!$ticket->Id) {
         return [ "# Ticket $id does not exist.", [], {}, 1 ];
     }
-    elsif (!$ticket->CurrentUserHasRight('ShowTicket') ||
-           (%data && !$ticket->CurrentUserHasRight('ModifyTicket')))
-    {
-        my $act = %data ? "modify" : "display";
-        return [ "# You are not allowed to $act ticket $id.", [], {}, 1 ];
+    elsif ( %data ) {
+        if ( $data{status} && lc $data{status} eq 'deleted' && ! grep { $_ ne 'id' && $_ ne 'status' } keys %data ) {
+            if ( !$ticket->CurrentUserHasRight('DeleteTicket') ) {
+                return [ "# You are not allowed to delete ticket $id.", [], {}, 1 ];
+            }
+        }
+        elsif ( !$ticket->CurrentUserHasRight('ModifyTicket') ) {
+                return [ "# You are not allowed to modify ticket $id.", [], {}, 1 ];
+        }
+    }
+    elsif (!$ticket->CurrentUserHasRight('ShowTicket')) {
+        return [ "# You are not allowed to display ticket $id.", [], {}, 1 ];
     }
 }
 else {
     if (!keys(%data)) {
         # GET ticket/new: Return a suitable default form.
         # We get defaults from queue/1 (XXX: What if it isn't there?).
-        my $due = new RT::Date $session{CurrentUser};
-        my $queue = new RT::Queue $session{CurrentUser};
-        my $starts = new RT::Date $session{CurrentUser};
+        my $queue = RT::Queue->new($session{CurrentUser});
         $queue->Load(1);
-        $due->SetToNow;
-        $due->AddDays($queue->DefaultDueIn) if $queue->DefaultDueIn;
+
+        my $due;
+        if ($queue->DefaultDueIn) {
+            $due = RT::Date->new($session{CurrentUser});
+            $due->SetToNow;
+            $due->AddDays($queue->DefaultDueIn);
+        }
+        my $starts = RT::Date->new($session{CurrentUser});
         $starts->SetToNow;
 
         return [
             "# Required: id, Queue",
             [ qw(id Queue Requestor Subject Cc AdminCc Owner Status Priority
-                 InitialPriority FinalPriority TimeEstimated Starts Due Text) ],
+                 InitialPriority FinalPriority TimeEstimated Starts Due Attachment Text) ],
             {
                 id               => "ticket/new",
                 Queue            => $queue->Name,
@@ -117,8 +128,9 @@ else {
                 InitialPriority  => $queue->InitialPriority,
                 FinalPriority    => $queue->FinalPriority,
                 TimeEstimated    => 0,
-                Starts           => $starts->ISO,
-                Due              => $due->ISO,
+                Starts           => $starts->ISO(Timezone => 'user'),
+                Due              => $due ? $due->ISO(Timezone => 'user') : undef,
+                Attachment       => '',
                 Text             => "",
             },
             0
@@ -127,12 +139,12 @@ else {
     else {
         # We'll create a new ticket, and fall through to set fields that
         # can't be set in the call to Create().
-        my (%v, $text);
+        my (%v, $text, @atts);
 
         foreach my $k (keys %data) {
             # flexibly parse any dates
             if ($dates{lc $k}) {
-                my $time = new RT::Date $session{CurrentUser};
+                my $time = RT::Date->new($session{CurrentUser});
                 $time->Set(Format => 'unknown', Value => $data{$k});
                 $data{$k} = $time->ISO;
             }
@@ -142,30 +154,66 @@ else {
             }
             # Set custom field
             elsif ($k =~ /^$cf_spec/) {
-                my $cf = RT::CustomField->new( $RT::SystemUser );
-                my $cfk = $1 || $2;
-                unless($cf->LoadByName( Name => $cfk )) {
-                    push @comments, "# Invalid custom field name ($cfk)";
+                my $key = $1 || $2;
+
+                my $cf = RT::CustomField->new( $session{CurrentUser} );
+                $cf->LoadByName(
+                    Name          => $key,
+                    LookupType    => RT::Ticket->CustomFieldLookupType,
+                    ObjectId      => $data{Queue} || $v{Queue},
+                    IncludeGlobal => 1,
+                );
+
+                if (not $cf->id) {
+                    push @comments, "# Invalid custom field name ($key)";
                     delete $data{$k};
                     next;
                 }
-                $v{"CustomField-".$cf->Id()} = delete $data{$k};
+                my $val = delete $data{$k};
+                next unless defined $val && length $val;
+                $v{"CustomField-".$cf->Id()} = $cf->SingleValue ? $val : vsplit($val,1);
             }
             elsif (lc $k eq 'text') {
                 $text = delete $data{$k};
             }
+            elsif (lc $k eq 'attachment') {
+                push @atts, @{ vsplit(delete $data{$k}) };
+            }
+            elsif ( $k !~ /^(?:id|requestors)$/i ) {
+                $e = 1;
+                push @$o, $k;
+                push(@comments, "# $k: Unknown field");
+            }
+        }
+
+        if ( $e ) {
+            unshift @comments, "# Could not create ticket.";
+            $k = \%data;
+            goto DONE;
         }
 
         # people fields allow multiple values
         $v{$_} = vsplit($v{$_}) foreach ( grep $create{lc $_}, @people );
 
-        if ($text) {
+        if ($text || @atts) {
             $v{MIMEObj} =
                 MIME::Entity->build(
-                    From => $session{CurrentUser}->EmailAddress,
-                    Subject => $v{Subject},
-                    Data => $text
+                    Type => "multipart/mixed",
+                    From => Encode::encode( "UTF-8", $session{CurrentUser}->EmailAddress ),
+                    Subject => Encode::encode( "UTF-8", $v{Subject}),
+                    'X-RT-Interface' => 'REST',
                 );
+            $v{MIMEObj}->attach(
+                Type    => $v{'Content-Type'} || 'text/plain',
+                Charset => "UTF-8",
+                Data    => Encode::encode( "UTF-8", $text ),
+            ) if $text;
+            my ($status, $msg) = process_attachments($v{'MIMEObj'}, @atts);
+            unless ($status) {
+                push(@comments, "# $msg");
+                goto DONE;
+            }
+            $v{MIMEObj}->make_singlepart;
         }
 
         my($tid,$trid,$terr) = $ticket->Create(%v);    
@@ -188,15 +236,15 @@ if (!keys(%data)) {
     my ($time, $key, $val, @data);
 
     push @data, [ id    => "ticket/".$ticket->Id   ];
-    push @data, [ Queue => $ticket->QueueObj->Name ] 
-       if (!%$fields || exists $fields->{lc 'Queue'});
+    push @data, [ Queue => $ticket->QueueObj->Name ]
+        if (!%$fields || exists $fields->{lc 'Queue'});
     push @data, [ Owner => $ticket->OwnerObj->Name ]
-       if (!%$fields || exists $fields->{lc 'Owner'});
+        if (!%$fields || exists $fields->{lc 'Owner'});
     push @data, [ Creator => $ticket->CreatorObj->Name ]
-       if (!%$fields || exists $fields->{lc 'Creator'});
+        if (!%$fields || exists $fields->{lc 'Creator'});
 
     foreach (qw(Subject Status Priority InitialPriority FinalPriority)) {
-       next unless (!%$fields || (exists $fields->{lc $_}));
+        next unless (!%$fields || (exists $fields->{lc $_}));
         push @data, [$_ => $ticket->$_ ];
     }
 
@@ -205,16 +253,16 @@ if (!keys(%data)) {
         push @data, [ $key => [ $ticket->$key->MemberEmailAddresses ] ];
     }
 
-    $time = new RT::Date ($session{CurrentUser});
+    $time = RT::Date->new ($session{CurrentUser});
     foreach $key (@dates) {
-       next unless (!%$fields || (exists $fields->{lc $key}));
+        next unless (!%$fields || (exists $fields->{lc $key}));
         $time->Set(Format => 'sql', Value => $ticket->$key);
         push @data, [ $key => $time->AsString ];
     }
 
-    $time = new RT::Date ($session{CurrentUser});
+    $time = RT::Date->new ($session{CurrentUser});
     foreach $key (qw(TimeEstimated TimeWorked TimeLeft)) {
-       next unless (!%$fields || (exists $fields->{lc $key}));
+        next unless (!%$fields || (exists $fields->{lc $key}));
         $val = $ticket->$key || 0;
         $val = "$val minutes" if $val;
         push @data, [ $key => $val ];
@@ -236,8 +284,8 @@ if (!keys(%data)) {
         else {
             while (my $v = $vals->Next()) {
                 my $content = $v->Content;
-                $content =~ s/'/\\'/g;
                 if ( $v->Content =~ /,/ ) {
+                    $content =~ s/([\\'])/\\$1/g;
                     push @out, q{'} . $content . q{'};
                 }
                 else {
@@ -254,6 +302,7 @@ if (!keys(%data)) {
 }
 else {
     my ($get, $set, $key, $val, $n, $s);
+    my $updated;
 
     foreach $key (keys %data) {
         $val = $data{$key};
@@ -279,8 +328,10 @@ else {
         elsif (exists $simple{$key}) {
             $key = $simple{$key};
             $set = "Set$key";
+            my $current = $ticket->$key;
+            $current = '' unless defined $current;
 
-            next if (($val eq $ticket->$key)|| ($ticket->$key =~ /^\d+$/ && $val == $ticket->$key));
+            next if ($val eq $current) or ($current =~ /^\d+$/ && $val =~ /^\d+$/ && $val == $current);
             ($n, $s) = $ticket->$set("$val");
         }
         elsif (exists $dates{$key}) {
@@ -295,7 +346,7 @@ else {
 
             $set = "Set$key";
 
-            my $time = new RT::Date $session{CurrentUser};
+            my $time = RT::Date->new($session{CurrentUser});
             $time->Set(Format => 'sql', Value => $ticket->$key);
             next if ($val =~ /^not set$/i || $val eq $time->AsString);
 
@@ -318,13 +369,6 @@ else {
                 }
             }
             foreach $p (keys %new) {
-                # XXX: This is a stupid test.
-                unless ($p =~ /^[\w.+-]+\@([\w.-]+\.)*\w+.?$/) {
-                    $s = 0;
-                    $n = "$p is not a valid email address.";
-                    push @msgs, [ $s, $n ];
-                    next;
-                }
                 unless ($ticket->IsWatcher(Type => $type, Email => $p)) {
                     ($s, $n) = $ticket->AddWatcher(Type => $type,
                                                    Email => $p);
@@ -341,63 +385,39 @@ else {
         }
         # Set custom field
         elsif ($key =~ /^$cf_spec/) {
-            my $cf = RT::CustomField->new( $RT::SystemUser );
             $key = $1 || $2;
-            if (not $cf->LoadByName( Name => $key )) {
+
+            my $cf = RT::CustomField->new( $session{CurrentUser} );
+            $cf->ContextObject( $ticket );
+            $cf->LoadByName(
+                Name          => $key,
+                LookupType    => RT::Ticket->CustomFieldLookupType,
+                ObjectId      => $ticket->Queue,
+                IncludeGlobal => 1,
+            );
+
+            if (not $cf->id) {
                 $n = 0;
                 $s = "Unknown custom field.";
             }
             else {
                 my $vals = $ticket->CustomFieldValues($cf->id);
 
-                if ( $cf->SingleValue ) {
-                    my $old = $vals->Next;
-                    if ( $old ) {
-                        if ( $val ne $old->Content ) {
-                            $old->Delete;
-                            ($n, $s) = $ticket->AddCustomFieldValue(
-                                 Field => $cf, Value => $val );
-                            $s =~ s/^# // if defined $s;
-                        }
-                    }
-                    else {
-                        ($n, $s) = $ticket->AddCustomFieldValue(
-                             Field => $cf, Value => $val );
+                if ( !defined $val || !length $val ) {
+                    while ( my $val = $vals->Next ) {
+                        ($n, $s) = $ticket->DeleteCustomFieldValue(
+                            Field => $cf, ValueId => $val->id,
+                        );
                         $s =~ s/^# // if defined $s;
                     }
                 }
+                elsif ( $cf->SingleValue ) {
+                    ($n, $s) = $ticket->AddCustomFieldValue(
+                         Field => $cf, Value => $val );
+                    $s =~ s/^# // if defined $s;
+                }
                 else {
-                    my @new;
-                    my ( $a, $b ) = split /,/, $val, 2;
-                    while ($a) {
-                        no warnings 'uninitialized';
-                        if ( $a =~ /^'/ ) {
-                            my $s = $a;
-                            while ( $a !~ /'$/ || ( $a !~ /(\\\\)+'$/
-                                            && $a =~ /(\\)+'$/ ) ) {
-                                ( $a, $b ) = split /,/, $b, 2;
-                                $s .= ',' . $a;
-                            }
-                            $s =~ s/^'//;
-                            $s =~ s/'$//;
-                            $s =~ s/\\'/'/g;
-                            push @new, $s;
-                        }
-                        elsif ( $a =~ /^q{/ ) {
-                            my $s = $a;
-                            while ( $a !~ /}$/ ) {
-                                ( $a, $b ) = split /,/, $b, 2;
-                                $s .= ',' . $a;
-                            }
-                            $s =~ s/^q{//;
-                            $s =~ s/}//;
-                            push @new, $s;
-                        }
-                        else {
-                            push @new, $a;
-                        }
-                        ( $a, $b ) = split /,/, $b, 2;
-                    }
+                    my @new = @{vsplit($val, 1)};
 
                     my %new;
                     $new{$_}++ for @new;
@@ -408,7 +428,7 @@ else {
                             $new{$c}--;
                         }
                         else {
-                            $v->Delete();
+                            $ticket->DeleteCustomFieldValue( Field => $cf, ValueId => $v->id );
                         }
                     }
                     for ( @new ) {
@@ -421,7 +441,7 @@ else {
                 }
             }
         }
-        elsif ($key ne 'id' && $key ne 'type' && $key ne 'creator') {
+        elsif ($key ne 'id' && $key ne 'type' && $key ne 'creator' && $key ne 'content-type' ) {
             $n = 0;
             $s = "Unknown field.";
         }
@@ -436,8 +456,11 @@ else {
                 $k = $changes;
             }
         }
+        else {
+            $updated ||= 1;
+        }
     }
-    push(@comments, "# Ticket ".$ticket->id." updated.") unless $n == 0;
+    push(@comments, "# Ticket ".$ticket->id." updated.") if $updated;
 }
 
 DONE: