[freeside-commits] freeside/rt/lib/RT Groups_Overlay.pm, 1.3, 1.4 Record.pm, 1.5, 1.6 SearchBuilder.pm, 1.6, 1.7 Ticket_Overlay.pm, 1.8, 1.9 Transaction_Overlay.pm, 1.3, 1.4 User_Overlay.pm, 1.3, 1.4 Users_Overlay.pm, 1.3, 1.4

Ivan,,, ivan at wavetail.420.am
Thu Dec 31 06:00:31 PST 2009


Update of /home/cvs/cvsroot/freeside/rt/lib/RT
In directory wavetail.420.am:/tmp/cvs-serv560/lib/RT

Modified Files:
	Groups_Overlay.pm Record.pm SearchBuilder.pm Ticket_Overlay.pm 
	Transaction_Overlay.pm User_Overlay.pm Users_Overlay.pm 
Log Message:
merging 3.8.7!!!

Index: SearchBuilder.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/rt/lib/RT/SearchBuilder.pm,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- SearchBuilder.pm	31 Dec 2009 12:44:09 -0000	1.6
+++ SearchBuilder.pm	31 Dec 2009 14:00:28 -0000	1.7
@@ -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 at bestpractical.com>
 # 
 # (Except where explicitly superseded by other copyright notices)
@@ -45,6 +45,7 @@
 # those contributions and any derivatives thereof.
 # 
 # END BPS TAGGED BLOCK }}}
+
 =head1 NAME
 
   RT::SearchBuilder - a baseclass for RT collection objects
@@ -57,11 +58,6 @@
 =head1 METHODS
 
 
-=begin testing
-
-ok (require RT::SearchBuilder);
-
-=end testing
 
 
 =cut
@@ -72,10 +68,10 @@
 use DBIx::SearchBuilder "1.50";
 
 use strict;
-use vars qw(@ISA);
- at ISA = qw(DBIx::SearchBuilder RT::Base);
+use warnings;
+
+use base qw(DBIx::SearchBuilder RT::Base);
 
-# {{{ sub _Init 
 sub _Init  {
     my $self = shift;
     
@@ -88,13 +84,10 @@
     }
     $self->SUPER::_Init( 'Handle' => $RT::Handle);
 }
-# }}}
-
-# {{{ sub LimitToEnabled
 
 =head2 LimitToEnabled
 
-Only find items that haven\'t been disabled
+Only find items that haven't been disabled
 
 =cut
 
@@ -105,9 +98,6 @@
 		  VALUE => '0',
 		  OPERATOR => '=' );
 }
-# }}}
-
-# {{{ sub LimitToDisabled
 
 =head2 LimitToDeleted
 
@@ -124,9 +114,6 @@
 		  VALUE => '1'
 		);
 }
-# }}}
-
-# {{{ sub LimitAttribute
 
 =head2 LimitAttribute PARAMHASH
 
@@ -140,17 +127,17 @@
 
 =cut
 
-my %Negate = qw(
-    =		!=
-    !=		=
-    >		<=
-    <		>=
-    >=		<
-    <=		>
-    LIKE	NOT LIKE
-    NOT LIKE	LIKE
-    IS		IS NOT
-    IS NOT	IS
+my %Negate = (
+    '='        => '!=',
+    '!='       => '=',
+    '>'        => '<=',
+    '<'        => '>=',
+    '>='       => '<',
+    '<='       => '>',
+    'LIKE'     => 'NOT LIKE',
+    'NOT LIKE' => 'LIKE',
+    'IS'       => 'IS NOT',
+    'IS NOT'   => 'IS',
 );
 
 sub LimitAttribute {
@@ -217,9 +204,6 @@
 	VALUE      => 'NULL',
     ) if $args{NULL};
 }
-# }}}
-
-# {{{ sub LimitCustomField
 
 =head2 LimitCustomField
 
@@ -278,8 +262,6 @@
     );
 }
 
-# {{{ sub FindAllRows
-
 =head2 FindAllRows
 
 Find all matching rows, regardless of whether they are disabled or not
@@ -290,8 +272,6 @@
     shift->{'find_disabled_rows'} = 1;
 }
 
-# {{{ sub Limit 
-
 =head2 Limit PARAMHASH
 
 This Limit sub calls SUPER::Limit, but defaults "CASESENSITIVE" to 1, thus
@@ -308,10 +288,6 @@
     return $self->SUPER::Limit(%args);
 }
 
-# }}}
-
-# {{{ sub ItemsOrderBy
-
 =head2 ItemsOrderBy
 
 If it has a SortOrder attribute, sort the array by SortOrder.
@@ -335,55 +311,21 @@
     return $items;
 }
 
-# }}}
-
-# {{{ sub ItemsArrayRef
-
 =head2 ItemsArrayRef
 
 Return this object's ItemsArray, in the order that ItemsOrderBy sorts
 it.
 
-=begin testing
-
-use_ok(RT::Queues);
-ok(my $queues = RT::Queues->new($RT::SystemUser), 'Created a queues object');
-ok( $queues->UnLimit(),'Unlimited the result set of the queues object');
-my $items = $queues->ItemsArrayRef();
-my @items = @{$items};
-
-ok($queues->NewItem->_Accessible('Name','read'));
-my @sorted = sort {lc($a->Name) cmp lc($b->Name)} @items;
-ok (@sorted, "We have an array of queues, sorted". join(',',map {$_->Name} @sorted));
-
-ok (@items, "We have an array of queues, raw". join(',',map {$_->Name} @items));
-my @sorted_ids = map {$_->id } @sorted;
-my @items_ids = map {$_->id } @items;
-
-is ($#sorted, $#items);
-is ($sorted[0]->Name, $items[0]->Name);
-is ($sorted[-1]->Name, $items[-1]->Name);
-is_deeply(\@items_ids, \@sorted_ids, "ItemsArrayRef sorts alphabetically by name");;
-
-
-=end testing
-
 =cut
 
 sub ItemsArrayRef {
     my $self = shift;
-    my @items;
-    
     return $self->ItemsOrderBy($self->SUPER::ItemsArrayRef());
 }
 
-# }}}
-
 eval "require RT::SearchBuilder_Vendor";
 die $@ if ($@ && $@ !~ qr{^Can't locate RT/SearchBuilder_Vendor.pm});
 eval "require RT::SearchBuilder_Local";
 die $@ if ($@ && $@ !~ qr{^Can't locate RT/SearchBuilder_Local.pm});
 
 1;
-
-

Index: User_Overlay.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/rt/lib/RT/User_Overlay.pm,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- User_Overlay.pm	31 Dec 2009 12:44:09 -0000	1.3
+++ User_Overlay.pm	31 Dec 2009 14:00:29 -0000	1.4
@@ -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 at bestpractical.com>
 # 
 # (Except where explicitly superseded by other copyright notices)
@@ -45,6 +45,7 @@
[...1321 lines suppressed...]
+        Content => $key,
+    );
+    return ($status, $self->loc("Couldn't set private key"))    
+        unless $status;
+    return ($status, $self->loc("Unset private key"));
+}
 
 sub BasicColumns {
     (
-	[ Name => 'User Id' ],
-	[ EmailAddress => 'Email' ],
-	[ RealName => 'Name' ],
-	[ Organization => 'Organization' ],
+    [ Name => 'User Id' ],
+    [ EmailAddress => 'Email' ],
+    [ RealName => 'Name' ],
+    [ Organization => 'Organization' ],
     );
 }
 

Index: Groups_Overlay.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/rt/lib/RT/Groups_Overlay.pm,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- Groups_Overlay.pm	31 Dec 2009 12:44:08 -0000	1.3
+++ Groups_Overlay.pm	31 Dec 2009 14:00:28 -0000	1.4
@@ -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 at bestpractical.com>
 # 
 # (Except where explicitly superseded by other copyright notices)
@@ -45,6 +45,7 @@
 # those contributions and any derivatives thereof.
 # 
 # END BPS TAGGED BLOCK }}}
+
 =head1 NAME
 
   RT::Groups - a collection of RT::Group objects
@@ -52,7 +53,7 @@
 =head1 SYNOPSIS
 
   use RT::Groups;
-  my $groups = $RT::Groups->new($CurrentUser);
+  my $groups = RT::Groups->new($CurrentUser);
   $groups->UnLimit();
   while (my $group = $groups->Next()) {
      print $group->Id ." is a group id\n";
@@ -64,11 +65,6 @@
 =head1 METHODS
 
 
-=begin testing
-
-ok (require RT::Groups);
-
-=end testing
 
 =cut
 
@@ -88,24 +84,6 @@
 
 # {{{ sub _Init
 
-=begin testing
-
-# next had bugs
-# Groups->Limit( FIELD => 'id', OPERATOR => '!=', VALUE => xx );
-my $g = RT::Group->new($RT::SystemUser);
-my ($id, $msg) = $g->CreateUserDefinedGroup(Name => 'GroupsNotEqualTest');
-ok ($id, "created group #". $g->id) or diag("error: $msg");
-
-my $groups = RT::Groups->new($RT::SystemUser);
-$groups->Limit( FIELD => 'id', OPERATOR => '!=', VALUE => $g->id );
-$groups->LimitToUserDefinedGroups();
-my $bug = grep $_->id == $g->id, @{$groups->ItemsArrayRef};
-ok (!$bug, "didn't find group");
-
-=end testing
-
-=cut
-
 sub _Init { 
   my $self = shift;
   $self->{'table'} = "Groups";
@@ -172,7 +150,7 @@
 
 # {{{ LimiToUserDefinedGroups
 
-=head2 LimitToUserDefined Groups
+=head2 LimitToUserDefinedGroups
 
 Return only UserDefined Groups
 
@@ -189,7 +167,7 @@
 
 # }}}
 
-# {{{ LimiToPersonalGroups
+# {{{ LimiToPersonalGroupsFor
 
 =head2 LimitToPersonalGroupsFor PRINCIPAL_ID
 
@@ -265,27 +243,6 @@
 
 Limits the set of groups returned to groups which have
 Principal PRINCIPAL_ID as a member
-   
-=begin testing
-
-my $u = RT::User->new($RT::SystemUser);
-$u->Create(Name => 'Membertests');
-my $g = RT::Group->new($RT::SystemUser);
-my ($id, $msg) = $g->CreateUserDefinedGroup(Name => 'Membertests');
-ok ($id, $msg);
-
-my ($aid, $amsg) =$g->AddMember($u->id);
-ok ($aid, $amsg);
-ok($g->HasMember($u->PrincipalObj),"G has member u");
-
-my $groups = RT::Groups->new($RT::SystemUser);
-$groups->LimitToUserDefinedGroups();
-$groups->WithMember(PrincipalId => $u->id);
-ok ($groups->Count == 1,"found the 1 group - " . $groups->Count);
-ok ($groups->First->Id == $g->Id, "it's the right one");
-
-=end testing
-
 
 =cut
 
@@ -307,92 +264,42 @@
     $self->Limit(ALIAS => $members, FIELD => 'MemberId', OPERATOR => '=', VALUE => $args{'PrincipalId'});
 }
 
+sub WithoutMember {
+    my $self = shift;
+    my %args = (
+        PrincipalId => undef,
+        Recursively => undef,
+        @_
+    );
+
+    my $members = $args{'Recursively'} ? 'CachedGroupMembers' : 'GroupMembers';
+    my $members_alias = $self->Join(
+        TYPE   => 'LEFT',
+        FIELD1 => 'id',
+        TABLE2 => $members,
+        FIELD2 => 'GroupId',
+    );
+    $self->Limit(
+        LEFTJOIN => $members_alias,
+        ALIAS    => $members_alias,
+        FIELD    => 'MemberId',
+        OPERATOR => '=',
+        VALUE    => $args{'PrincipalId'},
+    );
+    $self->Limit(
+        ALIAS    => $members_alias,
+        FIELD    => 'MemberId',
+        OPERATOR => 'IS',
+        VALUE    => 'NULL',
+        QUOTEVALUE => 0,
+    );
+}
 
 =head2 WithRight { Right => RIGHTNAME, Object => RT::Record, IncludeSystemRights => 1, IncludeSuperusers => 0, EquivObjects => [ ] }
 
 
 Find all groups which have RIGHTNAME for RT::Record. Optionally include global rights and superusers. By default, include the global rights, but not the superusers.
 
-=begin testing
-
-my $q = RT::Queue->new($RT::SystemUser);
-my ($id, $msg) =$q->Create( Name => 'GlobalACLTest');
-ok ($id, $msg);
-
-my $testuser = RT::User->new($RT::SystemUser);
-($id,$msg) = $testuser->Create(Name => 'JustAnAdminCc');
-ok ($id,$msg);
-
-my $global_admin_cc = RT::Group->new($RT::SystemUser);
-$global_admin_cc->LoadSystemRoleGroup('AdminCc');
-ok($global_admin_cc->id, "Found the global admincc group");
-my $groups = RT::Groups->new($RT::SystemUser);
-$groups->WithRight(Right => 'OwnTicket', Object => $q);
-is($groups->Count, 1);
-($id, $msg) = $global_admin_cc->PrincipalObj->GrantRight(Right =>'OwnTicket', Object=> $RT::System);
-ok ($id,$msg);
-ok (!$testuser->HasRight(Object => $q, Right => 'OwnTicket') , "The test user does not have the right to own tickets in the test queue");
-($id, $msg) = $q->AddWatcher(Type => 'AdminCc', PrincipalId => $testuser->id);
-ok($id,$msg);
-ok ($testuser->HasRight(Object => $q, Right => 'OwnTicket') , "The test user does have the right to own tickets now. thank god.");
-
-$groups = RT::Groups->new($RT::SystemUser);
-$groups->WithRight(Right => 'OwnTicket', Object => $q);
-ok ($id,$msg);
-is($groups->Count, 3);
-
-my $RTxGroup = RT::Group->new($RT::SystemUser);
-($id, $msg) = $RTxGroup->CreateUserDefinedGroup( Name => 'RTxGroup', Description => "RTx extension group");
-ok ($id,$msg);
-
-my $RTxSysObj = {};
-bless $RTxSysObj, 'RTx::System';
-*RTx::System::Id = sub { 1; };
-*RTx::System::id = *RTx::System::Id;
-my $ace = RT::Record->new($RT::SystemUser);
-$ace->Table('ACL');
-$ace->_BuildTableAttributes unless ($_TABLE_ATTR->{ref($self)});
-($id, $msg) = $ace->Create( PrincipalId => $RTxGroup->id, PrincipalType => 'Group', RightName => 'RTxGroupRight', ObjectType => 'RTx::System', ObjectId  => 1);
-ok ($id, "ACL for RTxSysObj created");
-
-my $RTxObj = {};
-bless $RTxObj, 'RTx::System::Record';
-*RTx::System::Record::Id = sub { 4; };
-*RTx::System::Record::id = *RTx::System::Record::Id;
-
-$groups = RT::Groups->new($RT::SystemUser);
-$groups->WithRight(Right => 'RTxGroupRight', Object => $RTxSysObj);
-is($groups->Count, 1, "RTxGroupRight found for RTxSysObj");
-
-$groups = RT::Groups->new($RT::SystemUser);
-$groups->WithRight(Right => 'RTxGroupRight', Object => $RTxObj);
-is($groups->Count, 0, "RTxGroupRight not found for RTxObj");
-
-$groups = RT::Groups->new($RT::SystemUser);
-$groups->WithRight(Right => 'RTxGroupRight', Object => $RTxObj, EquivObjects => [ $RTxSysObj ]);
-is($groups->Count, 1, "RTxGroupRight found for RTxObj using EquivObjects");
-
-$ace = RT::Record->new($RT::SystemUser);
-$ace->Table('ACL');
-$ace->_BuildTableAttributes unless ($_TABLE_ATTR->{ref($self)});
-($id, $msg) = $ace->Create( PrincipalId => $RTxGroup->id, PrincipalType => 'Group', RightName => 'RTxGroupRight', ObjectType => 'RTx::System::Record', ObjectId  => 5 );
-ok ($id, "ACL for RTxObj created");
-
-my $RTxObj2 = {};
-bless $RTxObj2, 'RTx::System::Record';
-*RTx::System::Record::Id = sub { 5; };
-
-$groups = RT::Groups->new($RT::SystemUser);
-$groups->WithRight(Right => 'RTxGroupRight', Object => $RTxObj2);
-is($groups->Count, 1, "RTxGroupRight found for RTxObj2");
-
-$groups = RT::Groups->new($RT::SystemUser);
-$groups->WithRight(Right => 'RTxGroupRight', Object => $RTxObj2, EquivObjects => [ $RTxSysObj ]);
-is($groups->Count, 1, "RTxGroupRight found for RTxObj2");
-
-
-
-=end testing
 
 
 =cut

Index: Ticket_Overlay.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/rt/lib/RT/Ticket_Overlay.pm,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- Ticket_Overlay.pm	31 Dec 2009 12:44:09 -0000	1.8
+++ Ticket_Overlay.pm	31 Dec 2009 14:00:28 -0000	1.9
@@ -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 at bestpractical.com>
 # 
 # (Except where explicitly superseded by other copyright notices)
@@ -45,6 +45,7 @@
[...2170 lines suppressed...]
+=head2 ACLEquivalenceObjects
+
+This method returns a list of objects for which a user's rights also apply
+to this ticket. Generally, this is only the ticket's queue, but some RT 
+extensions may make other objects available too.
+
+This method is called from L<RT::Principal/HasRight>.
+
+=cut
+
+sub ACLEquivalenceObjects {
+    my $self = shift;
+    return $self->QueueObj;
+
+}
+
+
 1;
 
 =head1 AUTHOR

Index: Transaction_Overlay.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/rt/lib/RT/Transaction_Overlay.pm,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- Transaction_Overlay.pm	31 Dec 2009 12:44:09 -0000	1.3
+++ Transaction_Overlay.pm	31 Dec 2009 14:00:28 -0000	1.4
@@ -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 at bestpractical.com>
 # 
 # (Except where explicitly superseded by other copyright notices)
@@ -45,6 +45,7 @@
 # those contributions and any derivatives thereof.
 # 
 # END BPS TAGGED BLOCK }}}
+
 =head1 NAME
 
   RT::Transaction - RT\'s transaction object
@@ -64,11 +65,6 @@
 
 =head1 METHODS
 
-=begin testing
-
-ok(require RT::Transaction);
-
-=end testing
 
 =cut
 
@@ -82,11 +78,11 @@
 
 use RT::Attachments;
 use RT::Scrips;
+use RT::Ruleset;
 
 use HTML::FormatText;
 use HTML::TreeBuilder;
 
-
 # {{{ sub Create 
 
 =head2 Create
@@ -176,9 +172,21 @@
             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);
         }
     }
 
@@ -243,26 +251,28 @@
 
 =head2 Message
 
-  Returns the RT::Attachments Object which contains the "top-level"object
-  attachment for this transaction
+Returns the L<RT::Attachments> object which contains the "top-level" object
+attachment for this transaction.
 
 =cut
 
 sub Message {
-
     my $self = shift;
+
+    # XXX: Where is ACL check?
     
-    if ( !defined( $self->{'message'} ) ) {
+    unless ( defined $self->{'message'} ) {
 
-        $self->{'message'} = new RT::Attachments( $self->CurrentUser );
+        $self->{'message'} = RT::Attachments->new( $self->CurrentUser );
         $self->{'message'}->Limit(
             FIELD => 'TransactionId',
             VALUE => $self->Id
         );
-
         $self->{'message'}->ChildrenOf(0);
+    } else {
+        $self->{'message'}->GotoFirstItem;
     }
-    return ( $self->{'message'} );
+    return $self->{'message'};
 }
 
 # }}}
@@ -278,16 +288,18 @@
 Takes a paramhash.  If the $args{'Quote'} parameter is set, wraps this message 
 at $args{'Wrap'}.  $args{'Wrap'} defaults to $RT::MessageBoxWidth - 2 or 70.
 
-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>.
+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'.
 
 =cut
 
 sub Content {
     my $self = shift;
     my %args = (
-        Type  => $PreferredContentType,
+        Type  => $PreferredContentType || 'text/plain',
         Quote => 0,
         Wrap  => 70,
         Wrap  => ( $RT::MessageBoxWidth || 72 ) - 2,
@@ -295,24 +307,23 @@
     );
 
     my $content;
-    if (my $content_obj = $self->ContentObj) {
-        $content = $content_obj->Content;
+    if ( my $content_obj = $self->ContentObj( Type => $args{Type} ) ) {
+        $content = $content_obj->Content ||'';
 
-	if ($content_obj->ContentType =~ m{^text/html$}i) {
+        if ( lc $content_obj->ContentType eq 'text/html' ) {
             $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(
-                    HTML::TreeBuilder->new_from_content( $content )
-                );
+                )->format( $tree);
+                $tree->delete;
             }
-	}
+        }
         else {
             $content =~ s/\n-- \n.*?$//s if $args{'Quote'};
-
             if ($args{Type} eq 'text/html') {
                 # Extremely simple text->html converter
                 $content =~ s/&/&#38;/g;
@@ -333,7 +344,7 @@
         # 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 > $args{'Wrap'}+6 ) { # 76 ) {
@@ -347,7 +358,7 @@
         }
 
         $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";
     }
 
@@ -356,6 +367,26 @@
 
 # }}}
 
+
+=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 
@@ -366,16 +397,13 @@
 
 
 sub ContentObj {
-
     my $self = shift;
+    my %args = ( Type => $PreferredContentType || 'text/plain',
+                 @_ );
 
-    # If we don\'t have any content, return undef now.
-    unless ( $self->Attachments->First ) {
-        return (undef);
-    }
-
+    # If we don't have any content, return undef now.
     # Get the set of toplevel attachments to this transaction.
-    my $Attachment = $self->Attachments->First();
+    return undef unless my $Attachment = $self->Attachments->First;
 
     # If it's a textual part, just return the body.
     if ( RT::I18N::IsTextualContentType($Attachment->ContentType) ) {
@@ -385,27 +413,23 @@
     # 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 => ($PreferredContentType || 'text/plain') );
+    elsif ( $Attachment->ContentType =~ '^multipart/' ) {
+        my $plain_parts = $Attachment->Children;
+        $plain_parts->ContentType( VALUE => $args{Type} );
+        $plain_parts->LimitNotEmpty;
 
         # If we actully found a part, return its content
-        if ( $plain_parts->First && $plain_parts->First->Content ne '' ) {
-            return ( $plain_parts->First );
+        if ( my $first = $plain_parts->First ) {
+            return $first;
         }
 
-
         # If that fails, return the first textual part which has some content.
-
-        else {
-            my $all_parts = $self->Attachments();
-            while ( my $part = $all_parts->Next ) {
-                if ( ( RT::I18N::IsTextualContentType($part->ContentType) ) and ( $part->Content() ne '' ) ) {
-                    return ($part);
-                }
-            }
+        my $all_parts = $self->Attachments;
+        while ( my $part = $all_parts->Next ) {
+            next unless RT::I18N::IsTextualContentType($part->ContentType)
+                        && $part->Content;
+            return $part;
         }
-
     }
 
     # We found no content. suck
@@ -425,12 +449,8 @@
 
 sub Subject {
     my $self = shift;
-    if ( $self->Attachments->First ) {
-        return ( $self->Attachments->First->Subject );
-    }
-    else {
-        return (undef);
-    }
+    return undef unless my $first = $self->Attachments->First;
+    return $first->Subject;
 }
 
 # }}}
@@ -439,7 +459,7 @@
 
 =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.
 
@@ -448,38 +468,28 @@
 sub Attachments {
     my $self = shift;
 
-    unless ( $self->{'attachments'} ) {
-        $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'} );
-            }
-        }
+    if ( $self->{'attachments'} ) {
+        $self->{'attachments'}->GotoFirstItem;
+        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'} = RT::Attachments->new( $self->CurrentUser );
 
-        $self->{'attachments'}->Limit( FIELD => 'TransactionId',
-                                       VALUE => $self->Id );
+    unless ( $self->CurrentUserCanSee ) {
+        $self->{'attachments'}->Limit(FIELD => 'id', VALUE => '0');
+        return $self->{'attachments'};
+    }
 
-        # 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'}->Limit( FIELD => 'TransactionId', VALUE => $self->Id );
 
-        $self->{'attachments'}->OrderBy( ALIAS => 'main',
-                                         FIELD => 'id',
-                                         ORDER => 'asc' );
+    # 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.
 
-    }
-    return ( $self->{'attachments'} );
+    $self->{'attachments'}->OrderBy( FIELD => 'id', ORDER => 'ASC' );
 
+    return $self->{'attachments'};
 }
 
 # }}}
@@ -496,26 +506,70 @@
     my $self       = shift;
     my $MIMEObject = shift;
 
-    if ( !defined($MIMEObject) ) {
-        $RT::Logger->error(
-"$self _Attach: We can't attach a mime object if you don't give us one.\n"
-        );
+    unless ( defined $MIMEObject ) {
+        $RT::Logger->error("We can't attach a mime object if you don't give us one.");
         return ( 0, $self->loc("[_1]: no attachment specified", $self) );
     }
 
-    my $Attachment = new RT::Attachment( $self->CurrentUser );
+    my $Attachment = RT::Attachment->new( $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 
@@ -529,28 +583,15 @@
 sub Description {
     my $self = shift;
 
-    #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") );
-        }
-    }
-
-    #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") );
-        }
+    unless ( $self->CurrentUserCanSee ) {
+        return ( $self->loc("Permission Denied") );
     }
 
-    if ( !defined( $self->Type ) ) {
+    unless ( 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 );
 }
 
 # }}}
@@ -566,24 +607,13 @@
 sub BriefDescription {
     my $self = shift;
 
-    #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") );
-        }
+    unless ( $self->CurrentUserCanSee ) {
+        return ( $self->loc("Permission Denied") );
     }
 
     my $type = $self->Type;    #cache this, rather than calling it 30 times
 
-    if ( !defined($type) ) {
+    unless ( defined $type ) {
         return $self->loc("No transaction type specified");
     }
 
@@ -592,6 +622,12 @@
     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' ) {
@@ -665,10 +701,10 @@
             $field = $cf->Name();
         }
 
-        if ( $self->OldValue eq '' ) {
+        if ( ! defined $self->OldValue || $self->OldValue eq '' ) {
             return ( $self->loc("[_1] [_2] added", $field, $self->NewValue) );
         }
-        elsif ( $self->NewValue eq '' ) {
+        elsif ( !defined $self->NewValue || $self->NewValue eq '' ) {
             return ( $self->loc("[_1] [_2] deleted", $field, $self->OldValue) );
 
         }
@@ -797,6 +833,21 @@
             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' ) {
@@ -807,7 +858,8 @@
             $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->Field , $q1->Name , $q2->Name);
+            return $self->loc("[_1] changed from [_2] to [_3]",
+                              $self->loc($self->Field) , $q1->Name , $q2->Name);
         }
 
         # Write the date/time change at local time:
@@ -816,10 +868,12 @@
             $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->Field, $t2->AsString, $t1->AsString );
+            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->Field, ($self->OldValue? "'".$self->OldValue ."'" : $self->loc("(no value)")) , "'". $self->NewValue."'" );
+            return $self->loc( "[_1] changed from [_2] to [_3]",
+                               $self->loc($self->Field),
+                               ($self->OldValue? "'".$self->OldValue ."'" : $self->loc("(no value)")) , "'". $self->NewValue."'" );
         }
     },
     PurgeTransaction => sub {
@@ -904,52 +958,19 @@
 =cut
 
 sub _Value {
-
     my $self  = shift;
     my $field = shift;
 
     #if the field is public, return it.
     if ( $self->_Accessible( $field, 'public' ) ) {
-        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);
-        }
-
-    }
-    # 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') );
+        return $self->SUPER::_Value( $field );
     }
 
-
-    #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);
-        }
+    unless ( $self->CurrentUserCanSee ) {
+        return undef;
     }
 
-    return ( $self->__Value($field) );
-
+    return $self->SUPER::_Value( $field );
 }
 
 # }}}
@@ -966,14 +987,60 @@
 sub CurrentUserHasRight {
     my $self  = shift;
     my $right = shift;
-    return (
-        $self->CurrentUser->HasRight(
-            Right     => "$right",
-            Object => $self->TicketObj
-          )
+    return $self->CurrentUser->HasRight(
+        Right  => $right,
+        Object => $self->Object
     );
 }
 
+=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 {
@@ -1018,7 +1085,7 @@
     my $self  = shift;
     my $Object = $self->__Value('ObjectType')->new($self->CurrentUser);
     $Object->Load($self->__Value('ObjectId'));
-    return($Object);
+    return $Object;
 }
 
 sub FriendlyObjectType {
@@ -1048,7 +1115,6 @@
     # 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
 
@@ -1096,9 +1162,11 @@
 
     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;
@@ -1124,7 +1192,54 @@
     "RT::Queue-RT::Ticket-RT::Transaction";
 }
 
-# Transactions don't change. by adding this cache congif directiove, we don't lose pathalogically on long tickets.
+
+=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.
 sub _CacheConfig {
   {
      'cache_p'        => 1,
@@ -1132,4 +1247,27 @@
      '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;

Index: Users_Overlay.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/rt/lib/RT/Users_Overlay.pm,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- Users_Overlay.pm	31 Dec 2009 12:44:09 -0000	1.3
+++ Users_Overlay.pm	31 Dec 2009 14:00:29 -0000	1.4
@@ -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 at bestpractical.com>
 # 
 # (Except where explicitly superseded by other copyright notices)
@@ -45,6 +45,7 @@
 # those contributions and any derivatives thereof.
 # 
 # END BPS TAGGED BLOCK }}}
+
 =head1 NAME
 
   RT::Users - Collection of RT::User objects
@@ -59,11 +60,6 @@
 
 =head1 METHODS
 
-=begin testing
-
-ok(require RT::Users);
-
-=end testing
 
 =cut
 
@@ -232,68 +228,6 @@
 
 =head2 WhoHaveRight { Right => 'name', Object => $rt_object , IncludeSuperusers => undef, IncludeSubgroupMembers => undef, IncludeSystemRights => undef, EquivObjects => [ ] }
 
-=begin testing
-
-ok(my $users = RT::Users->new($RT::SystemUser));
-$users->WhoHaveRight(Object =>$RT::System, Right =>'SuperUser');
-ok($users->Count == 1, "There is one privileged superuser - Found ". $users->Count );
-# TODO: this wants more testing
-
-my $RTxUser = RT::User->new($RT::SystemUser);
-($id, $msg) = $RTxUser->Create( Name => 'RTxUser', Comments => "RTx extension user", Privileged => 1);
-ok ($id,$msg);
-
-my $group = RT::Group->new($RT::SystemUser);
-$group->LoadACLEquivalenceGroup($RTxUser->PrincipalObj);
-
-my $RTxSysObj = {};
-bless $RTxSysObj, 'RTx::System';
-*RTx::System::Id = sub { 1; };
-*RTx::System::id = *RTx::System::Id;
-my $ace = RT::Record->new($RT::SystemUser);
-$ace->Table('ACL');
-$ace->_BuildTableAttributes unless ($_TABLE_ATTR->{ref($self)});
-($id, $msg) = $ace->Create( PrincipalId => $group->id, PrincipalType => 'Group', RightName => 'RTxUserRight', ObjectType => 'RTx::System', ObjectId  => 1 );
-ok ($id, "ACL for RTxSysObj created");
-
-my $RTxObj = {};
-bless $RTxObj, 'RTx::System::Record';
-*RTx::System::Record::Id = sub { 4; };
-*RTx::System::Record::id = *RTx::System::Record::Id;
-
-$users = RT::Users->new($RT::SystemUser);
-$users->WhoHaveRight(Right => 'RTxUserRight', Object => $RTxSysObj);
-is($users->Count, 1, "RTxUserRight found for RTxSysObj");
-
-$users = RT::Users->new($RT::SystemUser);
-$users->WhoHaveRight(Right => 'RTxUserRight', Object => $RTxObj);
-is($users->Count, 0, "RTxUserRight not found for RTxObj");
-
-$users = RT::Users->new($RT::SystemUser);
-$users->WhoHaveRight(Right => 'RTxUserRight', Object => $RTxObj, EquivObjects => [ $RTxSysObj ]);
-is($users->Count, 1, "RTxUserRight found for RTxObj using EquivObjects");
-
-$ace = RT::Record->new($RT::SystemUser);
-$ace->Table('ACL');
-$ace->_BuildTableAttributes unless ($_TABLE_ATTR->{ref($self)});
-($id, $msg) = $ace->Create( PrincipalId => $group->id, PrincipalType => 'Group', RightName => 'RTxUserRight', ObjectType => 'RTx::System::Record', ObjectId => 5 );
-ok ($id, "ACL for RTxObj created");
-
-my $RTxObj2 = {};
-bless $RTxObj2, 'RTx::System::Record';
-*RTx::System::Record::Id = sub { 5; };
-*RTx::System::Record::id = sub { 5; };
-
-$users = RT::Users->new($RT::SystemUser);
-$users->WhoHaveRight(Right => 'RTxUserRight', Object => $RTxObj2);
-is($users->Count, 1, "RTxUserRight found for RTxObj2");
-
-$users = RT::Users->new($RT::SystemUser);
-$users->WhoHaveRight(Right => 'RTxUserRight', Object => $RTxObj2, EquivObjects => [ $RTxSysObj ]);
-is($users->Count, 1, "RTxUserRight found for RTxObj2");
-
-
-=end testing
 
 find all users who the right Right for this group, either individually
 or as members of groups
@@ -363,6 +297,16 @@
         @_,
     );
 
+    if ( $args{'Right'} ) {
+        my $canonic = RT::ACE->CanonicalizeRightName( $args{'Right'} );
+        unless ( $canonic ) {
+            $RT::Logger->error("Invalid right. Couldn't canonicalize right '$args{'Right'}'");
+        }
+        else {
+            $args{'Right'} = $canonic;
+        }
+    }
+
     my $acl = $self->NewAlias('ACL');
     $self->Limit(
         ALIAS    => $acl,
@@ -403,7 +347,7 @@
 
         # XXX: This should be abstracted into object itself
         if( $args{'Object'}->id ) {
-            push @objects, $args{'Object'}->QueueObj;
+            push @objects, $args{'Object'}->ACLEquivalenceObjects;
         } else {
             push @objects, 'RT::Queue';
         }

Index: Record.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/rt/lib/RT/Record.pm,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- Record.pm	31 Dec 2009 12:44:08 -0000	1.5
+++ Record.pm	31 Dec 2009 14:00:28 -0000	1.6
@@ -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 at bestpractical.com>
 # 
 # (Except where explicitly superseded by other copyright notices)
@@ -45,6 +45,7 @@
[...976 lines suppressed...]
 }
 
+sub ACLEquivalenceObjects { } 
 
-# }}}
-
-# }}}
-
-# }}}
-
-sub BasicColumns {
-}
+sub BasicColumns { }
 
 sub WikiBase {
-  return $RT::WebPath. "/index.html?q=";
+    return RT->Config->Get('WebPath'). "/index.html?q=";
 }
 
 eval "require RT::Record_Vendor";



More information about the freeside-commits mailing list