rt 4.0.23
[freeside.git] / rt / lib / RT / CustomField.pm
index 8d16c1f..de912ed 100644 (file)
@@ -2,7 +2,7 @@
 #
 # COPYRIGHT:
 #
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2015 Best Practical Solutions, LLC
 #                                          <sales@bestpractical.com>
 #
 # (Except where explicitly superseded by other copyright notices)
@@ -51,7 +51,7 @@ package RT::CustomField;
 use strict;
 use warnings;
 
-
+use Scalar::Util 'blessed';
 
 use base 'RT::Record';
 
@@ -710,7 +710,7 @@ sub ValidateValuesClass {
     my $self = shift;
     my $class = shift;
 
-    return 1 if !defined $class || $class eq 'RT::CustomFieldValues';
+    return 1 if !$class || $class eq 'RT::CustomFieldValues';
     return 1 if grep $class eq $_, RT->Config->Get('CustomFieldValuesSources');
     return undef;
 }
@@ -1111,11 +1111,6 @@ sub SetRenderType {
                                 $self->FriendlyType));
     }
 
-    # XXX: Remove this restriction once we support lists and cascaded selects
-    if ( $self->BasedOnObj->id and $type =~ /List/ ) {
-        return (0, $self->loc("We can't currently render as a List when basing categories on another custom field.  Please use another render type."));
-    }
-
     return $self->_Set( Field => 'RenderType', Value => $type, @_ );
 }
 
@@ -1193,7 +1188,7 @@ Returns an array of LookupTypes available
 
 sub LookupTypes {
     my $self = shift;
-    return keys %FRIENDLY_OBJECT_TYPES;
+    return sort keys %FRIENDLY_OBJECT_TYPES;
 }
 
 my @FriendlyObjectTypes = (
@@ -1222,14 +1217,57 @@ sub FriendlyLookupType {
     return ( $self->loc( $FriendlyObjectTypes[$#types], @types ) );
 }
 
+=head1 RecordClassFromLookupType
+
+Returns the type of Object referred to by ObjectCustomFields' ObjectId column
+
+Optionally takes a LookupType to use instead of using the value on the loaded
+record.  In this case, the method may be called on the class instead of an
+object.
+
+=cut
+
 sub RecordClassFromLookupType {
     my $self = shift;
-    my ($class) = ($self->LookupType =~ /^([^-]+)/);
+    my $type = shift || $self->LookupType;
+    my ($class) = ($type =~ /^([^-]+)/);
     unless ( $class ) {
-        $RT::Logger->error(
-            "Custom Field #". $self->id 
-            ." has incorrect LookupType '". $self->LookupType ."'"
-        );
+        if (blessed($self) and $self->LookupType eq $type) {
+            $RT::Logger->error(
+                "Custom Field #". $self->id
+                ." has incorrect LookupType '$type'"
+            );
+        } else {
+            RT->Logger->error("Invalid LookupType passed as argument: $type");
+        }
+        return undef;
+    }
+    return $class;
+}
+
+=head1 ObjectTypeFromLookupType
+
+Returns the ObjectType used in ObjectCustomFieldValues rows for this CF
+
+Optionally takes a LookupType to use instead of using the value on the loaded
+record.  In this case, the method may be called on the class instead of an
+object.
+
+=cut
+
+sub ObjectTypeFromLookupType {
+    my $self = shift;
+    my $type = shift || $self->LookupType;
+    my ($class) = ($type =~ /([^-]+)$/);
+    unless ( $class ) {
+        if (blessed($self) and $self->LookupType eq $type) {
+            $RT::Logger->error(
+                "Custom Field #". $self->id
+                ." has incorrect LookupType '$type'"
+            );
+        } else {
+            RT->Logger->error("Invalid LookupType passed as argument: $type");
+        }
         return undef;
     }
     return $class;
@@ -1509,12 +1547,6 @@ sub AddValueForObject {
         }
     }
 
-    if (my $canonicalizer = $self->can('_CanonicalizeValue'.$self->Type)) {
-         $canonicalizer->($self, \%args);
-    }
-
-
-
     my $newval = RT::ObjectCustomFieldValue->new( $self->CurrentUser );
     my ($val, $msg) = $newval->Create(
         ObjectType   => ref($obj),
@@ -1536,6 +1568,17 @@ sub AddValueForObject {
 }
 
 
+sub _CanonicalizeValue {
+    my $self = shift;
+    my $args = shift;
+
+    my $type = $self->_Value('Type');
+    return 1 unless $type;
+
+    my $method = '_CanonicalizeValue'. $type;
+    return 1 unless $self->can($method);
+    $self->$method($args);
+}
 
 sub _CanonicalizeValueDateTime {
     my $self    = shift;
@@ -1544,6 +1587,7 @@ sub _CanonicalizeValueDateTime {
     $DateObj->Set( Format => 'unknown',
                    Value  => $args->{'Content'} );
     $args->{'Content'} = $DateObj->ISO;
+    return 1;
 }
 
 # For date, we need to store Content as ISO date
@@ -1556,9 +1600,35 @@ sub _CanonicalizeValueDate {
     my $DateObj = RT::Date->new( $self->CurrentUser );
     $DateObj->Set( Format   => 'unknown',
                    Value    => $args->{'Content'},
-                   Timezone => 'UTC',
                  );
-    $args->{'Content'} = $DateObj->Date( Timezone => 'UTC' );
+    $args->{'Content'} = $DateObj->Date( Timezone => 'user' );
+    return 1;
+}
+
+sub _CanonicalizeValueIPAddress {
+    my $self = shift;
+    my $args = shift;
+
+    $args->{Content} = RT::ObjectCustomFieldValue->ParseIP( $args->{Content} );
+    return (0, $self->loc("Content is not a valid IP address"))
+        unless $args->{Content};
+    return 1;
+}
+
+sub _CanonicalizeValueIPAddressRange {
+    my $self = shift;
+    my $args = shift;
+
+    my $content = $args->{Content};
+    $content .= "-".$args->{LargeContent} if $args->{LargeContent};
+
+    ($args->{Content}, $args->{LargeContent})
+        = RT::ObjectCustomFieldValue->ParseIPRange( $content );
+
+    $args->{ContentType} = 'text/plain';
+    return (0, $self->loc("Content is not a valid IP address range"))
+        unless $args->{Content};
+    return 1;
 }
 
 =head2 MatchPattern STRING
@@ -1666,14 +1736,13 @@ sub ValuesForObject {
     my $object = shift;
 
     my $values = RT::ObjectCustomFieldValues->new($self->CurrentUser);
-    unless ($self->CurrentUserHasRight('SeeCustomField')) {
+    unless ($self->id and $self->CurrentUserHasRight('SeeCustomField')) {
         # Return an empty object if they have no rights to see
+        $values->Limit( FIELD => "id", VALUE => 0, SUBCLAUSE => "ACL" );
         return ($values);
     }
-    
-    
+
     $values->LimitToCustomField($self->Id);
-    $values->LimitToEnabled();
     $values->LimitToObject($object);
 
     return ($values);
@@ -1690,6 +1759,7 @@ Examples:
     'RT::Queue-RT::Ticket-RT::Transaction' => "Ticket Transactions",    # loc
     'RT::User'                             => "Users",                  # loc
     'RT::Group'                            => "Groups",                 # loc
+    'RT::Queue'                            => "Queues",                 # loc
 
 This is a class method. 
 
@@ -2103,6 +2173,8 @@ sub _CoreAccessible {
         {read => 1, write => 1, sql_type => -4, length => 0,  is_blob => 1,  is_numeric => 0,  type => 'text', default => ''},
         Repeated => 
         {read => 1, write => 1, sql_type => 5, length => 6,  is_blob => 0,  is_numeric => 1,  type => 'smallint(6)', default => '0'},
+        ValuesClass => 
+        {read => 1, write => 1, sql_type => 12, length => 64,  is_blob => 0,  is_numeric => 0,  type => 'varchar(64)', default => ''},
         BasedOn => 
         {read => 1, write => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => ''},
         Description =>