Merge branch 'master' of git.freeside.biz:/home/git/freeside
[freeside.git] / rt / lib / RT / Groups.pm
index e7734e0..3099f1b 100755 (executable)
@@ -2,7 +2,7 @@
 #
 # COPYRIGHT:
 #
-# This software is Copyright (c) 1996-2013 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)
@@ -74,14 +74,11 @@ package RT::Groups;
 use strict;
 use warnings;
 
-
-
-use RT::Group;
-
 use base 'RT::SearchBuilder';
 
 sub Table { 'Groups'}
 
+use RT::Group;
 use RT::Users;
 
 # XXX: below some code is marked as subject to generalize in Groups, Users classes.
@@ -98,8 +95,8 @@ sub _Init {
   my @result = $self->SUPER::_Init(@_);
 
   $self->OrderBy( ALIAS => 'main',
-                 FIELD => 'Name',
-                 ORDER => 'ASC');
+                  FIELD => 'Name',
+                  ORDER => 'ASC');
 
   # XXX: this code should be generalized
   $self->{'princalias'} = $self->Join(
@@ -144,7 +141,7 @@ Return only SystemInternal Groups, such as "privileged" "unprivileged" and "ever
 
 sub LimitToSystemInternalGroups {
     my $self = shift;
-    $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'SystemInternal');
+    $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'SystemInternal', CASESENSITIVE => 0 );
     # All system internal groups have the same instance. No reason to limit down further
     #$self->Limit(FIELD => 'Instance', OPERATOR => '=', VALUE => '0');
 }
@@ -161,16 +158,34 @@ Return only UserDefined Groups
 
 sub LimitToUserDefinedGroups {
     my $self = shift;
-    $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'UserDefined');
+    $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'UserDefined', CASESENSITIVE => 0 );
     # All user-defined groups have the same instance. No reason to limit down further
     #$self->Limit(FIELD => 'Instance', OPERATOR => '=', VALUE => '');
 }
 
+=head2 LimitToRolesForObject OBJECT
 
+Limits the set of groups to role groups specifically for the object in question
+based on the object's class and ID.  If the object has no ID, the roles are not
+limited by group C<Instance>.  That is, calling this method on an unloaded
+object will find all role groups for that class of object.
 
+Replaces L</LimitToRolesForQueue>, L</LimitToRolesForTicket>, and
+L</LimitToRolesForSystem>.
+
+=cut
+
+sub LimitToRolesForObject {
+    my $self   = shift;
+    my $object = shift;
+    $self->Limit(FIELD => 'Domain',   OPERATOR => '=', VALUE => ref($object) . "-Role", CASESENSITIVE => 0 );
+    $self->Limit(FIELD => 'Instance', OPERATOR => '=', VALUE => $object->id);
+}
 
 =head2 LimitToRolesForQueue QUEUE_ID
 
+B<DEPRECATED>. Use L</LimitToRolesForObject> instead.
+
 Limits the set of groups found to role groups for queue QUEUE_ID
 
 =cut
@@ -178,7 +193,11 @@ Limits the set of groups found to role groups for queue QUEUE_ID
 sub LimitToRolesForQueue {
     my $self = shift;
     my $queue = shift;
-    $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'RT::Queue-Role');
+    RT->Deprecated(
+        Instead => "LimitToRolesForObject",
+        Remove => "4.4",
+    );
+    $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'RT::Queue-Role', CASESENSITIVE => 0 );
     $self->Limit(FIELD => 'Instance', OPERATOR => '=', VALUE => $queue);
 }
 
@@ -186,6 +205,8 @@ sub LimitToRolesForQueue {
 
 =head2 LimitToRolesForTicket Ticket_ID
 
+B<DEPRECATED>. Use L</LimitToRolesForObject> instead.
+
 Limits the set of groups found to role groups for Ticket Ticket_ID
 
 =cut
@@ -193,21 +214,32 @@ Limits the set of groups found to role groups for Ticket Ticket_ID
 sub LimitToRolesForTicket {
     my $self = shift;
     my $Ticket = shift;
-    $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'RT::Ticket-Role');
-    $self->Limit(FIELD => 'Instance', OPERATOR => '=', VALUE => '$Ticket');
+    RT->Deprecated(
+        Instead => "LimitToRolesForObject",
+        Remove => "4.4",
+    );
+    $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'RT::Ticket-Role', CASESENSITIVE => 0 );
+    $self->Limit(FIELD => 'Instance', OPERATOR => '=', VALUE => $Ticket);
 }
 
 
 
 =head2 LimitToRolesForSystem System_ID
 
+B<DEPRECATED>. Use L</LimitToRolesForObject> instead.
+
 Limits the set of groups found to role groups for System System_ID
 
 =cut
 
 sub LimitToRolesForSystem {
     my $self = shift;
-    $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'RT::System-Role');
+    RT->Deprecated(
+        Instead => "LimitToRolesForObject",
+        Remove => "4.4",
+    );
+    $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'RT::System-Role', CASESENSITIVE => 0 );
+    $self->Limit(FIELD => 'Instance', OPERATOR => '=', VALUE => RT::System->Id );
 }
 
 
@@ -223,15 +255,15 @@ sub WithMember {
     my %args = ( PrincipalId => undef,
                  Recursively => undef,
                  @_);
-    my $members;
-
-    if ($args{'Recursively'}) {
-        $members = $self->NewAlias('CachedGroupMembers');
-    } else {
-        $members = $self->NewAlias('GroupMembers');
-    }
-    $self->Join(ALIAS1 => 'main', FIELD1 => 'id',
-                ALIAS2 => $members, FIELD2 => 'GroupId');
+    my $members = $self->Join(
+        ALIAS1 => 'main', FIELD1 => 'id',
+        $args{'Recursively'}
+            ? (TABLE2 => 'CachedGroupMembers')
+            # (GroupId, MemberId) is unique in GM table
+            : (TABLE2 => 'GroupMembers', DISTINCT => 1)
+        ,
+        FIELD2 => 'GroupId',
+    );
 
     $self->Limit(ALIAS => $members, FIELD => 'MemberId', OPERATOR => '=', VALUE => $args{'PrincipalId'});
     $self->Limit(ALIAS => $members, FIELD => 'Disabled', VALUE => 0)
@@ -240,6 +272,15 @@ sub WithMember {
     return $members;
 }
 
+sub WithCurrentUser {
+    my $self = shift;
+    $self->{with_current_user} = 1;
+    return $self->WithMember(
+        PrincipalId => $self->CurrentUser->PrincipalId,
+        Recursively => 1,
+    );
+}
+
 sub WithoutMember {
     my $self = shift;
     my %args = (
@@ -254,6 +295,7 @@ sub WithoutMember {
         FIELD1 => 'id',
         TABLE2 => $members,
         FIELD2 => 'GroupId',
+        DISTINCT => $members eq 'GroupMembers',
     );
     $self->Limit(
         LEFTJOIN => $members_alias,
@@ -427,50 +469,32 @@ sub LimitToDeleted {
 
 
 
-sub Next {
+sub AddRecord {
     my $self = shift;
+    my ($record) = @_;
 
-    # Don't show groups which the user isn't allowed to see.
+    # If we've explicitly limited to groups the user is a member of (for
+    # dashboard or savedsearch privacy objects), skip the ACL.
+    return unless $self->{with_current_user}
+        or $record->CurrentUserHasRight('SeeGroup');
 
-    my $Group = $self->SUPER::Next();
-    if ((defined($Group)) and (ref($Group))) {
-       unless ($Group->CurrentUserHasRight('SeeGroup')) {
-           return $self->Next();
-       }
-       
-       return $Group;
-    }
-    else {
-       return undef;
-    }
+    return $self->SUPER::AddRecord( $record );
 }
 
 
 
 sub _DoSearch {
     my $self = shift;
-    
+
     #unless we really want to find disabled rows, make sure we're only finding enabled ones.
     unless($self->{'find_disabled_rows'}) {
-       $self->LimitToEnabled();
+        $self->LimitToEnabled();
     }
-    
-    return($self->SUPER::_DoSearch(@_));
-    
-}
-
-
-
-=head2 NewItem
-
-Returns an empty new RT::Group item
 
-=cut
+    return($self->SUPER::_DoSearch(@_));
 
-sub NewItem {
-    my $self = shift;
-    return(RT::Group->new($self->CurrentUser));
 }
+
 RT::Base->_ImportOverlays();
 
 1;