X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=blobdiff_plain;f=rt%2Flib%2FRT%2FCachedGroupMember.pm;h=821b619bc42ceee4df77a6fadc0eb869a21644f3;hp=fc3e1bf0049e9674e94b29f5c6166baee87f7951;hb=187086c479a09629b7d180eec513fb7657f4e291;hpb=2041a9143fac20b79ead4a1ae01224dedf5b27c2 diff --git a/rt/lib/RT/CachedGroupMember.pm b/rt/lib/RT/CachedGroupMember.pm index fc3e1bf00..821b619bc 100644 --- a/rt/lib/RT/CachedGroupMember.pm +++ b/rt/lib/RT/CachedGroupMember.pm @@ -1,123 +1,339 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2018 Best Practical Solutions, LLC +# +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK -# Autogenerated by DBIx::SearchBuilder factory (by ) -# WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST. -# -# !! DO NOT EDIT THIS FILE !! # +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +package RT::CachedGroupMember; use strict; +use warnings; -=head1 NAME +use base 'RT::Record'; -RT::CachedGroupMember +sub Table {'CachedGroupMembers'} +=head1 NAME + + RT::CachedGroupMember =head1 SYNOPSIS + use RT::CachedGroupMember; + =head1 DESCRIPTION =head1 METHODS =cut -package RT::CachedGroupMember; -use RT::Record; +# {{ Create + +=head2 Create PARAMHASH +Create takes a hash of values and creates a row in the database: + + 'Group' is the "top level" group we're building the cache for. This + is an RT::Principal object + + 'Member' is the RT::Principal of the user or group we're adding to + the cache. + + 'ImmediateParent' is the RT::Principal of the group that this + principal belongs to to get here + + int(11) 'Via' is an internal reference to CachedGroupMembers->Id of + the "parent" record of this cached group member. It should be empty if + this member is a "direct" member of this group. (In that case, it will + be set to this cached group member's id after creation) -use vars qw( @ISA ); -@ISA= qw( RT::Record ); + This routine should _only_ be called by GroupMember->Create -sub _Init { - my $self = shift; +=cut + +sub Create { + my $self = shift; + my %args = ( Group => '', + Member => '', + ImmediateParent => '', + Via => '0', + Disabled => '0', + @_ ); + + unless ( $args{'Member'} + && UNIVERSAL::isa( $args{'Member'}, 'RT::Principal' ) + && $args{'Member'}->Id ) { + $RT::Logger->debug("$self->Create: bogus Member argument"); + } + + unless ( $args{'Group'} + && UNIVERSAL::isa( $args{'Group'}, 'RT::Principal' ) + && $args{'Group'}->Id ) { + $RT::Logger->debug("$self->Create: bogus Group argument"); + } + + unless ( $args{'ImmediateParent'} + && UNIVERSAL::isa( $args{'ImmediateParent'}, 'RT::Principal' ) + && $args{'ImmediateParent'}->Id ) { + $RT::Logger->debug("$self->Create: bogus ImmediateParent argument"); + } + + # If the parent group for this group member is disabled, it's disabled too, along with all its children + if ( $args{'ImmediateParent'}->Disabled ) { + $args{'Disabled'} = $args{'ImmediateParent'}->Disabled; + } + + my $id = $self->SUPER::Create( + GroupId => $args{'Group'}->Id, + MemberId => $args{'Member'}->Id, + ImmediateParentId => $args{'ImmediateParent'}->Id, + Disabled => $args{'Disabled'}, + Via => $args{'Via'}, ); + + unless ($id) { + $RT::Logger->warning( "Couldn't create " + . $args{'Member'} + . " as a cached member of " + . $args{'Group'}->Id . " via " + . $args{'Via'} ); + return (undef); #this will percolate up and bail out of the transaction + } + if ( $self->__Value('Via') == 0 ) { + my ( $vid, $vmsg ) = $self->__Set( Field => 'Via', Value => $id ); + unless ($vid) { + $RT::Logger->warning( "Due to a via error, couldn't create " + . $args{'Member'} + . " as a cached member of " + . $args{'Group'}->Id . " via " + . $args{'Via'} ); + return (undef) + ; #this will percolate up and bail out of the transaction + } + } + + return $id if $args{'Member'}->id == $args{'Group'}->id; + + if ( $args{'Member'}->IsGroup() ) { + my $GroupMembers = $args{'Member'}->Object->MembersObj(); + while ( my $member = $GroupMembers->Next() ) { + my $cached_member = + RT::CachedGroupMember->new( $self->CurrentUser ); + my $c_id = $cached_member->Create( + Group => $args{'Group'}, + Member => $member->MemberObj, + ImmediateParent => $args{'Member'}, + Disabled => $args{'Disabled'}, + Via => $id ); + unless ($c_id) { + return (undef); #percolate the error upwards. + # the caller will log an error and abort the transaction + } + + } + } + + return ($id); - $self->Table('CachedGroupMembers'); - $self->SUPER::_Init(@_); } +=head2 Delete +Deletes the current CachedGroupMember from the group it's in and cascades +the delete to all submembers. This routine could be completely excised if +mysql supported foreign keys with cascading deletes. -=item Create PARAMHASH +=cut -Create takes a hash of values and creates a row in the database: +sub Delete { + my $self = shift; - int(11) 'GroupId'. - int(11) 'MemberId'. - int(11) 'Via'. - int(11) 'ImmediateParentId'. - smallint(6) 'Disabled'. + + my $member = $self->MemberObj(); + if ( $member->IsGroup ) { + my $deletable = RT::CachedGroupMembers->new( $self->CurrentUser ); + + $deletable->Limit( FIELD => 'id', + OPERATOR => '!=', + VALUE => $self->id ); + $deletable->Limit( FIELD => 'Via', + OPERATOR => '=', + VALUE => $self->id ); + + while ( my $kid = $deletable->Next ) { + my $kid_err = $kid->Delete(); + unless ($kid_err) { + $RT::Logger->error( + "Couldn't delete CachedGroupMember " . $kid->Id ); + return (undef); + } + } + } + my $ret = $self->SUPER::Delete(); + unless ($ret) { + $RT::Logger->error( "Couldn't delete CachedGroupMember " . $self->Id ); + return (undef); + } + return $ret; +} -=cut +=head2 SetDisabled +SetDisableds the current CachedGroupMember from the group it's in and cascades +the SetDisabled to all submembers. This routine could be completely excised if +mysql supported foreign keys with cascading SetDisableds. -sub Create { +=cut + +sub SetDisabled { my $self = shift; - my %args = ( - GroupId => '', - MemberId => '', - Via => '', - ImmediateParentId => '', - Disabled => '0', - - @_); - $self->SUPER::Create( - GroupId => $args{'GroupId'}, - MemberId => $args{'MemberId'}, - Via => $args{'Via'}, - ImmediateParentId => $args{'ImmediateParentId'}, - Disabled => $args{'Disabled'}, -); + my $val = shift; + + # if it's already disabled, we're good. + return (1) if ( $self->__Value('Disabled') == $val); + my $err = $self->_Set(Field => 'Disabled', Value => $val); + my ($retval, $msg) = $err->as_array(); + unless ($retval) { + $RT::Logger->error( "Couldn't SetDisabled CachedGroupMember " . $self->Id .": $msg"); + return ($err); + } + + my $member = $self->MemberObj(); + if ( $member->IsGroup ) { + my $deletable = RT::CachedGroupMembers->new( $self->CurrentUser ); + + $deletable->Limit( FIELD => 'Via', OPERATOR => '=', VALUE => $self->id ); + $deletable->Limit( FIELD => 'id', OPERATOR => '!=', VALUE => $self->id ); + + while ( my $kid = $deletable->Next ) { + my $kid_err = $kid->SetDisabled($val ); + unless ($kid_err) { + $RT::Logger->error( "Couldn't SetDisabled CachedGroupMember " . $kid->Id ); + return ($kid_err); + } + } + } + return ($err); +} + + + +=head2 GroupObj + +Returns the RT::Principal object for this group Group +=cut + +sub GroupObj { + my $self = shift; + my $principal = RT::Principal->new( $self->CurrentUser ); + $principal->Load( $self->GroupId ); + return ($principal); +} + + + +=head2 ImmediateParentObj + +Returns the RT::Principal object for this group ImmediateParent + +=cut + +sub ImmediateParentObj { + my $self = shift; + my $principal = RT::Principal->new( $self->CurrentUser ); + $principal->Load( $self->ImmediateParentId ); + return ($principal); } -=item id +=head2 MemberObj + +Returns the RT::Principal object for this group member + +=cut + +sub MemberObj { + my $self = shift; + my $principal = RT::Principal->new( $self->CurrentUser ); + $principal->Load( $self->MemberId ); + return ($principal); +} + +# }}} + + + + -Returns the current value of id. + +=head2 id + +Returns the current value of id. (In the database, id is stored as int(11).) =cut -=item GroupId +=head2 GroupId -Returns the current value of GroupId. +Returns the current value of GroupId. (In the database, GroupId is stored as int(11).) -=item SetGroupId VALUE +=head2 SetGroupId VALUE -Set GroupId to VALUE. +Set GroupId to VALUE. Returns (1, 'Status message') on success and (0, 'Error Message') on failure. (In the database, GroupId will be stored as a int(11).) @@ -125,17 +341,17 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item MemberId +=head2 MemberId -Returns the current value of MemberId. +Returns the current value of MemberId. (In the database, MemberId is stored as int(11).) -=item SetMemberId VALUE +=head2 SetMemberId VALUE -Set MemberId to VALUE. +Set MemberId to VALUE. Returns (1, 'Status message') on success and (0, 'Error Message') on failure. (In the database, MemberId will be stored as a int(11).) @@ -143,17 +359,17 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Via +=head2 Via -Returns the current value of Via. +Returns the current value of Via. (In the database, Via is stored as int(11).) -=item SetVia VALUE +=head2 SetVia VALUE -Set Via to VALUE. +Set Via to VALUE. Returns (1, 'Status message') on success and (0, 'Error Message') on failure. (In the database, Via will be stored as a int(11).) @@ -161,17 +377,17 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item ImmediateParentId +=head2 ImmediateParentId -Returns the current value of ImmediateParentId. +Returns the current value of ImmediateParentId. (In the database, ImmediateParentId is stored as int(11).) -=item SetImmediateParentId VALUE +=head2 SetImmediateParentId VALUE -Set ImmediateParentId to VALUE. +Set ImmediateParentId to VALUE. Returns (1, 'Status message') on success and (0, 'Error Message') on failure. (In the database, ImmediateParentId will be stored as a int(11).) @@ -179,17 +395,17 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Disabled +=head2 Disabled -Returns the current value of Disabled. +Returns the current value of Disabled. (In the database, Disabled is stored as smallint(6).) -=item SetDisabled VALUE +=head2 SetDisabled VALUE -Set Disabled to VALUE. +Set Disabled to VALUE. Returns (1, 'Status message') on success and (0, 'Error Message') on failure. (In the database, Disabled will be stored as a smallint(6).) @@ -198,61 +414,68 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. -sub _ClassAccessible { +sub _CoreAccessible { { - + id => - {read => 1, type => 'int(11)', default => ''}, - GroupId => - {read => 1, write => 1, type => 'int(11)', default => ''}, - MemberId => - {read => 1, write => 1, type => 'int(11)', default => ''}, - Via => - {read => 1, write => 1, type => 'int(11)', default => ''}, - ImmediateParentId => - {read => 1, write => 1, type => 'int(11)', default => ''}, - Disabled => - {read => 1, write => 1, type => 'smallint(6)', default => '0'}, + {read => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''}, + GroupId => + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''}, + MemberId => + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''}, + Via => + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''}, + ImmediateParentId => + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''}, + Disabled => + {read => 1, write => 1, sql_type => 5, length => 6, is_blob => 0, is_numeric => 1, type => 'smallint(6)', default => '0'}, } }; +sub Serialize { + die "CachedGroupMembers should never be serialized"; +} - eval "require RT::CachedGroupMember_Overlay"; - if ($@ && $@ !~ qr{^Can't locate RT/CachedGroupMember_Overlay.pm}) { - die $@; - }; - - eval "require RT::CachedGroupMember_Vendor"; - if ($@ && $@ !~ qr{^Can't locate RT/CachedGroupMember_Vendor.pm}) { - die $@; - }; - - eval "require RT::CachedGroupMember_Local"; - if ($@ && $@ !~ qr{^Can't locate RT/CachedGroupMember_Local.pm}) { - die $@; - }; - - - - -=head1 SEE ALSO - -This class allows "overlay" methods to be placed -into the following files _Overlay is for a System overlay by the original author, -_Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customizations. - -These overlay files can contain new subs or subs to replace existing subs in this module. - -If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line - - no warnings qw(redefine); - -so that perl does not kick and scream when you redefine a subroutine or variable in your overlay. - -RT::CachedGroupMember_Overlay, RT::CachedGroupMember_Vendor, RT::CachedGroupMember_Local - -=cut +sub __DependsOn +{ + my $self = shift; + my %args = ( + Shredder => undef, + Dependencies => undef, + @_, + ); + my $deps = $args{'Dependencies'}; + my $list = []; + +# deep memebership + my $objs = RT::CachedGroupMembers->new( $self->CurrentUser ); + $objs->Limit( FIELD => 'Via', VALUE => $self->Id ); + $objs->Limit( FIELD => 'id', OPERATOR => '!=', VALUE => $self->Id ); + push( @$list, $objs ); + +# principal lost group membership and lost some rights which he could delegate to +# some body + +# XXX: Here is problem cause HasMemberRecursively would return true allways +# cause we didn't delete anything yet. :( + # if pricipal is not member anymore(could be via other groups) then proceed + if( $self->GroupObj->Object->HasMemberRecursively( $self->MemberObj ) ) { + my $acl = RT::ACL->new( $self->CurrentUser ); + $acl->LimitToPrincipal( Id => $self->GroupId ); + } + + + $deps->_PushDependencies( + BaseObject => $self, + Flags => RT::Shredder::Constants::DEPENDS_ON, + TargetObjects => $list, + Shredder => $args{'Shredder'} + ); + + return $self->SUPER::__DependsOn( %args ); +} +RT::Base->_ImportOverlays(); 1;