X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=rt%2Flib%2FRT%2FCustomField_Overlay.pm;h=9cf608e5ac4b17b97ae0e43159369fd98c0fdb5e;hb=fc6209f398899f0211cfcedeb81a3cd65e04a941;hp=9286d7a1d65e72011124d5ea57d84ce70af28d83;hpb=b4b0c7e72d7eaee2fbfc7022022c9698323203dd;p=freeside.git diff --git a/rt/lib/RT/CustomField_Overlay.pm b/rt/lib/RT/CustomField_Overlay.pm index 9286d7a1d..9cf608e5a 100644 --- a/rt/lib/RT/CustomField_Overlay.pm +++ b/rt/lib/RT/CustomField_Overlay.pm @@ -1,40 +1,40 @@ # BEGIN BPS TAGGED BLOCK {{{ -# +# # COPYRIGHT: -# -# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC -# -# +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# +# # (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 }}} package RT::CustomField; @@ -52,6 +52,7 @@ use strict; no warnings qw(redefine); use RT::CustomFieldValues; +use RT::ObjectCustomFields; use RT::ObjectCustomFieldValues; @@ -111,6 +112,7 @@ RT::CustomField->_ForObjectType( 'RT::Group' => "Groups", ); our $RIGHTS = { SeeCustomField => 'See custom fields', # loc_pair AdminCustomField => 'Create, delete and modify custom fields', # loc_pair + AdminCustomFieldValues => 'Create, delete and modify custom fields values', # loc_pair ModifyCustomField => 'Add, delete and modify custom field values for objects' #loc_pair }; @@ -342,7 +344,7 @@ sub LoadByName { # When loading by name, we _can_ load disabled fields, but prefer # non-disabled fields. - $CFs->{'find_disabled_rows'}=1; + $CFs->FindAllRows; $CFs->OrderByCols( { FIELD => "Disabled", ORDER => 'ASC' }, ); @@ -399,7 +401,7 @@ sub AddValue { my $self = shift; my %args = @_; - unless ($self->CurrentUserHasRight('AdminCustomField')) { + unless ($self->CurrentUserHasRight('AdminCustomField') || $self->CurrentUserHasRight('AdminCustomFieldValues')) { return (0, $self->loc('Permission Denied')); } @@ -428,7 +430,7 @@ Does not remove this value for any article which has had it selected sub DeleteValue { my $self = shift; my $id = shift; - unless ( $self->CurrentUserHasRight('AdminCustomField') ) { + unless ( $self->CurrentUserHasRight('AdminCustomField') || $self->CurrentUserHasRight('AdminCustomFieldValues') ) { return (0, $self->loc('Permission Denied')); } @@ -808,24 +810,6 @@ sub SetTypeComposite { ); } -=head2 SetLookupType - -Autrijus: care to doc how LookupTypes work? - -=cut - -sub SetLookupType { - my $self = shift; - my $lookup = shift; - if ( $lookup ne $self->LookupType ) { - # Okay... We need to invalidate our existing relationships - my $ObjectCustomFields = RT::ObjectCustomFields->new($self->CurrentUser); - $ObjectCustomFields->LimitToCustomField($self->Id); - $_->Delete foreach @{$ObjectCustomFields->ItemsArrayRef}; - } - return $self->SUPER::SetLookupType($lookup); -} - =head2 TypeComposite Returns a composite value composed of this object's type and maximum values @@ -849,6 +833,24 @@ sub TypeComposites { return grep !/(?:[Tt]ext|Combobox)-0/, map { ("$_-1", "$_-0") } $self->Types; } +=head2 SetLookupType + +Autrijus: care to doc how LookupTypes work? + +=cut + +sub SetLookupType { + my $self = shift; + my $lookup = shift; + if ( $lookup ne $self->LookupType ) { + # Okay... We need to invalidate our existing relationships + my $ObjectCustomFields = RT::ObjectCustomFields->new($self->CurrentUser); + $ObjectCustomFields->LimitToCustomField($self->Id); + $_->Delete foreach @{$ObjectCustomFields->ItemsArrayRef}; + } + return $self->SUPER::SetLookupType($lookup); +} + =head2 LookupTypes Returns an array of LookupTypes available @@ -867,7 +869,7 @@ my @FriendlyObjectTypes = ( "[_1]'s [_2]'s [_3] objects", # loc ); -=head2 FriendlyTypeLookup +=head2 FriendlyLookupType Returns a localized description of the type of this custom field @@ -887,6 +889,137 @@ sub FriendlyLookupType { return ( $self->loc( $FriendlyObjectTypes[$#types], @types ) ); } +sub RecordClassFromLookupType { + my $self = shift; + my ($class) = ($self->LookupType =~ /^([^-]+)/); + unless ( $class ) { + $RT::Logger->error( + "Custom Field #". $self->id + ." has incorrect LookupType '". $self->LookupType ."'" + ); + return undef; + } + return $class; +} + +sub CollectionClassFromLookupType { + my $self = shift; + + my $record_class = $self->RecordClassFromLookupType; + return undef unless $record_class; + + my $collection_class; + if ( UNIVERSAL::can($record_class.'Collection', 'new') ) { + $collection_class = $record_class.'Collection'; + } elsif ( UNIVERSAL::can($record_class.'es', 'new') ) { + $collection_class = $record_class.'es'; + } elsif ( UNIVERSAL::can($record_class.'s', 'new') ) { + $collection_class = $record_class.'s'; + } else { + $RT::Logger->error("Can not find a collection class for record class '$record_class'"); + return undef; + } + return $collection_class; +} + +=head1 AppliedTo + +Returns collection with objects this custom field is applied to. +Class of the collection depends on L. +See all L . + +Doesn't takes into account if object is applied globally. + +=cut + +sub AppliedTo { + my $self = shift; + + my ($res, $ocfs_alias) = $self->_AppliedTo; + return $res unless $res; + + $res->Limit( + ALIAS => $ocfs_alias, + FIELD => 'id', + OPERATOR => 'IS NOT', + VALUE => 'NULL', + ); + + return $res; +} + +=head1 NotAppliedTo + +Returns collection with objects this custom field is not applied to. +Class of the collection depends on L. +See all L . + +Doesn't takes into account if object is applied globally. + +=cut + +sub NotAppliedTo { + my $self = shift; + + my ($res, $ocfs_alias) = $self->_AppliedTo; + return $res unless $res; + + $res->Limit( + ALIAS => $ocfs_alias, + FIELD => 'id', + OPERATOR => 'IS', + VALUE => 'NULL', + ); + + return $res; +} + +sub _AppliedTo { + my $self = shift; + + my ($class) = $self->CollectionClassFromLookupType; + return undef unless $class; + + my $res = $class->new( $self->CurrentUser ); + + # If CF is a Group CF, only display user-defined groups + if ( $class eq 'RT::Groups' ) { + $res->LimitToUserDefinedGroups; + } + + $res->OrderBy( FIELD => 'Name' ); + my $ocfs_alias = $res->Join( + TYPE => 'LEFT', + ALIAS1 => 'main', + FIELD1 => 'id', + TABLE2 => 'ObjectCustomFields', + FIELD2 => 'ObjectId', + ); + $res->Limit( + LEFTJOIN => $ocfs_alias, + ALIAS => $ocfs_alias, + FIELD => 'CustomField', + VALUE => $self->id, + ); + return ($res, $ocfs_alias); +} + +=head2 IsApplied + +Takes object id and returns corresponding L +record if this custom field is applied to the object. Use 0 to check +if custom field is applied globally. + +=cut + +sub IsApplied { + my $self = shift; + my $id = shift; + my $ocf = RT::ObjectCustomField->new( $self->CurrentUser ); + $ocf->LoadByCols( CustomField => $self->id, ObjectId => $id || 0 ); + return undef unless $ocf->id; + return $ocf; +} =head2 AddToObject OBJECT @@ -910,14 +1043,27 @@ sub AddToObject { return ( 0, $self->loc('Permission Denied') ); } - my $ObjectCF = RT::ObjectCustomField->new( $self->CurrentUser ); - $ObjectCF->LoadByCols( ObjectId => $id, CustomField => $self->Id ); - if ( $ObjectCF->Id ) { - return ( 0, $self->loc("That is already the current value") ); + if ( $self->IsApplied( $id ) ) { + return ( 0, $self->loc("Custom field is already applied to the object") ); + } + + if ( $id ) { + # applying locally + return (0, $self->loc("Couldn't apply custom field to an object as it's global already") ) + if $self->IsApplied( 0 ); + } + else { + my $applied = RT::ObjectCustomFields->new( $self->CurrentUser ); + $applied->LimitToCustomField( $self->id ); + while ( my $record = $applied->Next ) { + $record->Delete; + } } - my ( $oid, $msg ) = - $ObjectCF->Create( ObjectId => $id, CustomField => $self->Id ); + my $ocf = RT::ObjectCustomField->new( $self->CurrentUser ); + my ( $oid, $msg ) = $ocf->Create( + ObjectId => $id, CustomField => $self->id, + ); return ( $oid, $msg ); } @@ -930,7 +1076,6 @@ Takes an object =cut - sub RemoveFromObject { my $self = shift; my $object = shift; @@ -944,14 +1089,13 @@ sub RemoveFromObject { return ( 0, $self->loc('Permission Denied') ); } - my $ObjectCF = RT::ObjectCustomField->new( $self->CurrentUser ); - $ObjectCF->LoadByCols( ObjectId => $id, CustomField => $self->Id ); - unless ( $ObjectCF->Id ) { + my $ocf = $self->IsApplied( $id ); + unless ( $ocf ) { return ( 0, $self->loc("This custom field does not apply to that object") ); } - # XXX: Delete doesn't return anything - my ( $oid, $msg ) = $ObjectCF->Delete; + # XXX: Delete doesn't return anything + my ( $oid, $msg ) = $ocf->Delete; return ( $oid, $msg ); }