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' );
192 $self->Limit( ALIAS => "$groupalias",
200 =head2 LimitToPrivileged
202 Limits to users who can be made members of ACLs and groups
206 sub LimitToPrivileged {
208 $self->MemberOfGroup( RT->PrivilegedUsers->id );
211 =head2 LimitToUnprivileged
213 Limits to unprivileged users only
217 sub LimitToUnprivileged {
219 $self->MemberOfGroup( RT->UnprivilegedUsers->id);
226 $args{'CASESENSITIVE'} = 0 unless exists $args{'CASESENSITIVE'};
227 return $self->SUPER::Limit( %args );
230 =head2 WhoHaveRight { Right => 'name', Object => $rt_object , IncludeSuperusers => undef, IncludeSubgroupMembers => undef, IncludeSystemRights => undef, EquivObjects => [ ] }
233 find all users who the right Right for this group, either individually
234 or as members of groups
236 If passed a queue object, with no id, it will find users who have that right for _any_ queue
240 # XXX: should be generalized
241 sub _JoinGroupMembers
245 IncludeSubgroupMembers => 1,
249 my $principals = $self->PrincipalsAlias;
251 # The cachedgroupmembers table is used for unrolling group memberships
252 # to allow fast lookups. if we bind to CachedGroupMembers, we'll find
253 # all members of groups recursively. if we don't we'll find only 'direct'
254 # members of the group in question
256 if ( $args{'IncludeSubgroupMembers'} ) {
257 $group_members = $self->NewAlias('CachedGroupMembers');
260 $group_members = $self->NewAlias('GroupMembers');
264 ALIAS1 => $group_members,
265 FIELD1 => 'MemberId',
266 ALIAS2 => $principals,
270 return $group_members;
273 # XXX: should be generalized
279 my $group_members = $self->_JoinGroupMembers( %args );
280 my $groups = $self->NewAlias('Groups');
284 ALIAS2 => $group_members,
291 # XXX: should be generalized
297 IncludeSuperusers => undef,
301 if ( $args{'Right'} ) {
302 my $canonic = RT::ACE->CanonicalizeRightName( $args{'Right'} );
303 unless ( $canonic ) {
304 $RT::Logger->error("Invalid right. Couldn't canonicalize right '$args{'Right'}'");
307 $args{'Right'} = $canonic;
311 my $acl = $self->NewAlias('ACL');
314 FIELD => 'RightName',
315 OPERATOR => ( $args{Right} ? '=' : 'IS NOT' ),
316 VALUE => $args{Right} || 'NULL',
317 ENTRYAGGREGATOR => 'OR'
319 if ( $args{'IncludeSuperusers'} and $args{'Right'} ) {
322 FIELD => 'RightName',
324 VALUE => 'SuperUser',
325 ENTRYAGGREGATOR => 'OR'
331 # XXX: should be generalized
337 IncludeSystemRights => undef,
341 return () unless $args{'Object'};
343 my @objects = ($args{'Object'});
344 if ( UNIVERSAL::isa( $args{'Object'}, 'RT::Ticket' ) ) {
345 # If we're looking at ticket rights, we also want to look at the associated queue rights.
346 # this is a little bit hacky, but basically, now that we've done the ticket roles magic,
347 # we load the queue object and ask all the rest of our questions about the queue.
349 # XXX: This should be abstracted into object itself
350 if( $args{'Object'}->id ) {
351 push @objects, $args{'Object'}->ACLEquivalenceObjects;
353 push @objects, 'RT::Queue';
357 if( $args{'IncludeSystemRights'} ) {
358 push @objects, 'RT::System';
360 push @objects, @{ $args{'EquivObjects'} };
361 return grep $_, @objects;
364 # XXX: should be generalized
370 IncludeSystemRights => undef,
371 IncludeSuperusers => undef,
372 IncludeSubgroupMembers => 1,
377 if ( defined $args{'ObjectType'} || defined $args{'ObjectId'} ) {
378 $RT::Logger->crit( "WhoHaveRight called with the Obsolete ObjectId/ObjectType API");
382 my $from_role = $self->Clone;
383 $from_role->WhoHaveRoleRight( %args );
385 my $from_group = $self->Clone;
386 $from_group->WhoHaveGroupRight( %args );
389 use DBIx::SearchBuilder 1.50; #no version on ::Union :(
390 use DBIx::SearchBuilder::Union;
391 my $union = DBIx::SearchBuilder::Union->new();
392 $union->add( $from_group );
393 $union->add( $from_role );
395 bless $self, ref($union);
400 # XXX: should be generalized
407 IncludeSystemRights => undef,
408 IncludeSuperusers => undef,
409 IncludeSubgroupMembers => 1,
414 my @objects = $self->_GetEquivObjects( %args );
416 # RT::Principal->RolesWithRight only expects EquivObjects, so we need to
417 # fill it. At the very least it needs $args{Object}, which
418 # _GetEquivObjects above does for us.
419 unshift @{$args{'EquivObjects'}}, @objects;
421 my @roles = RT::Principal->RolesWithRight( %args );
423 $self->_AddSubClause( "WhichRole", "(main.id = 0)" );
427 my $groups = $self->_JoinGroups( %args );
430 $self->Limit( ALIAS => $self->PrincipalsAlias,
433 VALUE => RT->SystemUser->id
436 $self->_AddSubClause( "WhichRole", "(". join( ' OR ', map "$groups.Type = '$_'", @roles ) .")" );
438 my @groups_clauses = $self->_RoleClauses( $groups, @objects );
439 $self->_AddSubClause( "WhichObject", "(". join( ' OR ', @groups_clauses ) .")" )
451 foreach my $obj ( @objects ) {
452 my $type = ref($obj)? ref($obj): $obj;
454 $id = $obj->id if ref($obj) && UNIVERSAL::can($obj, 'id') && $obj->id;
456 my $role_clause = "$groups.Domain = '$type-Role'";
457 # XXX: Groups.Instance is VARCHAR in DB, we should quote value
458 # if we want mysql 4.0 use indexes here. we MUST convert that
459 # field to integer and drop this quotes.
460 $role_clause .= " AND $groups.Instance = '$id'" if $id;
461 push @groups_clauses, "($role_clause)";
463 return @groups_clauses;
466 # XXX: should be generalized
467 sub _JoinGroupMembersForGroupRights
471 my $group_members = $self->_JoinGroupMembers( %args );
472 $self->Limit( ALIAS => $args{'ACLAlias'},
473 FIELD => 'PrincipalId',
474 VALUE => "$group_members.GroupId",
477 return $group_members;
480 # XXX: should be generalized
481 sub WhoHaveGroupRight
487 IncludeSystemRights => undef,
488 IncludeSuperusers => undef,
489 IncludeSubgroupMembers => 1,
494 # Find only rows where the right granted is
495 # the one we're looking up or _possibly_ superuser
496 my $acl = $self->_JoinACL( %args );
498 my ($check_objects) = ('');
499 my @objects = $self->_GetEquivObjects( %args );
503 foreach my $obj ( @objects ) {
504 my $type = ref($obj)? ref($obj): $obj;
506 $id = $obj->id if ref($obj) && UNIVERSAL::can($obj, 'id') && $obj->id;
508 my $object_clause = "$acl.ObjectType = '$type'";
509 $object_clause .= " AND $acl.ObjectId = $id" if $id;
510 push @object_clauses, "($object_clause)";
513 $check_objects = join ' OR ', @object_clauses;
515 if( !$args{'IncludeSystemRights'} ) {
516 $check_objects = "($acl.ObjectType != 'RT::System')";
519 $self->_AddSubClause( "WhichObject", "($check_objects)" );
521 my $group_members = $self->_JoinGroupMembersForGroupRights( %args, ACLAlias => $acl );
522 # Find only members of groups that have the right.
523 $self->Limit( ALIAS => $acl,
524 FIELD => 'PrincipalType',
529 $self->Limit( ALIAS => $self->PrincipalsAlias,
532 VALUE => RT->SystemUser->id
534 return $group_members;
538 =head2 WhoBelongToGroups { Groups => ARRAYREF, IncludeSubgroupMembers => 1 }
542 # XXX: should be generalized
543 sub WhoBelongToGroups {
545 my %args = ( Groups => undef,
546 IncludeSubgroupMembers => 1,
549 # Unprivileged users can't be granted real system rights.
550 # is this really the right thing to be saying?
551 $self->LimitToPrivileged();
553 my $group_members = $self->_JoinGroupMembers( %args );
555 foreach my $groupid (@{$args{'Groups'}}) {
556 $self->Limit( ALIAS => $group_members,
560 ENTRYAGGREGATOR => 'OR',
568 Returns an empty new RT::User item
574 return(RT::User->new($self->CurrentUser));
576 RT::Base->_ImportOverlays();