rt 4.2.16
[freeside.git] / rt / lib / RT / ObjectCustomFieldValue.pm
index de4bc74..9b699c4 100644 (file)
@@ -2,7 +2,7 @@
 #
 # COPYRIGHT:
 #
-# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2019 Best Practical Solutions, LLC
 #                                          <sales@bestpractical.com>
 #
 # (Except where explicitly superseded by other copyright notices)
@@ -50,6 +50,7 @@ package RT::ObjectCustomFieldValue;
 
 use strict;
 use warnings;
+use base 'RT::Record';
 
 use RT::Interface::Web;
 use Regexp::Common qw(RE_net_IPv4);
@@ -60,10 +61,7 @@ require Net::CIDR;
 # Allow the empty IPv6 address
 $IPv6_re = qr/(?:$IPv6_re|::)/;
 
-
-
 use RT::CustomField;
-use base 'RT::Record';
 
 sub Table {'ObjectCustomFieldValues'}
 
@@ -84,44 +82,23 @@ sub Create {
         @_,
     );
 
+    my $cf = RT::CustomField->new( $self->CurrentUser );
+    $cf->Load( $args{CustomField} );
 
-    my $cf_as_sys = RT::CustomField->new(RT->SystemUser);
-    $cf_as_sys->Load($args{'CustomField'});
-
-    if($cf_as_sys->Type eq 'IPAddress') {
-        if ( $args{'Content'} ) {
-            $args{'Content'} = $self->ParseIP( $args{'Content'} );
-        }
-
-        unless ( defined $args{'Content'} ) {
-            return
-              wantarray
-              ? ( 0, $self->loc("Content is an invalid IP address") )
-              : 0;
-        }
-    }
-
-    if($cf_as_sys->Type eq 'IPAddressRange') {
-        if ($args{'Content'}) {
-            ($args{'Content'}, $args{'LargeContent'}) = $self->ParseIPRange( $args{'Content'} );
-        }
-        $args{'ContentType'} = 'text/plain';
-
-        unless ( defined $args{'Content'} ) {
-            return
-              wantarray
-              ? ( 0, $self->loc("Content is an invalid IP address range") )
-              : 0;
-        }
-    }
+    my ($val, $msg) = $cf->_CanonicalizeValue(\%args);
+    return ($val, $msg) unless $val;
 
-    if ( defined $args{'Content'} && length( Encode::encode_utf8($args{'Content'}) ) > 255 ) {
+    my $encoded = Encode::encode("UTF-8", $args{'Content'});
+    if ( defined $args{'Content'} && length( $encoded ) > 255 ) {
         if ( defined $args{'LargeContent'} && length $args{'LargeContent'} ) {
             $RT::Logger->error("Content is longer than 255 bytes and LargeContent specified");
         }
         else {
-            $args{'LargeContent'} = $args{'Content'};
-            $args{'Content'} = '';
+            # _EncodeLOB, and thus LargeContent, takes bytes; Content is
+            # in characters.  Encode it; this may replace illegal
+            # codepoints (e.g. \x{FDD0}) with \x{FFFD}.
+            $args{'LargeContent'} = Encode::encode("UTF-8",$args{'Content'});
+            $args{'Content'} = undef;
             $args{'ContentType'} ||= 'text/plain';
         }
     }
@@ -130,7 +107,7 @@ sub Create {
         $self->_EncodeLOB( $args{'LargeContent'}, $args{'ContentType'} )
             if defined $args{'LargeContent'};
 
-    return $self->SUPER::Create(
+    ( my $id, $msg ) = $self->SUPER::Create(
         CustomField     => $args{'CustomField'},
         ObjectType      => $args{'ObjectType'},
         ObjectId        => $args{'ObjectId'},
@@ -140,6 +117,23 @@ sub Create {
         ContentType     => $args{'ContentType'},
         ContentEncoding => $args{'ContentEncoding'},
     );
+
+    if ( $id ) {
+        my $new_value = RT::ObjectCustomFieldValue->new( $self->CurrentUser );
+        $new_value->Load( $id );
+        my $ocfv_key = $new_value->GetOCFVCacheKey();
+        if ( $RT::ObjectCustomFieldValues::_OCFV_CACHE->{$ocfv_key} ) {
+            push @{ $RT::ObjectCustomFieldValues::_OCFV_CACHE->{$ocfv_key} },
+              {
+                'ObjectId'       => $new_value->Id,
+                'CustomFieldObj' => $new_value->CustomFieldObj,
+                'Content'        => $new_value->_Value('Content'),
+                'LargeContent'   => $new_value->LargeContent,
+              };
+        }
+    }
+
+    return wantarray ? ( $id, $msg ) : $id;
 }
 
 
@@ -164,16 +158,9 @@ sub LoadByCols {
     if ( $args{CustomField} ) {
         $cf = RT::CustomField->new( $self->CurrentUser );
         $cf->Load( $args{CustomField} );
-        if ( $cf->Type && $cf->Type eq 'IPAddressRange' ) {
-
-            my ( $sIP, $eIP ) = $cf->ParseIPRange( $args{'Content'} );
-            if ( $sIP && $eIP ) {
-                $self->SUPER::LoadByCols( %args,
-                                          Content      => $sIP,
-                                          LargeContent => $eIP
-                                        );
-            }
-        }
+
+        my ($ok, $msg) = $cf->_CanonicalizeValue(\%args);
+        return ($ok, $msg) unless $ok;
     }
     return $self->SUPER::LoadByCols(%args);
 }
@@ -318,7 +305,15 @@ Disable this value. Used to remove "current" values from records while leaving t
 
 sub Delete {
     my $self = shift;
-    return $self->SetDisabled(1);
+    my ( $ret, $msg ) = $self->SetDisabled( 1 );
+    if ( $ret ) {
+        my $ocfv_key = $self->GetOCFVCacheKey();
+        if ( $RT::ObjectCustomFieldValues::_OCFV_CACHE->{$ocfv_key} ) {
+            @{ $RT::ObjectCustomFieldValues::_OCFV_CACHE->{$ocfv_key} } =
+              grep { $_->{'ObjectId'} != $self->Id } @{ $RT::ObjectCustomFieldValues::_OCFV_CACHE->{$ocfv_key} };
+        }
+    }
+    return wantarray ? ( $ret, $msg ) : $ret;
 }
 
 =head2 _FillInTemplateURL URL
@@ -511,6 +506,20 @@ sub ParseIP {
 }
 
 
+=head2 GetOCFVCacheKey
+
+Get the OCFV cache key for this object
+
+=cut
+
+sub GetOCFVCacheKey {
+    my $self = shift;
+    my $ocfv_key = "CustomField-" . $self->CustomField
+        . '-ObjectType-' . $self->ObjectType
+        . '-ObjectId-' . $self->ObjectId;
+    return $ocfv_key;
+}
+
 =head2 id
 
 Returns the current value of id.
@@ -722,37 +731,47 @@ sub _CoreAccessible {
     {
 
         id =>
-               {read => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => ''},
+                {read => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => ''},
         CustomField =>
-               {read => 1, write => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => ''},
+                {read => 1, write => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => ''},
         ObjectType =>
-               {read => 1, write => 1, sql_type => 12, length => 255,  is_blob => 0,  is_numeric => 0,  type => 'varchar(255)', default => ''},
+                {read => 1, write => 1, sql_type => 12, length => 255,  is_blob => 0,  is_numeric => 0,  type => 'varchar(255)', default => ''},
         ObjectId =>
-               {read => 1, write => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => ''},
+                {read => 1, write => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => ''},
         SortOrder =>
-               {read => 1, write => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => '0'},
+                {read => 1, write => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => '0'},
         Content =>
-               {read => 1, write => 1, sql_type => 12, length => 255,  is_blob => 0,  is_numeric => 0,  type => 'varchar(255)', default => ''},
+                {read => 1, write => 1, sql_type => 12, length => 255,  is_blob => 0,  is_numeric => 0,  type => 'varchar(255)', default => ''},
         LargeContent =>
-               {read => 1, write => 1, sql_type => -4, length => 0,  is_blob => 1,  is_numeric => 0,  type => 'longblob', default => ''},
+                {read => 1, write => 1, sql_type => -4, length => 0,  is_blob => 1,  is_numeric => 0,  type => 'longblob', default => ''},
         ContentType =>
-               {read => 1, write => 1, sql_type => 12, length => 80,  is_blob => 0,  is_numeric => 0,  type => 'varchar(80)', default => ''},
+                {read => 1, write => 1, sql_type => 12, length => 80,  is_blob => 0,  is_numeric => 0,  type => 'varchar(80)', default => ''},
         ContentEncoding =>
-               {read => 1, write => 1, sql_type => 12, length => 80,  is_blob => 0,  is_numeric => 0,  type => 'varchar(80)', default => ''},
+                {read => 1, write => 1, sql_type => 12, length => 80,  is_blob => 0,  is_numeric => 0,  type => 'varchar(80)', default => ''},
         Creator =>
-               {read => 1, auto => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => '0'},
+                {read => 1, auto => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => '0'},
         Created =>
-               {read => 1, auto => 1, sql_type => 11, length => 0,  is_blob => 0,  is_numeric => 0,  type => 'datetime', default => ''},
+                {read => 1, auto => 1, sql_type => 11, length => 0,  is_blob => 0,  is_numeric => 0,  type => 'datetime', default => ''},
         LastUpdatedBy =>
-               {read => 1, auto => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => '0'},
+                {read => 1, auto => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => '0'},
         LastUpdated =>
-               {read => 1, auto => 1, sql_type => 11, length => 0,  is_blob => 0,  is_numeric => 0,  type => 'datetime', default => ''},
+                {read => 1, auto => 1, sql_type => 11, length => 0,  is_blob => 0,  is_numeric => 0,  type => 'datetime', default => ''},
         Disabled =>
-               {read => 1, write => 1, sql_type => 5, length => 6,  is_blob => 0,  is_numeric => 1,  type => 'smallint(6)', default => '0'},
+                {read => 1, write => 1, sql_type => 5, length => 6,  is_blob => 0,  is_numeric => 1,  type => 'smallint(6)', default => '0'},
 
  }
 };
 
+sub FindDependencies {
+    my $self = shift;
+    my ($walker, $deps) = @_;
+
+    $self->SUPER::FindDependencies($walker, $deps);
+
+    $deps->Add( out => $self->CustomFieldObj );
+    $deps->Add( out => $self->Object );
+}
+
 RT::Base->_ImportOverlays();
 
 1;