diff options
Diffstat (limited to 'rt/lib/RT/Transaction_Overlay.pm')
| -rw-r--r-- | rt/lib/RT/Transaction_Overlay.pm | 487 |
1 files changed, 175 insertions, 312 deletions
diff --git a/rt/lib/RT/Transaction_Overlay.pm b/rt/lib/RT/Transaction_Overlay.pm index 96ccf51d4..1a5473b3c 100644 --- a/rt/lib/RT/Transaction_Overlay.pm +++ b/rt/lib/RT/Transaction_Overlay.pm @@ -1,8 +1,8 @@ # BEGIN BPS TAGGED BLOCK {{{ # # COPYRIGHT: -# -# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC # <jesse@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -45,7 +45,6 @@ # those contributions and any derivatives thereof. # # END BPS TAGGED BLOCK }}} - =head1 NAME RT::Transaction - RT\'s transaction object @@ -65,6 +64,11 @@ It can have arbitrary MIME attachments. =head1 METHODS +=begin testing + +ok(require RT::Transaction); + +=end testing =cut @@ -78,11 +82,11 @@ use vars qw( %_BriefDescriptions $PreferredContentType ); use RT::Attachments; use RT::Scrips; -use RT::Ruleset; use HTML::FormatText; use HTML::TreeBuilder; + # {{{ sub Create =head2 Create @@ -172,21 +176,9 @@ sub Create { Ticket => $args{'ObjectId'}, Transaction => $self->id, ); - - # Entry point of the rule system - my $ticket = RT::Ticket->new($RT::SystemUser); - $ticket->Load($args{'ObjectId'}); - my $rules = RT::Ruleset->FindAllRules( - Stage => 'TransactionCreate', - Type => $args{'Type'}, - TicketObj => $ticket, - TransactionObj => $self, - ); - if ($args{'CommitScrips'} ) { $RT::Logger->debug('About to commit scrips for transaction #' .$self->Id); $self->{'scrips'}->Commit(); - RT::Ruleset->CommitRules($rules); } } @@ -251,28 +243,26 @@ sub Delete { =head2 Message -Returns the L<RT::Attachments> object which contains the "top-level" object -attachment for this transaction. + Returns the RT::Attachments Object which contains the "top-level"object + attachment for this transaction =cut sub Message { - my $self = shift; - # XXX: Where is ACL check? + my $self = shift; - unless ( defined $self->{'message'} ) { + if ( !defined( $self->{'message'} ) ) { - $self->{'message'} = RT::Attachments->new( $self->CurrentUser ); + $self->{'message'} = new RT::Attachments( $self->CurrentUser ); $self->{'message'}->Limit( FIELD => 'TransactionId', VALUE => $self->Id ); + $self->{'message'}->ChildrenOf(0); - } else { - $self->{'message'}->GotoFirstItem; } - return $self->{'message'}; + return ( $self->{'message'} ); } # }}} @@ -286,43 +276,43 @@ textual part (as defined in RT::I18N::IsTextualContentType). Otherwise, returns undef. Takes a paramhash. If the $args{'Quote'} parameter is set, wraps this message -at $args{'Wrap'}. $args{'Wrap'} defaults to 70. +at $args{'Wrap'}. $args{'Wrap'} defaults to $RT::MessageBoxWidth - 2 or 70. -If $args{'Type'} is set to C<text/html>, this will return an HTML -part of the message, if available. Otherwise it looks for a text/plain -part. If $args{'Type'} is missing, it defaults to the value of -C<$RT::Transaction::PreferredContentType>, if that's missing too, -defaults to 'text/plain'. +If $args{'Type'} is set to C<text/html>, plain texts are upgraded to HTML. +Otherwise, HTML texts are downgraded to plain text. If $args{'Type'} is +missing, it defaults to the value of C<$RT::Transaction::PreferredContentType>. =cut sub Content { my $self = shift; my %args = ( - Type => $PreferredContentType || 'text/plain', + Type => $PreferredContentType, Quote => 0, Wrap => 70, + Wrap => ( $RT::MessageBoxWidth || 72 ) - 2, @_ ); my $content; - if ( my $content_obj = $self->ContentObj( Type => $args{Type} ) ) { - $content = $content_obj->Content ||''; + if (my $content_obj = $self->ContentObj) { + $content = $content_obj->Content; - if ( lc $content_obj->ContentType eq 'text/html' ) { + if ($content_obj->ContentType =~ m{^text/html$}i) { $content =~ s/<p>--\s+<br \/>.*?$//s if $args{'Quote'}; if ($args{Type} ne 'text/html') { - my $tree = HTML::TreeBuilder->new_from_content( $content ); $content = HTML::FormatText->new( leftmargin => 0, rightmargin => 78, - )->format( $tree); - $tree->delete; + )->format( + HTML::TreeBuilder->new_from_content( $content ) + ); } - } + } else { $content =~ s/\n-- \n.*?$//s if $args{'Quote'}; + if ($args{Type} eq 'text/html') { # Extremely simple text->html converter $content =~ s/&/&/g; @@ -343,10 +333,10 @@ sub Content { # What's the longest line like? my $max = 0; foreach ( split ( /\n/, $content ) ) { - $max = length if length > $max; + $max = length if ( length > $max ); } - if ( $max > 76 ) { + if ( $max > $args{'Wrap'}+6 ) { # 76 ) { require Text::Wrapper; my $wrapper = new Text::Wrapper( columns => $args{'Wrap'}, @@ -357,7 +347,7 @@ sub Content { } $content =~ s/^/> /gm; - $content = $self->loc("On [_1], [_2] wrote:", $self->CreatedAsString, $self->CreatorObj->Name) + $content = $self->loc("On [_1], [_2] wrote:", $self->CreatedAsString(), $self->CreatorObj->Name()) . "\n$content\n\n"; } @@ -366,26 +356,6 @@ sub Content { # }}} - -=head2 Addresses - -Returns a hashref of addresses related to this transaction. See L<RT::Attachment/Addresses> for details. - -=cut - -sub Addresses { - my $self = shift; - - if (my $attach = $self->Attachments->First) { - return $attach->Addresses; - } - else { - return {}; - } - -} - - # {{{ ContentObj =head2 ContentObj @@ -396,13 +366,16 @@ Returns the RT::Attachment object which contains the content for this Transactio sub ContentObj { + my $self = shift; - my %args = ( Type => $PreferredContentType || 'text/plain', - @_ ); - # If we don't have any content, return undef now. + # If we don\'t have any content, return undef now. + unless ( $self->Attachments->First ) { + return (undef); + } + # Get the set of toplevel attachments to this transaction. - return undef unless my $Attachment = $self->Attachments->First; + my $Attachment = $self->Attachments->First(); # If it's a textual part, just return the body. if ( RT::I18N::IsTextualContentType($Attachment->ContentType) ) { @@ -412,23 +385,27 @@ sub ContentObj { # If it's a multipart object, first try returning the first part with preferred # MIME type ('text/plain' by default). - elsif ( $Attachment->ContentType =~ '^multipart/' ) { - my $plain_parts = $Attachment->Children; - $plain_parts->ContentType( VALUE => $args{Type} ); - $plain_parts->LimitNotEmpty; + elsif ( $Attachment->ContentType() =~ '^multipart/' ) { + my $plain_parts = $Attachment->Children(); + $plain_parts->ContentType( VALUE => ($PreferredContentType || 'text/plain') ); # If we actully found a part, return its content - if ( my $first = $plain_parts->First ) { - return $first; + if ( $plain_parts->First && $plain_parts->First->Content ne '' ) { + return ( $plain_parts->First ); } + # If that fails, return the first textual part which has some content. - my $all_parts = $self->Attachments; - while ( my $part = $all_parts->Next ) { - next unless RT::I18N::IsTextualContentType($part->ContentType) - && $part->Content; - return $part; + + else { + my $all_parts = $self->Attachments(); + while ( my $part = $all_parts->Next ) { + if ( ( RT::I18N::IsTextualContentType($part->ContentType) ) and ( $part->Content() ne '' ) ) { + return ($part); + } + } } + } # We found no content. suck @@ -448,8 +425,12 @@ Otherwise, returns null sub Subject { my $self = shift; - return undef unless my $first = $self->Attachments->First; - return $first->Subject; + if ( $self->Attachments->First ) { + return ( $self->Attachments->First->Subject ); + } + else { + return (undef); + } } # }}} @@ -458,7 +439,7 @@ sub Subject { =head2 Attachments -Returns all the RT::Attachment objects which are attached + Returns all the RT::Attachment objects which are attached to this transaction. Takes an optional parameter, which is a ContentType that Attachments should be restricted to. @@ -467,28 +448,38 @@ a ContentType that Attachments should be restricted to. sub Attachments { my $self = shift; - if ( $self->{'attachments'} ) { - $self->{'attachments'}->GotoFirstItem; - return $self->{'attachments'}; - } + unless ( $self->{'attachments'} ) { + $self->{'attachments'} = RT::Attachments->new( $self->CurrentUser ); - $self->{'attachments'} = RT::Attachments->new( $self->CurrentUser ); + #If it's a comment, return an empty object if they don't have the right to see it + if ( $self->Type eq 'Comment' ) { + unless ( $self->CurrentUserHasRight('ShowTicketComments') ) { + return ( $self->{'attachments'} ); + } + } - unless ( $self->CurrentUserCanSee ) { - $self->{'attachments'}->Limit(FIELD => 'id', VALUE => '0'); - return $self->{'attachments'}; - } + #if they ain't got rights to see, return an empty object + elsif ($self->__Value('ObjectType') eq "RT::Ticket") { + unless ( $self->CurrentUserHasRight('ShowTicket') ) { + return ( $self->{'attachments'} ); + } + } + + $self->{'attachments'}->Limit( FIELD => 'TransactionId', + VALUE => $self->Id ); - $self->{'attachments'}->Limit( FIELD => 'TransactionId', VALUE => $self->Id ); + # Get the self->{'attachments'} in the order they're put into + # the database. Arguably, we should be returning a tree + # of self->{'attachments'}, not a set...but no current app seems to need + # it. - # Get the self->{'attachments'} in the order they're put into - # the database. Arguably, we should be returning a tree - # of self->{'attachments'}, not a set...but no current app seems to need - # it. + $self->{'attachments'}->OrderBy( ALIAS => 'main', + FIELD => 'id', + ORDER => 'asc' ); - $self->{'attachments'}->OrderBy( FIELD => 'id', ORDER => 'ASC' ); + } + return ( $self->{'attachments'} ); - return $self->{'attachments'}; } # }}} @@ -505,70 +496,26 @@ sub _Attach { my $self = shift; my $MIMEObject = shift; - unless ( defined $MIMEObject ) { - $RT::Logger->error("We can't attach a mime object if you don't give us one."); + if ( !defined($MIMEObject) ) { + $RT::Logger->error( +"$self _Attach: We can't attach a mime object if you don't give us one.\n" + ); return ( 0, $self->loc("[_1]: no attachment specified", $self) ); } - my $Attachment = RT::Attachment->new( $self->CurrentUser ); + my $Attachment = new RT::Attachment( $self->CurrentUser ); my ($id, $msg) = $Attachment->Create( TransactionId => $self->Id, Attachment => $MIMEObject ); return ( $Attachment, $msg || $self->loc("Attachment created") ); + } # }}} # }}} -sub ContentAsMIME { - my $self = shift; - - my $main_content = $self->ContentObj; - my $entity = $main_content->ContentAsMIME; - - if ( $main_content->Parent ) { - # main content is not top most entity, we shouldn't loose - # From/To/Cc headers that are on a top part - my $attachments = RT::Attachments->new( $self->CurrentUser ); - $attachments->Columns(qw(id Parent TransactionId Headers)); - $attachments->Limit( FIELD => 'TransactionId', VALUE => $self->id ); - $attachments->Limit( FIELD => 'Parent', VALUE => 0 ); - $attachments->Limit( FIELD => 'Parent', OPERATOR => 'IS', VALUE => 'NULL', QUOTEVALUE => 0 ); - $attachments->OrderBy( FIELD => 'id', ORDER => 'ASC' ); - my $tmp = $attachments->First; - if ( $tmp && $tmp->id ne $main_content->id ) { - $entity->make_multipart; - $entity->head->add( split /:/, $_, 2 ) foreach $tmp->SplitHeaders; - $entity->make_singlepart; - } - } - - my $attachments = RT::Attachments->new( $self->CurrentUser ); - $attachments->Limit( FIELD => 'TransactionId', VALUE => $self->id ); - $attachments->Limit( - FIELD => 'id', - OPERATOR => '!=', - VALUE => $main_content->id, - ); - $attachments->Limit( - FIELD => 'ContentType', - OPERATOR => 'NOT STARTSWITH', - VALUE => 'multipart/', - ); - $attachments->Limit( - FIELD => 'Content', - OPERATOR => '!=', - VALUE => '', - ); - while ( my $a = $attachments->Next ) { - $entity->make_multipart unless $entity->is_multipart; - $entity->add_part( $a->ContentAsMIME ); - } - return $entity; -} - # {{{ Routines dealing with Transaction Attributes # {{{ sub Description @@ -582,15 +529,28 @@ Returns a text string which describes this transaction sub Description { my $self = shift; - unless ( $self->CurrentUserCanSee ) { - return ( $self->loc("Permission Denied") ); + #Check those ACLs + #If it's a comment or a comment email record, + # we need to be extra special careful + + if ( $self->__Value('Type') =~ /^Comment/ ) { + unless ( $self->CurrentUserHasRight('ShowTicketComments') ) { + return ( $self->loc("Permission Denied") ); + } } - unless ( defined $self->Type ) { + #if they ain't got rights to see, don't let em + elsif ($self->__Value('ObjectType') eq "RT::Ticket") { + unless ( $self->CurrentUserHasRight('ShowTicket') ) { + return ($self->loc("Permission Denied") ); + } + } + + if ( !defined( $self->Type ) ) { return ( $self->loc("No transaction type specified")); } - return $self->loc("[_1] by [_2]", $self->BriefDescription , $self->CreatorObj->Name ); + return ( $self->loc("[_1] by [_2]",$self->BriefDescription , $self->CreatorObj->Name )); } # }}} @@ -606,13 +566,24 @@ Returns a text string which briefly describes this transaction sub BriefDescription { my $self = shift; - unless ( $self->CurrentUserCanSee ) { - return ( $self->loc("Permission Denied") ); + #If it's a comment or a comment email record, + # we need to be extra special careful + if ( $self->__Value('Type') =~ /^Comment/ ) { + unless ( $self->CurrentUserHasRight('ShowTicketComments') ) { + return ( $self->loc("Permission Denied") ); + } + } + + #if they ain't got rights to see, don't let em + elsif ( $self->__Value('ObjectType') eq "RT::Ticket" ) { + unless ( $self->CurrentUserHasRight('ShowTicket') ) { + return ( $self->loc("Permission Denied") ); + } } my $type = $self->Type; #cache this, rather than calling it 30 times - unless ( defined $type ) { + if ( !defined($type) ) { return $self->loc("No transaction type specified"); } @@ -621,12 +592,6 @@ sub BriefDescription { if ( $type eq 'Create' ) { return ( $self->loc( "[_1] created", $obj_type ) ); } - elsif ( $type eq 'Enabled' ) { - return ( $self->loc( "[_1] enabled", $obj_type ) ); - } - elsif ( $type eq 'Disabled' ) { - return ( $self->loc( "[_1] disabled", $obj_type ) ); - } elsif ( $type =~ /Status/ ) { if ( $self->Field eq 'Status' ) { if ( $self->NewValue eq 'deleted' ) { @@ -700,10 +665,10 @@ sub BriefDescription { $field = $cf->Name(); } - if ( ! defined $self->OldValue || $self->OldValue eq '' ) { + if ( $self->OldValue eq '' ) { return ( $self->loc("[_1] [_2] added", $field, $self->NewValue) ); } - elsif ( !defined $self->NewValue || $self->NewValue eq '' ) { + elsif ( $self->NewValue eq '' ) { return ( $self->loc("[_1] [_2] deleted", $field, $self->OldValue) ); } @@ -832,21 +797,6 @@ sub BriefDescription { return ( $self->Data ); } }, - Told => sub { - my $self = shift; - if ( $self->Field eq 'Told' ) { - my $t1 = new RT::Date($self->CurrentUser); - $t1->Set(Format => 'ISO', Value => $self->NewValue); - my $t2 = new RT::Date($self->CurrentUser); - $t2->Set(Format => 'ISO', Value => $self->OldValue); - return $self->loc( "[_1] changed from [_2] to [_3]", $self->loc($self->Field), $t2->AsString, $t1->AsString ); - } - else { - return $self->loc( "[_1] changed from [_2] to [_3]", - $self->loc($self->Field), - ($self->OldValue? "'".$self->OldValue ."'" : $self->loc("(no value)")) , "'". $self->NewValue."'" ); - } - }, Set => sub { my $self = shift; if ( $self->Field eq 'Password' ) { @@ -857,8 +807,7 @@ sub BriefDescription { $q1->Load( $self->OldValue ); my $q2 = new RT::Queue( $self->CurrentUser ); $q2->Load( $self->NewValue ); - return $self->loc("[_1] changed from [_2] to [_3]", - $self->loc($self->Field) , $q1->Name , $q2->Name); + return $self->loc("[_1] changed from [_2] to [_3]", $self->Field , $q1->Name , $q2->Name); } # Write the date/time change at local time: @@ -867,12 +816,10 @@ sub BriefDescription { $t1->Set(Format => 'ISO', Value => $self->NewValue); my $t2 = new RT::Date($self->CurrentUser); $t2->Set(Format => 'ISO', Value => $self->OldValue); - return $self->loc( "[_1] changed from [_2] to [_3]", $self->loc($self->Field), $t2->AsString, $t1->AsString ); + return $self->loc( "[_1] changed from [_2] to [_3]", $self->Field, $t2->AsString, $t1->AsString ); } else { - return $self->loc( "[_1] changed from [_2] to [_3]", - $self->loc($self->Field), - ($self->OldValue? "'".$self->OldValue ."'" : $self->loc("(no value)")) , "'". $self->NewValue."'" ); + return $self->loc( "[_1] changed from [_2] to [_3]", $self->Field, ($self->OldValue? "'".$self->OldValue ."'" : $self->loc("(no value)")) , "'". $self->NewValue."'" ); } }, PurgeTransaction => sub { @@ -957,19 +904,52 @@ Returns its value as a string, if the user passes an ACL check =cut sub _Value { + my $self = shift; my $field = shift; #if the field is public, return it. if ( $self->_Accessible( $field, 'public' ) ) { - return $self->SUPER::_Value( $field ); + return ( $self->__Value($field) ); + + } + + #If it's a comment, we need to be extra special careful + if ( $self->__Value('Type') eq 'Comment' ) { + unless ( $self->CurrentUserHasRight('ShowTicketComments') ) { + return (undef); + } + } + elsif ( $self->__Value('Type') eq 'CommentEmailRecord' ) { + unless ( $self->CurrentUserHasRight('ShowTicketComments') + && $self->CurrentUserHasRight('ShowOutgoingEmail') ) { + return (undef); + } + } + elsif ( $self->__Value('Type') eq 'EmailRecord' ) { + unless ( $self->CurrentUserHasRight('ShowOutgoingEmail')) { + return (undef); + } - unless ( $self->CurrentUserCanSee ) { - return undef; + } + # Make sure the user can see the custom field before showing that it changed + elsif ( ( $self->__Value('Type') eq 'CustomField' ) && $self->__Value('Field') ) { + my $cf = RT::CustomField->new( $self->CurrentUser ); + $cf->Load( $self->__Value('Field') ); + return (undef) unless ( $cf->CurrentUserHasRight('SeeCustomField') ); + } + + + #if they ain't got rights to see, don't let em + elsif ($self->__Value('ObjectType') eq "RT::Ticket") { + unless ( $self->CurrentUserHasRight('ShowTicket') ) { + return (undef); + } } - return $self->SUPER::_Value( $field ); + return ( $self->__Value($field) ); + } # }}} @@ -986,60 +966,14 @@ passed in here. sub CurrentUserHasRight { my $self = shift; my $right = shift; - return $self->CurrentUser->HasRight( - Right => $right, - Object => $self->Object + return ( + $self->CurrentUser->HasRight( + Right => "$right", + Object => $self->TicketObj + ) ); } -=head2 CurrentUserCanSee - -Returns true if current user has rights to see this particular transaction. - -This fact depends on type of the transaction, type of an object the transaction -is attached to and may be other conditions, so this method is prefered over -custom implementations. - -=cut - -sub CurrentUserCanSee { - my $self = shift; - - # If it's a comment, we need to be extra special careful - my $type = $self->__Value('Type'); - if ( $type eq 'Comment' ) { - unless ( $self->CurrentUserHasRight('ShowTicketComments') ) { - return 0; - } - } - elsif ( $type eq 'CommentEmailRecord' ) { - unless ( $self->CurrentUserHasRight('ShowTicketComments') - && $self->CurrentUserHasRight('ShowOutgoingEmail') ) { - return 0; - } - } - elsif ( $type eq 'EmailRecord' ) { - unless ( $self->CurrentUserHasRight('ShowOutgoingEmail') ) { - return 0; - } - } - # Make sure the user can see the custom field before showing that it changed - elsif ( $type eq 'CustomField' and my $cf_id = $self->__Value('Field') ) { - my $cf = RT::CustomField->new( $self->CurrentUser ); - $cf->SetContextObject( $self->Object ); - $cf->Load( $cf_id ); - return 0 unless $cf->CurrentUserHasRight('SeeCustomField'); - } - #if they ain't got rights to see, don't let em - elsif ( $self->__Value('ObjectType') eq "RT::Ticket" ) { - unless ( $self->CurrentUserHasRight('ShowTicket') ) { - return 0; - } - } - - return 1; -} - # }}} sub Ticket { @@ -1084,7 +1018,7 @@ sub Object { my $self = shift; my $Object = $self->__Value('ObjectType')->new($self->CurrentUser); $Object->Load($self->__Value('ObjectId')); - return $Object; + return($Object); } sub FriendlyObjectType { @@ -1114,6 +1048,7 @@ sub UpdateCustomFields { # value "ARGSRef", which was a reference to a hash of arguments. # This was insane. The next few lines of code preserve that API # while giving us something saner. + # TODO: 3.6: DEPRECATE OLD API @@ -1161,11 +1096,9 @@ sub CustomFieldValues { if ( UNIVERSAL::can( $self->Object, 'QueueObj' ) ) { - # XXX: $field could be undef when we want fetch values for all CFs - # do we want to cover this situation somehow here? unless ( defined $field && $field =~ /^\d+$/o ) { my $CFs = RT::CustomFields->new( $self->CurrentUser ); - $CFs->Limit( FIELD => 'Name', VALUE => $field ); + $CFs->Limit( FIELD => 'Name', VALUE => $field); $CFs->LimitToLookupType($self->CustomFieldLookupType); $CFs->LimitToGlobalOrObjectId($self->Object->QueueObj->id); $field = $CFs->First->id if $CFs->First; @@ -1191,54 +1124,7 @@ sub CustomFieldLookupType { "RT::Queue-RT::Ticket-RT::Transaction"; } - -=head2 DeferredRecipients($freq, $include_sent ) - -Takes the following arguments: - -=over - -=item * a string to indicate the frequency of digest delivery. Valid values are "daily", "weekly", or "susp". - -=item * an optional argument which, if true, will return addresses even if this notification has been marked as 'sent' for this transaction. - -=back - -Returns an array of users who should now receive the notification that -was recorded in this transaction. Returns an empty array if there were -no deferred users, or if $include_sent was not specified and the deferred -notifications have been sent. - -=cut - -sub DeferredRecipients { - my $self = shift; - my $freq = shift; - my $include_sent = @_? shift : 0; - - my $attr = $self->FirstAttribute('DeferredRecipients'); - - return () unless ($attr); - - my $deferred = $attr->Content; - - return () unless ( ref($deferred) eq 'HASH' && exists $deferred->{$freq} ); - - # Skip it. - - for my $user (keys %{$deferred->{$freq}}) { - if ($deferred->{$freq}->{$user}->{_sent} && !$include_sent) { - delete $deferred->{$freq}->{$user} - } - } - # Now get our users. Easy. - - return keys %{ $deferred->{$freq} }; -} - - - -# Transactions don't change. by adding this cache config directive, we don't lose pathalogically on long tickets. +# Transactions don't change. by adding this cache congif directiove, we don't lose pathalogically on long tickets. sub _CacheConfig { { 'cache_p' => 1, @@ -1246,27 +1132,4 @@ sub _CacheConfig { 'cache_for_sec' => 6000, } } - - -=head2 ACLEquivalenceObjects - -This method returns a list of objects for which a user's rights also apply -to this Transaction. - -This currently only applies to Transaction Custom Fields on Tickets, so we return -the Ticket's Queue and the Ticket. - -This method is called from L<RT::Principal/HasRight>. - -=cut - -sub ACLEquivalenceObjects { - my $self = shift; - - return unless $self->ObjectType eq 'RT::Ticket'; - my $object = $self->Object; - return $object,$object->QueueObj; - -} - 1; |
