diff options
Diffstat (limited to 'rt/lib/RT/Ticket_Overlay.pm')
-rw-r--r-- | rt/lib/RT/Ticket_Overlay.pm | 298 |
1 files changed, 102 insertions, 196 deletions
diff --git a/rt/lib/RT/Ticket_Overlay.pm b/rt/lib/RT/Ticket_Overlay.pm index 5960f0b63..a294dcafd 100644 --- a/rt/lib/RT/Ticket_Overlay.pm +++ b/rt/lib/RT/Ticket_Overlay.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2007 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2005 Best Practical Solutions, LLC # <jesse@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -22,9 +22,7 @@ # # 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/copyleft/gpl.html. +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # # # CONTRIBUTION SUBMISSION POLICY: @@ -153,7 +151,6 @@ use RT::Date; use RT::CustomFields; use RT::Tickets; use RT::Transactions; -use RT::Reminders; use RT::URI::fsck_com_rt; use RT::URI; use MIME::Entity; @@ -330,20 +327,10 @@ Arguments: ARGS is a hash of named parameters. Valid parameters are: MIMEObj -- a MIME::Entity object with the content of the initial ticket request. CustomField-<n> -- a scalar or array of values for the customfield with the id <n> -Ticket links can be set up during create by passing the link type as a hask key and -the ticket id to be linked to as a value (or a URI when linking to other objects). -Multiple links of the same type can be created by passing an array ref. For example: - - Parent => 45, - DependsOn => [ 15, 22 ], - RefersTo => 'http://www.bestpractical.com', - -Supported link types are C<MemberOf>, C<HasMember>, C<RefersTo>, C<ReferredToBy>, -C<DependsOn> and C<DependedOnBy>. Also, C<Parents> is alias for C<MemberOf> and -C<Members> and C<Children> are aliases for C<HasMember>. Returns: TICKETID, Transaction Object, Error Message + =begin testing my $t = RT::Ticket->new($RT::SystemUser); @@ -476,9 +463,10 @@ sub Create { #If the status is an inactive status, set the resolved date if ( $QueueObj->IsInactiveStatus( $args{'Status'} ) && !$args{'Resolved'} ) { - $RT::Logger->debug( "Got a ". $args{'Status'} - ." ticket with undefined resolved date. Setting to now." - ); + $RT::Logger->debug( "Got a " + . $args{'Status'} + . "ticket with a resolved of " + . $args{'Resolved'} ); $Resolved->SetToNow; } @@ -690,20 +678,6 @@ sub Create { foreach my $link ( ref( $args{$type} ) ? @{ $args{$type} } : ( $args{$type} ) ) { - # Check rights on the other end of the link if we must - # then run _AddLink that doesn't check for ACLs - if ( $RT::StrictLinkACL ) { - my ($val, $msg, $obj) = $self->__GetTicketFromURI( URI => $link ); - unless ( $val ) { - push @non_fatal_errors, $msg; - next; - } - if ( $obj && !$obj->CurrentUserHasRight('ModifyTicket') ) { - push @non_fatal_errors, $self->loc('Linking. Permission denied'); - next; - } - } - my ( $wval, $wmsg ) = $self->_AddLink( Type => $LINKTYPEMAP{$type}->{'Type'}, $LINKTYPEMAP{$type}->{'Mode'} => $link, @@ -1347,10 +1321,7 @@ sub AddWatcher { # {{{ Check ACLS #If the watcher we're trying to add is for the current user - if ( $self->CurrentUser->PrincipalId == ($args{'PrincipalId'} || 0) - or lc( $self->CurrentUser->UserObj->EmailAddress ) - eq lc( RT::User::CanonicalizeEmailAddress(undef, $args{'Email'}) || '' ) ) - { + if ( $self->CurrentUser->PrincipalId eq $args{'PrincipalId'}) { # If it's an AdminCc and they don't have # 'WatchAsAdminCc' or 'ModifyTicket', bail if ( $args{'Type'} eq 'AdminCc' ) { @@ -1514,7 +1485,7 @@ sub DeleteWatcher { # {{{ Check ACLS #If the watcher we're trying to add is for the current user - if ( $self->CurrentUser->PrincipalId == $principal->id ) { + if ( $self->CurrentUser->PrincipalId eq $args{'PrincipalId'} ) { # If it's an AdminCc and they don't have # 'WatchAsAdminCc' or 'ModifyTicket', bail @@ -2125,12 +2096,12 @@ sub SetStarted { my $time = shift || 0; unless ( $self->CurrentUserHasRight('ModifyTicket') ) { - return ( 0, $self->loc("Permission Denied") ); + return ( 0, self->loc("Permission Denied") ); } #We create a date object to catch date weirdness my $time_obj = new RT::Date( $self->CurrentUser() ); - if ( $time ) { + if ( $time != 0 ) { $time_obj->Set( Format => 'ISO', Value => $time ); } else { @@ -2423,9 +2394,8 @@ sub _RecordNote { # If this is from an external source, we need to come up with its # internal Message-ID now, so all emails sent because of this # message have a common Message-ID - unless ( ($args{'MIMEObj'}->head->get('Message-ID') || '') - =~ /<(rt-.*?-\d+-\d+)\.(\d+-0-0)\@\Q$RT::Organization>/ ) - { + unless ($args{'MIMEObj'}->head->get('Message-ID') + =~ /<(rt-.*?-\d+-\d+)\.(\d+-0-0)\@$RT::Organization>/) { $args{'MIMEObj'}->head->set( 'RT-Message-ID', "<rt-" . $RT::VERSION . "-" @@ -2515,29 +2485,11 @@ sub DeleteLink { @_ ); - 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('ModifyTicket'); - if ( !$right && $RT::StrictLinkACL ) { - return ( 0, $self->loc("Permission Denied") ); - } + unless ( $self->CurrentUserHasRight('ModifyTicket') ) { + $RT::Logger->debug("No permission to delete links\n"); + 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); @@ -2605,52 +2557,13 @@ sub AddLink { 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('ModifyTicket'); - 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 ) ) - { + unless ( $self->CurrentUserHasRight('ModifyTicket') ) { 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); + $self->_AddLink(%args); } =head2 _AddLink @@ -2667,8 +2580,45 @@ sub _AddLink { Silent => undef, @_ ); - my ($val, $msg, $exist) = $self->SUPER::_AddLink(%args); - return ($val, $msg) if !$val || $exist; + # {{{ If the other URI is an RT::Ticket, we want to make sure the user + # can modify it too... + my $other_ticket_uri = RT::URI->new($self->CurrentUser); + + if ( $args{'Target'} ) { + $other_ticket_uri->FromURI( $args{'Target'} ); + + } + elsif ( $args{'Base'} ) { + $other_ticket_uri->FromURI( $args{'Base'} ); + } + + unless ( $other_ticket_uri->Resolver && $other_ticket_uri->Scheme ) { + my $msg = $args{'Target'} ? $self->loc("Couldn't resolve target '[_1]' into a URI.", $args{'Target'}) + : $self->loc("Couldn't resolve base '[_1]' into a URI.", $args{'Base'}); + $RT::Logger->warning( "$self $msg\n" ); + + return( 0, $msg ); + } + + if ( $other_ticket_uri->Resolver->Scheme eq 'fsck.com-rt') { + my $object = $other_ticket_uri->Resolver->Object; + + if ( UNIVERSAL::isa( $object, 'RT::Ticket' ) + && $object->id + && !$object->CurrentUserHasRight('ModifyTicket') ) + { + return ( 0, $self->loc("Permission Denied") ); + } + + } + + # }}} + + my ($val, $Msg) = $self->SUPER::_AddLink(%args); + + if (!$val) { + return ($val, $Msg); + } my ($direction, $remote_link); if ( $args{'Target'} ) { @@ -2681,10 +2631,10 @@ sub _AddLink { # Don't write the transaction if we're doing this on create if ( $args{'Silent'} ) { - return ( $val, $msg ); + return ( $val, $Msg ); } else { - my $remote_uri = RT::URI->new( $self->CurrentUser ); + my $remote_uri = RT::URI->new( $self->CurrentUser ); $remote_uri->FromURI( $remote_link ); #Write the transaction @@ -2782,24 +2732,15 @@ sub MergeInto { return ( 0, $self->loc("Merge failed. Couldn't set EffectiveId") ); } + my ( $status_val, $status_msg ) = $self->__Set( Field => 'Status', Value => 'resolved'); - if ( $self->__Value('Status') ne 'resolved' ) { - - my ( $status_val, $status_msg ) - = $self->__Set( Field => 'Status', Value => 'resolved' ); - - unless ($status_val) { - $RT::Handle->Rollback(); - $RT::Logger->error( - $self->loc( - "[_1] couldn't set status to resolved. RT's Database may be inconsistent.", - $self - ) - ); - return ( 0, $self->loc("Merge failed. Couldn't set Status") ); - } + unless ($status_val) { + $RT::Handle->Rollback(); + $RT::Logger->error( $self->loc("[_1] couldn't set status to resolved. RT's Database may be inconsistent.", $self) ); + return ( 0, $self->loc("Merge failed. Couldn't set Status") ); } + # update all the links that point to that old ticket my $old_links_to = RT::Links->new($self->CurrentUser); $old_links_to->Limit(FIELD => 'Target', VALUE => $self->URI); @@ -2975,8 +2916,6 @@ my $txns = RT::Transactions->new($RT::SystemUser); $txns->OrderBy(FIELD => 'id', ORDER => 'DESC'); $txns->Limit(FIELD => 'ObjectId', VALUE => '1'); $txns->Limit(FIELD => 'ObjectType', VALUE => 'RT::Ticket'); -$txns->Limit(FIELD => 'Type', OPERATOR => '!=', VALUE => 'EmailRecord'); - my $steal = $txns->First; ok($steal->OldValue == $root->Id , "Stolen from root"); ok($steal->NewValue == $RT::SystemUser->Id , "Stolen by the systemuser"); @@ -2990,77 +2929,68 @@ sub SetOwner { my $NewOwner = shift; my $Type = shift || "Give"; - $RT::Handle->BeginTransaction(); - - $self->_SetLastUpdated(); # lock the ticket - $self->Load( $self->id ); # in case $self changed while waiting for lock - - my $OldOwnerObj = $self->OwnerObj; - - my $NewOwnerObj = RT::User->new( $self->CurrentUser ); - $NewOwnerObj->Load( $NewOwner ); - unless ( $NewOwnerObj->Id ) { - $RT::Handle->Rollback(); - return ( 0, $self->loc("That user does not exist") ); - } - - # must have ModifyTicket rights # or TakeTicket/StealTicket and $NewOwner is self # see if it's a take - if ( $OldOwnerObj->Id == $RT::Nobody->Id ) { + if ( $self->OwnerObj->Id == $RT::Nobody->Id ) { unless ( $self->CurrentUserHasRight('ModifyTicket') || $self->CurrentUserHasRight('TakeTicket') ) { - $RT::Handle->Rollback(); return ( 0, $self->loc("Permission Denied") ); } } # see if it's a steal - elsif ( $OldOwnerObj->Id != $RT::Nobody->Id - && $OldOwnerObj->Id != $self->CurrentUser->id ) { + elsif ( $self->OwnerObj->Id != $RT::Nobody->Id + && $self->OwnerObj->Id != $self->CurrentUser->id ) { unless ( $self->CurrentUserHasRight('ModifyTicket') || $self->CurrentUserHasRight('StealTicket') ) { - $RT::Handle->Rollback(); return ( 0, $self->loc("Permission Denied") ); } } else { unless ( $self->CurrentUserHasRight('ModifyTicket') ) { - $RT::Handle->Rollback(); return ( 0, $self->loc("Permission Denied") ); } } + my $NewOwnerObj = RT::User->new( $self->CurrentUser ); + my $OldOwnerObj = $self->OwnerObj; - # If we're not stealing and the ticket has an owner and it's not - # the current user - if ( $Type ne 'Steal' and $Type ne 'Force' - and $OldOwnerObj->Id != $RT::Nobody->Id - and $OldOwnerObj->Id != $self->CurrentUser->Id ) - { - $RT::Handle->Rollback(); - return ( 0, $self->loc("You can only take tickets that are unowned") ) - if $NewOwnerObj->id == $self->CurrentUser->id; - return ( - 0, - $self->loc("You can only reassign tickets that you own or that are unowned" ) - ); + $NewOwnerObj->Load($NewOwner); + if ( !$NewOwnerObj->Id ) { + return ( 0, $self->loc("That user does not exist") ); + } + + #If thie ticket has an owner and it's not the current user + + if ( ( $Type ne 'Steal' ) + and ( $Type ne 'Force' ) + and #If we're not stealing + ( $self->OwnerObj->Id != $RT::Nobody->Id ) and #and the owner is set + ( $self->CurrentUser->Id ne $self->OwnerObj->Id() ) + ) { #and it's not us + return ( 0, + $self->loc( +"You can only reassign tickets that you own or that are unowned" ) ); } #If we've specified a new owner and that user can't modify the ticket - elsif ( !$NewOwnerObj->HasRight( Right => 'OwnTicket', Object => $self ) ) { - $RT::Handle->Rollback(); + elsif ( ( $NewOwnerObj->Id ) + and ( !$NewOwnerObj->HasRight( Right => 'OwnTicket', + Object => $self ) ) + ) { return ( 0, $self->loc("That user may not own tickets in that queue") ); } - # If the ticket has an owner and it's the new owner, we don't need - # To do anything - elsif ( $NewOwnerObj->Id == $OldOwnerObj->Id ) { - $RT::Handle->Rollback(); + #If the ticket has an owner and it's the new owner, we don't need + #To do anything + elsif ( ( $self->OwnerObj ) + and ( $NewOwnerObj->Id eq $self->OwnerObj->Id ) ) { return ( 0, $self->loc("That user already owns that ticket") ); } + $RT::Handle->BeginTransaction(); + # Delete the owner in the owner group, then add a new one # TODO: is this safe? it's not how we really want the API to work # for most things, but it's fast. @@ -3095,6 +3025,8 @@ sub SetOwner { return ( 0, $self->loc("Could not change owner. ") . $msg ); } + $RT::Handle->Commit(); + ($val, $msg) = $self->_NewTransaction( Type => $Type, Field => 'Owner', @@ -3106,14 +3038,9 @@ sub SetOwner { if ( $val ) { $msg = $self->loc( "Owner changed from [_1] to [_2]", $OldOwnerObj->Name, $NewOwnerObj->Name ); - } - else { - $RT::Handle->Rollback(); - return ( 0, $msg ); - } - - $RT::Handle->Commit(); + # TODO: make sure the trans committed properly + } return ( $val, $msg ); } @@ -3458,8 +3385,6 @@ sub DESTROY { return if $self->{_Destroyed}++; my $batch = $self->TransactionBatch or return; - return unless @$batch; - require RT::Scrips; RT::Scrips->new($RT::SystemUser)->Apply( Stage => 'TransactionBatch', @@ -3692,26 +3617,6 @@ sub HasRight { # }}} -=head2 Reminders - -Return the Reminders object for this ticket. (It's an RT::Reminders object.) -It isn't acutally a searchbuilder collection itself. - -=cut - -sub Reminders { - my $self = shift; - - unless ($self->{'__reminders'}) { - $self->{'__reminders'} = RT::Reminders->new($self->CurrentUser); - $self->{'__reminders'}->Ticket($self->id); - } - return $self->{'__reminders'}; - -} - - - # {{{ sub Transactions =head2 Transactions @@ -3756,7 +3661,7 @@ sub Transactions { =head2 TransactionCustomFields - Returns the custom fields that transactions on tickets will have. + Returns the custom fields that transactions on tickets will ahve. =cut @@ -3791,6 +3696,7 @@ sub CustomFieldValues { # If we didn't find a valid cfid, give up. return RT::CustomFieldValues->new($self->CurrentUser); } + $field = $cf->id; } return $self->SUPER::CustomFieldValues($field); } |