#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2005 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC
# <jesse@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
#
# 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:
# those contributions and any derivatives thereof.
#
# END BPS TAGGED BLOCK }}}
-
=head1 NAME
RT::Users - Collection of RT::User objects
$self->{'princalias'} = $self->NewAlias('Principals');
+ # XXX: should be generalized
$self->Join( ALIAS1 => 'main',
FIELD1 => 'id',
ALIAS2 => $self->{'princalias'},
FIELD2 => 'id' );
+ $self->Limit( ALIAS => $self->{'princalias'},
+ FIELD => 'PrincipalType',
+ VALUE => 'User',
+ );
return (@result);
}
Returns the string that represents this Users object's primary "Principals" alias.
-
=cut
+# XXX: should be generalized
sub PrincipalsAlias {
my $self = shift;
return($self->{'princalias'});
=cut
+# XXX: should be generalized
sub LimitToEnabled {
my $self = shift;
- $self->Limit( ALIAS => $self->{'princalias'},
+ $self->Limit( ALIAS => $self->PrincipalsAlias,
FIELD => 'Disabled',
VALUE => '0',
OPERATOR => '=' );
my $groupalias = $self->NewAlias('CachedGroupMembers');
# Join the principal to the groups table
- $self->Join( ALIAS1 => $self->{'princalias'},
+ $self->Join( ALIAS1 => $self->PrincipalsAlias,
FIELD1 => 'id',
ALIAS2 => $groupalias,
FIELD2 => 'MemberId' );
=end testing
-
find all users who the right Right for this group, either individually
or as members of groups
-
If passed a queue object, with no id, it will find users who have that right for _any_ queue
-
-
=cut
-sub WhoHaveRight {
+# XXX: should be generalized
+sub _JoinGroupMembers
+{
my $self = shift;
my %args = (
- Right => undef,
- Object => undef,
- IncludeSystemRights => undef,
- IncludeSuperusers => undef,
IncludeSubgroupMembers => 1,
- EquivObjects => [ ],
@_
);
- if ( defined $args{'ObjectType'} || defined $args{'ObjectId'} ) {
- $RT::Logger->crit( "$self WhoHaveRight called with the Obsolete ObjectId/ObjectType API");
- return (undef);
- }
-
-
- # Find only members of groups that have the right.
-
- my $acl = $self->NewAlias('ACL');
- my $groups = $self->NewAlias('Groups');
- my $userprinc = $self->{'princalias'};
-
-# The cachedgroupmembers table is used for unrolling group memberships to allow fast lookups
-# if we bind to CachedGroupMembers, we'll find all members of groups recursively.
-# if we don't we'll find only 'direct' members of the group in question
- my $cgm;
+ my $principals = $self->PrincipalsAlias;
+ # The cachedgroupmembers table is used for unrolling group memberships
+ # to allow fast lookups. if we bind to CachedGroupMembers, we'll find
+ # all members of groups recursively. if we don't we'll find only 'direct'
+ # members of the group in question
+ my $group_members;
if ( $args{'IncludeSubgroupMembers'} ) {
- $cgm = $self->NewAlias('CachedGroupMembers');
+ $group_members = $self->NewAlias('CachedGroupMembers');
}
else {
- $cgm = $self->NewAlias('GroupMembers');
+ $group_members = $self->NewAlias('GroupMembers');
}
-#Tie the users we're returning ($userprinc) to the groups that have rights granted to them ($groupprinc)
$self->Join(
- ALIAS1 => $cgm,
+ ALIAS1 => $group_members,
FIELD1 => 'MemberId',
- ALIAS2 => $userprinc,
+ ALIAS2 => $principals,
FIELD2 => 'id'
);
+ return $group_members;
+}
+
+# XXX: should be generalized
+sub _JoinGroups
+{
+ my $self = shift;
+ my %args = (@_);
+
+ my $group_members = $self->_JoinGroupMembers( %args );
+ my $groups = $self->NewAlias('Groups');
$self->Join(
ALIAS1 => $groups,
FIELD1 => 'id',
- ALIAS2 => $cgm,
+ ALIAS2 => $group_members,
FIELD2 => 'GroupId'
);
-# {{{ Find only rows where the right granted is the one we're looking up or _possibly_ superuser
+ return $groups;
+}
+
+# XXX: should be generalized
+sub _JoinACL
+{
+ my $self = shift;
+ my %args = (
+ Right => undef,
+ IncludeSuperusers => undef,
+ @_,
+ );
+
+ my $acl = $self->NewAlias('ACL');
$self->Limit(
ALIAS => $acl,
FIELD => 'RightName',
VALUE => $args{Right} || 'NULL',
ENTRYAGGREGATOR => 'OR'
);
-
if ( $args{'IncludeSuperusers'} and $args{'Right'} ) {
$self->Limit(
ALIAS => $acl,
ENTRYAGGREGATOR => 'OR'
);
}
+ return $acl;
+}
+
+# XXX: should be generalized
+sub _GetEquivObjects
+{
+ my $self = shift;
+ my %args = (
+ Object => undef,
+ IncludeSystemRights => undef,
+ EquivObjects => [ ],
+ @_
+ );
+ return () unless $args{'Object'};
+
+ my @objects = ($args{'Object'});
+ if ( UNIVERSAL::isa( $args{'Object'}, 'RT::Ticket' ) ) {
+ # If we're looking at ticket rights, we also want to look at the associated queue rights.
+ # this is a little bit hacky, but basically, now that we've done the ticket roles magic,
+ # we load the queue object and ask all the rest of our questions about the queue.
+
+ # XXX: This should be abstracted into object itself
+ if( $args{'Object'}->id ) {
+ push @objects, $args{'Object'}->QueueObj;
+ } else {
+ push @objects, 'RT::Queue';
+ }
+ }
+
+ if( $args{'IncludeSystemRights'} ) {
+ push @objects, 'RT::System';
+ }
+ push @objects, @{ $args{'EquivObjects'} };
+ return grep $_, @objects;
+}
+
+# XXX: should be generalized
+sub WhoHaveRight {
+ my $self = shift;
+ my %args = (
+ Right => undef,
+ Object => undef,
+ IncludeSystemRights => undef,
+ IncludeSuperusers => undef,
+ IncludeSubgroupMembers => 1,
+ EquivObjects => [ ],
+ @_
+ );
+
+ if ( defined $args{'ObjectType'} || defined $args{'ObjectId'} ) {
+ $RT::Logger->crit( "WhoHaveRight called with the Obsolete ObjectId/ObjectType API");
+ return (undef);
+ }
- # }}}
+ my @from_role = $self->Clone->_WhoHaveRoleRightSplitted( %args );
- my ( $or_check_ticket_roles, $or_check_roles );
- my $which_object = "$acl.ObjectType = 'RT::System'";
+ my $from_group = $self->Clone;
+ $from_group->WhoHaveGroupRight( %args );
- if ( defined $args{'Object'} ) {
- if ( ref( $args{'Object'} ) eq 'RT::Ticket' ) {
- $or_check_ticket_roles = " OR ( $groups.Domain = 'RT::Ticket-Role' AND $groups.Instance = " . $args{'Object'}->Id . ") ";
+ #XXX: DIRTY HACK
+ use DBIx::SearchBuilder 1.50; #no version on ::Union :(
+ use DBIx::SearchBuilder::Union;
+ my $union = new DBIx::SearchBuilder::Union;
+ $union->add( $_ ) foreach @from_role;
+ $union->add( $from_group );
+ %$self = %$union;
+ bless $self, ref($union);
-# If we're looking at ticket rights, we also want to look at the associated queue rights.
-# this is a little bit hacky, but basically, now that we've done the ticket roles magic,
-# we load the queue object and ask all the rest of our questions about the queue.
- $args{'Object'} = $args{'Object'}->QueueObj;
- }
+ return;
+}
+# }}}
- # TODO XXX This really wants some refactoring
- if ( ref( $args{'Object'} ) eq 'RT::Queue' ) {
- $or_check_roles = " OR ( ( ($groups.Domain = 'RT::Queue-Role' ";
- $or_check_roles .= "AND $groups.Instance = " . $args{'Object'}->id if ( $args{'Object'}->id );
- $or_check_roles .= ") $or_check_ticket_roles ) " . " AND $groups.Type = $acl.PrincipalType) ";
- }
- if ( $args{'IncludeSystemRights'} ) {
- $which_object .= ' OR ';
- }
- else {
- $which_object = '';
- }
- foreach my $obj ( @{ $args{'EquivObjects'} } ) {
- $which_object .= "($acl.ObjectType = '" . ref( $obj ) . "' AND $acl.ObjectId = " . $obj->id . ") OR ";
+# XXX: should be generalized
+sub WhoHaveRoleRight
+{
+ my $self = shift;
+ my %args = (
+ Right => undef,
+ Object => undef,
+ IncludeSystemRights => undef,
+ IncludeSuperusers => undef,
+ IncludeSubgroupMembers => 1,
+ EquivObjects => [ ],
+ @_
+ );
+
+ my $groups = $self->_JoinGroups( %args );
+ my $acl = $self->_JoinACL( %args );
+
+ $self->Limit( ALIAS => $acl,
+ FIELD => 'PrincipalType',
+ VALUE => "$groups.Type",
+ QUOTEVALUE => 0,
+ );
+
+ # no system user
+ $self->Limit( ALIAS => $self->PrincipalsAlias,
+ FIELD => 'id',
+ OPERATOR => '!=',
+ VALUE => $RT::SystemUser->id
+ );
+
+ my @objects = $self->_GetEquivObjects( %args );
+ unless ( @objects ) {
+ unless ( $args{'IncludeSystemRights'} ) {
+ $self->_AddSubClause( WhichObjects => "($acl.ObjectType != 'RT::System')" );
}
- $which_object .= " ($acl.ObjectType = '" . ref( $args{'Object'} ) . "'";
- if ( $args{'Object'}->id ) {
- $which_object .= " AND $acl.ObjectId = " . $args{'Object'}->id;
+ return;
+ }
+
+ my ($groups_clauses, $acl_clauses) = $self->_RoleClauses( $groups, $acl, @objects );
+ $self->_AddSubClause( "WhichObject", "(". join( ' OR ', @$groups_clauses ) .")" );
+ $self->_AddSubClause( "WhichRole", "(". join( ' OR ', @$acl_clauses ) .")" );
+
+ return;
+}
+
+sub _WhoHaveRoleRightSplitted {
+ my $self = shift;
+ my %args = (
+ Right => undef,
+ Object => undef,
+ IncludeSystemRights => undef,
+ IncludeSuperusers => undef,
+ IncludeSubgroupMembers => 1,
+ EquivObjects => [ ],
+ @_
+ );
+
+ my $groups = $self->_JoinGroups( %args );
+ my $acl = $self->_JoinACL( %args );
+
+ $self->Limit( ALIAS => $acl,
+ FIELD => 'PrincipalType',
+ VALUE => "$groups.Type",
+ QUOTEVALUE => 0,
+ );
+
+ # no system user
+ $self->Limit( ALIAS => $self->PrincipalsAlias,
+ FIELD => 'id',
+ OPERATOR => '!=',
+ VALUE => $RT::SystemUser->id
+ );
+
+ my @objects = $self->_GetEquivObjects( %args );
+ unless ( @objects ) {
+ unless ( $args{'IncludeSystemRights'} ) {
+ $self->_AddSubClause( WhichObjects => "($acl.ObjectType != 'RT::System')" );
}
+ return $self;
+ }
- $which_object .= ") ";
+ my ($groups_clauses, $acl_clauses) = $self->_RoleClauses( $groups, $acl, @objects );
+ $self->_AddSubClause( "WhichRole", "(". join( ' OR ', @$acl_clauses ) .")" );
+
+ my @res;
+ foreach ( @$groups_clauses ) {
+ my $tmp = $self->Clone;
+ $tmp->_AddSubClause( WhichObject => $_ );
+ push @res, $tmp;
}
- $self->_AddSubClause( "WhichObject", "($which_object)" );
- $self->_AddSubClause(
- "WhichGroup",
- qq{ ( ( $acl.PrincipalId = $groups.id AND $acl.PrincipalType = 'Group'
- AND ( $groups.Domain = 'SystemInternal' OR $groups.Domain = 'UserDefined' OR $groups.Domain = 'ACLEquivalence'))
- $or_check_roles) }
+
+ return @res;
+}
+
+sub _RoleClauses {
+ my $self = shift;
+ my $groups = shift;
+ my $acl = shift;
+ my @objects = @_;
+
+ my @groups_clauses;
+ my @acl_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)";
+
+ my $object_clause = "$acl.ObjectType = '$type'";
+ $object_clause .= " AND $acl.ObjectId = $id" if $id;
+ push @acl_clauses, "($object_clause)";
+ }
+ return (\@groups_clauses, \@acl_clauses);
+}
+
+# XXX: should be generalized
+sub _JoinGroupMembersForGroupRights
+{
+ my $self = shift;
+ my %args = (@_);
+ my $group_members = $self->_JoinGroupMembers( %args );
+ $self->Limit( ALIAS => $args{'ACLAlias'},
+ FIELD => 'PrincipalId',
+ VALUE => "$group_members.GroupId",
+ QUOTEVALUE => 0,
+ );
+}
+
+# XXX: should be generalized
+sub WhoHaveGroupRight
+{
+ my $self = shift;
+ my %args = (
+ Right => undef,
+ Object => undef,
+ IncludeSystemRights => undef,
+ IncludeSuperusers => undef,
+ IncludeSubgroupMembers => 1,
+ EquivObjects => [ ],
+ @_
);
- # only include regular RT users
- $self->LimitToEnabled;
- # no system user
- $self->Limit( ALIAS => $userprinc, FIELD => 'id', OPERATOR => '!=', VALUE => $RT::SystemUser->id);
+ # Find only rows where the right granted is
+ # the one we're looking up or _possibly_ superuser
+ my $acl = $self->_JoinACL( %args );
+
+ my ($check_objects) = ('');
+ my @objects = $self->_GetEquivObjects( %args );
+
+ if ( @objects ) {
+ 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 $object_clause = "$acl.ObjectType = '$type'";
+ $object_clause .= " AND $acl.ObjectId = $id" if $id;
+ push @object_clauses, "($object_clause)";
+ }
+
+ $check_objects = join ' OR ', @object_clauses;
+ } else {
+ if( !$args{'IncludeSystemRights'} ) {
+ $check_objects = "($acl.ObjectType != 'RT::System')";
+ }
+ }
+ $self->_AddSubClause( "WhichObject", "($check_objects)" );
+
+ $self->_JoinGroupMembersForGroupRights( %args, ACLAlias => $acl );
+ # Find only members of groups that have the right.
+ $self->Limit( ALIAS => $acl,
+ FIELD => 'PrincipalType',
+ VALUE => 'Group',
+ );
+
+ # no system user
+ $self->Limit( ALIAS => $self->PrincipalsAlias,
+ FIELD => 'id',
+ OPERATOR => '!=',
+ VALUE => $RT::SystemUser->id
+ );
+ return;
}
-# }}}
-# {{{ WhoBelongToGroups
+# {{{ WhoBelongToGroups
=head2 WhoBelongToGroups { Groups => ARRAYREF, IncludeSubgroupMembers => 1 }
=cut
+# XXX: should be generalized
sub WhoBelongToGroups {
my $self = shift;
my %args = ( Groups => undef,
IncludeSubgroupMembers => 1,
@_ );
- # Unprivileged users can't be granted real system rights.
+ # Unprivileged users can't be granted real system rights.
# is this really the right thing to be saying?
$self->LimitToPrivileged();
- my $userprinc = $self->{'princalias'};
- my $cgm;
-
- # The cachedgroupmembers table is used for unrolling group memberships to allow fast lookups
- # if we bind to CachedGroupMembers, we'll find all members of groups recursively.
- # if we don't we'll find only 'direct' members of the group in question
-
- if ( $args{'IncludeSubgroupMembers'} ) {
- $cgm = $self->NewAlias('CachedGroupMembers');
- }
- else {
- $cgm = $self->NewAlias('GroupMembers');
- }
-
- #Tie the users we're returning ($userprinc) to the groups that have rights granted to them ($groupprinc)
- $self->Join( ALIAS1 => $cgm, FIELD1 => 'MemberId',
- ALIAS2 => $userprinc, FIELD2 => 'id' );
+ my $group_members = $self->_JoinGroupMembers( %args );
foreach my $groupid (@{$args{'Groups'}}) {
- $self->Limit(ALIAS => $cgm, FIELD => 'GroupId', VALUE => $groupid, QUOTEVALUE => 0, ENTRYAGGREGATOR=> 'OR')
-
+ $self->Limit( ALIAS => $group_members,
+ FIELD => 'GroupId',
+ VALUE => $groupid,
+ QUOTEVALUE => 0,
+ ENTRYAGGREGATOR => 'OR',
+ );
}
}
# }}}