[Rt-commit] rt branch, 3.9-acl_on_sql_for_queues, created. rt-3.9.7-798-g3674530

Ruslan Zakirov ruz at bestpractical.com
Fri Dec 10 22:13:07 EST 2010


The branch, 3.9-acl_on_sql_for_queues has been created
        at  367453004f46002b9f06dfe062bc7250c9472dbc (commit)

- Log -----------------------------------------------------------------
commit 4e737f72ce8deb22f33afbc877eea59075bf72b2
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Fri Dec 10 09:02:54 2010 +0300

    JoinRoleGroups for collections method

diff --git a/lib/RT/SearchBuilder.pm b/lib/RT/SearchBuilder.pm
index cd8e3f7..3b3a821 100755
--- a/lib/RT/SearchBuilder.pm
+++ b/lib/RT/SearchBuilder.pm
@@ -298,6 +298,58 @@ sub ColumnMapClassName {
     return $Class;
 }
 
+sub JoinRoleGroups {
+    my $self = shift;
+    my %args = (
+        New   => 0,
+        Left  => 0,
+        Alias => 'main',
+        Field => 'id',
+        Class => undef,
+        Type  => '',
+        @_
+    );
+    unless ( $args{'Class'} ) {
+        $args{'Class'} = ref $self;
+        $args{'Class'} =~ s/s$//;
+    }
+    unless ( $args{'New'} ) {
+        return $self->{'_sql_aliases'}{'role_groups'}{ join '-', @args{qw(Alias Field Class Type)} }
+            if $self->{'_sql_aliases'}{'role_groups'}{ join '-', @args{qw(Alias Field Class Type)} }
+    }
+
+    # we always have watcher groups, so we're safe to use INNER join,
+    # but we would love to see groups on demand, so make it possible
+    my $groups = $self->Join(
+        $args{'Left'}? (TYPE => 'LEFT') : (),
+        ALIAS1          => $args{'Alias'},
+        FIELD1          => $args{'Field'},
+        TABLE2          => 'Groups',
+        FIELD2          => 'Instance',
+        ENTRYAGGREGATOR => 'AND',
+    );
+    my $limit = 'Limit';
+    # special case for tickets :(
+    $limit = '_SQLLimit' if $self->isa('RT::Tickets');
+    $self->$limit(
+        LEFTJOIN => $groups,
+        ALIAS    => $groups,
+        FIELD    => 'Domain',
+        VALUE    => $args{'Class'} .'-Role',
+    );
+    $self->$limit(
+        LEFTJOIN => $groups,
+        ALIAS    => $groups,
+        FIELD    => 'Type',
+        VALUE    => $args{'Type'},
+    ) if $args{'Type'};
+
+    $self->{'_sql_aliases'}{'role_groups'}{ join '-', @args{qw(Alias Field Class Type)} } = $groups
+        unless $args{'New'};
+
+    return $groups;
+}
+
 RT::Base->_ImportOverlays();
 
 1;

commit 502c99cb56bcf88ce6052bc4cb90f833daeaeb4b
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Fri Dec 10 09:03:58 2010 +0300

    _RolesWithRight and _ObjectsDirectlyHasRightOn private class methods in RT::ACL

diff --git a/lib/RT/ACL_Overlay.pm b/lib/RT/ACL_Overlay.pm
index c0b1bf4..329a4c7 100755
--- a/lib/RT/ACL_Overlay.pm
+++ b/lib/RT/ACL_Overlay.pm
@@ -310,4 +310,100 @@ sub HasEntry {
     }
 }
 
+sub _RolesWithRight {
+    my $self = shift;
+    my %args = (
+        Right => undef,
+        @_
+    );
+
+    my $right = $args{'Right'} or return ();
+
+    my $cache_key = 'RolesWithRight;:;'. $right;
+ 
+    if ( my $cached = $RT::Principal::_ACL_CACHE->fetch( $cache_key ) ) {
+        return %$cached;
+    }
+
+    my $ACL = RT::ACL->new( RT->SystemUser );
+    $ACL->Limit( FIELD => 'RightName', VALUE => $right );
+    $ACL->Limit( FIELD => 'PrincipalType', OPERATOR => '!=', VALUE => 'Group' );
+    my $principal_alias = $ACL->Join(
+        ALIAS1 => 'main',
+        FIELD1 => 'PrincipalId',
+        TABLE2 => 'Principals',
+        FIELD2 => 'id',
+    );
+    $ACL->Limit( ALIAS => $principal_alias, FIELD => 'Disabled', VALUE => 0 );
+
+    my $query = 'SELECT main.PrincipalType, main.ObjectType, main.ObjectId'
+        .' FROM '. $ACL->_BuildJoins .' '. $ACL->_WhereClause;
+
+    my %res = ();
+    foreach my $row ( @{ $RT::Handle->SimpleQuery($query)->fetchall_arrayref } ) {
+        my ($role, $type, $id) = @$row;
+        if ( $type eq 'RT::System' ) {
+            $res{ $role } = { 'RT::System' => 1 };
+        }
+        else {
+            next if $res{ $role }{'RT::System'};
+            push @{ $res{ $role }{ $type } ||= [] }, $id;
+        }
+    }
+    $RT::Principal::_ACL_CACHE->set( $cache_key => \%res );
+    return %res;
+}
+
+sub _ObjectsDirectlyHasRightOn {
+    my $self = shift;
+    my %args = (
+        Right => undef,
+        User => undef,
+        @_
+    );
+    my $right = $args{'Right'} or return ();
+    my $id = $args{'User'} || $self->CurrentUser->id;
+
+    my $cache_key = 'User-'. $id .';:;'. $right .';:;ObjectsDirectlyHasRightOn';
+    if ( my $cached = $RT::Principal::_ACL_CACHE->fetch( $cache_key ) ) {
+        return %$cached;
+    }
+
+    my $ACL = RT::ACL->new( RT->SystemUser );
+    $ACL->Limit( FIELD => 'RightName', VALUE => $right );
+    my $principal_alias = $ACL->Join(
+        ALIAS1 => 'main',
+        FIELD1 => 'PrincipalId',
+        TABLE2 => 'Principals',
+        FIELD2 => 'id',
+    );
+    $ACL->Limit( ALIAS => $principal_alias, FIELD => 'Disabled', VALUE => 0 );
+    my $cgm_alias = $ACL->Join(
+        ALIAS1 => 'main',
+        FIELD1 => 'PrincipalId',
+        TABLE2 => 'CachedGroupMembers',
+        FIELD2 => 'GroupId',
+    );
+    $ACL->Limit( ALIAS => $cgm_alias, FIELD => 'MemberId', VALUE => $id );
+    $ACL->Limit( ALIAS => $cgm_alias, FIELD => 'Disabled', VALUE => 0 );
+
+    my $query = 'SELECT main.ObjectType, main.ObjectId'
+        .' FROM '. $ACL->_BuildJoins .' '. $ACL->_WhereClause;
+
+    my %res = ();
+    foreach my $row ( @{ $RT::Handle->SimpleQuery($query)->fetchall_arrayref } ) {
+        my ($type, $id) = @$row;
+        if ( $type eq 'RT::System' ) {
+            # If user is direct member of a group that has the right
+            # on the system then he has this right on any object
+            %res = ('RT::System' => 1);
+        }
+        else {
+            push @{ $res{$type} ||= [] }, $id;
+        }
+    }
+    $RT::Principal::_ACL_CACHE->set( $cache_key => \%res );
+    return %res;
+}
+
 1;

commit 315bad3a653bd3c206b89ef5fb18f540c5acb5e0
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Fri Dec 10 09:06:12 2010 +0300

    make it possible to override subclause

diff --git a/lib/RT/Tickets_Overlay_SQL.pm b/lib/RT/Tickets_Overlay_SQL.pm
index 6fd2619..a61e1a2 100755
--- a/lib/RT/Tickets_Overlay_SQL.pm
+++ b/lib/RT/Tickets_Overlay_SQL.pm
@@ -86,11 +86,11 @@ sub _SQLLimit {
          (!$args{'ALIAS'} || $args{'ALIAS'} eq 'main' ) ) {
         $self->{'looking_at_type'} = 1;
     }
+    $args{'SUBCLAUSE'} ||= 'ticketsql';
 
   # All SQL stuff goes into one SB subclause so we can deal with all
   # the aggregation
-  $self->SUPER::Limit(%args,
-                      SUBCLAUSE => 'ticketsql');
+  $self->SUPER::Limit( %args );
 }
 
 sub _SQLJoin {

commit 7a1c051446fbf2b394c11d2b61dcdc0758c89f9c
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Fri Dec 10 09:08:32 2010 +0300

    switch RT::Tickets over JoinRoleGroups

diff --git a/lib/RT/Tickets_Overlay.pm b/lib/RT/Tickets_Overlay.pm
index b3fc99e..c154832 100755
--- a/lib/RT/Tickets_Overlay.pm
+++ b/lib/RT/Tickets_Overlay.pm
@@ -245,7 +245,6 @@ sub CleanSlate {
         _sql_cf_alias
         _sql_group_members_aliases
         _sql_object_cfv_alias
-        _sql_role_group_aliases
         _sql_trattachalias
         _sql_u_watchers_alias_for_sort
         _sql_u_watchers_aliases
@@ -1013,36 +1012,12 @@ sub _WatcherLimit {
 
 sub _RoleGroupsJoin {
     my $self = shift;
-    my %args = (New => 0, Class => 'Ticket', Type => '', @_);
-    return $self->{'_sql_role_group_aliases'}{ $args{'Class'} .'-'. $args{'Type'} }
-        if $self->{'_sql_role_group_aliases'}{ $args{'Class'} .'-'. $args{'Type'} }
-           && !$args{'New'};
-
-    # we always have watcher groups for ticket, so we use INNER join
-    my $groups = $self->Join(
-        ALIAS1          => 'main',
-        FIELD1          => $args{'Class'} eq 'Queue'? 'Queue': 'id',
-        TABLE2          => 'Groups',
-        FIELD2          => 'Instance',
-        ENTRYAGGREGATOR => 'AND',
-    );
-    $self->SUPER::Limit(
-        LEFTJOIN        => $groups,
-        ALIAS           => $groups,
-        FIELD           => 'Domain',
-        VALUE           => 'RT::'. $args{'Class'} .'-Role',
-    );
-    $self->SUPER::Limit(
-        LEFTJOIN        => $groups,
-        ALIAS           => $groups,
-        FIELD           => 'Type',
-        VALUE           => $args{'Type'},
-    ) if $args{'Type'};
-
-    $self->{'_sql_role_group_aliases'}{ $args{'Class'} .'-'. $args{'Type'} } = $groups
-        unless $args{'New'};
-
-    return $groups;
+    my %args = (Class => 'RT::Ticket', @_);
+    if ( $args{'Class'} eq 'Queue' ) {
+        $args{'Class'} = 'RT::Queue';
+        $args{'Field'} = 'Queue';
+    }
+    return $self->JoinRoleGroups( %args );
 }
 
 sub _GroupMembersJoin {

commit 08fc8dc5df8bbc8ec4def3422bbaf042842374ab
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Fri Dec 10 09:09:54 2010 +0300

    use Queue IN (1,2,3,...) instead long OR sequences

diff --git a/lib/RT/Tickets_Overlay.pm b/lib/RT/Tickets_Overlay.pm
index c154832..cd0dde6 100755
--- a/lib/RT/Tickets_Overlay.pm
+++ b/lib/RT/Tickets_Overlay.pm
@@ -3040,29 +3040,16 @@ sub CurrentUserCanSee {
             my $ea = shift;
             my @queues = @_;
 
-            return unless @queues;
-            if ( @queues == 1 ) {
-                $self->SUPER::Limit(
-                    SUBCLAUSE => 'ACL',
-                    ALIAS => 'main',
-                    FIELD => 'Queue',
-                    VALUE => $_[0],
-                    ENTRYAGGREGATOR => $ea,
-                );
-            } else {
-                $self->SUPER::_OpenParen('ACL');
-                foreach my $q ( @queues ) {
-                    $self->SUPER::Limit(
-                        SUBCLAUSE => 'ACL',
-                        ALIAS => 'main',
-                        FIELD => 'Queue',
-                        VALUE => $q,
-                        ENTRYAGGREGATOR => $ea,
-                    );
-                    $ea = 'OR';
-                }
-                $self->SUPER::_CloseParen('ACL');
-            }
+            return 0 unless @queues;
+            $self->SUPER::Limit(
+                SUBCLAUSE => 'ACL',
+                ALIAS => 'main',
+                FIELD => 'Queue',
+                OPERATOR => 'IN',
+                VALUE => '('. join(', ', @queues) .')',
+                QUOTEVALUE => 0,
+                ENTRYAGGREGATOR => $ea,
+            );
             return 1;
         };
 

commit a3bc83c5400ecff47d26dfca5e5d33b493a77cc1
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Fri Dec 10 09:11:04 2010 +0300

    switch over generic methods we have in RT::ACL

diff --git a/lib/RT/Tickets_Overlay.pm b/lib/RT/Tickets_Overlay.pm
index cd0dde6..6c2ed86 100755
--- a/lib/RT/Tickets_Overlay.pm
+++ b/lib/RT/Tickets_Overlay.pm
@@ -2862,92 +2862,6 @@ sub _DoCount {
     return $self->SUPER::_DoCount( @_ );
 }
 
-sub _RolesCanSee {
-    my $self = shift;
-
-    my $cache_key = 'RolesHasRight;:;ShowTicket';
- 
-    if ( my $cached = $RT::Principal::_ACL_CACHE->fetch( $cache_key ) ) {
-        return %$cached;
-    }
-
-    my $ACL = RT::ACL->new( RT->SystemUser );
-    $ACL->Limit( FIELD => 'RightName', VALUE => 'ShowTicket' );
-    $ACL->Limit( FIELD => 'PrincipalType', OPERATOR => '!=', VALUE => 'Group' );
-    my $principal_alias = $ACL->Join(
-        ALIAS1 => 'main',
-        FIELD1 => 'PrincipalId',
-        TABLE2 => 'Principals',
-        FIELD2 => 'id',
-    );
-    $ACL->Limit( ALIAS => $principal_alias, FIELD => 'Disabled', VALUE => 0 );
-
-    my %res = ();
-    foreach my $ACE ( @{ $ACL->ItemsArrayRef } ) {
-        my $role = $ACE->__Value('PrincipalType');
-        my $type = $ACE->__Value('ObjectType');
-        if ( $type eq 'RT::System' ) {
-            $res{ $role } = 1;
-        }
-        elsif ( $type eq 'RT::Queue' ) {
-            next if $res{ $role } && !ref $res{ $role };
-            push @{ $res{ $role } ||= [] }, $ACE->__Value('ObjectId');
-        }
-        else {
-            $RT::Logger->error('ShowTicket right is granted on unsupported object');
-        }
-    }
-    $RT::Principal::_ACL_CACHE->set( $cache_key => \%res );
-    return %res;
-}
-
-sub _DirectlyCanSeeIn {
-    my $self = shift;
-    my $id = $self->CurrentUser->id;
-
-    my $cache_key = 'User-'. $id .';:;ShowTicket;:;DirectlyCanSeeIn';
-    if ( my $cached = $RT::Principal::_ACL_CACHE->fetch( $cache_key ) ) {
-        return @$cached;
-    }
-
-    my $ACL = RT::ACL->new( RT->SystemUser );
-    $ACL->Limit( FIELD => 'RightName', VALUE => 'ShowTicket' );
-    my $principal_alias = $ACL->Join(
-        ALIAS1 => 'main',
-        FIELD1 => 'PrincipalId',
-        TABLE2 => 'Principals',
-        FIELD2 => 'id',
-    );
-    $ACL->Limit( ALIAS => $principal_alias, FIELD => 'Disabled', VALUE => 0 );
-    my $cgm_alias = $ACL->Join(
-        ALIAS1 => 'main',
-        FIELD1 => 'PrincipalId',
-        TABLE2 => 'CachedGroupMembers',
-        FIELD2 => 'GroupId',
-    );
-    $ACL->Limit( ALIAS => $cgm_alias, FIELD => 'MemberId', VALUE => $id );
-    $ACL->Limit( ALIAS => $cgm_alias, FIELD => 'Disabled', VALUE => 0 );
-
-    my @res = ();
-    foreach my $ACE ( @{ $ACL->ItemsArrayRef } ) {
-        my $type = $ACE->__Value('ObjectType');
-        if ( $type eq 'RT::System' ) {
-            # If user is direct member of a group that has the right
-            # on the system then he can see any ticket
-            $RT::Principal::_ACL_CACHE->set( $cache_key => [-1] );
-            return (-1);
-        }
-        elsif ( $type eq 'RT::Queue' ) {
-            push @res, $ACE->__Value('ObjectId');
-        }
-        else {
-            $RT::Logger->error('ShowTicket right is granted on unsupported object');
-        }
-    }
-    $RT::Principal::_ACL_CACHE->set( $cache_key => \@res );
-    return @res;
-}
-
 sub CurrentUserCanSee {
     my $self = shift;
     return if $self->{'_sql_current_user_can_see_applied'};
@@ -2960,21 +2874,30 @@ sub CurrentUserCanSee {
     my $id = $self->CurrentUser->id;
 
     # directly can see in all queues then we have nothing to do
-    my @direct_queues = $self->_DirectlyCanSeeIn;
+    my %direct = RT::ACL->_ObjectsDirectlyHasRightOn(
+        User => $id,
+        Right => 'ShowTicket',
+    );
     return $self->{'_sql_current_user_can_see_applied'} = 1
-        if @direct_queues && $direct_queues[0] == -1;
+        if $direct{'RT::System'};
+
+    # from this point we only interested in queues
+    %direct = ('RT::Queue' => $direct{'RT::Queue'} || []);
+
+    my %roles = RT::ACL->_RolesWithRight( Right => 'ShowTicket' );
 
-    my %roles = $self->_RolesCanSee;
     {
-        my %skip = map { $_ => 1 } @direct_queues;
+        my %skip = map { $_ => 1 } @{ $direct{'RT::Queue'} };
         foreach my $role ( keys %roles ) {
-            next unless ref $roles{ $role };
-
-            my @queues = grep !$skip{$_}, @{ $roles{ $role } };
-            if ( @queues ) {
-                $roles{ $role } = \@queues;
+            if ( $roles{ $role }{'RT::System'} ) {
+                $roles{ $role } = 1;
             } else {
-                delete $roles{ $role };
+                my @queues = grep !$skip{$_}, @{ $roles{ $role }{'RT::Queue'} || [] };
+                if ( @queues ) {
+                    $roles{ $role } = \@queues;
+                } else {
+                    delete $roles{ $role };
+                }
             }
         }
     }
@@ -3007,11 +2930,11 @@ sub CurrentUserCanSee {
         $groups->Limit( ALIAS => $cgm_alias, FIELD => 'MemberId', VALUE => $id );
         $groups->Limit( ALIAS => $cgm_alias, FIELD => 'Disabled', VALUE => 0 );
         while ( my $group = $groups->Next ) {
-            push @direct_queues, $group->Instance;
+            push @{ $direct{'RT::Queue'} }, $group->Instance;
         }
     }
 
-    unless ( @direct_queues || keys %roles ) {
+    unless ( @{ $direct{'RT::Queue'} } || keys %roles ) {
         $self->SUPER::Limit(
             SUBCLAUSE => 'ACL',
             ALIAS => 'main',
@@ -3055,7 +2978,7 @@ sub CurrentUserCanSee {
 
         $self->SUPER::_OpenParen('ACL');
         my $ea = 'AND';
-        $ea = 'OR' if $limit_queues->( $ea, @direct_queues );
+        $ea = 'OR' if $limit_queues->( $ea, @{ $direct{'RT::Queue'} } );
         while ( my ($role, $queues) = each %roles ) {
             $self->SUPER::_OpenParen('ACL');
             if ( $role eq 'Owner' ) {

commit f90a8d35f2b6c6d270405f1e2c7a3218f9c11879
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Sat Dec 11 06:03:14 2010 +0300

    SUBLCAUSE doesn't work with LEFTJOIN in Limit

diff --git a/lib/RT/Tickets_Overlay_SQL.pm b/lib/RT/Tickets_Overlay_SQL.pm
index a61e1a2..3634aa4 100755
--- a/lib/RT/Tickets_Overlay_SQL.pm
+++ b/lib/RT/Tickets_Overlay_SQL.pm
@@ -86,7 +86,7 @@ sub _SQLLimit {
          (!$args{'ALIAS'} || $args{'ALIAS'} eq 'main' ) ) {
         $self->{'looking_at_type'} = 1;
     }
-    $args{'SUBCLAUSE'} ||= 'ticketsql';
+    $args{'SUBCLAUSE'} ||= 'ticketsql' unless $args{'LEFTJOIN'};
 
   # All SQL stuff goes into one SB subclause so we can deal with all
   # the aggregation

commit 8f381bf73efd0e9b9258930c9bf1046d9e936f1e
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Sat Dec 11 06:04:29 2010 +0300

    JoinGroupMembers in RT::SearchBuilder

diff --git a/lib/RT/SearchBuilder.pm b/lib/RT/SearchBuilder.pm
index 3b3a821..7cd1789 100755
--- a/lib/RT/SearchBuilder.pm
+++ b/lib/RT/SearchBuilder.pm
@@ -350,6 +350,29 @@ sub JoinRoleGroups {
     return $groups;
 }
 
+sub JoinGroupMembers {
+    my $self = shift;
+    my %args = (New => 1, GroupsAlias => undef, Left => 1, @_);
+
+    return $self->{'_sql_aliases'}{'group_members'}{ $args{'GroupsAlias'} }
+        if $self->{'_sql_aliases'}{'group_members'}{ $args{'GroupsAlias'} }
+            && !$args{'New'};
+
+    my $alias = $self->Join(
+        $args{'Left'} ? (TYPE            => 'LEFT') : (),
+        ALIAS1          => $args{'GroupsAlias'},
+        FIELD1          => 'id',
+        TABLE2          => 'CachedGroupMembers',
+        FIELD2          => 'GroupId',
+        ENTRYAGGREGATOR => 'AND',
+    );
+
+    $self->{'_sql_aliases'}{'group_members'}{ $args{'GroupsAlias'} } = $alias
+        unless $args{'New'};
+
+    return $alias;
+}
+
 RT::Base->_ImportOverlays();
 
 1;
diff --git a/lib/RT/Tickets_Overlay.pm b/lib/RT/Tickets_Overlay.pm
index 6c2ed86..08428a7 100755
--- a/lib/RT/Tickets_Overlay.pm
+++ b/lib/RT/Tickets_Overlay.pm
@@ -243,7 +243,6 @@ sub CleanSlate {
     $self->SUPER::CleanSlate( @_ );
     delete $self->{$_} foreach qw(
         _sql_cf_alias
-        _sql_group_members_aliases
         _sql_object_cfv_alias
         _sql_trattachalias
         _sql_u_watchers_alias_for_sort
@@ -1021,26 +1020,7 @@ sub _RoleGroupsJoin {
 }
 
 sub _GroupMembersJoin {
-    my $self = shift;
-    my %args = (New => 1, GroupsAlias => undef, Left => 1, @_);
-
-    return $self->{'_sql_group_members_aliases'}{ $args{'GroupsAlias'} }
-        if $self->{'_sql_group_members_aliases'}{ $args{'GroupsAlias'} }
-            && !$args{'New'};
-
-    my $alias = $self->Join(
-        $args{'Left'} ? (TYPE            => 'LEFT') : (),
-        ALIAS1          => $args{'GroupsAlias'},
-        FIELD1          => 'id',
-        TABLE2          => 'CachedGroupMembers',
-        FIELD2          => 'GroupId',
-        ENTRYAGGREGATOR => 'AND',
-    );
-
-    $self->{'_sql_group_members_aliases'}{ $args{'GroupsAlias'} } = $alias
-        unless $args{'New'};
-
-    return $alias;
+    return (shift)->JoinGroupMembers( @_ );
 }
 
 =head2 _WatcherJoin

commit 362d2769facc1db27221703c9ea41d6a17676023
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Sat Dec 11 06:05:10 2010 +0300

    restore backwards compatibility in RT::Tickets::_RoleGroupsJoin

diff --git a/lib/RT/Tickets_Overlay.pm b/lib/RT/Tickets_Overlay.pm
index 08428a7..fdba2fa 100755
--- a/lib/RT/Tickets_Overlay.pm
+++ b/lib/RT/Tickets_Overlay.pm
@@ -1016,6 +1016,10 @@ sub _RoleGroupsJoin {
         $args{'Class'} = 'RT::Queue';
         $args{'Field'} = 'Queue';
     }
+    elsif ( $args{'Class'} eq 'Ticket' ) {
+        $args{'Class'} = 'RT::Ticket';
+        $args{'Field'} = 'id';
+    }
     return $self->JoinRoleGroups( %args );
 }
 

commit 367453004f46002b9f06dfe062bc7250c9472dbc
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Sat Dec 11 06:12:24 2010 +0300

    UseSQLForACLChecks for RT::Queues

diff --git a/lib/RT/Queues_Overlay.pm b/lib/RT/Queues_Overlay.pm
index 856b1b3..b39b3fa 100755
--- a/lib/RT/Queues_Overlay.pm
+++ b/lib/RT/Queues_Overlay.pm
@@ -101,11 +101,133 @@ This is used for filtering objects for both Next and ItemsArrayRef.
 sub AddRecord {
     my $self = shift;
     my $Queue = shift;
-    return unless $Queue->CurrentUserHasRight('SeeQueue');
+    return if !$self->{'_sql_current_user_can_see_applied'}
+        && !$Queue->CurrentUserHasRight('SeeQueue');
 
     push @{$self->{'items'}}, $Queue;
     $self->{'rows'}++;
 }
 
-1;
+sub _DoSearch {
+    my $self = shift;
+    $self->CurrentUserCanSee if RT->Config->Get('UseSQLForACLChecks');
+    return $self->SUPER::_DoSearch( @_ );
+}
+
+sub _DoCount {
+    my $self = shift;
+    $self->CurrentUserCanSee if RT->Config->Get('UseSQLForACLChecks');
+    return $self->SUPER::_DoCount( @_ );
+}
 
+
+sub CurrentUserCanSee {
+    my $self = shift;
+    return if $self->{'_sql_current_user_can_see_applied'};
+
+    return $self->{'_sql_current_user_can_see_applied'} = 1
+        if $self->CurrentUser->UserObj->HasRight(
+            Right => 'SuperUser', Object => $RT::System
+        );
+
+    my $id = $self->CurrentUser->id;
+
+    # directly can see in all queues then we have nothing to do
+    my %direct = RT::ACL->_ObjectsDirectlyHasRightOn(
+        User => $id,
+        Right => 'SeeQueue',
+    );
+    return $self->{'_sql_current_user_can_see_applied'} = 1
+        if $direct{'RT::System'};
+
+    # from this point we only interested in queues
+    %direct = ('RT::Queue' => $direct{'RT::Queue'} || []);
+
+    my %roles = RT::ACL->_RolesWithRight( Right => 'SeeQueue' );
+    {
+        my %skip = map { $_ => 1 } @{ $direct{'RT::Queue'} };
+        foreach my $role ( keys %roles ) {
+            if ( $roles{ $role }{'RT::System'} ) {
+                $roles{ $role } = 1;
+            } else {
+                my @queues = grep !$skip{$_}, @{ $roles{ $role }{'RT::Queue'} || [] };
+                if ( @queues ) {
+                    $roles{ $role } = \@queues;
+                } else {
+                    delete $roles{ $role };
+                }
+            }
+        }
+    }
+
+    unless ( @{$direct{'RT::Queue'}} || keys %roles ) {
+        $self->SUPER::Limit(
+            SUBCLAUSE => 'ACL',
+            ALIAS => 'main',
+            FIELD => 'id',
+            VALUE => 0,
+            ENTRYAGGREGATOR => 'AND',
+        );
+        return $self->{'_sql_current_user_can_see_applied'} = 1;
+    }
+
+    {
+        my ($role_group_alias, $cgm_alias);
+        if ( keys %roles ) {
+            $role_group_alias = $self->JoinRoleGroups( New => 1 );
+            $cgm_alias = $self->JoinGroupMembers( GroupsAlias => $role_group_alias );
+            $self->Limit(
+                LEFTJOIN   => $cgm_alias,
+                FIELD      => 'MemberId',
+                OPERATOR   => '=',
+                VALUE      => $id,
+            );
+        }
+        my $limit_queues = sub {
+            my $ea = shift;
+            my @queues = @_;
+
+            return 0 unless @queues;
+            $self->Limit(
+                SUBCLAUSE => 'ACL',
+                ALIAS => 'main',
+                FIELD => 'id',
+                OPERATOR => 'IN',
+                VALUE => '('. join(', ', @queues) .')',
+                QUOTEVALUE => 0,
+                ENTRYAGGREGATOR => $ea,
+            );
+            return 1;
+        };
+
+        $self->SUPER::_OpenParen('ACL');
+        my $ea = 'AND';
+        $ea = 'OR' if $limit_queues->( $ea, @{ $direct{'RT::Queue'} } );
+        while ( my ($role, $queues) = each %roles ) {
+            $self->SUPER::_OpenParen('ACL');
+            $self->Limit(
+                SUBCLAUSE       => 'ACL',
+                ALIAS           => $cgm_alias,
+                FIELD           => 'MemberId',
+                OPERATOR        => 'IS NOT',
+                VALUE           => 'NULL',
+                QUOTEVALUE      => 0,
+                ENTRYAGGREGATOR => $ea,
+            );
+            $self->Limit(
+                SUBCLAUSE       => 'ACL',
+                ALIAS           => $role_group_alias,
+                FIELD           => 'Type',
+                VALUE           => $role,
+                ENTRYAGGREGATOR => 'AND',
+            );
+            $limit_queues->( 'AND', @$queues ) if ref $queues;
+            $ea = 'OR' if $ea eq 'AND';
+            $self->SUPER::_CloseParen('ACL');
+        }
+        $self->SUPER::_CloseParen('ACL');
+    }
+    return $self->{'_sql_current_user_can_see_applied'} = 1;
+}
+
+1;

-----------------------------------------------------------------------


More information about the Rt-commit mailing list