X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=blobdiff_plain;f=rt%2Flib%2FRT%2FRecord.pm;h=6962221ea0ba8852800f8bb17bd395bda4ce2826;hp=5340f7de4d2253d3f20434253e70dbe841d8d16a;hb=945721f48f74d5cfffef7c7cf3a3d6bc2521f5dd;hpb=160be29a0dc62e79a4fb95d2ab8c0c7e5996760e diff --git a/rt/lib/RT/Record.pm b/rt/lib/RT/Record.pm index 5340f7de4..6962221ea 100755 --- a/rt/lib/RT/Record.pm +++ b/rt/lib/RT/Record.pm @@ -1,5 +1,26 @@ -#$Header: /home/cvs/cvsroot/freeside/rt/lib/RT/Record.pm,v 1.1 2002-08-12 06:17:07 ivan Exp $ - +# BEGIN LICENSE BLOCK +# +# Copyright (c) 1996-2003 Jesse Vincent +# +# (Except where explictly superceded by other copyright notices) +# +# 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. +# +# Unless otherwise specified, all modifications, corrections or +# extensions to this work which alter its source code become the +# property of Best Practical Solutions, LLC when submitted for +# inclusion in the work. +# +# +# END LICENSE BLOCK =head1 NAME RT::Record - Base class for RT record objects @@ -20,20 +41,31 @@ ok (require RT::Record); =cut - package RT::Record; -use DBIx::SearchBuilder::Record::Cachable; use RT::Date; use RT::User; -@ISA= qw(DBIx::SearchBuilder::Record::Cachable); +use RT::Base; +use DBIx::SearchBuilder::Record::Cachable; + +use strict; +use vars qw/@ISA/; + +@ISA = qw(RT::Base); + +if ($RT::DontCacheSearchBuilderRecords ) { + push (@ISA, 'DBIx::SearchBuilder::Record'); +} else { + push (@ISA, 'DBIx::SearchBuilder::Record::Cachable'); + +} # {{{ sub _Init -sub _Init { - my $self = shift; - $self->_MyCurrentUser(@_); - +sub _Init { + my $self = shift; + $self->CurrentUser(@_); + } # }}} @@ -48,68 +80,108 @@ The primary keys for RT classes is 'id' sub _PrimaryKeys { my $self = shift; - return(['id']); + return ( ['id'] ); } # }}} -# {{{ sub _MyCurrentUser - -sub _MyCurrentUser { +# {{{ sub _Handle +sub _Handle { my $self = shift; - - $self->CurrentUser(@_); - if(!defined($self->CurrentUser)) { - use Carp; - Carp::cluck(); - $RT::Logger->err("$self was created without a CurrentUser\n"); - return(0); - } + return ($RT::Handle); } # }}} -# {{{ sub _Handle -sub _Handle { - my $self = shift; - return($RT::Handle); -} -# }}} - # {{{ sub Create -sub Create { - my $self = shift; - my $now = new RT::Date($self->CurrentUser); - $now->Set(Format=> 'unix', Value => time); - push @_, 'Created', $now->ISO() - if ($self->_Accessible('Created', 'auto')); - - - push @_, 'Creator', $self->{'user'}->id - if $self->_Accessible('Creator', 'auto'); - - push @_, 'LastUpdated', $now->ISO() - if ($self->_Accessible('LastUpdated', 'auto')); - - push @_, 'LastUpdatedBy', $self->{'user'}->id - if $self->_Accessible('LastUpdatedBy', 'auto'); - - - - my $id = $self->SUPER::Create(@_); - - if ($id) { - $self->Load($id); +=item Create PARAMHASH + +Takes a PARAMHASH of Column -> Value pairs. +If any Column has a Validate$PARAMNAME subroutine defined and the +value provided doesn't pass validation, this routine returns +an error. + +If this object's table has any of the following atetributes defined as +'Auto', this routine will automatically fill in their values. + +=cut + +sub Create { + my $self = shift; + my %attribs = (@_); + foreach my $key ( keys %attribs ) { + my $method = "Validate$key"; + unless ( $self->$method( $attribs{$key} ) ) { + if (wantarray) { + return ( 0, $self->loc('Invalid value for [_1]', $key) ); + } + else { + return (0); + } + } + } + my $now = RT::Date->new( $self->CurrentUser ); + $now->Set( Format => 'unix', Value => time ); + $attribs{'Created'} = $now->ISO() if ( $self->_Accessible( 'Created', 'auto' ) && !$attribs{'Created'}); + + if ($self->_Accessible( 'Creator', 'auto' ) && !$attribs{'Creator'}) { + $attribs{'Creator'} = $self->CurrentUser->id || '0'; + } + $attribs{'LastUpdated'} = $now->ISO() + if ( $self->_Accessible( 'LastUpdated', 'auto' ) && !$attribs{'LastUpdated'}); + + $attribs{'LastUpdatedBy'} = $self->CurrentUser->id || '0' + if ( $self->_Accessible( 'LastUpdatedBy', 'auto' ) && !$attribs{'LastUpdatedBy'}); + + my $id = $self->SUPER::Create(%attribs); + if ( UNIVERSAL::isa( $id, 'Class::ReturnValue' ) ) { + if ( $id->errno ) { + if (wantarray) { + return ( 0, + $self->loc( "Internal Error: [_1]", $id->{error_message} ) ); + } + else { + return (0); + } + } + } + # If the object was created in the database, + # load it up now, so we're sure we get what the database + # has. Arguably, this should not be necessary, but there + # isn't much we can do about it. + + unless ($id) { + if (wantarray) { + return ( $id, $self->loc('Object could not be created') ); + } + else { + return ($id); + } + + } + + if (UNIVERSAL::isa('errno',$id)) { + exit(0); + warn "It's here!"; + return(undef); + } + + $self->Load($id) if ($id); + + + + if (wantarray) { + return ( $id, $self->loc('Object created') ); + } + else { + return ($id); } - - return($id); - + } # }}} - # {{{ sub LoadByCols =head2 LoadByCols @@ -125,28 +197,33 @@ sub LoadByCols { # If this database is case sensitive we need to uncase objects for # explicit loading - if ($self->_Handle->CaseSensitive) { - my %newhash; - foreach my $key (keys %hash) { - # If we've been passed an empty value, we can't do the lookup. - # We don't need to explicitly downcase integers or an id. - if ($key =~ '^id$' || $hash{$key} =~/^\d+$/ || !defined ($hash{$key}) ) { - $newhash{$key} = $hash{$key}; - } - else { - $newhash{"lower(".$key.")"} = lc($hash{$key}); - } - } - $self->SUPER::LoadByCols(%newhash); - } - else { - $self->SUPER::LoadByCols(%hash); + if ( $self->_Handle->CaseSensitive ) { + my %newhash; + foreach my $key ( keys %hash ) { + + # If we've been passed an empty value, we can't do the lookup. + # We don't need to explicitly downcase integers or an id. + if ( $key =~ '^id$' + || !defined( $hash{$key} ) + || $hash{$key} =~ /^\d+$/ + ) + { + $newhash{$key} = $hash{$key}; + } + else { + $newhash{ "lower(" . $key . ")" } = lc( $hash{$key} ); + } + } + + # We've clobbered everything we care about. bash the old hash + # and replace it with the new hash + %hash = %newhash; } + $self->SUPER::LoadByCols(%hash); } # }}} - # {{{ Datehandling # There is room for optimizations in most of those subs: @@ -154,10 +231,10 @@ sub LoadByCols { # {{{ LastUpdatedObj sub LastUpdatedObj { - my $self=shift; - my $obj = new RT::Date($self->CurrentUser); - - $obj->Set(Format => 'sql', Value => $self->LastUpdated); + my $self = shift; + my $obj = new RT::Date( $self->CurrentUser ); + + $obj->Set( Format => 'sql', Value => $self->LastUpdated ); return $obj; } @@ -166,12 +243,11 @@ sub LastUpdatedObj { # {{{ CreatedObj sub CreatedObj { - my $self=shift; - my $obj = new RT::Date($self->CurrentUser); - - $obj->Set(Format => 'sql', Value => $self->Created); + my $self = shift; + my $obj = new RT::Date( $self->CurrentUser ); + + $obj->Set( Format => 'sql', Value => $self->Created ); - return $obj; } @@ -182,9 +258,10 @@ sub CreatedObj { # TODO: This should be deprecated # sub AgeAsString { - my $self=shift; - return($self->CreatedObj->AgeAsString()); + my $self = shift; + return ( $self->CreatedObj->AgeAsString() ); } + # }}} # {{{ LastUpdatedAsString @@ -192,12 +269,13 @@ sub AgeAsString { # TODO this should be deprecated sub LastUpdatedAsString { - my $self=shift; - if ($self->LastUpdated) { - return ($self->LastUpdatedObj->AsString()); - - } else { - return "never"; + my $self = shift; + if ( $self->LastUpdated ) { + return ( $self->LastUpdatedObj->AsString() ); + + } + else { + return "never"; } } @@ -209,8 +287,9 @@ sub LastUpdatedAsString { # sub CreatedAsString { my $self = shift; - return ($self->CreatedObj->AsString()); + return ( $self->CreatedObj->AsString() ); } + # }}} # {{{ LongSinceUpdateAsString @@ -218,42 +297,47 @@ sub CreatedAsString { # TODO This should be deprecated # sub LongSinceUpdateAsString { - my $self=shift; - if ($self->LastUpdated) { - - return ($self->LastUpdatedObj->AgeAsString()); - - } else { - return "never"; + my $self = shift; + if ( $self->LastUpdated ) { + + return ( $self->LastUpdatedObj->AgeAsString() ); + + } + else { + return "never"; } } + # }}} # }}} Datehandling - # {{{ sub _Set -sub _Set { - my $self = shift; +sub _Set { + my $self = shift; - my %args = ( Field => undef, - Value => undef, - IsSQL => undef, - @_ ); + my %args = ( + Field => undef, + Value => undef, + IsSQL => undef, + @_ + ); + #if the user is trying to modify the record + # TODO: document _why_ this code is here - #if the user is trying to modify the record - if ((!defined ($args{'Field'})) || (!defined ($args{'Value'}))) { - $args{'Value'} = 0; - } + if ( ( !defined( $args{'Field'} ) ) || ( !defined( $args{'Value'} ) ) ) { + $args{'Value'} = 0; + } - $self->_SetLastUpdated(); - $self->SUPER::_Set(Field => $args{'Field'}, - Value => $args{'Value'}, - IsSQL => $args{'IsSQL'}); - - + $self->_SetLastUpdated(); + my ( $val, $msg ) = $self->SUPER::_Set( + Field => $args{'Field'}, + Value => $args{'Value'}, + IsSQL => $args{'IsSQL'} + ); } + # }}} # {{{ sub _SetLastUpdated @@ -268,16 +352,20 @@ It takes no options. Arguably, this is a bug sub _SetLastUpdated { my $self = shift; use RT::Date; - my $now = new RT::Date($self->CurrentUser); + my $now = new RT::Date( $self->CurrentUser ); $now->SetToNow(); - if ($self->_Accessible('LastUpdated','auto')) { - my ($msg, $val) = $self->__Set( Field => 'LastUpdated', - Value => $now->ISO); + if ( $self->_Accessible( 'LastUpdated', 'auto' ) ) { + my ( $msg, $val ) = $self->__Set( + Field => 'LastUpdated', + Value => $now->ISO + ); } - if ($self->_Accessible('LastUpdatedBy','auto')) { - my ($msg, $val) = $self->__Set( Field => 'LastUpdatedBy', - Value => $self->CurrentUser->id); + if ( $self->_Accessible( 'LastUpdatedBy', 'auto' ) ) { + my ( $msg, $val ) = $self->__Set( + Field => 'LastUpdatedBy', + Value => $self->CurrentUser->id + ); } } @@ -291,15 +379,16 @@ Returns an RT::User object with the RT account of the creator of this row =cut -sub CreatorObj { - my $self = shift; - unless (exists $self->{'CreatorObj'}) { - - $self->{'CreatorObj'} = RT::User->new($self->CurrentUser); - $self->{'CreatorObj'}->Load($self->Creator); - } - return($self->{'CreatorObj'}); +sub CreatorObj { + my $self = shift; + unless ( exists $self->{'CreatorObj'} ) { + + $self->{'CreatorObj'} = RT::User->new( $self->CurrentUser ); + $self->{'CreatorObj'}->Load( $self->Creator ); + } + return ( $self->{'CreatorObj'} ); } + # }}} # {{{ sub LastUpdatedByObj @@ -311,35 +400,56 @@ sub CreatorObj { =cut sub LastUpdatedByObj { - my $self=shift; - unless (exists $self->{LastUpdatedByObj}) { - $self->{'LastUpdatedByObj'}=RT::User->new($self->CurrentUser); - $self->{'LastUpdatedByObj'}->Load($self->LastUpdatedBy); + my $self = shift; + unless ( exists $self->{LastUpdatedByObj} ) { + $self->{'LastUpdatedByObj'} = RT::User->new( $self->CurrentUser ); + $self->{'LastUpdatedByObj'}->Load( $self->LastUpdatedBy ); } return $self->{'LastUpdatedByObj'}; } # }}} -# {{{ sub CurrentUser -=head2 CurrentUser +require Encode::compat if $] < 5.007001; +require Encode; -If called with an argument, sets the current user to that user object. -This will affect ACL decisions, etc. -Returns the current user +sub __Value { + my $self = shift; + my $field = shift; + my %args = ( decode_utf8 => 1, + @_ ); -=cut + unless (defined $field && $field) { + $RT::Logger->error("$self __Value called with undef field"); + } + my $value = $self->SUPER::__Value($field); + + return('') if ( !defined($value) || $value eq ''); + + return Encode::decode_utf8($value) || $value if $args{'decode_utf8'}; + return $value; +} -sub CurrentUser { - my $self = shift; +# Set up defaults for DBIx::SearchBuilder::Record::Cachable - if (@_) { - $self->{'user'} = shift; +sub _CacheConfig { + { + 'cache_p' => 1, + 'fast_update_p' => 1, + 'cache_for_sec' => 30, } - return ($self->{'user'}); } -# }}} +=head2 _DecodeUTF8 + + When passed a string will "decode" it int a proper UTF-8 string + +=cut + +eval "require RT::Record_Vendor"; +die $@ if ($@ && $@ !~ qr{^Can't locate RT/Record_Vendor.pm}); +eval "require RT::Record_Local"; +die $@ if ($@ && $@ !~ qr{^Can't locate RT/Record_Local.pm}); 1;