+ id => $principal_id,
+ Name => $args{'Name'},
+ Description => $args{'Description'},
+ Type => $args{'Type'},
+ Domain => $args{'Domain'},
+ Instance => ($args{'Instance'} || '0')
+ );
+ my $id = $self->Id;
+ unless ($id) {
+ $RT::Handle->Rollback() unless ($args{'InsideTransaction'});
+ return ( 0, $self->loc('Could not create group') );
+ }
+
+ # If we couldn't create a principal Id, get the fuck out.
+ unless ($principal_id) {
+ $RT::Handle->Rollback() unless ($args{'InsideTransaction'});
+ $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') );
+ }
+
+ # Now we make the group a member of itself as a cached group member
+ # this needs to exist so that group ACL checks don't fall over.
+ # you're checking CachedGroupMembers to see if the principal in question
+ # is a member of the principal the rights have been granted too
+
+ # in the ordinary case, this would fail badly because it would recurse and add all the members of this group as
+ # cached members. thankfully, we're creating the group now...so it has no members.
+ my $cgm = RT::CachedGroupMember->new($self->CurrentUser);
+ $cgm->Create(Group =>$self->PrincipalObj, Member => $self->PrincipalObj, ImmediateParent => $self->PrincipalObj);
+
+
+ if ( $args{'_RecordTransaction'} ) {
+ $self->_NewTransaction( Type => "Create" );
+ }
+
+ $RT::Handle->Commit() unless ($args{'InsideTransaction'});
+
+ return ( $id, $self->loc("Group created") );
+}
+
+
+
+=head2 CreateUserDefinedGroup { Name => "name", Description => "Description"}
+
+A helper subroutine which creates a system group
+
+Returns a tuple of (Id, Message). If id is 0, the create failed
+
+=cut
+
+sub CreateUserDefinedGroup {
+ my $self = shift;
+
+ unless ( $self->CurrentUserHasRight('AdminGroup') ) {
+ $RT::Logger->warning( $self->CurrentUser->Name
+ . " Tried to create a group without permission." );
+ return ( 0, $self->loc('Permission Denied') );
+ }
+
+ return($self->_Create( Domain => 'UserDefined', Type => '', Instance => '', @_));
+}
+
+=head2 ValidateName VALUE
+
+Enforces unique user defined group names when updating
+
+=cut
+
+sub ValidateName {
+ my ($self, $value) = @_;
+
+ if ($self->Domain and $self->Domain eq 'UserDefined') {
+ my ($ok, $msg) = $self->_ValidateUserDefinedName($value);
+ # It's really too bad we can't pass along the actual error
+ return 0 if not $ok;
+ }
+ return $self->SUPER::ValidateName($value);
+}
+
+=head2 _ValidateUserDefinedName VALUE
+
+Returns true if the user defined group name isn't in use, false otherwise.
+
+=cut
+
+sub _ValidateUserDefinedName {
+ my ($self, $value) = @_;
+
+ return (0, 'Name is required') unless length $value;
+
+ my $dupcheck = RT::Group->new(RT->SystemUser);
+ $dupcheck->LoadUserDefinedGroup($value);
+ if ( $dupcheck->id && ( !$self->id || $self->id != $dupcheck->id ) ) {
+ return ( 0, $self->loc( "Group name '[_1]' is already in use", $value ) );
+ }
+ return 1;
+}
+
+=head2 _CreateACLEquivalenceGroup { Principal }
+
+A helper subroutine which creates a group containing only
+an individual user. This gets used by the ACL system to check rights.
+Yes, it denormalizes the data, but that's ok, as we totally win on performance.
+
+Returns a tuple of (Id, Message). If id is 0, the create failed
+
+=cut
+
+sub _CreateACLEquivalenceGroup {
+ my $self = shift;
+ my $princ = shift;
+
+ my $id = $self->_Create( Domain => 'ACLEquivalence',
+ Type => 'UserEquiv',
+ Name => 'User '. $princ->Object->Id,
+ Description => 'ACL equiv. for user '.$princ->Object->Id,
+ Instance => $princ->Id,
+ InsideTransaction => 1,
+ _RecordTransaction => 0 );
+ unless ($id) {
+ $RT::Logger->crit("Couldn't create ACL equivalence group");
+ return undef;
+ }
+
+ # We use stashuser so we don't get transactions inside transactions
+ # and so we bypass all sorts of cruft we don't need
+ my $aclstash = RT::GroupMember->new($self->CurrentUser);
+ my ($stash_id, $add_msg) = $aclstash->_StashUser(Group => $self->PrincipalObj,
+ Member => $princ);
+
+ unless ($stash_id) {
+ $RT::Logger->crit("Couldn't add the user to his own acl equivalence group:".$add_msg);
+ # We call super delete so we don't get acl checked.
+ $self->SUPER::Delete();
+ return(undef);
+ }
+ return ($id);
+}
+
+
+
+
+=head2 CreateRoleGroup { Domain => DOMAIN, Type => TYPE, Instance => ID }
+
+A helper subroutine which creates a ticket group. (What RT 2.0 called Ticket watchers)
+Type is one of ( "Requestor" || "Cc" || "AdminCc" || "Owner")
+Domain is one of (RT::Ticket-Role || RT::Queue-Role || RT::System-Role)
+Instance is the id of the ticket or queue in question
+
+This routine expects to be called from {Ticket||Queue}->CreateTicketGroups _inside of a transaction_
+
+Returns a tuple of (Id, Message). If id is 0, the create failed
+
+=cut
+
+sub CreateRoleGroup {
+ my $self = shift;
+ my %args = ( Instance => undef,
+ Type => undef,
+ Domain => undef,
+ @_ );
+
+ unless (RT::Queue->IsRoleGroupType($args{Type})) {
+ return ( 0, $self->loc("Invalid Group Type") );
+ }
+
+
+ return ( $self->_Create( Domain => $args{'Domain'},
+ Instance => $args{'Instance'},
+ Type => $args{'Type'},
+ InsideTransaction => 1 ) );
+}
+
+
+
+=head2 Delete
+
+Delete this object
+
+=cut
+
+sub Delete {
+ my $self = shift;
+
+ unless ( $self->CurrentUserHasRight('AdminGroup') ) {
+ return ( 0, 'Permission Denied' );
+ }
+
+ $RT::Logger->crit("Deleting groups violates referential integrity until we go through and fix this");
+ # TODO XXX
+
+ # Remove the principal object
+ # Remove this group from anything it's a member of.
+ # Remove all cached members of this group
+ # Remove any rights granted to this group
+ # remove any rights delegated by way of this group
+
+ return ( $self->SUPER::Delete(@_) );
+}
+
+
+=head2 SetDisabled BOOL
+
+If passed a positive value, this group will be disabled. No rights it commutes or grants will be honored.
+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