1 # BEGIN BPS TAGGED BLOCK {{{
5 # This software is Copyright (c) 1996-2015 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::Groups - a collection of RT::Group objects
56 my $groups = RT::Groups->new($CurrentUser);
58 while (my $group = $groups->Next()) {
59 print $group->Id ." is a group id\n";
77 use base 'RT::SearchBuilder';
84 # XXX: below some code is marked as subject to generalize in Groups, Users classes.
85 # RUZ suggest name Principals::Generic or Principals::Base as abstract class, but
86 # Jesse wants something that doesn't imply it's a Principals.pm subclass.
87 # See comments below for candidats.
93 $self->{'with_disabled_column'} = 1;
95 my @result = $self->SUPER::_Init(@_);
97 $self->OrderBy( ALIAS => 'main',
101 # XXX: this code should be generalized
102 $self->{'princalias'} = $self->Join(
105 TABLE2 => 'Principals',
109 # even if this condition is useless and ids in the Groups table
110 # only match principals with type 'Group' this could speed up
111 # searches in some DBs.
112 $self->Limit( ALIAS => $self->{'princalias'},
113 FIELD => 'PrincipalType',
120 =head2 PrincipalsAlias
122 Returns the string that represents this Users object's primary "Principals" alias.
126 # XXX: should be generalized, code duplication
127 sub PrincipalsAlias {
129 return($self->{'princalias'});
135 =head2 LimitToSystemInternalGroups
137 Return only SystemInternal Groups, such as "privileged" "unprivileged" and "everyone"
142 sub LimitToSystemInternalGroups {
144 $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'SystemInternal', CASESENSITIVE => 0 );
145 # All system internal groups have the same instance. No reason to limit down further
146 #$self->Limit(FIELD => 'Instance', OPERATOR => '=', VALUE => '0');
152 =head2 LimitToUserDefinedGroups
154 Return only UserDefined Groups
159 sub LimitToUserDefinedGroups {
161 $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'UserDefined', CASESENSITIVE => 0 );
162 # All user-defined groups have the same instance. No reason to limit down further
163 #$self->Limit(FIELD => 'Instance', OPERATOR => '=', VALUE => '');
166 =head2 LimitToRolesForObject OBJECT
168 Limits the set of groups to role groups specifically for the object in question
169 based on the object's class and ID. If the object has no ID, the roles are not
170 limited by group C<Instance>. That is, calling this method on an unloaded
171 object will find all role groups for that class of object.
173 Replaces L</LimitToRolesForQueue>, L</LimitToRolesForTicket>, and
174 L</LimitToRolesForSystem>.
178 sub LimitToRolesForObject {
181 $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => ref($object) . "-Role", CASESENSITIVE => 0 );
182 $self->Limit(FIELD => 'Instance', OPERATOR => '=', VALUE => $object->id);
185 =head2 LimitToRolesForQueue QUEUE_ID
187 B<DEPRECATED>. Use L</LimitToRolesForObject> instead.
189 Limits the set of groups found to role groups for queue QUEUE_ID
193 sub LimitToRolesForQueue {
197 Instead => "LimitToRolesForObject",
200 $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'RT::Queue-Role', CASESENSITIVE => 0 );
201 $self->Limit(FIELD => 'Instance', OPERATOR => '=', VALUE => $queue);
206 =head2 LimitToRolesForTicket Ticket_ID
208 B<DEPRECATED>. Use L</LimitToRolesForObject> instead.
210 Limits the set of groups found to role groups for Ticket Ticket_ID
214 sub LimitToRolesForTicket {
218 Instead => "LimitToRolesForObject",
221 $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'RT::Ticket-Role', CASESENSITIVE => 0 );
222 $self->Limit(FIELD => 'Instance', OPERATOR => '=', VALUE => $Ticket);
227 =head2 LimitToRolesForSystem System_ID
229 B<DEPRECATED>. Use L</LimitToRolesForObject> instead.
231 Limits the set of groups found to role groups for System System_ID
235 sub LimitToRolesForSystem {
238 Instead => "LimitToRolesForObject",
241 $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'RT::System-Role', CASESENSITIVE => 0 );
242 $self->Limit(FIELD => 'Instance', OPERATOR => '=', VALUE => RT::System->Id );
246 =head2 WithMember {PrincipalId => PRINCIPAL_ID, Recursively => undef}
248 Limits the set of groups returned to groups which have
249 Principal PRINCIPAL_ID as a member. Returns the alias used for the join.
255 my %args = ( PrincipalId => undef,
256 Recursively => undef,
258 my $members = $self->Join(
259 ALIAS1 => 'main', FIELD1 => 'id',
261 ? (TABLE2 => 'CachedGroupMembers')
262 # (GroupId, MemberId) is unique in GM table
263 : (TABLE2 => 'GroupMembers', DISTINCT => 1)
268 $self->Limit(ALIAS => $members, FIELD => 'MemberId', OPERATOR => '=', VALUE => $args{'PrincipalId'});
269 $self->Limit(ALIAS => $members, FIELD => 'Disabled', VALUE => 0)
270 if $args{'Recursively'};
275 sub WithCurrentUser {
277 $self->{with_current_user} = 1;
278 return $self->WithMember(
279 PrincipalId => $self->CurrentUser->PrincipalId,
287 PrincipalId => undef,
288 Recursively => undef,
292 my $members = $args{'Recursively'} ? 'CachedGroupMembers' : 'GroupMembers';
293 my $members_alias = $self->Join(
298 DISTINCT => $members eq 'GroupMembers',
301 LEFTJOIN => $members_alias,
302 ALIAS => $members_alias,
305 VALUE => $args{'PrincipalId'},
308 LEFTJOIN => $members_alias,
309 ALIAS => $members_alias,
312 ) if $args{'Recursively'};
314 ALIAS => $members_alias,
322 =head2 WithRight { Right => RIGHTNAME, Object => RT::Record, IncludeSystemRights => 1, IncludeSuperusers => 0, EquivObjects => [ ] }
325 Find all groups which have RIGHTNAME for RT::Record. Optionally include global rights and superusers. By default, include the global rights, but not the superusers.
331 #XXX: should be generilized
334 my %args = ( Right => undef,
336 IncludeSystemRights => 1,
337 IncludeSuperusers => undef,
338 IncludeSubgroupMembers => 0,
342 my $from_role = $self->Clone;
343 $from_role->WithRoleRight( %args );
345 my $from_group = $self->Clone;
346 $from_group->WithGroupRight( %args );
349 use DBIx::SearchBuilder 1.50; #no version on ::Union :(
350 use DBIx::SearchBuilder::Union;
351 my $union = DBIx::SearchBuilder::Union->new();
352 $union->add($from_role);
353 $union->add($from_group);
355 bless $self, ref($union);
360 #XXX: methods are active aliases to Users class to prevent code duplication
361 # should be generalized
365 return 'main' unless $args{'IncludeSubgroupMembers'};
366 return $self->RT::Users::_JoinGroups( %args );
368 sub _JoinGroupMembers {
371 return 'main' unless $args{'IncludeSubgroupMembers'};
372 return $self->RT::Users::_JoinGroupMembers( %args );
374 sub _JoinGroupMembersForGroupRights {
377 my $group_members = $self->_JoinGroupMembers( %args );
378 unless( $group_members eq 'main' ) {
379 return $self->RT::Users::_JoinGroupMembersForGroupRights( %args );
381 $self->Limit( ALIAS => $args{'ACLAlias'},
382 FIELD => 'PrincipalId',
387 sub _JoinACL { return (shift)->RT::Users::_JoinACL( @_ ) }
388 sub _RoleClauses { return (shift)->RT::Users::_RoleClauses( @_ ) }
389 sub _WhoHaveRoleRightSplitted { return (shift)->RT::Users::_WhoHaveRoleRightSplitted( @_ ) }
390 sub _GetEquivObjects { return (shift)->RT::Users::_GetEquivObjects( @_ ) }
391 sub WithGroupRight { return (shift)->RT::Users::WhoHaveGroupRight( @_ ) }
392 sub WithRoleRight { return (shift)->RT::Users::WhoHaveRoleRight( @_ ) }
394 sub ForWhichCurrentUserHasRight {
398 IncludeSuperusers => undef,
402 # Non-disabled groups...
403 $self->LimitToEnabled;
405 # ...which are the target object of an ACL with that right, or
406 # where the target is the system object (a global right)
407 my $acl = $self->_JoinACL( %args );
408 $self->_AddSubClause(
409 ACLObjects => "( (main.id = $acl.ObjectId AND $acl.ObjectType = 'RT::Group')"
410 . " OR $acl.ObjectType = 'RT::System')");
412 # ...and where that right is granted to any group..
413 my $member = $self->Join(
415 FIELD1 => 'PrincipalId',
416 TABLE2 => 'CachedGroupMembers',
425 # ...with the current user in it
429 VALUE => $self->CurrentUser->Id,
435 =head2 LimitToEnabled
437 Only find items that haven't been disabled
444 $self->{'handled_disabled_column'} = 1;
446 ALIAS => $self->PrincipalsAlias,
453 =head2 LimitToDeleted
455 Only find items that have been deleted.
462 $self->{'handled_disabled_column'} = $self->{'find_disabled_rows'} = 1;
464 ALIAS => $self->PrincipalsAlias,
476 # If we've explicitly limited to groups the user is a member of (for
477 # dashboard or savedsearch privacy objects), skip the ACL.
478 return unless $self->{with_current_user}
479 or $record->CurrentUserHasRight('SeeGroup');
481 return $self->SUPER::AddRecord( $record );
489 #unless we really want to find disabled rows, make sure we're only finding enabled ones.
490 unless($self->{'find_disabled_rows'}) {
491 $self->LimitToEnabled();
494 return($self->SUPER::_DoSearch(@_));
498 RT::Base->_ImportOverlays();