import rt 3.8.10
[freeside.git] / rt / lib / RT / Users_Overlay.pm
index 19f1bea..9640925 100644 (file)
@@ -1,38 +1,40 @@
 # BEGIN BPS TAGGED BLOCK {{{
-# 
+#
 # COPYRIGHT:
-#  
-# This software is Copyright (c) 1996-2005 Best Practical Solutions, LLC 
-#                                          <jesse@bestpractical.com>
-# 
+#
+# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC
+#                                          <sales@bestpractical.com>
+#
 # (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., 675 Mass Ave, Cambridge, MA 02139, USA.
-# 
-# 
+# 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
@@ -41,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 }}}
 
 =head1 NAME
 
 =head1 METHODS
 
-=begin testing
-
-ok(require RT::Users);
-
-=end testing
 
 =cut
 
@@ -76,11 +73,10 @@ no warnings qw(redefine);
 sub _Init {
     my $self = shift;
     $self->{'table'} = 'Users';
-        $self->{'primary_key'} = 'id';
-
+    $self->{'primary_key'} = 'id';
+    $self->{'with_disabled_column'} = 1;
 
-
-    my @result =          $self->SUPER::_Init(@_);
+    my @result = $self->SUPER::_Init(@_);
     # By default, order by name
     $self->OrderBy( ALIAS => 'main',
                     FIELD => 'Name',
@@ -117,46 +113,41 @@ sub PrincipalsAlias {
 }
 
 
-# {{{ sub _DoSearch 
-
-=head2 _DoSearch
+=head2 LimitToEnabled
 
-  A subclass of DBIx::SearchBuilder::_DoSearch that makes sure that _Disabled rows never get seen unless
-we're explicitly trying to see them.
+Only find items that haven\'t been disabled
 
 =cut
 
-sub _DoSearch {
+# XXX: should be generalized
+sub LimitToEnabled {
     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();
-    }
-    return ( $self->SUPER::_DoSearch(@_) );
-
+    $self->{'handled_disabled_column'} = 1;
+    $self->Limit(
+        ALIAS    => $self->PrincipalsAlias,
+        FIELD    => 'Disabled',
+        VALUE    => '0',
+    );
 }
 
-# }}}
-# {{{ sub LimitToEnabled
+=head2 LimitToDeleted
 
-=head2 LimitToEnabled
-
-Only find items that haven\'t been disabled
+Only find items that have been deleted.
 
 =cut
 
-# XXX: should be generalized
-sub LimitToEnabled {
+sub LimitToDeleted {
     my $self = shift;
-
-    $self->Limit( ALIAS    => $self->PrincipalsAlias,
-                  FIELD    => 'Disabled',
-                  VALUE    => '0',
-                  OPERATOR => '=' );
+    
+    $self->{'handled_disabled_column'} = $self->{'find_disabled_rows'} = 1;
+    $self->Limit(
+        ALIAS => $self->PrincipalsAlias,
+        FIELD => 'Disabled',
+        VALUE => 1,
+    );
 }
 
-# }}}
 
 # {{{ LimitToEmail
 
@@ -231,68 +222,6 @@ sub LimitToPrivileged {
 
 =head2 WhoHaveRight { Right => 'name', Object => $rt_object , IncludeSuperusers => undef, IncludeSubgroupMembers => undef, IncludeSystemRights => undef, EquivObjects => [ ] }
 
-=begin testing
-
-ok(my $users = RT::Users->new($RT::SystemUser));
-$users->WhoHaveRight(Object =>$RT::System, Right =>'SuperUser');
-ok($users->Count == 1, "There is one privileged superuser - Found ". $users->Count );
-# TODO: this wants more testing
-
-my $RTxUser = RT::User->new($RT::SystemUser);
-($id, $msg) = $RTxUser->Create( Name => 'RTxUser', Comments => "RTx extension user", Privileged => 1);
-ok ($id,$msg);
-
-my $group = RT::Group->new($RT::SystemUser);
-$group->LoadACLEquivalenceGroup($RTxUser->PrincipalObj);
-
-my $RTxSysObj = {};
-bless $RTxSysObj, 'RTx::System';
-*RTx::System::Id = sub { 1; };
-*RTx::System::id = *RTx::System::Id;
-my $ace = RT::Record->new($RT::SystemUser);
-$ace->Table('ACL');
-$ace->_BuildTableAttributes unless ($_TABLE_ATTR->{ref($self)});
-($id, $msg) = $ace->Create( PrincipalId => $group->id, PrincipalType => 'Group', RightName => 'RTxUserRight', ObjectType => 'RTx::System', ObjectId  => 1 );
-ok ($id, "ACL for RTxSysObj created");
-
-my $RTxObj = {};
-bless $RTxObj, 'RTx::System::Record';
-*RTx::System::Record::Id = sub { 4; };
-*RTx::System::Record::id = *RTx::System::Record::Id;
-
-$users = RT::Users->new($RT::SystemUser);
-$users->WhoHaveRight(Right => 'RTxUserRight', Object => $RTxSysObj);
-is($users->Count, 1, "RTxUserRight found for RTxSysObj");
-
-$users = RT::Users->new($RT::SystemUser);
-$users->WhoHaveRight(Right => 'RTxUserRight', Object => $RTxObj);
-is($users->Count, 0, "RTxUserRight not found for RTxObj");
-
-$users = RT::Users->new($RT::SystemUser);
-$users->WhoHaveRight(Right => 'RTxUserRight', Object => $RTxObj, EquivObjects => [ $RTxSysObj ]);
-is($users->Count, 1, "RTxUserRight found for RTxObj using EquivObjects");
-
-$ace = RT::Record->new($RT::SystemUser);
-$ace->Table('ACL');
-$ace->_BuildTableAttributes unless ($_TABLE_ATTR->{ref($self)});
-($id, $msg) = $ace->Create( PrincipalId => $group->id, PrincipalType => 'Group', RightName => 'RTxUserRight', ObjectType => 'RTx::System::Record', ObjectId => 5 );
-ok ($id, "ACL for RTxObj created");
-
-my $RTxObj2 = {};
-bless $RTxObj2, 'RTx::System::Record';
-*RTx::System::Record::Id = sub { 5; };
-*RTx::System::Record::id = sub { 5; };
-
-$users = RT::Users->new($RT::SystemUser);
-$users->WhoHaveRight(Right => 'RTxUserRight', Object => $RTxObj2);
-is($users->Count, 1, "RTxUserRight found for RTxObj2");
-
-$users = RT::Users->new($RT::SystemUser);
-$users->WhoHaveRight(Right => 'RTxUserRight', Object => $RTxObj2, EquivObjects => [ $RTxSysObj ]);
-is($users->Count, 1, "RTxUserRight found for RTxObj2");
-
-
-=end testing
 
 find all users who the right Right for this group, either individually
 or as members of groups
@@ -362,6 +291,16 @@ sub _JoinACL
         @_,
     );
 
+    if ( $args{'Right'} ) {
+        my $canonic = RT::ACE->CanonicalizeRightName( $args{'Right'} );
+        unless ( $canonic ) {
+            $RT::Logger->error("Invalid right. Couldn't canonicalize right '$args{'Right'}'");
+        }
+        else {
+            $args{'Right'} = $canonic;
+        }
+    }
+
     my $acl = $self->NewAlias('ACL');
     $self->Limit(
         ALIAS    => $acl,
@@ -402,7 +341,7 @@ sub _GetEquivObjects
 
         # XXX: This should be abstracted into object itself
         if( $args{'Object'}->id ) {
-            push @objects, $args{'Object'}->QueueObj;
+            push @objects, $args{'Object'}->ACLEquivalenceObjects;
         } else {
             push @objects, 'RT::Queue';
         }
@@ -442,8 +381,8 @@ sub WhoHaveRight {
     #XXX: DIRTY HACK
     use DBIx::SearchBuilder::Union;
     my $union = new DBIx::SearchBuilder::Union;
-    $union->add($from_role);
-    $union->add($from_group);
+    $union->add( $from_group );
+    $union->add( $from_role );
     %$self = %$union;
     bless $self, ref($union);
 
@@ -465,48 +404,20 @@ sub WhoHaveRoleRight
         @_
     );
 
-    my $groups = $self->_JoinGroups( %args );
-    my $acl = $self->_JoinACL( %args );
-
-    my ($check_roles, $check_objects) = ('','');
-    
     my @objects = $self->_GetEquivObjects( %args );
-    if ( @objects ) {
-        my @role_clauses;
-        my @object_clauses;
-        foreach my $obj ( @objects ) {
-            my $type = ref($obj)? ref($obj): $obj;
-            my $id;
-            $id = $obj->id if ref($obj) && UNIVERSAL::can($obj, 'id') && $obj->id;
 
-            my $role_clause = "$groups.Domain = '$type-Role'";
-            # XXX: Groups.Instance is VARCHAR in DB, we should quote value
-            # if we want mysql 4.0 use indexes here. we MUST convert that
-            # field to integer and drop this quotes.
-            $role_clause   .= " AND $groups.Instance = '$id'" if $id;
-            push @role_clauses, "($role_clause)";
+    # RT::Principal->RolesWithRight only expects EquivObjects, so we need to
+    # fill it.  At the very least it needs $args{Object}, which
+    # _GetEquivObjects above does for us.
+    unshift @{$args{'EquivObjects'}}, @objects;
 
-            my $object_clause = "$acl.ObjectType = '$type'";
-            $object_clause   .= " AND $acl.ObjectId = $id" if $id;
-            push @object_clauses, "($object_clause)";
-        }
-
-        $check_roles .= join ' OR ', @role_clauses;
-        $check_objects = join ' OR ', @object_clauses;
-    } else {
-        if( !$args{'IncludeSystemRights'} ) {
-            $check_objects = "($acl.ObjectType != 'RT::System')";
-        }
+    my @roles = RT::Principal->RolesWithRight( %args );
+    unless ( @roles ) {
+        $self->_AddSubClause( "WhichRole", "(main.id = 0)" );
+        return;
     }
 
-    $self->_AddSubClause( "WhichObject", "($check_objects)" );
-    $self->_AddSubClause( "WhichRole", "($check_roles)" );
-
-    $self->Limit( ALIAS => $acl,
-                  FIELD => 'PrincipalType',
-                  VALUE => "$groups.Type",
-                  QUOTEVALUE => 0,
-                );
+    my $groups = $self->_JoinGroups( %args );
 
     # no system user
     $self->Limit( ALIAS => $self->PrincipalsAlias,
@@ -514,9 +425,37 @@ sub WhoHaveRoleRight
                   OPERATOR => '!=',
                   VALUE => $RT::SystemUser->id
                 );
+
+    $self->_AddSubClause( "WhichRole", "(". join( ' OR ', map "$groups.Type = '$_'", @roles ) .")" );
+
+    my @groups_clauses = $self->_RoleClauses( $groups, @objects );
+    $self->_AddSubClause( "WhichObject", "(". join( ' OR ', @groups_clauses ) .")" )
+        if @groups_clauses;
+
     return;
 }
 
+sub _RoleClauses {
+    my $self = shift;
+    my $groups = shift;
+    my @objects = @_;
+
+    my @groups_clauses;
+    foreach my $obj ( @objects ) {
+        my $type = ref($obj)? ref($obj): $obj;
+        my $id;
+        $id = $obj->id if ref($obj) && UNIVERSAL::can($obj, 'id') && $obj->id;
+
+        my $role_clause = "$groups.Domain = '$type-Role'";
+        # XXX: Groups.Instance is VARCHAR in DB, we should quote value
+        # if we want mysql 4.0 use indexes here. we MUST convert that
+        # field to integer and drop this quotes.
+        $role_clause   .= " AND $groups.Instance = '$id'" if $id;
+        push @groups_clauses, "($role_clause)";
+    }
+    return @groups_clauses;
+}
+
 # XXX: should be generalized
 sub _JoinGroupMembersForGroupRights
 {