3 # Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
5 # (Except where explictly superceded by other copyright notices)
7 # This work is made available to you under the terms of Version 2 of
8 # the GNU General Public License. A copy of that license should have
9 # been provided with this software, but in any event can be snarfed
12 # This work is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 # General Public License for more details.
17 # Unless otherwise specified, all modifications, corrections or
18 # extensions to this work which alter its source code become the
19 # property of Best Practical Solutions, LLC when submitted for
20 # inclusion in the work.
25 no warnings qw(redefine);
29 =item Create PARAMHASH
31 Create takes a hash of values and creates a row in the database:
33 'Group' is the "top level" group we're building the cache for. This is an
36 'Member' is the RT::Principal of the user or group we're adding
39 'ImmediateParent' is the RT::Principal of the group that this principal
40 belongs to to get here
42 int(11) 'Via' is an internal reference to CachedGroupMembers->Id of
43 the "parent" record of this cached group member. It should be empty if this
44 member is a "direct" member of this group. (In that case, it will be set to this
45 cached group member's id after creation)
47 This routine should _only_ be called by GroupMember->Create
53 my %args = ( Group => '',
55 ImmediateParent => '',
60 unless ( $args{'Member'}
61 && UNIVERSAL::isa( $args{'Member'}, 'RT::Principal' )
62 && $args{'Member'}->Id ) {
63 $RT::Logger->debug("$self->Create: bogus Member argument");
66 unless ( $args{'Group'}
67 && UNIVERSAL::isa( $args{'Group'}, 'RT::Principal' )
68 && $args{'Group'}->Id ) {
69 $RT::Logger->debug("$self->Create: bogus Group argument");
72 unless ( $args{'ImmediateParent'}
73 && UNIVERSAL::isa( $args{'ImmediateParent'}, 'RT::Principal' )
74 && $args{'ImmediateParent'}->Id ) {
75 $RT::Logger->debug("$self->Create: bogus ImmediateParent argument");
78 # If the parent group for this group member is disabled, it's disabled too, along with all its children
79 if ( $args{'ImmediateParent'}->Disabled ) {
80 $args{'Disabled'} = $args{'ImmediateParent'}->Disabled;
83 my $id = $self->SUPER::Create(
84 GroupId => $args{'Group'}->Id,
85 MemberId => $args{'Member'}->Id,
86 ImmediateParentId => $args{'ImmediateParent'}->Id,
87 Disabled => $args{'Disabled'},
88 Via => $args{'Via'}, );
91 $RT::Logger->warning( "Couldn't create "
93 . " as a cached member of "
94 . $args{'Group'}->Id . " via "
96 return (undef); #this will percolate up and bail out of the transaction
98 if ( $self->__Value('Via') == 0 ) {
99 my ( $vid, $vmsg ) = $self->__Set( Field => 'Via', Value => $id );
101 $RT::Logger->warning( "Due to a via error, couldn't create "
103 . " as a cached member of "
104 . $args{'Group'}->Id . " via "
107 ; #this will percolate up and bail out of the transaction
111 if ( $args{'Member'}->IsGroup() ) {
112 my $GroupMembers = $args{'Member'}->Object->MembersObj();
113 while ( my $member = $GroupMembers->Next() ) {
115 RT::CachedGroupMember->new( $self->CurrentUser );
116 my $c_id = $cached_member->Create(
117 Group => $args{'Group'},
118 Member => $member->MemberObj,
119 ImmediateParent => $args{'Member'},
120 Disabled => $args{'Disabled'},
123 return (undef); #percolate the error upwards.
124 # the caller will log an error and abort the transaction
140 Deletes the current CachedGroupMember from the group it's in and cascades
141 the delete to all submembers. This routine could be completely excised if
142 mysql supported foreign keys with cascading deletes.
150 my $member = $self->MemberObj();
151 if ( $member->IsGroup ) {
152 my $deletable = RT::CachedGroupMembers->new( $self->CurrentUser );
154 $deletable->Limit( FIELD => 'id',
156 VALUE => $self->id );
157 $deletable->Limit( FIELD => 'Via',
159 VALUE => $self->id );
161 while ( my $kid = $deletable->Next ) {
162 my $kid_err = $kid->Delete();
165 "Couldn't delete CachedGroupMember " . $kid->Id );
170 my $err = $self->SUPER::Delete();
172 $RT::Logger->error( "Couldn't delete CachedGroupMember " . $self->Id );
176 # Unless $self->GroupObj still has the member recursively $self->MemberObj
177 # (Since we deleted the database row above, $self no longer counts)
178 unless ( $self->GroupObj->Object->HasMemberRecursively( $self->MemberObj ) ) {
181 # Find all ACEs granted to $self->GroupId
182 my $acl = RT::ACL->new($RT::SystemUser);
183 $acl->LimitToPrincipal( Id => $self->GroupId );
186 while ( my $this_ace = $acl->Next() ) {
187 # Find all ACEs which $self-MemberObj has delegated from $this_ace
188 my $delegations = RT::ACL->new($RT::SystemUser);
189 $delegations->DelegatedFrom( Id => $this_ace->Id );
190 $delegations->DelegatedBy( Id => $self->MemberId );
192 # For each delegation
193 while ( my $delegation = $delegations->Next ) {
195 my $del_ret = $delegation->_Delete(InsideTransaction => 1);
197 $RT::Logger->crit("Couldn't delete an ACL delegation that we know exists ". $delegation->Id);
212 SetDisableds the current CachedGroupMember from the group it's in and cascades
213 the SetDisabled to all submembers. This routine could be completely excised if
214 mysql supported foreign keys with cascading SetDisableds.
222 my $err = $self->SUPER::SetDisabled($val);
224 $RT::Logger->error( "Couldn't SetDisabled CachedGroupMember " . $self->Id );
228 my $member = $self->MemberObj();
229 if ( $member->IsGroup ) {
230 my $deletable = RT::CachedGroupMembers->new( $self->CurrentUser );
232 $deletable->Limit( FIELD => 'Via', OPERATOR => '=', VALUE => $self->id );
233 $deletable->Limit( FIELD => 'id', OPERATOR => '!=', VALUE => $self->id );
235 while ( my $kid = $deletable->Next ) {
236 my $kid_err = $kid->SetDisabled($val );
238 $RT::Logger->error( "Couldn't SetDisabled CachedGroupMember " . $kid->Id );
244 # Unless $self->GroupObj still has the member recursively $self->MemberObj
245 # (Since we SetDisabledd the database row above, $self no longer counts)
246 unless ( $self->GroupObj->Object->HasMemberRecursively( $self->MemberObj ) ) {
247 # Find all ACEs granted to $self->GroupId
248 my $acl = RT::ACL->new($RT::SystemUser);
249 $acl->LimitToPrincipal( Id => $self->GroupId );
251 while ( my $this_ace = $acl->Next() ) {
252 # Find all ACEs which $self-MemberObj has delegated from $this_ace
253 my $delegations = RT::ACL->new($RT::SystemUser);
254 $delegations->DelegatedFrom( Id => $this_ace->Id );
255 $delegations->DelegatedBy( Id => $self->MemberId );
257 # For each delegation, blow away the delegation
258 while ( my $delegation = $delegations->Next ) {
260 my $del_ret = $delegation->_Delete(InsideTransaction => 1);
262 $RT::Logger->crit("Couldn't delete an ACL delegation that we know exists ". $delegation->Id);
277 Returns the RT::Principal object for this group Group
283 my $principal = RT::Principal->new( $self->CurrentUser );
284 $principal->Load( $self->GroupId );
290 # {{{ ImmediateParentObj
292 =head2 ImmediateParentObj
294 Returns the RT::Principal object for this group ImmediateParent
298 sub ImmediateParentObj {
300 my $principal = RT::Principal->new( $self->CurrentUser );
301 $principal->Load( $self->ImmediateParentId );
311 Returns the RT::Principal object for this group member
317 my $principal = RT::Principal->new( $self->CurrentUser );
318 $principal->Load( $self->MemberId );