: Check Select* CF fields for valid values in ticket REST interface

This patch to /share/html/REST/1.0/Forms/ticket/default checks
Select* fields for valid values and won’t set them if the value isn’t
valid. Works for multiple fields too. This has to be enforced in the
REST code - it’s enforced in the GUI simply by the semantics of select
boxes.
Patch should be valid against 3.6.x

— /tmp/rt-3.6.3/html/REST/1.0/Forms/ticket/default 2006-09-26
08:06:31.000000000 -0700
+++ /usr/local/rt/share/html/REST/1.0/Forms/ticket/default
2006-12-24 09:58:22.553405248 -0800
@@ -128,18 +128,6 @@
if (exists $create{lc $k}) {
$v{$create{lc $k}} = delete $data{$k};
}

  •        # Set custom field
    
  •        elsif ($k =~ /^CF-/i) {
    
  •            my $cf = RT::CustomField->new( $RT::SystemUser );
    
  •            my $cfk = $k;
    
  •            $cfk =~ s/^CF-//i;
    
  •            unless($cf->LoadByName( Name => $cfk )) {
    
  •                push @comments, "# Invalid custom field name
    

($cfk)";

  •                delete $data{$k};
    
  •                next;
    
  •            }
    
  •            $v{"CustomField-".$cf->Id()} = delete $data{$k};
    
  •        }
           elsif (lc $k eq 'text') {
               $text = delete $data{$k};
           }
    

@@ -157,6 +145,8 @@
);
}

  •    # Don't add custom fields here - let it fall through to check
    

them later

  •    # This creates a seperate transaction but that's ok
       $ticket->Create(%v);
       unless ($ticket->Id) {
           return [ "# Could not create ticket.", [], {}, 1 ];
    

@@ -229,7 +219,7 @@
foreach $key (keys %data) {
$val = $data{$key};
$key = lc $key;

  •    $n = 1;
    
  •   # $n = 1;
    
       if (ref $val eq 'ARRAY') {
           unless ($key =~ /^(?:Requestors|Cc|AdminCc)$/i) {
    

@@ -302,17 +292,131 @@
}
# Set custom field
elsif ($key =~ /^CF-/i) {

  •        my $cf = RT::CustomField->new( $RT::SystemUser );
    
  •        my @msgs;
    
  •        my $CustomFieldObj = RT::CustomField->new( $RT::SystemUser
    

);
$key =~ s/^CF-//i;

  •        if (not $cf->LoadByName( Name => $key )) {
    
  •            $n = 0;
    
  •            $s = "Unknown custom field.";
    
  •        }
    
  •        else {
    
  •            ($n, $s) = $ticket->AddCustomFieldValue(
    
  •                         Field => $cf, Value => $val );
    
  •            $s =~ s/^# // if defined $s;
    
  •        }
    
  •    	my ($r, $rmsg) = (undef, undef);
    
  •    	$CustomFieldObj->LoadByName( Name => $key );
    
  •      unless ($CustomFieldObj->Id) {
    
  •      	$s = 0;
    
  •        $n = "Could not load Custom Field \"$key\" - does it
    

exist?";

  •        push @msgs, [ $s, $n ];
    
  •        goto CFEND;
    
  •      }
    
  •    	if
    

($CustomFieldObj->CurrentUserHasRight(‘ModifyCustomField’)) {

  •        # Don't change any field that hasn't changed - otherwise
    

the Asset History shows

  •        # that every field changes on changing any field.
    
  •        my $CFvalues = $ticket->CustomFieldValues($key);
    
  •        goto CFEND unless ($CFvalues->Count || length($val)); # If
    

new and old are both empty, do nothing

  •        # Single-Valued Field
    
  •         if ($CustomFieldObj->SingleValue) {
    
  •         	# First check for valid value for Select fields,
    

as long as value isn’t null (this is just a delete)

  •         	if (($CustomFieldObj->Type eq "Select") &&
    

length($val)) {

  •   	      	my $ValidVals = $CustomFieldObj->Values;
    
  •   	      	my $valok = 0;
    
  •   	      	while (my $vv = $ValidVals->Next()) {
    
  •   	      	  if ($vv->Name eq $val) {
    
  •   	      	  	$valok = 1;
    
  •   	      	  	last;
    
  •   	      	  }
    
  •   	      	}
    
  •   	      	if (!$valok) { # Stop processing this Custom
    

field if it’s not a valid value.

  •   	      	  $s = 0;
    
  •              $n = "$val is not a valid Value for Ticket Custom
    

Field $key";

  •              push @msgs, [ $s, $n ];
    
  •              goto CFEND;
    
  •            }
    
  •          }
    
  •           	if ((my $CFvalue = $CFvalues->Next()) ||
    

length($val) ) {

  •           		# Skip delete unless we're going
    

from a value to nothing (changing a value doesn’t need a delete first)

  •           		goto SVCFADD unless ((defined
    

$CFvalue) && (! length($val)));

  •           		goto CFEND if ($CFvalue->Content
    

eq $val); # Skip delete and add if there is nothing to do

  •        	  unless ($ticket->DeleteCustomFieldValue(Field =>
    

$CustomFieldObj, Value => $CFvalue->Content)) {

  •              $s = 0;
    
  •              $n = "Could not delete Ticket Custom Field Value
    

“.$CFvalue->Content.” for Field $key";

  •              push @msgs, [ $s, $n ];
    
  •            }
    

+SVCFADD:

  •            goto CFEND unless length($val);
    
  •          	unless ($ticket->AddCustomFieldValue(Field =>
    

$CustomFieldObj, Value => $val)) {

  •                  $s = 0;
    
  •                  $n = "Could not add value $val to Ticket Custom
    

Field $key";

  •                  push @msgs, [ $s, $n ];
    
  •                }
    
  •          }
    
  •           }
    
  •           # Multi-Valued Field
    
  •           elsif (! $CustomFieldObj->SingleValue) {
    
  •           	my @val = @ { vsplit($val) };
    
  •             # First check for valid value for Select
    

fields, as long as value isn’t null (this is just a delete)

  •         	if ($CustomFieldObj->Type eq "Select") {
    
  •   	      	my @ValidVals =
    

@{$CustomFieldObj->Values->ItemsArrayRef};

  •   	      	my $valok;
    
  •   	      	foreach my $pv (@val) {
    
  •   	      		$valok = 0;
    
  •  		      	foreach my $vv (@ValidVals) {
    
  •  		      	  if ($vv->Name eq $pv) {
    
  •  		      	  	$valok = 1;
    
  •  		      	  	last;
    
  •  		      	  }
    
  •  		      	}
    
  •  		      	if (!$valok) { # Stop processing this Custom
    

field if it’s not a valid value.

  •   	      	    $s = 0;
    
  •                $n = "$pv is not a valid Value for Ticket Custom
    

Field $key";

  •                push @msgs, [ $s, $n ];
    
  •                goto CFEND;
    
  •              }
    
  •  		      }     	
    
  •          }
    
  •          my @CFVALS = map {$_->Content}
    

@{$CFvalues->ItemsArrayRef};

  •           	my $CFvalue;
    
  •           	my $mv;
    
  •           	# Process additions
    
  •           	foreach my $newval (@val) {
    
  •           	  if (! grep {$newval eq $_} @CFVALS ) {
    
  •           	    unless
    

($ticket->AddCustomFieldValue(Field => $CustomFieldObj, Value =>
$newval)) {

  •                $s = 0;
    
  •                $n = "Could not add Ticket Custom Field Value
    

$newval to Ticket Custom Field $key";

  •                push @msgs, [ $s, $n ];
    
  •              }
    
  •           	  }
    
  •           	}
    
  •           	# Process deletions
    
  •           	foreach my $oldval (@CFVALS) {
    
  •           	  if (! grep {$oldval eq $_} @val ) {
    
  •           	    unless
    

($ticket->DeleteCustomFieldValue(Field => $CustomFieldObj, Value =>
$oldval)) {

  •                $s = 0;
    
  •                $n = "Could not delete Ticket Custom Field Value
    

$oldval to Ticket Custom Field $key";

  •                push @msgs, [ $s, $n ];
    
  •              }
    
  •           	  }
    
  •           	}
    
  •        }  
    
  •    	}
    
  •      else {
    
  •    	  $n = 0;
    
  •        $s = "You do not have permission to modify these custom
    

fields";

  •      }
    

+CFEND:

  •      # collate all error messages from the above transactions into
    

one string

  •      $n = 1;
    
  •      if (@msgs = grep {$_->[0] == 0} @msgs) {
    
  •          $n = 0;
    
  •          $s = join "\n", map {"# ".$_->[1]} @msgs;
    
  •          $s =~ s/^# //;
    
  •      }
       }
       elsif ($key ne 'id' && $key ne 'type' && $key ne 'creator') {
           $n = 0;

This patch to /share/html/REST/1.0/Forms/ticket/default checks
Select* fields for valid values and won’t set them if the value isn’t
valid. Works for multiple fields too. This has to be enforced in the
REST code - it’s enforced in the GUI simply by the semantics of select
boxes.
Patch should be valid against 3.6.x

I’m not sure this isn’t something we should be enforcing in
RT core libraries.

-Todd