X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=rt%2Flib%2FRT%2FUser_Overlay.pm;h=2b50fac8228b840ce8d9702eb71020dcce0b3fd9;hb=cbb4c260c40779ba84c794dd68147c54f3de2f52;hp=4de0d2aad29fab9e1e90b99a55d3ffe48eed75c3;hpb=fc6209f398899f0211cfcedeb81a3cd65e04a941;p=freeside.git diff --git a/rt/lib/RT/User_Overlay.pm b/rt/lib/RT/User_Overlay.pm index 4de0d2aad..2b50fac82 100644 --- a/rt/lib/RT/User_Overlay.pm +++ b/rt/lib/RT/User_Overlay.pm @@ -1090,7 +1090,7 @@ sub IsPassword { # crypt() output return 0 unless crypt(encode_utf8($value), $stored) eq $stored; } else { - $RT::Logger->warn("Unknown password form"); + $RT::Logger->warning("Unknown password form"); return 0; } @@ -1349,6 +1349,268 @@ sub OwnGroups { return $groups; } +# }}} + +# {{{ Links + +#much false laziness w/Ticket_Overlay.pm. now with RT 3.8! + +# A helper table for links mapping to make it easier +# to build and parse links between tickets + +use vars '%LINKDIRMAP'; + +%LINKDIRMAP = ( + MemberOf => { Base => 'MemberOf', + Target => 'HasMember', }, + RefersTo => { Base => 'RefersTo', + Target => 'ReferredToBy', }, + DependsOn => { Base => 'DependsOn', + Target => 'DependedOnBy', }, + MergedInto => { Base => 'MergedInto', + Target => 'MergedInto', }, + +); + +sub LINKDIRMAP { return \%LINKDIRMAP } + +#sub _Links { +# my $self = shift; +# +# #TODO: Field isn't the right thing here. but I ahave no idea what mnemonic --- +# #tobias meant by $f +# my $field = shift; +# my $type = shift || ""; +# +# unless ( $self->{"$field$type"} ) { +# $self->{"$field$type"} = new RT::Links( $self->CurrentUser ); +# if ( $self->CurrentUserHasRight('ShowTicket') ) { +# # Maybe this ticket is a merged ticket +# my $Tickets = new RT::Tickets( $self->CurrentUser ); +# # at least to myself +# $self->{"$field$type"}->Limit( FIELD => $field, +# VALUE => $self->URI, +# ENTRYAGGREGATOR => 'OR' ); +# $Tickets->Limit( FIELD => 'EffectiveId', +# VALUE => $self->EffectiveId ); +# while (my $Ticket = $Tickets->Next) { +# $self->{"$field$type"}->Limit( FIELD => $field, +# VALUE => $Ticket->URI, +# ENTRYAGGREGATOR => 'OR' ); +# } +# $self->{"$field$type"}->Limit( FIELD => 'Type', +# VALUE => $type ) +# if ($type); +# } +# } +# return ( $self->{"$field$type"} ); +#} + +=head2 DeleteLink + +Delete a link. takes a paramhash of Base, Target and Type. +Either Base or Target must be null. The null value will +be replaced with this ticket\'s id + +=cut + +sub DeleteLink { + my $self = shift; + my %args = ( + Base => undef, + Target => undef, + Type => undef, + @_ + ); + + unless ( $args{'Target'} || $args{'Base'} ) { + $RT::Logger->error("Base or Target must be specified\n"); + return ( 0, $self->loc('Either base or target must be specified') ); + } + + #check acls + my $right = 0; + $right++ if $self->CurrentUserHasRight('AdminUsers'); + if ( !$right && $RT::StrictLinkACL ) { + return ( 0, $self->loc("Permission Denied") ); + } + +# # If the other URI is an RT::Ticket, we want to make sure the user +# # can modify it too... +# my ($status, $msg, $other_ticket) = $self->__GetTicketFromURI( URI => $args{'Target'} || $args{'Base'} ); +# return (0, $msg) unless $status; +# if ( !$other_ticket || $other_ticket->CurrentUserHasRight('ModifyTicket') ) { +# $right++; +# } +# if ( ( !$RT::StrictLinkACL && $right == 0 ) || +# ( $RT::StrictLinkACL && $right < 2 ) ) +# { +# return ( 0, $self->loc("Permission Denied") ); +# } + + my ($val, $Msg) = $self->SUPER::_DeleteLink(%args); + + if ( !$val ) { + $RT::Logger->debug("Couldn't find that link\n"); + return ( 0, $Msg ); + } + + my ($direction, $remote_link); + + if ( $args{'Base'} ) { + $remote_link = $args{'Base'}; + $direction = 'Target'; + } + elsif ( $args{'Target'} ) { + $remote_link = $args{'Target'}; + $direction='Base'; + } + + if ( $args{'Silent'} ) { + return ( $val, $Msg ); + } + else { + my $remote_uri = RT::URI->new( $self->CurrentUser ); + $remote_uri->FromURI( $remote_link ); + + my ( $Trans, $Msg, $TransObj ) = $self->_NewTransaction( + Type => 'DeleteLink', + Field => $LINKDIRMAP{$args{'Type'}}->{$direction}, + OldValue => $remote_uri->URI || $remote_link, + TimeTaken => 0 + ); + + if ( $remote_uri->IsLocal ) { + + my $OtherObj = $remote_uri->Object; + my ( $val, $Msg ) = $OtherObj->_NewTransaction(Type => 'DeleteLink', + Field => $direction eq 'Target' ? $LINKDIRMAP{$args{'Type'}}->{Base} + : $LINKDIRMAP{$args{'Type'}}->{Target}, + OldValue => $self->URI, + ActivateScrips => ! $RT::LinkTransactionsRun1Scrip, + TimeTaken => 0 ); + } + + return ( $Trans, $Msg ); + } +} + +sub AddLink { + my $self = shift; + my %args = ( Target => '', + Base => '', + Type => '', + Silent => undef, + @_ ); + + unless ( $args{'Target'} || $args{'Base'} ) { + $RT::Logger->error("Base or Target must be specified\n"); + return ( 0, $self->loc('Either base or target must be specified') ); + } + + my $right = 0; + $right++ if $self->CurrentUserHasRight('AdminUsers'); + if ( !$right && $RT::StrictLinkACL ) { + return ( 0, $self->loc("Permission Denied") ); + } + +# # If the other URI is an RT::Ticket, we want to make sure the user +# # can modify it too... +# my ($status, $msg, $other_ticket) = $self->__GetTicketFromURI( URI => $args{'Target'} || $args{'Base'} ); +# return (0, $msg) unless $status; +# if ( !$other_ticket || $other_ticket->CurrentUserHasRight('ModifyTicket') ) { +# $right++; +# } +# if ( ( !$RT::StrictLinkACL && $right == 0 ) || +# ( $RT::StrictLinkACL && $right < 2 ) ) +# { +# return ( 0, $self->loc("Permission Denied") ); +# } + + return $self->_AddLink(%args); +} + +#sub __GetTicketFromURI { +# my $self = shift; +# my %args = ( URI => '', @_ ); +# +# # If the other URI is an RT::Ticket, we want to make sure the user +# # can modify it too... +# my $uri_obj = RT::URI->new( $self->CurrentUser ); +# $uri_obj->FromURI( $args{'URI'} ); +# +# unless ( $uri_obj->Resolver && $uri_obj->Scheme ) { +# my $msg = $self->loc( "Couldn't resolve '[_1]' into a URI.", $args{'URI'} ); +# $RT::Logger->warning( "$msg\n" ); +# return( 0, $msg ); +# } +# my $obj = $uri_obj->Resolver->Object; +# unless ( UNIVERSAL::isa($obj, 'RT::Ticket') && $obj->id ) { +# return (1, 'Found not a ticket', undef); +# } +# return (1, 'Found ticket', $obj); +#} + +=head2 _AddLink + +Private non-acled variant of AddLink so that links can be added during create. + +=cut + +sub _AddLink { + my $self = shift; + my %args = ( Target => '', + Base => '', + Type => '', + Silent => undef, + @_ ); + + my ($val, $msg, $exist) = $self->SUPER::_AddLink(%args); + return ($val, $msg) if !$val || $exist; + + my ($direction, $remote_link); + if ( $args{'Target'} ) { + $remote_link = $args{'Target'}; + $direction = 'Base'; + } elsif ( $args{'Base'} ) { + $remote_link = $args{'Base'}; + $direction = 'Target'; + } + + # Don't write the transaction if we're doing this on create + if ( $args{'Silent'} ) { + return ( $val, $msg ); + } + else { + my $remote_uri = RT::URI->new( $self->CurrentUser ); + $remote_uri->FromURI( $remote_link ); + + #Write the transaction + my ( $Trans, $Msg, $TransObj ) = + $self->_NewTransaction(Type => 'AddLink', + Field => $LINKDIRMAP{$args{'Type'}}->{$direction}, + NewValue => $remote_uri->URI || $remote_link, + TimeTaken => 0 ); + + if ( $remote_uri->IsLocal ) { + + my $OtherObj = $remote_uri->Object; + my ( $val, $Msg ) = $OtherObj->_NewTransaction(Type => 'AddLink', + Field => $direction eq 'Target' ? $LINKDIRMAP{$args{'Type'}}->{Base} + : $LINKDIRMAP{$args{'Type'}}->{Target}, + NewValue => $self->URI, + ActivateScrips => ! $RT::LinkTransactionsRun1Scrip, + TimeTaken => 0 ); + } + return ( $val, $Msg ); + } + +} + + + +# }}} + =head2 HasRight Shim around PrincipalObj->HasRight. See L. @@ -1360,6 +1622,37 @@ sub HasRight { return $self->PrincipalObj->HasRight(@_); } +=head2 CurrentUserCanSee [FIELD] + +Returns true if the current user can see the user, based on if it is +public, ourself, or we have AdminUsers + +=cut + +sub CurrentUserCanSee { + my $self = shift; + my ($what) = @_; + + # If it's public, fine. Note that $what may be "transaction", which + # doesn't have an Accessible value, and thus falls through below. + if ( $self->_Accessible( $what, 'public' ) ) { + return 1; + } + + # Users can see their own properties + elsif ( defined($self->Id) && $self->CurrentUser->Id == $self->Id ) { + return 1; + } + + # If the user has the admin users right, that's also enough + elsif ( $self->CurrentUser->HasRight( Right => 'AdminUsers', Object => $RT::System) ) { + return 1; + } + else { + return 0; + } +} + =head2 CurrentUserCanModify RIGHT If the user has rights for this object, either because @@ -1538,6 +1831,12 @@ sub WatchedQueues { FIELD => 'MemberId', VALUE => $self->PrincipalId, ); + $watched_queues->Limit( + ALIAS => $queues_alias, + FIELD => 'Disabled', + VALUE => 0, + ); + $RT::Logger->debug("WatchedQueues got " . $watched_queues->Count . " queues"); @@ -1545,7 +1844,7 @@ sub WatchedQueues { } -=head2 _CleanupInvalidDelegations { InsideTransaction => undef } +=head2 CleanupInvalidDelegations { InsideTransaction => undef } Revokes all ACE entries delegated by this user which are inconsistent with their current delegation rights. Does not perform permission @@ -1559,12 +1858,15 @@ and logs an internal error if the deletion fails (should not happen). =cut -# XXX Currently there is a _CleanupInvalidDelegations method in both +# 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 { +# backcompat for 3.8.8 and before +*_CleanupInvalidDelegations = \&CleanupInvalidDelegations; + +sub CleanupInvalidDelegations { my $self = shift; my %args = ( InsideTransaction => undef, @_ ); @@ -1643,7 +1945,9 @@ sub _Set { if ( $ret == 0 ) { return ( 0, $msg ); } if ( $args{'RecordTransaction'} == 1 ) { - + if ($args{'Field'} eq "Password") { + $args{'Value'} = $Old = '********'; + } my ( $Trans, $Msg, $TransObj ) = $self->_NewTransaction( Type => $args{'TransactionType'}, Field => $args{'Field'}, @@ -1670,33 +1974,9 @@ sub _Value { my $self = shift; my $field = shift; - #If the current user doesn't have ACLs, don't let em at it. - - my @PublicFields = qw( Name EmailAddress Organization Disabled - RealName NickName Gecos ExternalAuthId - AuthSystem ExternalContactInfoId - ContactInfoSystem ); - - #if the field is public, return it. - if ( $self->_Accessible( $field, 'public' ) ) { - return ( $self->SUPER::_Value($field) ); - - } - - #If the user wants to see their own values, let them - # TODO figure ouyt a better way to deal with this - elsif ( defined($self->Id) && $self->CurrentUser->Id == $self->Id ) { - return ( $self->SUPER::_Value($field) ); - } - - #If the user has the admin users right, return the field - elsif ( $self->CurrentUser->HasRight(Right =>'AdminUsers', Object => $RT::System) ) { - return ( $self->SUPER::_Value($field) ); - } - else { - return (undef); - } - + # Defer to the abstraction above to know if the field can be read + return $self->SUPER::_Value($field) if $self->CurrentUserCanSee($field); + return undef; } =head2 FriendlyName