import rt 3.6.6
[freeside.git] / rt / lib / RT / Group_Overlay.pm
index 69ada31..d2e2364 100644 (file)
@@ -1,9 +1,9 @@
 
 
-# {{{ BEGIN BPS TAGGED BLOCK
+# BEGIN BPS TAGGED BLOCK {{{
 # 
 # COPYRIGHT:
 #  
 # 
 # COPYRIGHT:
 #  
-# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+# This software is Copyright (c) 1996-2007 Best Practical Solutions, LLC 
 #                                          <jesse@bestpractical.com>
 # 
 # (Except where explicitly superseded by other copyright notices)
 #                                          <jesse@bestpractical.com>
 # 
 # (Except where explicitly superseded by other copyright notices)
@@ -23,7 +23,9 @@
 # 
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, write to the Free Software
 # 
 # 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 or visit their web page on the internet at
+# http://www.gnu.org/copyleft/gpl.html.
 # 
 # 
 # CONTRIBUTION SUBMISSION POLICY:
 # 
 # 
 # CONTRIBUTION SUBMISSION POLICY:
@@ -43,7 +45,7 @@
 # works based on those contributions, and sublicense and distribute
 # those contributions and any derivatives thereof.
 # 
 # works based on those contributions, and sublicense and distribute
 # those contributions and any derivatives thereof.
 # 
-# }}} END BPS TAGGED BLOCK
+# END BPS TAGGED BLOCK }}}
 # Released under the terms of version 2 of the GNU Public License
 
 =head1 NAME
 # Released under the terms of version 2 of the GNU Public License
 
 =head1 NAME
 
 =head1 SYNOPSIS
 
 
 =head1 SYNOPSIS
 
-  use RT::Group;
+use RT::Group;
 my $group = new RT::Group($CurrentUser);
 
 =head1 DESCRIPTION
 
 An RT group object.
 
 my $group = new RT::Group($CurrentUser);
 
 =head1 DESCRIPTION
 
 An RT group object.
 
-=head1 AUTHOR
-
-Jesse Vincent, jesse@bestpractical.com
-
-=head1 SEE ALSO
-
-RT
-
 =head1 METHODS
 
 
 =head1 METHODS
 
 
@@ -154,6 +148,9 @@ ok($group_3->HasMemberRecursively($principal_2) == undef, "group 3 has member 2
 
 =cut
 
 
 =cut
 
+
+package RT::Group;
+
 use strict;
 no warnings qw(redefine);
 
 use strict;
 no warnings qw(redefine);
 
@@ -171,6 +168,7 @@ $RIGHTS = {
     ModifyOwnMembership => 'Join or leave this group',                 # loc_pair
     EditSavedSearches => 'Edit saved searches for this group',        # loc_pair
     ShowSavedSearches => 'Display saved searches for this group',        # loc_pair
     ModifyOwnMembership => 'Join or leave this group',                 # loc_pair
     EditSavedSearches => 'Edit saved searches for this group',        # loc_pair
     ShowSavedSearches => 'Display saved searches for this group',        # loc_pair
+    SeeGroup => 'Make this group visible to user',                    # loc_pair
 };
 
 # Tell RT::ACE that this sort of object can get acls granted
 };
 
 # Tell RT::ACE that this sort of object can get acls granted
@@ -435,6 +433,7 @@ sub LoadSystemRoleGroup {
 # }}}
 
 # {{{ sub Create
 # }}}
 
 # {{{ sub Create
+
 =head2 Create
 
 You need to specify what sort of group you're creating by calling one of the other
 =head2 Create
 
 You need to specify what sort of group you're creating by calling one of the other
@@ -469,6 +468,7 @@ sub _Create {
         Type        => undef,
         Instance    => '0',
         InsideTransaction => undef,
         Type        => undef,
         Instance    => '0',
         InsideTransaction => undef,
+        _RecordTransaction => 1,
         @_
     );
 
         @_
     );
 
@@ -499,7 +499,7 @@ sub _Create {
     # If we couldn't create a principal Id, get the fuck out.
     unless ($principal_id) {
         $RT::Handle->Rollback() unless ($args{'InsideTransaction'});
     # If we couldn't create a principal Id, get the fuck out.
     unless ($principal_id) {
         $RT::Handle->Rollback() unless ($args{'InsideTransaction'});
-        $self->crit( "Couldn't create a Principal on new user create. Strange things are afoot at the circle K" );
+        $RT::Logger->crit( "Couldn't create a Principal on new user create. Strange things are afoot at the circle K" );
         return ( 0, $self->loc('Could not create group') );
     }
 
         return ( 0, $self->loc('Could not create group') );
     }
 
@@ -514,8 +514,12 @@ sub _Create {
     $cgm->Create(Group =>$self->PrincipalObj, Member => $self->PrincipalObj, ImmediateParent => $self->PrincipalObj);
 
 
     $cgm->Create(Group =>$self->PrincipalObj, Member => $self->PrincipalObj, ImmediateParent => $self->PrincipalObj);
 
 
+    if ( $args{'_RecordTransaction'} ) {
+       $self->_NewTransaction( Type => "Create" );
+    }
 
     $RT::Handle->Commit() unless ($args{'InsideTransaction'});
 
     $RT::Handle->Commit() unless ($args{'InsideTransaction'});
+
     return ( $id, $self->loc("Group created") );
 }
 
     return ( $id, $self->loc("Group created") );
 }
 
@@ -710,6 +714,7 @@ If passed a positive value, this group will be disabled. No rights it commutes o
 It will not appear in most group listings.
 
 This routine finds all the cached group members that are members of this group  (recursively) and disables them.
 It will not appear in most group listings.
 
 This routine finds all the cached group members that are members of this group  (recursively) and disables them.
+
 =cut 
 
  # }}}
 =cut 
 
  # }}}
@@ -754,7 +759,7 @@ This routine finds all the cached group members that are members of this group
 
     #Clear the key cache. TODO someday we may want to just clear a little bit of the keycache space. 
     # TODO what about the groups key cache?
 
     #Clear the key cache. TODO someday we may want to just clear a little bit of the keycache space. 
     # TODO what about the groups key cache?
-    RT::Principal->_InvalidateACLCache();
+    RT::Principal->InvalidateACLCache();
 
 
 
 
 
 
@@ -786,7 +791,8 @@ sub Disabled {
 
 =head2 DeepMembersObj
 
 
 =head2 DeepMembersObj
 
-Returns an RT::CachedGroupMembers object of this group's members.
+Returns an RT::CachedGroupMembers object of this group's members,
+including all members of subgroups.
 
 =cut
 
 
 =cut
 
@@ -839,7 +845,7 @@ sub UserMembersObj {
 
 =head2 MembersObj
 
 
 =head2 MembersObj
 
-Returns an RT::CachedGroupMembers object of this group's members.
+Returns an RT::GroupMembers object of this group's direct members.
 
 =cut
 
 
 =cut
 
@@ -1165,11 +1171,70 @@ sub _DeleteMember {
 
 # }}}
 
 
 # }}}
 
+# {{{ sub _CleanupInvalidDelegations
+
+=head2 _CleanupInvalidDelegations { InsideTransaction => undef }
+
+Revokes all ACE entries delegated by members of this group which are
+inconsistent with their current delegation rights.  Does not perform
+permission checks.  Should only ever be called from inside the RT
+library.
+
+If called from inside a transaction, specify a true value for the
+InsideTransaction parameter.
+
+Returns a true value if the deletion succeeded; returns a false value
+and logs an internal error if the deletion fails (should not happen).
+
+=cut
+
+# XXX Currently there is a _CleanupInvalidDelegations method in both
+# RT::User and RT::Group.  If the recursive cleanup call for groups is
+# ever unrolled and merged, this code will probably want to be
+# factored out into RT::Principal.
+
+sub _CleanupInvalidDelegations {
+    my $self = shift;
+    my %args = ( InsideTransaction => undef,
+                 @_ );
+
+    unless ( $self->Id ) {
+       $RT::Logger->warning("Group not loaded.");
+       return (undef);
+    }
+
+    my $in_trans = $args{InsideTransaction};
+
+    # TODO: Can this be unrolled such that the number of DB queries is constant rather than linear in exploded group size?
+    my $members = $self->DeepMembersObj();
+    $members->LimitToUsers();
+    $RT::Handle->BeginTransaction() unless $in_trans;
+    while ( my $member = $members->Next()) {
+       my $ret = $member->MemberObj->_CleanupInvalidDelegations(InsideTransaction => 1,
+                                                                Object => $args{Object});
+       unless ($ret) {
+           $RT::Handle->Rollback() unless $in_trans;
+           return (undef);
+       }
+    }
+    $RT::Handle->Commit() unless $in_trans;
+    return(1);
+}
+
+# }}}
+
 # {{{ ACL Related routines
 
 # {{{ sub _Set
 sub _Set {
     my $self = shift;
 # {{{ ACL Related routines
 
 # {{{ sub _Set
 sub _Set {
     my $self = shift;
+    my %args = (
+        Field => undef,
+        Value => undef,
+       TransactionType   => 'Set',
+       RecordTransaction => 1,
+        @_
+    );
 
        if ($self->Domain eq 'Personal') {
                if ($self->CurrentUser->PrincipalId == $self->Instance) {
 
        if ($self->Domain eq 'Personal') {
                if ($self->CurrentUser->PrincipalId == $self->Instance) {
@@ -1187,7 +1252,30 @@ sub _Set {
                return ( 0, $self->loc('Permission Denied') );
        }
        }
                return ( 0, $self->loc('Permission Denied') );
        }
        }
-    return ( $self->SUPER::_Set(@_) );
+
+    my $Old = $self->SUPER::_Value("$args{'Field'}");
+    
+    my ($ret, $msg) = $self->SUPER::_Set( Field => $args{'Field'},
+                                         Value => $args{'Value'} );
+    
+    #If we can't actually set the field to the value, don't record
+    # a transaction. instead, get out of here.
+    if ( $ret == 0 ) { return ( 0, $msg ); }
+
+    if ( $args{'RecordTransaction'} == 1 ) {
+
+        my ( $Trans, $Msg, $TransObj ) = $self->_NewTransaction(
+                                               Type => $args{'TransactionType'},
+                                               Field     => $args{'Field'},
+                                               NewValue  => $args{'Value'},
+                                               OldValue  => $Old,
+                                               TimeTaken => $args{'TimeTaken'},
+        );
+        return ( $Trans, scalar $TransObj->Description );
+    }
+    else {
+        return ( $ret, $msg );
+    }
 }
 
 # }}}
 }
 
 # }}}
@@ -1195,7 +1283,7 @@ sub _Set {
 
 
 
 
 
 
-=item CurrentUserHasRight RIGHTNAME
+=head2 CurrentUserHasRight RIGHTNAME
 
 Returns true if the current user has the specified right for this group.
 
 
 Returns true if the current user has the specified right for this group.
 
@@ -1275,5 +1363,21 @@ sub PrincipalId {
 }
 
 # }}}
 }
 
 # }}}
+
+sub BasicColumns {
+    (
+       [ Name => 'Name' ],
+       [ Description => 'Description' ],
+    );
+}
+
 1;
 
 1;
 
+=head1 AUTHOR
+
+Jesse Vincent, jesse@bestpractical.com
+
+=head1 SEE ALSO
+
+RT
+