1 # BEGIN BPS TAGGED BLOCK {{{
5 # This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
6 # <sales@bestpractical.com>
8 # (Except where explicitly superseded by other copyright notices)
13 # This work is made available to you under the terms of Version 2 of
14 # the GNU General Public License. A copy of that license should have
15 # been provided with this software, but in any event can be snarfed
18 # This work is distributed in the hope that it will be useful, but
19 # WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 # General Public License for more details.
23 # You should have received a copy of the GNU General Public License
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 # 02110-1301 or visit their web page on the internet at
27 # http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
30 # CONTRIBUTION SUBMISSION POLICY:
32 # (The following paragraph is not intended to limit the rights granted
33 # to you to modify and distribute this software under the terms of
34 # the GNU General Public License and is only of importance to you if
35 # you choose to contribute your changes and enhancements to the
36 # community by submitting them to Best Practical Solutions, LLC.)
38 # By intentionally submitting any modifications, corrections or
39 # derivatives to this work, or any other work intended for use with
40 # Request Tracker, to Best Practical Solutions, LLC, you confirm that
41 # you are the copyright holder for those contributions and you grant
42 # Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
43 # royalty-free, perpetual, license to use, copy, create derivative
44 # works based on those contributions, and sublicense and distribute
45 # those contributions and any derivatives thereof.
47 # END BPS TAGGED BLOCK }}}
51 RT::Users - Collection of RT::User objects
74 use base 'RT::SearchBuilder';
81 $self->{'with_disabled_column'} = 1;
83 my @result = $self->SUPER::_Init(@_);
84 # By default, order by name
85 $self->OrderBy( ALIAS => 'main',
89 $self->{'princalias'} = $self->NewAlias('Principals');
91 # XXX: should be generalized
92 $self->Join( ALIAS1 => 'main',
94 ALIAS2 => $self->{'princalias'},
96 $self->Limit( ALIAS => $self->{'princalias'},
97 FIELD => 'PrincipalType',
105 =head2 PrincipalsAlias
107 Returns the string that represents this Users object's primary "Principals" alias.
111 # XXX: should be generalized
112 sub PrincipalsAlias {
114 return($self->{'princalias'});
119 =head2 LimitToEnabled
121 Only find items that haven\'t been disabled
125 # XXX: should be generalized
129 $self->{'handled_disabled_column'} = 1;
131 ALIAS => $self->PrincipalsAlias,
137 =head2 LimitToDeleted
139 Only find items that have been deleted.
146 $self->{'handled_disabled_column'} = $self->{'find_disabled_rows'} = 1;
148 ALIAS => $self->PrincipalsAlias,
158 Takes one argument. an email address. limits the returned set to
166 $self->Limit( FIELD => 'EmailAddress', VALUE => "$addr" );
171 =head2 MemberOfGroup PRINCIPAL_ID
173 takes one argument, a group's principal id. Limits the returned set
174 to members of a given group
182 return $self->loc("No group specified") if ( !defined $group );
184 my $groupalias = $self->NewAlias('CachedGroupMembers');
186 # Join the principal to the groups table
187 $self->Join( ALIAS1 => $self->PrincipalsAlias,
189 ALIAS2 => $groupalias,
190 FIELD2 => 'MemberId' );
191 $self->Limit( ALIAS => $groupalias,
195 $self->Limit( ALIAS => "$groupalias",
203 =head2 LimitToPrivileged
205 Limits to users who can be made members of ACLs and groups
209 sub LimitToPrivileged {
211 $self->MemberOfGroup( RT->PrivilegedUsers->id );
214 =head2 LimitToUnprivileged
216 Limits to unprivileged users only
220 sub LimitToUnprivileged {
222 $self->MemberOfGroup( RT->UnprivilegedUsers->id);
229 $args{'CASESENSITIVE'} = 0 unless exists $args{'CASESENSITIVE'};
230 return $self->SUPER::Limit( %args );
233 =head2 WhoHaveRight { Right => 'name', Object => $rt_object , IncludeSuperusers => undef, IncludeSubgroupMembers => undef, IncludeSystemRights => undef, EquivObjects => [ ] }
236 find all users who the right Right for this group, either individually
237 or as members of groups
239 If passed a queue object, with no id, it will find users who have that right for _any_ queue
243 # XXX: should be generalized
244 sub _JoinGroupMembers
248 IncludeSubgroupMembers => 1,
252 my $principals = $self->PrincipalsAlias;
254 # The cachedgroupmembers table is used for unrolling group memberships
255 # to allow fast lookups. if we bind to CachedGroupMembers, we'll find
256 # all members of groups recursively. if we don't we'll find only 'direct'
257 # members of the group in question
259 if ( $args{'IncludeSubgroupMembers'} ) {
260 $group_members = $self->NewAlias('CachedGroupMembers');
263 $group_members = $self->NewAlias('GroupMembers');
267 ALIAS1 => $group_members,
268 FIELD1 => 'MemberId',
269 ALIAS2 => $principals,
273 ALIAS => $group_members,
276 ) if $args{'IncludeSubgroupMembers'};
278 return $group_members;
281 # XXX: should be generalized
287 my $group_members = $self->_JoinGroupMembers( %args );
288 my $groups = $self->NewAlias('Groups');
292 ALIAS2 => $group_members,
299 # XXX: should be generalized
305 IncludeSuperusers => undef,
309 if ( $args{'Right'} ) {
310 my $canonic = RT::ACE->CanonicalizeRightName( $args{'Right'} );
311 unless ( $canonic ) {
312 $RT::Logger->error("Invalid right. Couldn't canonicalize right '$args{'Right'}'");
315 $args{'Right'} = $canonic;
319 my $acl = $self->NewAlias('ACL');
322 FIELD => 'RightName',
323 OPERATOR => ( $args{Right} ? '=' : 'IS NOT' ),
324 VALUE => $args{Right} || 'NULL',
325 ENTRYAGGREGATOR => 'OR'
327 if ( $args{'IncludeSuperusers'} and $args{'Right'} ) {
330 FIELD => 'RightName',
332 VALUE => 'SuperUser',
333 ENTRYAGGREGATOR => 'OR'
339 # XXX: should be generalized
345 IncludeSystemRights => undef,
349 return () unless $args{'Object'};
351 my @objects = ($args{'Object'});
352 if ( UNIVERSAL::isa( $args{'Object'}, 'RT::Ticket' ) ) {
353 # If we're looking at ticket rights, we also want to look at the associated queue rights.
354 # this is a little bit hacky, but basically, now that we've done the ticket roles magic,
355 # we load the queue object and ask all the rest of our questions about the queue.
357 # XXX: This should be abstracted into object itself
358 if( $args{'Object'}->id ) {
359 push @objects, $args{'Object'}->ACLEquivalenceObjects;
361 push @objects, 'RT::Queue';
365 if( $args{'IncludeSystemRights'} ) {
366 push @objects, 'RT::System';
368 push @objects, @{ $args{'EquivObjects'} };
369 return grep $_, @objects;
372 # XXX: should be generalized
378 IncludeSystemRights => undef,
379 IncludeSuperusers => undef,
380 IncludeSubgroupMembers => 1,
385 if ( defined $args{'ObjectType'} || defined $args{'ObjectId'} ) {
386 $RT::Logger->crit( "WhoHaveRight called with the Obsolete ObjectId/ObjectType API");
390 my $from_role = $self->Clone;
391 $from_role->WhoHaveRoleRight( %args );
393 my $from_group = $self->Clone;
394 $from_group->WhoHaveGroupRight( %args );
397 use DBIx::SearchBuilder 1.50; #no version on ::Union :(
398 use DBIx::SearchBuilder::Union;
399 my $union = DBIx::SearchBuilder::Union->new();
400 $union->add( $from_group );
401 $union->add( $from_role );
403 bless $self, ref($union);
408 # XXX: should be generalized
415 IncludeSystemRights => undef,
416 IncludeSuperusers => undef,
417 IncludeSubgroupMembers => 1,
422 my @objects = $self->_GetEquivObjects( %args );
424 # RT::Principal->RolesWithRight only expects EquivObjects, so we need to
425 # fill it. At the very least it needs $args{Object}, which
426 # _GetEquivObjects above does for us.
427 unshift @{$args{'EquivObjects'}}, @objects;
429 my @roles = RT::Principal->RolesWithRight( %args );
431 $self->_AddSubClause( "WhichRole", "(main.id = 0)" );
435 my $groups = $self->_JoinGroups( %args );
438 $self->Limit( ALIAS => $self->PrincipalsAlias,
441 VALUE => RT->SystemUser->id
444 $self->_AddSubClause( "WhichRole", "(". join( ' OR ', map "$groups.Type = '$_'", @roles ) .")" );
446 my @groups_clauses = $self->_RoleClauses( $groups, @objects );
447 $self->_AddSubClause( "WhichObject", "(". join( ' OR ', @groups_clauses ) .")" )
459 foreach my $obj ( @objects ) {
460 my $type = ref($obj)? ref($obj): $obj;
462 $id = $obj->id if ref($obj) && UNIVERSAL::can($obj, 'id') && $obj->id;
464 my $role_clause = "$groups.Domain = '$type-Role'";
465 # XXX: Groups.Instance is VARCHAR in DB, we should quote value
466 # if we want mysql 4.0 use indexes here. we MUST convert that
467 # field to integer and drop this quotes.
468 $role_clause .= " AND $groups.Instance = '$id'" if $id;
469 push @groups_clauses, "($role_clause)";
471 return @groups_clauses;
474 # XXX: should be generalized
475 sub _JoinGroupMembersForGroupRights
479 my $group_members = $self->_JoinGroupMembers( %args );
480 $self->Limit( ALIAS => $args{'ACLAlias'},
481 FIELD => 'PrincipalId',
482 VALUE => "$group_members.GroupId",
485 return $group_members;
488 # XXX: should be generalized
489 sub WhoHaveGroupRight
495 IncludeSystemRights => undef,
496 IncludeSuperusers => undef,
497 IncludeSubgroupMembers => 1,
502 # Find only rows where the right granted is
503 # the one we're looking up or _possibly_ superuser
504 my $acl = $self->_JoinACL( %args );
506 my ($check_objects) = ('');
507 my @objects = $self->_GetEquivObjects( %args );
511 foreach my $obj ( @objects ) {
512 my $type = ref($obj)? ref($obj): $obj;
514 $id = $obj->id if ref($obj) && UNIVERSAL::can($obj, 'id') && $obj->id;
516 my $object_clause = "$acl.ObjectType = '$type'";
517 $object_clause .= " AND $acl.ObjectId = $id" if $id;
518 push @object_clauses, "($object_clause)";
521 $check_objects = join ' OR ', @object_clauses;
523 if( !$args{'IncludeSystemRights'} ) {
524 $check_objects = "($acl.ObjectType != 'RT::System')";
527 $self->_AddSubClause( "WhichObject", "($check_objects)" );
529 my $group_members = $self->_JoinGroupMembersForGroupRights( %args, ACLAlias => $acl );
530 # Find only members of groups that have the right.
531 $self->Limit( ALIAS => $acl,
532 FIELD => 'PrincipalType',
537 $self->Limit( ALIAS => $self->PrincipalsAlias,
540 VALUE => RT->SystemUser->id
542 return $group_members;
546 =head2 WhoBelongToGroups { Groups => ARRAYREF, IncludeSubgroupMembers => 1 }
550 # XXX: should be generalized
551 sub WhoBelongToGroups {
553 my %args = ( Groups => undef,
554 IncludeSubgroupMembers => 1,
557 # Unprivileged users can't be granted real system rights.
558 # is this really the right thing to be saying?
559 $self->LimitToPrivileged();
561 my $group_members = $self->_JoinGroupMembers( %args );
563 foreach my $groupid (@{$args{'Groups'}}) {
564 $self->Limit( ALIAS => $group_members,
568 ENTRYAGGREGATOR => 'OR',
576 Returns an empty new RT::User item
582 return(RT::User->new($self->CurrentUser));
584 RT::Base->_ImportOverlays();