Merge branch 'master' of git.uio.no:usit-rt
[usit-rt.git] / lib / RT / Groups.pm
CommitLineData
84fb5b46
MKG
1# BEGIN BPS TAGGED BLOCK {{{
2#
3# COPYRIGHT:
4#
5# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
6# <sales@bestpractical.com>
7#
8# (Except where explicitly superseded by other copyright notices)
9#
10#
11# LICENSE:
12#
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
16# from www.gnu.org.
17#
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.
22#
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.
28#
29#
30# CONTRIBUTION SUBMISSION POLICY:
31#
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.)
37#
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.
46#
47# END BPS TAGGED BLOCK }}}
48
49=head1 NAME
50
51 RT::Groups - a collection of RT::Group objects
52
53=head1 SYNOPSIS
54
55 use RT::Groups;
56 my $groups = RT::Groups->new($CurrentUser);
57 $groups->UnLimit();
58 while (my $group = $groups->Next()) {
59 print $group->Id ." is a group id\n";
60 }
61
62=head1 DESCRIPTION
63
64
65=head1 METHODS
66
67
68
69=cut
70
71
72package RT::Groups;
73
74use strict;
75use warnings;
76
77
78
79use RT::Group;
80
81use base 'RT::SearchBuilder';
82
83sub Table { 'Groups'}
84
85use RT::Users;
86
87# XXX: below some code is marked as subject to generalize in Groups, Users classes.
88# RUZ suggest name Principals::Generic or Principals::Base as abstract class, but
89# Jesse wants something that doesn't imply it's a Principals.pm subclass.
90# See comments below for candidats.
91
92
93
94sub _Init {
95 my $self = shift;
96 $self->{'with_disabled_column'} = 1;
97
98 my @result = $self->SUPER::_Init(@_);
99
100 $self->OrderBy( ALIAS => 'main',
101 FIELD => 'Name',
102 ORDER => 'ASC');
103
104 # XXX: this code should be generalized
105 $self->{'princalias'} = $self->Join(
106 ALIAS1 => 'main',
107 FIELD1 => 'id',
108 TABLE2 => 'Principals',
109 FIELD2 => 'id'
110 );
111
112 # even if this condition is useless and ids in the Groups table
113 # only match principals with type 'Group' this could speed up
114 # searches in some DBs.
115 $self->Limit( ALIAS => $self->{'princalias'},
116 FIELD => 'PrincipalType',
117 VALUE => 'Group',
118 );
119
120 return (@result);
121}
122
123=head2 PrincipalsAlias
124
125Returns the string that represents this Users object's primary "Principals" alias.
126
127=cut
128
129# XXX: should be generalized, code duplication
130sub PrincipalsAlias {
131 my $self = shift;
132 return($self->{'princalias'});
133
134}
135
136
137
138=head2 LimitToSystemInternalGroups
139
140Return only SystemInternal Groups, such as "privileged" "unprivileged" and "everyone"
141
142=cut
143
144
145sub LimitToSystemInternalGroups {
146 my $self = shift;
147 $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'SystemInternal');
148 # All system internal groups have the same instance. No reason to limit down further
149 #$self->Limit(FIELD => 'Instance', OPERATOR => '=', VALUE => '0');
150}
151
152
153
154
155=head2 LimitToUserDefinedGroups
156
157Return only UserDefined Groups
158
159=cut
160
161
162sub LimitToUserDefinedGroups {
163 my $self = shift;
164 $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'UserDefined');
165 # All user-defined groups have the same instance. No reason to limit down further
166 #$self->Limit(FIELD => 'Instance', OPERATOR => '=', VALUE => '');
167}
168
169
170
171
172=head2 LimitToRolesForQueue QUEUE_ID
173
174Limits the set of groups found to role groups for queue QUEUE_ID
175
176=cut
177
178sub LimitToRolesForQueue {
179 my $self = shift;
180 my $queue = shift;
181 $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'RT::Queue-Role');
182 $self->Limit(FIELD => 'Instance', OPERATOR => '=', VALUE => $queue);
183}
184
185
186
187=head2 LimitToRolesForTicket Ticket_ID
188
189Limits the set of groups found to role groups for Ticket Ticket_ID
190
191=cut
192
193sub LimitToRolesForTicket {
194 my $self = shift;
195 my $Ticket = shift;
196 $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'RT::Ticket-Role');
197 $self->Limit(FIELD => 'Instance', OPERATOR => '=', VALUE => '$Ticket');
198}
199
200
201
202=head2 LimitToRolesForSystem System_ID
203
204Limits the set of groups found to role groups for System System_ID
205
206=cut
207
208sub LimitToRolesForSystem {
209 my $self = shift;
210 $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'RT::System-Role');
211}
212
213
214=head2 WithMember {PrincipalId => PRINCIPAL_ID, Recursively => undef}
215
216Limits the set of groups returned to groups which have
217Principal PRINCIPAL_ID as a member. Returns the alias used for the join.
218
219=cut
220
221sub WithMember {
222 my $self = shift;
223 my %args = ( PrincipalId => undef,
224 Recursively => undef,
225 @_);
226 my $members;
227
228 if ($args{'Recursively'}) {
229 $members = $self->NewAlias('CachedGroupMembers');
230 } else {
231 $members = $self->NewAlias('GroupMembers');
232 }
233 $self->Join(ALIAS1 => 'main', FIELD1 => 'id',
234 ALIAS2 => $members, FIELD2 => 'GroupId');
235
236 $self->Limit(ALIAS => $members, FIELD => 'MemberId', OPERATOR => '=', VALUE => $args{'PrincipalId'});
237 $self->Limit(ALIAS => $members, FIELD => 'Disabled', VALUE => 0)
238 if $args{'Recursively'};
239
240 return $members;
241}
242
243sub WithoutMember {
244 my $self = shift;
245 my %args = (
246 PrincipalId => undef,
247 Recursively => undef,
248 @_
249 );
250
251 my $members = $args{'Recursively'} ? 'CachedGroupMembers' : 'GroupMembers';
252 my $members_alias = $self->Join(
253 TYPE => 'LEFT',
254 FIELD1 => 'id',
255 TABLE2 => $members,
256 FIELD2 => 'GroupId',
257 );
258 $self->Limit(
259 LEFTJOIN => $members_alias,
260 ALIAS => $members_alias,
261 FIELD => 'MemberId',
262 OPERATOR => '=',
263 VALUE => $args{'PrincipalId'},
264 );
265 $self->Limit(
266 LEFTJOIN => $members_alias,
267 ALIAS => $members_alias,
268 FIELD => 'Disabled',
269 VALUE => 0
270 ) if $args{'Recursively'};
271 $self->Limit(
272 ALIAS => $members_alias,
273 FIELD => 'MemberId',
274 OPERATOR => 'IS',
275 VALUE => 'NULL',
276 QUOTEVALUE => 0,
277 );
278}
279
280=head2 WithRight { Right => RIGHTNAME, Object => RT::Record, IncludeSystemRights => 1, IncludeSuperusers => 0, EquivObjects => [ ] }
281
282
283Find all groups which have RIGHTNAME for RT::Record. Optionally include global rights and superusers. By default, include the global rights, but not the superusers.
284
285
286
287=cut
288
289#XXX: should be generilized
290sub WithRight {
291 my $self = shift;
292 my %args = ( Right => undef,
293 Object => => undef,
294 IncludeSystemRights => 1,
295 IncludeSuperusers => undef,
296 IncludeSubgroupMembers => 0,
297 EquivObjects => [ ],
298 @_ );
299
300 my $from_role = $self->Clone;
301 $from_role->WithRoleRight( %args );
302
303 my $from_group = $self->Clone;
304 $from_group->WithGroupRight( %args );
305
306 #XXX: DIRTY HACK
307 use DBIx::SearchBuilder::Union;
308 my $union = DBIx::SearchBuilder::Union->new();
309 $union->add($from_role);
310 $union->add($from_group);
311 %$self = %$union;
312 bless $self, ref($union);
313
314 return;
315}
316
317#XXX: methods are active aliases to Users class to prevent code duplication
318# should be generalized
319sub _JoinGroups {
320 my $self = shift;
321 my %args = (@_);
322 return 'main' unless $args{'IncludeSubgroupMembers'};
323 return $self->RT::Users::_JoinGroups( %args );
324}
325sub _JoinGroupMembers {
326 my $self = shift;
327 my %args = (@_);
328 return 'main' unless $args{'IncludeSubgroupMembers'};
329 return $self->RT::Users::_JoinGroupMembers( %args );
330}
331sub _JoinGroupMembersForGroupRights {
332 my $self = shift;
333 my %args = (@_);
334 my $group_members = $self->_JoinGroupMembers( %args );
335 unless( $group_members eq 'main' ) {
336 return $self->RT::Users::_JoinGroupMembersForGroupRights( %args );
337 }
338 $self->Limit( ALIAS => $args{'ACLAlias'},
339 FIELD => 'PrincipalId',
340 VALUE => "main.id",
341 QUOTEVALUE => 0,
342 );
343}
344sub _JoinACL { return (shift)->RT::Users::_JoinACL( @_ ) }
345sub _RoleClauses { return (shift)->RT::Users::_RoleClauses( @_ ) }
346sub _WhoHaveRoleRightSplitted { return (shift)->RT::Users::_WhoHaveRoleRightSplitted( @_ ) }
347sub _GetEquivObjects { return (shift)->RT::Users::_GetEquivObjects( @_ ) }
348sub WithGroupRight { return (shift)->RT::Users::WhoHaveGroupRight( @_ ) }
349sub WithRoleRight { return (shift)->RT::Users::WhoHaveRoleRight( @_ ) }
350
351sub ForWhichCurrentUserHasRight {
352 my $self = shift;
353 my %args = (
354 Right => undef,
355 IncludeSuperusers => undef,
356 @_,
357 );
358
359 # Non-disabled groups...
360 $self->LimitToEnabled;
361
362 # ...which are the target object of an ACL with that right, or
363 # where the target is the system object (a global right)
364 my $acl = $self->_JoinACL( %args );
365 $self->_AddSubClause(
366 ACLObjects => "( (main.id = $acl.ObjectId AND $acl.ObjectType = 'RT::Group')"
367 . " OR $acl.ObjectType = 'RT::System')");
368
369 # ...and where that right is granted to any group..
370 my $member = $self->Join(
371 ALIAS1 => $acl,
372 FIELD1 => 'PrincipalId',
373 TABLE2 => 'CachedGroupMembers',
374 FIELD2 => 'GroupId',
375 );
376 $self->Limit(
377 ALIAS => $member,
378 FIELD => 'Disabled',
379 VALUE => '0',
380 );
381
382 # ...with the current user in it
383 $self->Limit(
384 ALIAS => $member,
385 FIELD => 'MemberId',
386 VALUE => $self->CurrentUser->Id,
387 );
388
389 return;
390}
391
392=head2 LimitToEnabled
393
394Only find items that haven\'t been disabled
395
396=cut
397
398sub LimitToEnabled {
399 my $self = shift;
400
401 $self->{'handled_disabled_column'} = 1;
402 $self->Limit(
403 ALIAS => $self->PrincipalsAlias,
404 FIELD => 'Disabled',
405 VALUE => '0',
406 );
407}
408
409
410=head2 LimitToDeleted
411
412Only find items that have been deleted.
413
414=cut
415
416sub LimitToDeleted {
417 my $self = shift;
418
419 $self->{'handled_disabled_column'} = $self->{'find_disabled_rows'} = 1;
420 $self->Limit(
421 ALIAS => $self->PrincipalsAlias,
422 FIELD => 'Disabled',
423 VALUE => 1,
424 );
425}
426
427
428
429sub Next {
430 my $self = shift;
431
432 # Don't show groups which the user isn't allowed to see.
433
434 my $Group = $self->SUPER::Next();
435 if ((defined($Group)) and (ref($Group))) {
436 unless ($Group->CurrentUserHasRight('SeeGroup')) {
437 return $self->Next();
438 }
439
440 return $Group;
441 }
442 else {
443 return undef;
444 }
445}
446
447
448
449sub _DoSearch {
450 my $self = shift;
451
452 #unless we really want to find disabled rows, make sure we\'re only finding enabled ones.
453 unless($self->{'find_disabled_rows'}) {
454 $self->LimitToEnabled();
455 }
456
457 return($self->SUPER::_DoSearch(@_));
458
459}
460
461
462
463=head2 NewItem
464
465Returns an empty new RT::Group item
466
467=cut
468
469sub NewItem {
470 my $self = shift;
471 return(RT::Group->new($self->CurrentUser));
472}
473RT::Base->_ImportOverlays();
474
4751;