1 # BEGIN BPS TAGGED BLOCK {{{
5 # This software is Copyright (c) 1996-2014 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 }}}
49 package RT::CachedGroupMember;
55 use base 'RT::Record';
57 sub Table {'CachedGroupMembers'}
65 use RT::CachedGroupMember;
75 =head2 Create PARAMHASH
77 Create takes a hash of values and creates a row in the database:
79 'Group' is the "top level" group we're building the cache for. This
80 is an RT::Principal object
82 'Member' is the RT::Principal of the user or group we're adding to
85 'ImmediateParent' is the RT::Principal of the group that this
86 principal belongs to to get here
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)
93 This routine should _only_ be called by GroupMember->Create
99 my %args = ( Group => '',
101 ImmediateParent => '',
106 unless ( $args{'Member'}
107 && UNIVERSAL::isa( $args{'Member'}, 'RT::Principal' )
108 && $args{'Member'}->Id ) {
109 $RT::Logger->debug("$self->Create: bogus Member argument");
112 unless ( $args{'Group'}
113 && UNIVERSAL::isa( $args{'Group'}, 'RT::Principal' )
114 && $args{'Group'}->Id ) {
115 $RT::Logger->debug("$self->Create: bogus Group argument");
118 unless ( $args{'ImmediateParent'}
119 && UNIVERSAL::isa( $args{'ImmediateParent'}, 'RT::Principal' )
120 && $args{'ImmediateParent'}->Id ) {
121 $RT::Logger->debug("$self->Create: bogus ImmediateParent argument");
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;
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'}, );
137 $RT::Logger->warning( "Couldn't create "
139 . " as a cached member of "
140 . $args{'Group'}->Id . " via "
142 return (undef); #this will percolate up and bail out of the transaction
144 if ( $self->__Value('Via') == 0 ) {
145 my ( $vid, $vmsg ) = $self->__Set( Field => 'Via', Value => $id );
147 $RT::Logger->warning( "Due to a via error, couldn't create "
149 . " as a cached member of "
150 . $args{'Group'}->Id . " via "
153 ; #this will percolate up and bail out of the transaction
157 return $id if $args{'Member'}->id == $args{'Group'}->id;
159 if ( $args{'Member'}->IsGroup() ) {
160 my $GroupMembers = $args{'Member'}->Object->MembersObj();
161 while ( my $member = $GroupMembers->Next() ) {
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'},
171 return (undef); #percolate the error upwards.
172 # the caller will log an error and abort the transaction
186 Deletes the current CachedGroupMember from the group it's in and cascades
187 the delete to all submembers. This routine could be completely excised if
188 mysql supported foreign keys with cascading deletes.
196 my $member = $self->MemberObj();
197 if ( $member->IsGroup ) {
198 my $deletable = RT::CachedGroupMembers->new( $self->CurrentUser );
200 $deletable->Limit( FIELD => 'id',
202 VALUE => $self->id );
203 $deletable->Limit( FIELD => 'Via',
205 VALUE => $self->id );
207 while ( my $kid = $deletable->Next ) {
208 my $kid_err = $kid->Delete();
211 "Couldn't delete CachedGroupMember " . $kid->Id );
216 my $ret = $self->SUPER::Delete();
218 $RT::Logger->error( "Couldn't delete CachedGroupMember " . $self->Id );
228 SetDisableds the current CachedGroupMember from the group it's in and cascades
229 the SetDisabled to all submembers. This routine could be completely excised if
230 mysql supported foreign keys with cascading SetDisableds.
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();
243 $RT::Logger->error( "Couldn't SetDisabled CachedGroupMember " . $self->Id .": $msg");
247 my $member = $self->MemberObj();
248 if ( $member->IsGroup ) {
249 my $deletable = RT::CachedGroupMembers->new( $self->CurrentUser );
251 $deletable->Limit( FIELD => 'Via', OPERATOR => '=', VALUE => $self->id );
252 $deletable->Limit( FIELD => 'id', OPERATOR => '!=', VALUE => $self->id );
254 while ( my $kid = $deletable->Next ) {
255 my $kid_err = $kid->SetDisabled($val );
257 $RT::Logger->error( "Couldn't SetDisabled CachedGroupMember " . $kid->Id );
269 Returns the RT::Principal object for this group Group
275 my $principal = RT::Principal->new( $self->CurrentUser );
276 $principal->Load( $self->GroupId );
282 =head2 ImmediateParentObj
284 Returns the RT::Principal object for this group ImmediateParent
288 sub ImmediateParentObj {
290 my $principal = RT::Principal->new( $self->CurrentUser );
291 $principal->Load( $self->ImmediateParentId );
299 Returns the RT::Principal object for this group member
305 my $principal = RT::Principal->new( $self->CurrentUser );
306 $principal->Load( $self->MemberId );
319 Returns the current value of id.
320 (In the database, id is stored as int(11).)
328 Returns the current value of GroupId.
329 (In the database, GroupId is stored as int(11).)
333 =head2 SetGroupId VALUE
336 Set GroupId to VALUE.
337 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
338 (In the database, GroupId will be stored as a int(11).)
346 Returns the current value of MemberId.
347 (In the database, MemberId is stored as int(11).)
351 =head2 SetMemberId VALUE
354 Set MemberId to VALUE.
355 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
356 (In the database, MemberId will be stored as a int(11).)
364 Returns the current value of Via.
365 (In the database, Via is stored as int(11).)
373 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
374 (In the database, Via will be stored as a int(11).)
380 =head2 ImmediateParentId
382 Returns the current value of ImmediateParentId.
383 (In the database, ImmediateParentId is stored as int(11).)
387 =head2 SetImmediateParentId VALUE
390 Set ImmediateParentId to VALUE.
391 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
392 (In the database, ImmediateParentId will be stored as a int(11).)
400 Returns the current value of Disabled.
401 (In the database, Disabled is stored as smallint(6).)
405 =head2 SetDisabled VALUE
408 Set Disabled to VALUE.
409 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
410 (In the database, Disabled will be stored as a smallint(6).)
417 sub _CoreAccessible {
421 {read => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''},
423 {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''},
425 {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''},
427 {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''},
429 {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''},
431 {read => 1, write => 1, sql_type => 5, length => 6, is_blob => 0, is_numeric => 1, type => 'smallint(6)', default => '0'},
436 RT::Base->_ImportOverlays();