1 # BEGIN BPS TAGGED BLOCK {{{
5 # This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC
6 # <jesse@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
70 no warnings qw(redefine);
75 $self->{'table'} = 'Users';
76 $self->{'primary_key'} = 'id';
77 $self->{'with_disabled_column'} = 1;
79 my @result = $self->SUPER::_Init(@_);
80 # By default, order by name
81 $self->OrderBy( ALIAS => 'main',
85 $self->{'princalias'} = $self->NewAlias('Principals');
87 # XXX: should be generalized
88 $self->Join( ALIAS1 => 'main',
90 ALIAS2 => $self->{'princalias'},
92 $self->Limit( ALIAS => $self->{'princalias'},
93 FIELD => 'PrincipalType',
102 =head2 PrincipalsAlias
104 Returns the string that represents this Users object's primary "Principals" alias.
108 # XXX: should be generalized
109 sub PrincipalsAlias {
111 return($self->{'princalias'});
116 =head2 LimitToEnabled
118 Only find items that haven\'t been disabled
122 # XXX: should be generalized
126 $self->{'handled_disabled_column'} = 1;
128 ALIAS => $self->PrincipalsAlias,
134 =head2 LimitToDeleted
136 Only find items that have been deleted.
143 $self->{'handled_disabled_column'} = $self->{'find_disabled_rows'} = 1;
145 ALIAS => $self->PrincipalsAlias,
156 Takes one argument. an email address. limits the returned set to
164 $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 # {{{ LimitToPrivileged
202 =head2 LimitToPrivileged
204 Limits to users who can be made members of ACLs and groups
208 sub LimitToPrivileged {
211 my $priv = RT::Group->new( $self->CurrentUser );
212 $priv->LoadSystemInternalGroup('Privileged');
213 unless ( $priv->Id ) {
214 $RT::Logger->crit("Couldn't find a privileged users group");
216 $self->MemberOfGroup( $priv->PrincipalId );
223 =head2 WhoHaveRight { Right => 'name', Object => $rt_object , IncludeSuperusers => undef, IncludeSubgroupMembers => undef, IncludeSystemRights => undef, EquivObjects => [ ] }
226 find all users who the right Right for this group, either individually
227 or as members of groups
229 If passed a queue object, with no id, it will find users who have that right for _any_ queue
233 # XXX: should be generalized
234 sub _JoinGroupMembers
238 IncludeSubgroupMembers => 1,
242 my $principals = $self->PrincipalsAlias;
244 # The cachedgroupmembers table is used for unrolling group memberships
245 # to allow fast lookups. if we bind to CachedGroupMembers, we'll find
246 # all members of groups recursively. if we don't we'll find only 'direct'
247 # members of the group in question
249 if ( $args{'IncludeSubgroupMembers'} ) {
250 $group_members = $self->NewAlias('CachedGroupMembers');
253 $group_members = $self->NewAlias('GroupMembers');
257 ALIAS1 => $group_members,
258 FIELD1 => 'MemberId',
259 ALIAS2 => $principals,
263 return $group_members;
266 # XXX: should be generalized
272 my $group_members = $self->_JoinGroupMembers( %args );
273 my $groups = $self->NewAlias('Groups');
277 ALIAS2 => $group_members,
284 # XXX: should be generalized
290 IncludeSuperusers => undef,
294 if ( $args{'Right'} ) {
295 my $canonic = RT::ACE->CanonicalizeRightName( $args{'Right'} );
296 unless ( $canonic ) {
297 $RT::Logger->error("Invalid right. Couldn't canonicalize right '$args{'Right'}'");
300 $args{'Right'} = $canonic;
304 my $acl = $self->NewAlias('ACL');
307 FIELD => 'RightName',
308 OPERATOR => ( $args{Right} ? '=' : 'IS NOT' ),
309 VALUE => $args{Right} || 'NULL',
310 ENTRYAGGREGATOR => 'OR'
312 if ( $args{'IncludeSuperusers'} and $args{'Right'} ) {
315 FIELD => 'RightName',
317 VALUE => 'SuperUser',
318 ENTRYAGGREGATOR => 'OR'
324 # XXX: should be generalized
330 IncludeSystemRights => undef,
334 return () unless $args{'Object'};
336 my @objects = ($args{'Object'});
337 if ( UNIVERSAL::isa( $args{'Object'}, 'RT::Ticket' ) ) {
338 # If we're looking at ticket rights, we also want to look at the associated queue rights.
339 # this is a little bit hacky, but basically, now that we've done the ticket roles magic,
340 # we load the queue object and ask all the rest of our questions about the queue.
342 # XXX: This should be abstracted into object itself
343 if( $args{'Object'}->id ) {
344 push @objects, $args{'Object'}->ACLEquivalenceObjects;
346 push @objects, 'RT::Queue';
350 if( $args{'IncludeSystemRights'} ) {
351 push @objects, 'RT::System';
353 push @objects, @{ $args{'EquivObjects'} };
354 return grep $_, @objects;
357 # XXX: should be generalized
363 IncludeSystemRights => undef,
364 IncludeSuperusers => undef,
365 IncludeSubgroupMembers => 1,
370 if ( defined $args{'ObjectType'} || defined $args{'ObjectId'} ) {
371 $RT::Logger->crit( "WhoHaveRight called with the Obsolete ObjectId/ObjectType API");
375 my $from_role = $self->Clone;
376 $from_role->WhoHaveRoleRight( %args );
378 my $from_group = $self->Clone;
379 $from_group->WhoHaveGroupRight( %args );
382 use DBIx::SearchBuilder 1.50; #no version on ::Union :(
383 use DBIx::SearchBuilder::Union;
384 my $union = new DBIx::SearchBuilder::Union;
385 $union->add( $from_group );
386 $union->add( $from_role );
388 bless $self, ref($union);
394 # XXX: should be generalized
401 IncludeSystemRights => undef,
402 IncludeSuperusers => undef,
403 IncludeSubgroupMembers => 1,
408 my @objects = $self->_GetEquivObjects( %args );
409 my @roles = RT::Principal->RolesWithRight( %args );
411 $self->_AddSubClause( "WhichRole", "(main.id = 0)" );
415 my $groups = $self->_JoinGroups( %args );
418 $self->Limit( ALIAS => $self->PrincipalsAlias,
421 VALUE => $RT::SystemUser->id
424 $self->_AddSubClause( "WhichRole", "(". join( ' OR ', map "$groups.Type = '$_'", @roles ) .")" );
426 my @groups_clauses = $self->_RoleClauses( $groups, @objects );
427 $self->_AddSubClause( "WhichObject", "(". join( ' OR ', @groups_clauses ) .")" )
439 foreach my $obj ( @objects ) {
440 my $type = ref($obj)? ref($obj): $obj;
442 $id = $obj->id if ref($obj) && UNIVERSAL::can($obj, 'id') && $obj->id;
444 my $role_clause = "$groups.Domain = '$type-Role'";
445 # XXX: Groups.Instance is VARCHAR in DB, we should quote value
446 # if we want mysql 4.0 use indexes here. we MUST convert that
447 # field to integer and drop this quotes.
448 $role_clause .= " AND $groups.Instance = '$id'" if $id;
449 push @groups_clauses, "($role_clause)";
451 return @groups_clauses;
454 # XXX: should be generalized
455 sub _JoinGroupMembersForGroupRights
459 my $group_members = $self->_JoinGroupMembers( %args );
460 $self->Limit( ALIAS => $args{'ACLAlias'},
461 FIELD => 'PrincipalId',
462 VALUE => "$group_members.GroupId",
467 # XXX: should be generalized
468 sub WhoHaveGroupRight
474 IncludeSystemRights => undef,
475 IncludeSuperusers => undef,
476 IncludeSubgroupMembers => 1,
481 # Find only rows where the right granted is
482 # the one we're looking up or _possibly_ superuser
483 my $acl = $self->_JoinACL( %args );
485 my ($check_objects) = ('');
486 my @objects = $self->_GetEquivObjects( %args );
490 foreach my $obj ( @objects ) {
491 my $type = ref($obj)? ref($obj): $obj;
493 $id = $obj->id if ref($obj) && UNIVERSAL::can($obj, 'id') && $obj->id;
495 my $object_clause = "$acl.ObjectType = '$type'";
496 $object_clause .= " AND $acl.ObjectId = $id" if $id;
497 push @object_clauses, "($object_clause)";
500 $check_objects = join ' OR ', @object_clauses;
502 if( !$args{'IncludeSystemRights'} ) {
503 $check_objects = "($acl.ObjectType != 'RT::System')";
506 $self->_AddSubClause( "WhichObject", "($check_objects)" );
508 $self->_JoinGroupMembersForGroupRights( %args, ACLAlias => $acl );
509 # Find only members of groups that have the right.
510 $self->Limit( ALIAS => $acl,
511 FIELD => 'PrincipalType',
516 $self->Limit( ALIAS => $self->PrincipalsAlias,
519 VALUE => $RT::SystemUser->id
524 # {{{ WhoBelongToGroups
526 =head2 WhoBelongToGroups { Groups => ARRAYREF, IncludeSubgroupMembers => 1 }
530 # XXX: should be generalized
531 sub WhoBelongToGroups {
533 my %args = ( Groups => undef,
534 IncludeSubgroupMembers => 1,
537 # Unprivileged users can't be granted real system rights.
538 # is this really the right thing to be saying?
539 $self->LimitToPrivileged();
541 my $group_members = $self->_JoinGroupMembers( %args );
543 foreach my $groupid (@{$args{'Groups'}}) {
544 $self->Limit( ALIAS => $group_members,
548 ENTRYAGGREGATOR => 'OR',