import rt 3.8.7
[freeside.git] / rt / lib / RT / Groups_Overlay.pm
1 # BEGIN BPS TAGGED BLOCK {{{
2
3 # COPYRIGHT:
4
5 # This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC
6 #                                          <jesse@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
72 package RT::Groups;
73
74 use strict;
75 no warnings qw(redefine);
76
77 use RT::Users;
78
79 # XXX: below some code is marked as subject to generalize in Groups, Users classes.
80 # RUZ suggest name Principals::Generic or Principals::Base as abstract class, but
81 # Jesse wants something that doesn't imply it's a Principals.pm subclass.
82 # See comments below for candidats.
83
84
85 # {{{ sub _Init
86
87 sub _Init { 
88   my $self = shift;
89   $self->{'table'} = "Groups";
90   $self->{'primary_key'} = "id";
91
92   my @result = $self->SUPER::_Init(@_);
93
94   $self->OrderBy( ALIAS => 'main',
95                   FIELD => 'Name',
96                   ORDER => 'ASC');
97
98   # XXX: this code should be generalized
99   $self->{'princalias'} = $self->Join(
100     ALIAS1 => 'main',
101     FIELD1 => 'id',
102     TABLE2 => 'Principals',
103     FIELD2 => 'id'
104   );
105
106   # even if this condition is useless and ids in the Groups table
107   # only match principals with type 'Group' this could speed up
108   # searches in some DBs.
109   $self->Limit( ALIAS => $self->{'princalias'},
110                 FIELD => 'PrincipalType',
111                 VALUE => 'Group',
112               );
113
114   return (@result);
115 }
116 # }}}
117
118 =head2 PrincipalsAlias
119
120 Returns the string that represents this Users object's primary "Principals" alias.
121
122 =cut
123
124 # XXX: should be generalized, code duplication
125 sub PrincipalsAlias {
126     my $self = shift;
127     return($self->{'princalias'});
128
129 }
130
131
132 # {{{ LimiToSystemInternalGroups
133
134 =head2 LimitToSystemInternalGroups
135
136 Return only SystemInternal Groups, such as "privileged" "unprivileged" and "everyone" 
137
138 =cut
139
140
141 sub LimitToSystemInternalGroups {
142     my $self = shift;
143     $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'SystemInternal');
144     # All system internal groups have the same instance. No reason to limit down further
145     #$self->Limit(FIELD => 'Instance', OPERATOR => '=', VALUE => '0');
146 }
147
148
149 # }}}
150
151 # {{{ LimiToUserDefinedGroups
152
153 =head2 LimitToUserDefinedGroups
154
155 Return only UserDefined Groups
156
157 =cut
158
159
160 sub LimitToUserDefinedGroups {
161     my $self = shift;
162     $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'UserDefined');
163     # All user-defined groups have the same instance. No reason to limit down further
164     #$self->Limit(FIELD => 'Instance', OPERATOR => '=', VALUE => '');
165 }
166
167
168 # }}}
169
170 # {{{ LimiToPersonalGroupsFor
171
172 =head2 LimitToPersonalGroupsFor PRINCIPAL_ID
173
174 Return only Personal Groups for the user whose principal id 
175 is PRINCIPAL_ID
176
177 =cut
178
179
180 sub LimitToPersonalGroupsFor {
181     my $self = shift;
182     my $princ = shift;
183
184     $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'Personal');
185     $self->Limit(   FIELD => 'Instance',   
186                     OPERATOR => '=', 
187                     VALUE => $princ);
188 }
189
190
191 # }}}
192
193 # {{{ LimitToRolesForQueue
194
195 =head2 LimitToRolesForQueue QUEUE_ID
196
197 Limits the set of groups found to role groups for queue QUEUE_ID
198
199 =cut
200
201 sub LimitToRolesForQueue {
202     my $self = shift;
203     my $queue = shift;
204     $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'RT::Queue-Role');
205     $self->Limit(FIELD => 'Instance', OPERATOR => '=', VALUE => $queue);
206 }
207
208 # }}}
209
210 # {{{ LimitToRolesForTicket
211
212 =head2 LimitToRolesForTicket Ticket_ID
213
214 Limits the set of groups found to role groups for Ticket Ticket_ID
215
216 =cut
217
218 sub LimitToRolesForTicket {
219     my $self = shift;
220     my $Ticket = shift;
221     $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'RT::Ticket-Role');
222     $self->Limit(FIELD => 'Instance', OPERATOR => '=', VALUE => '$Ticket');
223 }
224
225 # }}}
226
227 # {{{ LimitToRolesForSystem
228
229 =head2 LimitToRolesForSystem System_ID
230
231 Limits the set of groups found to role groups for System System_ID
232
233 =cut
234
235 sub LimitToRolesForSystem {
236     my $self = shift;
237     $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'RT::System-Role');
238 }
239
240 # }}}
241
242 =head2 WithMember {PrincipalId => PRINCIPAL_ID, Recursively => undef}
243
244 Limits the set of groups returned to groups which have
245 Principal PRINCIPAL_ID as a member
246
247 =cut
248
249 sub WithMember {
250     my $self = shift;
251     my %args = ( PrincipalId => undef,
252                  Recursively => undef,
253                  @_);
254     my $members;
255
256     if ($args{'Recursively'}) {
257         $members = $self->NewAlias('CachedGroupMembers');
258     } else {
259         $members = $self->NewAlias('GroupMembers');
260     }
261     $self->Join(ALIAS1 => 'main', FIELD1 => 'id',
262                 ALIAS2 => $members, FIELD2 => 'GroupId');
263
264     $self->Limit(ALIAS => $members, FIELD => 'MemberId', OPERATOR => '=', VALUE => $args{'PrincipalId'});
265 }
266
267 sub WithoutMember {
268     my $self = shift;
269     my %args = (
270         PrincipalId => undef,
271         Recursively => undef,
272         @_
273     );
274
275     my $members = $args{'Recursively'} ? 'CachedGroupMembers' : 'GroupMembers';
276     my $members_alias = $self->Join(
277         TYPE   => 'LEFT',
278         FIELD1 => 'id',
279         TABLE2 => $members,
280         FIELD2 => 'GroupId',
281     );
282     $self->Limit(
283         LEFTJOIN => $members_alias,
284         ALIAS    => $members_alias,
285         FIELD    => 'MemberId',
286         OPERATOR => '=',
287         VALUE    => $args{'PrincipalId'},
288     );
289     $self->Limit(
290         ALIAS    => $members_alias,
291         FIELD    => 'MemberId',
292         OPERATOR => 'IS',
293         VALUE    => 'NULL',
294         QUOTEVALUE => 0,
295     );
296 }
297
298 =head2 WithRight { Right => RIGHTNAME, Object => RT::Record, IncludeSystemRights => 1, IncludeSuperusers => 0, EquivObjects => [ ] }
299
300
301 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.
302
303
304
305 =cut
306
307 #XXX: should be generilized
308 sub WithRight {
309     my $self = shift;
310     my %args = ( Right                  => undef,
311                  Object =>              => undef,
312                  IncludeSystemRights    => 1,
313                  IncludeSuperusers      => undef,
314                  IncludeSubgroupMembers => 0,
315                  EquivObjects           => [ ],
316                  @_ );
317
318     my $from_role = $self->Clone;
319     $from_role->WithRoleRight( %args );
320
321     my $from_group = $self->Clone;
322     $from_group->WithGroupRight( %args );
323
324     #XXX: DIRTY HACK
325     use DBIx::SearchBuilder::Union;
326     my $union = new DBIx::SearchBuilder::Union;
327     $union->add($from_role);
328     $union->add($from_group);
329     %$self = %$union;
330     bless $self, ref($union);
331
332     return;
333 }
334
335 #XXX: methods are active aliases to Users class to prevent code duplication
336 # should be generalized
337 sub _JoinGroups {
338     my $self = shift;
339     my %args = (@_);
340     return 'main' unless $args{'IncludeSubgroupMembers'};
341     return $self->RT::Users::_JoinGroups( %args );
342 }
343 sub _JoinGroupMembers {
344     my $self = shift;
345     my %args = (@_);
346     return 'main' unless $args{'IncludeSubgroupMembers'};
347     return $self->RT::Users::_JoinGroupMembers( %args );
348 }
349 sub _JoinGroupMembersForGroupRights {
350     my $self = shift;
351     my %args = (@_);
352     my $group_members = $self->_JoinGroupMembers( %args );
353     unless( $group_members eq 'main' ) {
354         return $self->RT::Users::_JoinGroupMembersForGroupRights( %args );
355     }
356     $self->Limit( ALIAS => $args{'ACLAlias'},
357                   FIELD => 'PrincipalId',
358                   VALUE => "main.id",
359                   QUOTEVALUE => 0,
360                 );
361 }
362 sub _JoinACL                  { return (shift)->RT::Users::_JoinACL( @_ ) }
363 sub _RoleClauses              { return (shift)->RT::Users::_RoleClauses( @_ ) }
364 sub _WhoHaveRoleRightSplitted { return (shift)->RT::Users::_WhoHaveRoleRightSplitted( @_ ) }
365 sub _GetEquivObjects          { return (shift)->RT::Users::_GetEquivObjects( @_ ) }
366 sub WithGroupRight            { return (shift)->RT::Users::WhoHaveGroupRight( @_ ) }
367 sub WithRoleRight             { return (shift)->RT::Users::WhoHaveRoleRight( @_ ) }
368
369 # {{{ sub LimitToEnabled
370
371 =head2 LimitToEnabled
372
373 Only find items that haven\'t been disabled
374
375 =cut
376
377 sub LimitToEnabled {
378     my $self = shift;
379     
380     $self->Limit( ALIAS => $self->PrincipalsAlias,
381                           FIELD => 'Disabled',
382                           VALUE => '0',
383                           OPERATOR => '=',
384                 );
385 }
386 # }}}
387
388 # {{{ sub LimitToDisabled
389
390 =head2 LimitToDeleted
391
392 Only find items that have been deleted.
393
394 =cut
395
396 sub LimitToDeleted {
397     my $self = shift;
398     
399     $self->{'find_disabled_rows'} = 1;
400     $self->Limit( ALIAS => $self->PrincipalsAlias,
401                   FIELD => 'Disabled',
402                   OPERATOR => '=',
403                   VALUE => 1,
404                 );
405 }
406 # }}}
407
408 # {{{ sub Next
409
410 sub Next {
411     my $self = shift;
412
413     # Don't show groups which the user isn't allowed to see.
414
415     my $Group = $self->SUPER::Next();
416     if ((defined($Group)) and (ref($Group))) {
417         unless ($Group->CurrentUserHasRight('SeeGroup')) {
418             return $self->Next();
419         }
420         
421         return $Group;
422     }
423     else {
424         return undef;
425     }
426 }
427
428
429
430 sub _DoSearch {
431     my $self = shift;
432     
433     #unless we really want to find disabled rows, make sure we\'re only finding enabled ones.
434     unless($self->{'find_disabled_rows'}) {
435         $self->LimitToEnabled();
436     }
437     
438     return($self->SUPER::_DoSearch(@_));
439     
440 }
441
442 1;
443