X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=blobdiff_plain;f=rt%2Flib%2FRT%2FCachedGroupMember.pm;h=821b619bc42ceee4df77a6fadc0eb869a21644f3;hp=1c9188f62a98af8a1ca42635ccc61907d634a56d;hb=187086c479a09629b7d180eec513fb7657f4e291;hpb=b4b0c7e72d7eaee2fbfc7022022c9698323203dd diff --git a/rt/lib/RT/CachedGroupMember.pm b/rt/lib/RT/CachedGroupMember.pm index 1c9188f62..821b619bc 100644 --- a/rt/lib/RT/CachedGroupMember.pm +++ b/rt/lib/RT/CachedGroupMember.pm @@ -1,40 +1,40 @@ # BEGIN BPS TAGGED BLOCK {{{ -# +# # COPYRIGHT: -# -# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC -# -# +# +# 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. -# +# # 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 @@ -43,89 +43,280 @@ # 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 }}} -# Autogenerated by DBIx::SearchBuilder factory (by ) -# WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST. -# -# !! DO NOT EDIT THIS FILE !! -# +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 -use vars qw( @ISA ); -@ISA= qw( RT::Record ); + 'Member' is the RT::Principal of the user or group we're adding to + the cache. -sub _Init { - my $self = shift; + '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) + + This routine should _only_ be called by GroupMember->Create + +=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. -=head2 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); } +=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); +} + +# }}} + + + + + + =head2 id -Returns the current value of id. +Returns the current value of id. (In the database, id is stored as int(11).) @@ -134,7 +325,7 @@ Returns the current value of id. =head2 GroupId -Returns the current value of GroupId. +Returns the current value of GroupId. (In the database, GroupId is stored as int(11).) @@ -142,7 +333,7 @@ Returns the current value of GroupId. =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).) @@ -152,7 +343,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =head2 MemberId -Returns the current value of MemberId. +Returns the current value of MemberId. (In the database, MemberId is stored as int(11).) @@ -160,7 +351,7 @@ Returns the current value of MemberId. =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).) @@ -170,7 +361,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =head2 Via -Returns the current value of Via. +Returns the current value of Via. (In the database, Via is stored as int(11).) @@ -178,7 +369,7 @@ Returns the current value of Via. =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).) @@ -188,7 +379,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =head2 ImmediateParentId -Returns the current value of ImmediateParentId. +Returns the current value of ImmediateParentId. (In the database, ImmediateParentId is stored as int(11).) @@ -196,7 +387,7 @@ Returns the current value of ImmediateParentId. =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).) @@ -206,7 +397,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =head2 Disabled -Returns the current value of Disabled. +Returns the current value of Disabled. (In the database, Disabled is stored as smallint(6).) @@ -214,7 +405,7 @@ Returns the current value of Disabled. =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).) @@ -225,59 +416,66 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. sub _CoreAccessible { { - + id => - {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'}, + {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. - -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;