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 {{{
 # BEGIN BPS TAGGED BLOCK {{{
-# 
+#
 # COPYRIGHT:
 # 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)
 # (Except where explicitly superseded by other copyright notices)
-# 
-# 
+#
+#
 # LICENSE:
 # 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 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.
 # 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
 # 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:
 # 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.)
 # (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
 # 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.
 # 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
 # END BPS TAGGED BLOCK }}}
 
 =head1 NAME
 
 =head1 METHODS
 
 
 =head1 METHODS
 
-=begin testing
-
-ok(require RT::Users);
-
-=end testing
 
 =cut
 
 
 =cut
 
@@ -76,11 +73,10 @@ no warnings qw(redefine);
 sub _Init {
     my $self = shift;
     $self->{'table'} = 'Users';
 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',
     # 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
 
 
 =cut
 
-sub _DoSearch {
+# XXX: should be generalized
+sub LimitToEnabled {
     my $self = shift;
 
     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
 
 
 =cut
 
-# XXX: should be generalized
-sub LimitToEnabled {
+sub LimitToDeleted {
     my $self = shift;
     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
 
 
 # {{{ LimitToEmail
 
@@ -231,68 +222,6 @@ sub LimitToPrivileged {
 
 =head2 WhoHaveRight { Right => 'name', Object => $rt_object , IncludeSuperusers => undef, IncludeSubgroupMembers => undef, IncludeSystemRights => undef, EquivObjects => [ ] }
 
 
 =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
 
 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,
     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 ) {
 
         # 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';
         }
         } else {
             push @objects, 'RT::Queue';
         }
@@ -442,8 +381,8 @@ sub WhoHaveRight {
     #XXX: DIRTY HACK
     use DBIx::SearchBuilder::Union;
     my $union = new DBIx::SearchBuilder::Union;
     #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);
 
     %$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 );
     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,
 
     # no system user
     $self->Limit( ALIAS => $self->PrincipalsAlias,
@@ -514,9 +425,37 @@ sub WhoHaveRoleRight
                   OPERATOR => '!=',
                   VALUE => $RT::SystemUser->id
                 );
                   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;
 }
 
     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
 {
 # XXX: should be generalized
 sub _JoinGroupMembersForGroupRights
 {