Crontol standalone
[usit-rt.git] / lib / RT / CachedGroupMember.pm
CommitLineData
84fb5b46
MKG
1# BEGIN BPS TAGGED BLOCK {{{
2#
3# COPYRIGHT:
4#
403d7b0b 5# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
84fb5b46
MKG
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
49package RT::CachedGroupMember;
50
51use strict;
52use warnings;
53
54
55use base 'RT::Record';
56
57sub Table {'CachedGroupMembers'}
58
59=head1 NAME
60
61 RT::CachedGroupMember
62
63=head1 SYNOPSIS
64
65 use RT::CachedGroupMember;
66
67=head1 DESCRIPTION
68
69=head1 METHODS
70
71=cut
72
73# {{ Create
74
75=head2 Create PARAMHASH
76
77Create takes a hash of values and creates a row in the database:
78
79 'Group' is the "top level" group we're building the cache for. This
80 is an RT::Principal object
81
82 'Member' is the RT::Principal of the user or group we're adding to
83 the cache.
84
85 'ImmediateParent' is the RT::Principal of the group that this
86 principal belongs to to get here
87
88 int(11) 'Via' is an internal reference to CachedGroupMembers->Id of
89 the "parent" record of this cached group member. It should be empty if
90 this member is a "direct" member of this group. (In that case, it will
91 be set to this cached group member's id after creation)
92
93 This routine should _only_ be called by GroupMember->Create
94
95=cut
96
97sub Create {
98 my $self = shift;
99 my %args = ( Group => '',
100 Member => '',
101 ImmediateParent => '',
102 Via => '0',
103 Disabled => '0',
104 @_ );
105
106 unless ( $args{'Member'}
107 && UNIVERSAL::isa( $args{'Member'}, 'RT::Principal' )
108 && $args{'Member'}->Id ) {
109 $RT::Logger->debug("$self->Create: bogus Member argument");
110 }
111
112 unless ( $args{'Group'}
113 && UNIVERSAL::isa( $args{'Group'}, 'RT::Principal' )
114 && $args{'Group'}->Id ) {
115 $RT::Logger->debug("$self->Create: bogus Group argument");
116 }
117
118 unless ( $args{'ImmediateParent'}
119 && UNIVERSAL::isa( $args{'ImmediateParent'}, 'RT::Principal' )
120 && $args{'ImmediateParent'}->Id ) {
121 $RT::Logger->debug("$self->Create: bogus ImmediateParent argument");
122 }
123
124 # If the parent group for this group member is disabled, it's disabled too, along with all its children
125 if ( $args{'ImmediateParent'}->Disabled ) {
126 $args{'Disabled'} = $args{'ImmediateParent'}->Disabled;
127 }
128
129 my $id = $self->SUPER::Create(
130 GroupId => $args{'Group'}->Id,
131 MemberId => $args{'Member'}->Id,
132 ImmediateParentId => $args{'ImmediateParent'}->Id,
133 Disabled => $args{'Disabled'},
134 Via => $args{'Via'}, );
135
136 unless ($id) {
137 $RT::Logger->warning( "Couldn't create "
138 . $args{'Member'}
139 . " as a cached member of "
140 . $args{'Group'}->Id . " via "
141 . $args{'Via'} );
142 return (undef); #this will percolate up and bail out of the transaction
143 }
144 if ( $self->__Value('Via') == 0 ) {
145 my ( $vid, $vmsg ) = $self->__Set( Field => 'Via', Value => $id );
146 unless ($vid) {
147 $RT::Logger->warning( "Due to a via error, couldn't create "
148 . $args{'Member'}
149 . " as a cached member of "
150 . $args{'Group'}->Id . " via "
151 . $args{'Via'} );
152 return (undef)
153 ; #this will percolate up and bail out of the transaction
154 }
155 }
156
157 return $id if $args{'Member'}->id == $args{'Group'}->id;
158
159 if ( $args{'Member'}->IsGroup() ) {
160 my $GroupMembers = $args{'Member'}->Object->MembersObj();
161 while ( my $member = $GroupMembers->Next() ) {
162 my $cached_member =
163 RT::CachedGroupMember->new( $self->CurrentUser );
164 my $c_id = $cached_member->Create(
165 Group => $args{'Group'},
166 Member => $member->MemberObj,
167 ImmediateParent => $args{'Member'},
168 Disabled => $args{'Disabled'},
169 Via => $id );
170 unless ($c_id) {
171 return (undef); #percolate the error upwards.
172 # the caller will log an error and abort the transaction
173 }
174
175 }
176 }
177
178 return ($id);
179
180}
181
182
183
184=head2 Delete
185
186Deletes the current CachedGroupMember from the group it's in and cascades
187the delete to all submembers. This routine could be completely excised if
188mysql supported foreign keys with cascading deletes.
189
190=cut
191
192sub Delete {
193 my $self = shift;
194
195
196 my $member = $self->MemberObj();
197 if ( $member->IsGroup ) {
198 my $deletable = RT::CachedGroupMembers->new( $self->CurrentUser );
199
200 $deletable->Limit( FIELD => 'id',
201 OPERATOR => '!=',
202 VALUE => $self->id );
203 $deletable->Limit( FIELD => 'Via',
204 OPERATOR => '=',
205 VALUE => $self->id );
206
207 while ( my $kid = $deletable->Next ) {
208 my $kid_err = $kid->Delete();
209 unless ($kid_err) {
210 $RT::Logger->error(
211 "Couldn't delete CachedGroupMember " . $kid->Id );
212 return (undef);
213 }
214 }
215 }
216 my $ret = $self->SUPER::Delete();
217 unless ($ret) {
218 $RT::Logger->error( "Couldn't delete CachedGroupMember " . $self->Id );
219 return (undef);
220 }
221 return $ret;
222}
223
224
225
226=head2 SetDisabled
227
228SetDisableds the current CachedGroupMember from the group it's in and cascades
229the SetDisabled to all submembers. This routine could be completely excised if
230mysql supported foreign keys with cascading SetDisableds.
231
232=cut
233
234sub SetDisabled {
235 my $self = shift;
236 my $val = shift;
237
238 # if it's already disabled, we're good.
239 return (1) if ( $self->__Value('Disabled') == $val);
240 my $err = $self->_Set(Field => 'Disabled', Value => $val);
241 my ($retval, $msg) = $err->as_array();
242 unless ($retval) {
243 $RT::Logger->error( "Couldn't SetDisabled CachedGroupMember " . $self->Id .": $msg");
244 return ($err);
245 }
246
247 my $member = $self->MemberObj();
248 if ( $member->IsGroup ) {
249 my $deletable = RT::CachedGroupMembers->new( $self->CurrentUser );
250
251 $deletable->Limit( FIELD => 'Via', OPERATOR => '=', VALUE => $self->id );
252 $deletable->Limit( FIELD => 'id', OPERATOR => '!=', VALUE => $self->id );
253
254 while ( my $kid = $deletable->Next ) {
255 my $kid_err = $kid->SetDisabled($val );
256 unless ($kid_err) {
257 $RT::Logger->error( "Couldn't SetDisabled CachedGroupMember " . $kid->Id );
258 return ($kid_err);
259 }
260 }
261 }
262 return ($err);
263}
264
265
266
267=head2 GroupObj
268
269Returns the RT::Principal object for this group Group
270
271=cut
272
273sub GroupObj {
274 my $self = shift;
275 my $principal = RT::Principal->new( $self->CurrentUser );
276 $principal->Load( $self->GroupId );
277 return ($principal);
278}
279
280
281
282=head2 ImmediateParentObj
283
284Returns the RT::Principal object for this group ImmediateParent
285
286=cut
287
288sub ImmediateParentObj {
289 my $self = shift;
290 my $principal = RT::Principal->new( $self->CurrentUser );
291 $principal->Load( $self->ImmediateParentId );
292 return ($principal);
293}
294
295
296
297=head2 MemberObj
298
299Returns the RT::Principal object for this group member
300
301=cut
302
303sub MemberObj {
304 my $self = shift;
305 my $principal = RT::Principal->new( $self->CurrentUser );
306 $principal->Load( $self->MemberId );
307 return ($principal);
308}
309
310# }}}
311
312
313
314
315
316
317=head2 id
318
319Returns the current value of id.
320(In the database, id is stored as int(11).)
321
322
323=cut
324
325
326=head2 GroupId
327
328Returns the current value of GroupId.
329(In the database, GroupId is stored as int(11).)
330
331
332
333=head2 SetGroupId VALUE
334
335
336Set GroupId to VALUE.
337Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
338(In the database, GroupId will be stored as a int(11).)
339
340
341=cut
342
343
344=head2 MemberId
345
346Returns the current value of MemberId.
347(In the database, MemberId is stored as int(11).)
348
349
350
351=head2 SetMemberId VALUE
352
353
354Set MemberId to VALUE.
355Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
356(In the database, MemberId will be stored as a int(11).)
357
358
359=cut
360
361
362=head2 Via
363
364Returns the current value of Via.
365(In the database, Via is stored as int(11).)
366
367
368
369=head2 SetVia VALUE
370
371
372Set Via to VALUE.
373Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
374(In the database, Via will be stored as a int(11).)
375
376
377=cut
378
379
380=head2 ImmediateParentId
381
382Returns the current value of ImmediateParentId.
383(In the database, ImmediateParentId is stored as int(11).)
384
385
386
387=head2 SetImmediateParentId VALUE
388
389
390Set ImmediateParentId to VALUE.
391Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
392(In the database, ImmediateParentId will be stored as a int(11).)
393
394
395=cut
396
397
398=head2 Disabled
399
400Returns the current value of Disabled.
401(In the database, Disabled is stored as smallint(6).)
402
403
404
405=head2 SetDisabled VALUE
406
407
408Set Disabled to VALUE.
409Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
410(In the database, Disabled will be stored as a smallint(6).)
411
412
413=cut
414
415
416
417sub _CoreAccessible {
418 {
419
420 id =>
421 {read => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''},
422 GroupId =>
423 {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''},
424 MemberId =>
425 {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''},
426 Via =>
427 {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''},
428 ImmediateParentId =>
429 {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''},
430 Disabled =>
431 {read => 1, write => 1, sql_type => 5, length => 6, is_blob => 0, is_numeric => 1, type => 'smallint(6)', default => '0'},
432
433 }
434};
435
436RT::Base->_ImportOverlays();
437
4381;