1 # BEGIN BPS TAGGED BLOCK {{{
5 # This software is Copyright (c) 1996-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
28 # CONTRIBUTION SUBMISSION POLICY:
30 # (The following paragraph is not intended to limit the rights granted
31 # to you to modify and distribute this software under the terms of
32 # the GNU General Public License and is only of importance to you if
33 # you choose to contribute your changes and enhancements to the
34 # community by submitting them to Best Practical Solutions, LLC.)
36 # By intentionally submitting any modifications, corrections or
37 # derivatives to this work, or any other work intended for use with
38 # Request Tracker, to Best Practical Solutions, LLC, you confirm that
39 # you are the copyright holder for those contributions and you grant
40 # Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
41 # royalty-free, perpetual, license to use, copy, create derivative
42 # works based on those contributions, and sublicense and distribute
43 # those contributions and any derivatives thereof.
45 # END BPS TAGGED BLOCK }}}
49 RT::Users - Collection of RT::User objects
63 ok(require RT::Users);
73 no warnings qw(redefine);
78 $self->{'table'} = 'Users';
79 $self->{'primary_key'} = 'id';
83 my @result = $self->SUPER::_Init(@_);
84 # By default, order by name
85 $self->OrderBy( ALIAS => 'main',
89 $self->{'princalias'} = $self->NewAlias('Principals');
91 $self->Join( ALIAS1 => 'main',
93 ALIAS2 => $self->{'princalias'},
101 =head2 PrincipalsAlias
103 Returns the string that represents this Users object's primary "Principals" alias.
108 sub PrincipalsAlias {
110 return($self->{'princalias'});
119 A subclass of DBIx::SearchBuilder::_DoSearch that makes sure that _Disabled rows never get seen unless
120 we're explicitly trying to see them.
127 #unless we really want to find disabled rows, make sure we\'re only finding enabled ones.
128 unless ( $self->{'find_disabled_rows'} ) {
129 $self->LimitToEnabled();
131 return ( $self->SUPER::_DoSearch(@_) );
136 # {{{ sub LimitToEnabled
138 =head2 LimitToEnabled
140 Only find items that haven\'t been disabled
147 $self->Limit( ALIAS => $self->{'princalias'},
159 Takes one argument. an email address. limits the returned set to
167 $self->Limit( FIELD => 'EmailAddress', VALUE => "$addr" );
174 =head2 MemberOfGroup PRINCIPAL_ID
176 takes one argument, a group's principal id. Limits the returned set
177 to members of a given group
185 return $self->loc("No group specified") if ( !defined $group );
187 my $groupalias = $self->NewAlias('CachedGroupMembers');
189 # Join the principal to the groups table
190 $self->Join( ALIAS1 => $self->{'princalias'},
192 ALIAS2 => $groupalias,
193 FIELD2 => 'MemberId' );
195 $self->Limit( ALIAS => "$groupalias",
203 # {{{ LimitToPrivileged
205 =head2 LimitToPrivileged
207 Limits to users who can be made members of ACLs and groups
211 sub LimitToPrivileged {
214 my $priv = RT::Group->new( $self->CurrentUser );
215 $priv->LoadSystemInternalGroup('Privileged');
216 unless ( $priv->Id ) {
217 $RT::Logger->crit("Couldn't find a privileged users group");
219 $self->MemberOfGroup( $priv->PrincipalId );
226 =head2 WhoHaveRight { Right => 'name', Object => $rt_object , IncludeSuperusers => undef, IncludeSubgroupMembers => undef, IncludeSystemRights => undef, EquivObjects => [ ] }
230 ok(my $users = RT::Users->new($RT::SystemUser));
231 $users->WhoHaveRight(Object =>$RT::System, Right =>'SuperUser');
232 ok($users->Count == 1, "There is one privileged superuser - Found ". $users->Count );
233 # TODO: this wants more testing
235 my $RTxUser = RT::User->new($RT::SystemUser);
236 ($id, $msg) = $RTxUser->Create( Name => 'RTxUser', Comments => "RTx extension user", Privileged => 1);
239 my $group = RT::Group->new($RT::SystemUser);
240 $group->LoadACLEquivalenceGroup($RTxUser->PrincipalObj);
243 bless $RTxSysObj, 'RTx::System';
244 *RTx::System::Id = sub { 1; };
245 *RTx::System::id = *RTx::System::Id;
246 my $ace = RT::Record->new($RT::SystemUser);
248 $ace->_BuildTableAttributes unless ($_TABLE_ATTR->{ref($self)});
249 ($id, $msg) = $ace->Create( PrincipalId => $group->id, PrincipalType => 'Group', RightName => 'RTxUserRight', ObjectType => 'RTx::System', ObjectId => 1 );
250 ok ($id, "ACL for RTxSysObj created");
253 bless $RTxObj, 'RTx::System::Record';
254 *RTx::System::Record::Id = sub { 4; };
255 *RTx::System::Record::id = *RTx::System::Record::Id;
257 $users = RT::Users->new($RT::SystemUser);
258 $users->WhoHaveRight(Right => 'RTxUserRight', Object => $RTxSysObj);
259 is($users->Count, 1, "RTxUserRight found for RTxSysObj");
261 $users = RT::Users->new($RT::SystemUser);
262 $users->WhoHaveRight(Right => 'RTxUserRight', Object => $RTxObj);
263 is($users->Count, 0, "RTxUserRight not found for RTxObj");
265 $users = RT::Users->new($RT::SystemUser);
266 $users->WhoHaveRight(Right => 'RTxUserRight', Object => $RTxObj, EquivObjects => [ $RTxSysObj ]);
267 is($users->Count, 1, "RTxUserRight found for RTxObj using EquivObjects");
269 $ace = RT::Record->new($RT::SystemUser);
271 $ace->_BuildTableAttributes unless ($_TABLE_ATTR->{ref($self)});
272 ($id, $msg) = $ace->Create( PrincipalId => $group->id, PrincipalType => 'Group', RightName => 'RTxUserRight', ObjectType => 'RTx::System::Record', ObjectId => 5 );
273 ok ($id, "ACL for RTxObj created");
276 bless $RTxObj2, 'RTx::System::Record';
277 *RTx::System::Record::Id = sub { 5; };
278 *RTx::System::Record::id = sub { 5; };
280 $users = RT::Users->new($RT::SystemUser);
281 $users->WhoHaveRight(Right => 'RTxUserRight', Object => $RTxObj2);
282 is($users->Count, 1, "RTxUserRight found for RTxObj2");
284 $users = RT::Users->new($RT::SystemUser);
285 $users->WhoHaveRight(Right => 'RTxUserRight', Object => $RTxObj2, EquivObjects => [ $RTxSysObj ]);
286 is($users->Count, 1, "RTxUserRight found for RTxObj2");
292 find all users who the right Right for this group, either individually
293 or as members of groups
296 If passed a queue object, with no id, it will find users who have that right for _any_ queue
307 IncludeSystemRights => undef,
308 IncludeSuperusers => undef,
309 IncludeSubgroupMembers => 1,
314 if ( defined $args{'ObjectType'} || defined $args{'ObjectId'} ) {
315 $RT::Logger->crit( "$self WhoHaveRight called with the Obsolete ObjectId/ObjectType API");
320 # Find only members of groups that have the right.
322 my $acl = $self->NewAlias('ACL');
323 my $groups = $self->NewAlias('Groups');
324 my $userprinc = $self->{'princalias'};
326 # The cachedgroupmembers table is used for unrolling group memberships to allow fast lookups
327 # if we bind to CachedGroupMembers, we'll find all members of groups recursively.
328 # if we don't we'll find only 'direct' members of the group in question
331 if ( $args{'IncludeSubgroupMembers'} ) {
332 $cgm = $self->NewAlias('CachedGroupMembers');
335 $cgm = $self->NewAlias('GroupMembers');
338 #Tie the users we're returning ($userprinc) to the groups that have rights granted to them ($groupprinc)
341 FIELD1 => 'MemberId',
342 ALIAS2 => $userprinc,
353 # {{{ Find only rows where the right granted is the one we're looking up or _possibly_ superuser
356 FIELD => 'RightName',
357 OPERATOR => ( $args{Right} ? '=' : 'IS NOT' ),
358 VALUE => $args{Right} || 'NULL',
359 ENTRYAGGREGATOR => 'OR'
362 if ( $args{'IncludeSuperusers'} and $args{'Right'} ) {
365 FIELD => 'RightName',
367 VALUE => 'SuperUser',
368 ENTRYAGGREGATOR => 'OR'
374 my ( $or_check_ticket_roles, $or_check_roles );
375 my $which_object = "$acl.ObjectType = 'RT::System'";
377 if ( defined $args{'Object'} ) {
378 if ( ref( $args{'Object'} ) eq 'RT::Ticket' ) {
379 $or_check_ticket_roles = " OR ( $groups.Domain = 'RT::Ticket-Role' AND $groups.Instance = " . $args{'Object'}->Id . ") ";
381 # If we're looking at ticket rights, we also want to look at the associated queue rights.
382 # this is a little bit hacky, but basically, now that we've done the ticket roles magic,
383 # we load the queue object and ask all the rest of our questions about the queue.
384 $args{'Object'} = $args{'Object'}->QueueObj;
387 # TODO XXX This really wants some refactoring
388 if ( ref( $args{'Object'} ) eq 'RT::Queue' ) {
389 $or_check_roles = " OR ( ( ($groups.Domain = 'RT::Queue-Role' ";
390 $or_check_roles .= "AND $groups.Instance = " . $args{'Object'}->id if ( $args{'Object'}->id );
391 $or_check_roles .= ") $or_check_ticket_roles ) " . " AND $groups.Type = $acl.PrincipalType) ";
393 if ( $args{'IncludeSystemRights'} ) {
394 $which_object .= ' OR ';
399 foreach my $obj ( @{ $args{'EquivObjects'} } ) {
400 $which_object .= "($acl.ObjectType = '" . ref( $obj ) . "' AND $acl.ObjectId = " . $obj->id . ") OR ";
402 $which_object .= " ($acl.ObjectType = '" . ref( $args{'Object'} ) . "'";
403 if ( $args{'Object'}->id ) {
404 $which_object .= " AND $acl.ObjectId = " . $args{'Object'}->id;
407 $which_object .= ") ";
409 $self->_AddSubClause( "WhichObject", "($which_object)" );
410 $self->_AddSubClause(
412 qq{ ( ( $acl.PrincipalId = $groups.id AND $acl.PrincipalType = 'Group'
413 AND ( $groups.Domain = 'SystemInternal' OR $groups.Domain = 'UserDefined' OR $groups.Domain = 'ACLEquivalence'))
416 # only include regular RT users
417 $self->LimitToEnabled;
420 $self->Limit( ALIAS => $userprinc, FIELD => 'id', OPERATOR => '!=', VALUE => $RT::SystemUser->id);
425 # {{{ WhoBelongToGroups
427 =head2 WhoBelongToGroups { Groups => ARRAYREF, IncludeSubgroupMembers => 1 }
431 sub WhoBelongToGroups {
433 my %args = ( Groups => undef,
434 IncludeSubgroupMembers => 1,
437 # Unprivileged users can't be granted real system rights.
438 # is this really the right thing to be saying?
439 $self->LimitToPrivileged();
441 my $userprinc = $self->{'princalias'};
444 # The cachedgroupmembers table is used for unrolling group memberships to allow fast lookups
445 # if we bind to CachedGroupMembers, we'll find all members of groups recursively.
446 # if we don't we'll find only 'direct' members of the group in question
448 if ( $args{'IncludeSubgroupMembers'} ) {
449 $cgm = $self->NewAlias('CachedGroupMembers');
452 $cgm = $self->NewAlias('GroupMembers');
455 #Tie the users we're returning ($userprinc) to the groups that have rights granted to them ($groupprinc)
456 $self->Join( ALIAS1 => $cgm, FIELD1 => 'MemberId',
457 ALIAS2 => $userprinc, FIELD2 => 'id' );
459 foreach my $groupid (@{$args{'Groups'}}) {
460 $self->Limit(ALIAS => $cgm, FIELD => 'GroupId', VALUE => $groupid, QUOTEVALUE => 0, ENTRYAGGREGATOR=> 'OR')