X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=rt%2Flib%2FRT%2FGroups.pm;h=c2348584e0ca7aa4df50c8c2b510e59a8b1de7fb;hb=b8988e1d3ac75af63c85e8563e57701030315a9e;hp=f44f1fdb3b39fb3d59f2ab8dc24adbe2a55ad0ae;hpb=c0567c688084e89fcd11bf82348b6c418f1254ac;p=freeside.git diff --git a/rt/lib/RT/Groups.pm b/rt/lib/RT/Groups.pm index f44f1fdb3..c2348584e 100755 --- a/rt/lib/RT/Groups.pm +++ b/rt/lib/RT/Groups.pm @@ -1,4 +1,50 @@ -#$Header: /home/cvs/cvsroot/freeside/rt/lib/RT/Groups.pm,v 1.1 2002-08-12 06:17:07 ivan Exp $ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2014 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 +# 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 }}} =head1 NAME @@ -7,8 +53,8 @@ =head1 SYNOPSIS use RT::Groups; - my $groups = $RT::Groups->new($CurrentUser); - $groups->LimitToReal(); + my $groups = RT::Groups->new($CurrentUser); + $groups->UnLimit(); while (my $group = $groups->Next()) { print $group->Id ." is a group id\n"; } @@ -19,82 +65,412 @@ =head1 METHODS -=begin testing - -ok (require RT::TestHarness); -ok (require RT::Groups); - -=end testing =cut + package RT::Groups; -use RT::EasySearch; -use RT::Groups; -@ISA= qw(RT::EasySearch); +use strict; +use warnings; + + + +use RT::Group; + +use base 'RT::SearchBuilder'; + +sub Table { 'Groups'} + +use RT::Users; + +# XXX: below some code is marked as subject to generalize in Groups, Users classes. +# RUZ suggest name Principals::Generic or Principals::Base as abstract class, but +# Jesse wants something that doesn't imply it's a Principals.pm subclass. +# See comments below for candidats. + -# {{{ sub _Init sub _Init { my $self = shift; - $self->{'table'} = "Groups"; - $self->{'primary_key'} = "id"; + $self->{'with_disabled_column'} = 1; + + my @result = $self->SUPER::_Init(@_); $self->OrderBy( ALIAS => 'main', FIELD => 'Name', ORDER => 'ASC'); + # XXX: this code should be generalized + $self->{'princalias'} = $self->Join( + ALIAS1 => 'main', + FIELD1 => 'id', + TABLE2 => 'Principals', + FIELD2 => 'id' + ); + + # even if this condition is useless and ids in the Groups table + # only match principals with type 'Group' this could speed up + # searches in some DBs. + $self->Limit( ALIAS => $self->{'princalias'}, + FIELD => 'PrincipalType', + VALUE => 'Group', + ); + + return (@result); +} + +=head2 PrincipalsAlias + +Returns the string that represents this Users object's primary "Principals" alias. + +=cut + +# XXX: should be generalized, code duplication +sub PrincipalsAlias { + my $self = shift; + return($self->{'princalias'}); - return ( $self->SUPER::_Init(@_)); } -# }}} -# {{{ LimitToReal -=head2 LimitToReal -Make this groups object return only "real" groups, which can be -granted rights and have members assigned to them +=head2 LimitToSystemInternalGroups + +Return only SystemInternal Groups, such as "privileged" "unprivileged" and "everyone" =cut -sub LimitToReal { + +sub LimitToSystemInternalGroups { my $self = shift; + $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'SystemInternal'); + # All system internal groups have the same instance. No reason to limit down further + #$self->Limit(FIELD => 'Instance', OPERATOR => '=', VALUE => '0'); +} + + + + +=head2 LimitToUserDefinedGroups + +Return only UserDefined Groups + +=cut - return ($self->Limit( FIELD => 'Pseudo', - VALUE => '0', - OPERATOR => '=')); +sub LimitToUserDefinedGroups { + my $self = shift; + $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'UserDefined'); + # All user-defined groups have the same instance. No reason to limit down further + #$self->Limit(FIELD => 'Instance', OPERATOR => '=', VALUE => ''); } -# }}} -# {{{ sub LimitToPseudo -=head2 LimitToPseudo -Make this groups object return only "pseudo" groups, which can be -granted rights but whose membership lists are determined dynamically. + +=head2 LimitToRolesForQueue QUEUE_ID + +Limits the set of groups found to role groups for queue QUEUE_ID =cut - - sub LimitToPseudo { + +sub LimitToRolesForQueue { my $self = shift; + my $queue = shift; + $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'RT::Queue-Role'); + $self->Limit(FIELD => 'Instance', OPERATOR => '=', VALUE => $queue); +} + + - return ($self->Limit( FIELD => 'Pseudo', - VALUE => '1', - OPERATOR => '=')); +=head2 LimitToRolesForTicket Ticket_ID +Limits the set of groups found to role groups for Ticket Ticket_ID + +=cut + +sub LimitToRolesForTicket { + my $self = shift; + my $Ticket = shift; + $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'RT::Ticket-Role'); + $self->Limit(FIELD => 'Instance', OPERATOR => '=', VALUE => '$Ticket'); } -# }}} -# {{{ sub NewItem -sub NewItem { - my $self = shift; - return (RT::Group->new($self->CurrentUser)); + + +=head2 LimitToRolesForSystem System_ID + +Limits the set of groups found to role groups for System System_ID + +=cut + +sub LimitToRolesForSystem { + my $self = shift; + $self->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => 'RT::System-Role'); } -# }}} -1; +=head2 WithMember {PrincipalId => PRINCIPAL_ID, Recursively => undef} + +Limits the set of groups returned to groups which have +Principal PRINCIPAL_ID as a member. Returns the alias used for the join. + +=cut + +sub WithMember { + my $self = shift; + my %args = ( PrincipalId => undef, + Recursively => undef, + @_); + my $members; + + if ($args{'Recursively'}) { + $members = $self->NewAlias('CachedGroupMembers'); + } else { + $members = $self->NewAlias('GroupMembers'); + } + $self->Join(ALIAS1 => 'main', FIELD1 => 'id', + ALIAS2 => $members, FIELD2 => 'GroupId'); + + $self->Limit(ALIAS => $members, FIELD => 'MemberId', OPERATOR => '=', VALUE => $args{'PrincipalId'}); + $self->Limit(ALIAS => $members, FIELD => 'Disabled', VALUE => 0) + if $args{'Recursively'}; + + return $members; +} + +sub WithoutMember { + my $self = shift; + my %args = ( + PrincipalId => undef, + Recursively => undef, + @_ + ); + + my $members = $args{'Recursively'} ? 'CachedGroupMembers' : 'GroupMembers'; + my $members_alias = $self->Join( + TYPE => 'LEFT', + FIELD1 => 'id', + TABLE2 => $members, + FIELD2 => 'GroupId', + ); + $self->Limit( + LEFTJOIN => $members_alias, + ALIAS => $members_alias, + FIELD => 'MemberId', + OPERATOR => '=', + VALUE => $args{'PrincipalId'}, + ); + $self->Limit( + LEFTJOIN => $members_alias, + ALIAS => $members_alias, + FIELD => 'Disabled', + VALUE => 0 + ) if $args{'Recursively'}; + $self->Limit( + ALIAS => $members_alias, + FIELD => 'MemberId', + OPERATOR => 'IS', + VALUE => 'NULL', + QUOTEVALUE => 0, + ); +} + +=head2 WithRight { Right => RIGHTNAME, Object => RT::Record, IncludeSystemRights => 1, IncludeSuperusers => 0, EquivObjects => [ ] } + + +Find all groups which have RIGHTNAME for RT::Record. Optionally include global rights and superusers. By default, include the global rights, but not the superusers. + + + +=cut + +#XXX: should be generilized +sub WithRight { + my $self = shift; + my %args = ( Right => undef, + Object => => undef, + IncludeSystemRights => 1, + IncludeSuperusers => undef, + IncludeSubgroupMembers => 0, + EquivObjects => [ ], + @_ ); + + my $from_role = $self->Clone; + $from_role->WithRoleRight( %args ); + + my $from_group = $self->Clone; + $from_group->WithGroupRight( %args ); + + #XXX: DIRTY HACK + use DBIx::SearchBuilder 1.50; #no version on ::Union :( + use DBIx::SearchBuilder::Union; + my $union = DBIx::SearchBuilder::Union->new(); + $union->add($from_role); + $union->add($from_group); + %$self = %$union; + bless $self, ref($union); + + return; +} + +#XXX: methods are active aliases to Users class to prevent code duplication +# should be generalized +sub _JoinGroups { + my $self = shift; + my %args = (@_); + return 'main' unless $args{'IncludeSubgroupMembers'}; + return $self->RT::Users::_JoinGroups( %args ); +} +sub _JoinGroupMembers { + my $self = shift; + my %args = (@_); + return 'main' unless $args{'IncludeSubgroupMembers'}; + return $self->RT::Users::_JoinGroupMembers( %args ); +} +sub _JoinGroupMembersForGroupRights { + my $self = shift; + my %args = (@_); + my $group_members = $self->_JoinGroupMembers( %args ); + unless( $group_members eq 'main' ) { + return $self->RT::Users::_JoinGroupMembersForGroupRights( %args ); + } + $self->Limit( ALIAS => $args{'ACLAlias'}, + FIELD => 'PrincipalId', + VALUE => "main.id", + QUOTEVALUE => 0, + ); +} +sub _JoinACL { return (shift)->RT::Users::_JoinACL( @_ ) } +sub _RoleClauses { return (shift)->RT::Users::_RoleClauses( @_ ) } +sub _WhoHaveRoleRightSplitted { return (shift)->RT::Users::_WhoHaveRoleRightSplitted( @_ ) } +sub _GetEquivObjects { return (shift)->RT::Users::_GetEquivObjects( @_ ) } +sub WithGroupRight { return (shift)->RT::Users::WhoHaveGroupRight( @_ ) } +sub WithRoleRight { return (shift)->RT::Users::WhoHaveRoleRight( @_ ) } + +sub ForWhichCurrentUserHasRight { + my $self = shift; + my %args = ( + Right => undef, + IncludeSuperusers => undef, + @_, + ); + + # Non-disabled groups... + $self->LimitToEnabled; + + # ...which are the target object of an ACL with that right, or + # where the target is the system object (a global right) + my $acl = $self->_JoinACL( %args ); + $self->_AddSubClause( + ACLObjects => "( (main.id = $acl.ObjectId AND $acl.ObjectType = 'RT::Group')" + . " OR $acl.ObjectType = 'RT::System')"); + + # ...and where that right is granted to any group.. + my $member = $self->Join( + ALIAS1 => $acl, + FIELD1 => 'PrincipalId', + TABLE2 => 'CachedGroupMembers', + FIELD2 => 'GroupId', + ); + $self->Limit( + ALIAS => $member, + FIELD => 'Disabled', + VALUE => '0', + ); + + # ...with the current user in it + $self->Limit( + ALIAS => $member, + FIELD => 'MemberId', + VALUE => $self->CurrentUser->Id, + ); + + return; +} + +=head2 LimitToEnabled + +Only find items that haven't been disabled + +=cut + +sub LimitToEnabled { + my $self = shift; + + $self->{'handled_disabled_column'} = 1; + $self->Limit( + ALIAS => $self->PrincipalsAlias, + FIELD => 'Disabled', + VALUE => '0', + ); +} + +=head2 LimitToDeleted + +Only find items that have been deleted. + +=cut + +sub LimitToDeleted { + my $self = shift; + + $self->{'handled_disabled_column'} = $self->{'find_disabled_rows'} = 1; + $self->Limit( + ALIAS => $self->PrincipalsAlias, + FIELD => 'Disabled', + VALUE => 1, + ); +} + + + +sub Next { + my $self = shift; + + # Don't show groups which the user isn't allowed to see. + + my $Group = $self->SUPER::Next(); + if ((defined($Group)) and (ref($Group))) { + unless ($Group->CurrentUserHasRight('SeeGroup')) { + return $self->Next(); + } + + return $Group; + } + else { + return undef; + } +} + + + +sub _DoSearch { + my $self = shift; + + #unless we really want to find disabled rows, make sure we're only finding enabled ones. + unless($self->{'find_disabled_rows'}) { + $self->LimitToEnabled(); + } + + return($self->SUPER::_DoSearch(@_)); + +} + + + +=head2 NewItem + +Returns an empty new RT::Group item + +=cut + +sub NewItem { + my $self = shift; + return(RT::Group->new($self->CurrentUser)); +} +RT::Base->_ImportOverlays(); + +1;