[Rt-commit] rt branch, 4.2/html-transaction-descriptions, created. rt-4.1.5-25-g0f1c6f7

Alex Vandiver alexmv at bestpractical.com
Wed Dec 19 10:52:41 EST 2012


The branch, 4.2/html-transaction-descriptions has been created
        at  0f1c6f74ca70bade62df9745ad2a15e6e872c26f (commit)

- Log -----------------------------------------------------------------
commit 2901ecf0007e7b3b4c0eb2da47e1f6b419f5d11c
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Thu Dec 6 16:56:35 2012 -0800

    Link to added/started/completed reminders from their history entries
    
    We don't expose reminders through the normal ticket display framework,
    so link only to the per-ticket "all reminders" page, scrolled to the
    specific reminder in question via an anchor.

diff --git a/lib/RT/Transaction.pm b/lib/RT/Transaction.pm
index b1a5309..89e0129 100644
--- a/lib/RT/Transaction.pm
+++ b/lib/RT/Transaction.pm
@@ -981,19 +981,34 @@ sub _ProcessReturnValues {
         my $self = shift;
         my $ticket = RT::Ticket->new($self->CurrentUser);
         $ticket->Load($self->NewValue);
-        return ("Reminder '[_1]' added", $ticket->Subject); #loc
+        my $subject = [
+            \'<a href="', RT->Config->Get('WebPath'),
+            "/Ticket/Reminders.html?id=", $self->ObjectId,
+            "#reminder-", $ticket->id, \'">', $ticket->Subject, \'</a>'
+        ];
+        return ("Reminder '[_1]' added", $subject); #loc
     },
     OpenReminder => sub {
         my $self = shift;
         my $ticket = RT::Ticket->new($self->CurrentUser);
         $ticket->Load($self->NewValue);
-        return ("Reminder '[_1]' reopened", $ticket->Subject);  #loc
+        my $subject = [
+            \'<a href="', RT->Config->Get('WebPath'),
+            "/Ticket/Reminders.html?id=", $self->ObjectId,
+            "#reminder-", $ticket->id, \'">', $ticket->Subject, \'</a>'
+        ];
+        return ("Reminder '[_1]' reopened", $subject);  #loc
     },
     ResolveReminder => sub {
         my $self = shift;
         my $ticket = RT::Ticket->new($self->CurrentUser);
         $ticket->Load($self->NewValue);
-        return ("Reminder '[_1]' completed", $ticket->Subject); #loc
+        my $subject = [
+            \'<a href="', RT->Config->Get('WebPath'),
+            "/Ticket/Reminders.html?id=", $self->ObjectId,
+            "#reminder-", $ticket->id, \'">', $ticket->Subject, \'</a>'
+        ];
+        return ("Reminder '[_1]' completed", $subject); #loc
     }
 );
 
diff --git a/share/html/Ticket/Elements/Reminders b/share/html/Ticket/Elements/Reminders
index c12159e..1f2d881 100644
--- a/share/html/Ticket/Elements/Reminders
+++ b/share/html/Ticket/Elements/Reminders
@@ -150,7 +150,7 @@ $Reminder
 $Ticket
 $Index
 </%args>
-<tr class="<% $Index%2 ? 'oddline' : 'evenline' %>">
+<tr class="<% $Index%2 ? 'oddline' : 'evenline' %>" id="reminder-<% $Reminder->id %>">
 <td class="entry">
 % unless ( $Reminder->CurrentUserHasRight('ModifyTicket') ) {
 <input name="Complete-Reminder-<% $Reminder->id %>" type="hidden" 
@@ -192,7 +192,7 @@ $Index
 </%args>
 % my $dueobj = $Reminder->DueObj;
 % my $overdue = $dueobj->Unix > 0 && $dueobj->Diff < 0 ? 1 : 0;
-<tr class="<% $Index%2 ? 'oddline' : 'evenline' %>">
+<tr class="<% $Index%2 ? 'oddline' : 'evenline' %>" id="reminder-<% $Reminder->id %>">
 
 <td class="collection-as-table">
 % unless ( $Reminder->CurrentUserHasRight('ModifyTicket') ) {

commit 3aea0207df2e3b07c0f0d8b38ea2bf67508d7948
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Fri Dec 7 14:57:22 2012 -0800

    Use the per-reminder anchors for links in "My Reminders"

diff --git a/share/html/Elements/ShowReminders b/share/html/Elements/ShowReminders
index 34cde46..d1a8881 100644
--- a/share/html/Elements/ShowReminders
+++ b/share/html/Elements/ShowReminders
@@ -66,7 +66,7 @@ if ( my $ticket= $targets->First ) {
 </%PERL>
 <tr class="<% $i%2 ? 'oddline' : 'evenline' %>">
 <td class="collection-as-table">
-<a href="<% RT->Config->Get('WebPath') %>/Ticket/Reminders.html?id=<% $ticket->id %>"><% $reminder->Subject %></a>
+<a href="<% RT->Config->Get('WebPath') %>/Ticket/Reminders.html?id=<% $ticket->id %>#reminder-<% $reminder->id %>"><% $reminder->Subject %></a>
 </td>
 <td class="collection-as-table">
 <% $overdue ? '<span class="overdue">' : '' |n %><% $dueobj->AgeAsString || loc('Not set') %><% $overdue ? '</span>' : '' |n %>

commit 632aae7efaa7054892df19e62ef0458112adb50e
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Fri Dec 7 12:12:26 2012 -0800

    Remove extraneous license lines from the ShowUser components

diff --git a/share/html/Elements/ShowUser b/share/html/Elements/ShowUser
index 3654977..4e17473 100644
--- a/share/html/Elements/ShowUser
+++ b/share/html/Elements/ShowUser
@@ -45,7 +45,6 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-%# Released under the terms of version 2 of the GNU Public License
 <%INIT>
 # $User is an RT::User object
 # $Address is Email::Address object
diff --git a/share/html/Elements/ShowUserConcise b/share/html/Elements/ShowUserConcise
index b56ba83..09b4319 100644
--- a/share/html/Elements/ShowUserConcise
+++ b/share/html/Elements/ShowUserConcise
@@ -45,7 +45,6 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-%# Released under the terms of version 2 of the GNU Public License
 <% $display |n %>\
 <%ARGS>
 $User => undef
diff --git a/share/html/Elements/ShowUserVerbose b/share/html/Elements/ShowUserVerbose
index 9ff8cbb..6c3c509 100644
--- a/share/html/Elements/ShowUserVerbose
+++ b/share/html/Elements/ShowUserVerbose
@@ -45,7 +45,6 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-%# Released under the terms of version 2 of the GNU Public License
 <% $display |n %>\
 <%INIT>
 my $phrase = '';

commit 9c47cfb67eec9103bbc5d04d9252de4085e2133c
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Fri Dec 7 13:06:30 2012 -0800

    Attempt to load a user from the supplied address for all user formats
    
    Refactors the logic of ShowUserConcise into ShowUser to apply to all
    cases.  ShowUserVerbose is able to display more information if only an
    address is passed and but it corresponds to an existing RT::User.  An
    RT::User object is always better than just an email address.

diff --git a/share/html/Elements/ShowUser b/share/html/Elements/ShowUser
index 4e17473..386bb2a 100644
--- a/share/html/Elements/ShowUser
+++ b/share/html/Elements/ShowUser
@@ -57,9 +57,13 @@ unless ( RT::Interface::Web->ComponentPathIsSafe($comp) and $m->comp_exists( $co
         . ' picked UsernameFormat '. $style
         . ', but '. $comp . "doesn't exist"
     );
-    return $m->comp('/Elements/ShowUserConcise',
-        User => $User, Address => $Address, NoEscape => $NoEscape
-    );
+    $comp = '/Elements/ShowUserConcise';
+}
+
+if (not $User and $Address) {
+    $User = RT::User->new( $session{'CurrentUser'} );
+    $User->LoadByEmail( $Address->address );
+    undef $User unless $User->id;
 }
 return $m->comp( $comp, User => $User, Address => $Address, NoEscape => $NoEscape );
 </%INIT>
diff --git a/share/html/Elements/ShowUserConcise b/share/html/Elements/ShowUserConcise
index 09b4319..8002fa0 100644
--- a/share/html/Elements/ShowUserConcise
+++ b/share/html/Elements/ShowUserConcise
@@ -51,16 +51,7 @@ $User => undef
 $Address => undef
 </%ARGS>
 <%INIT>
-if ( !$User && $Address ) {
-    $User = RT::User->new( $session{'CurrentUser'} );
-    $User->LoadByEmail( $Address->address );
-    if ( $User->Id ) {
-        $Address = '';
-    } else {
-        $Address = $Address->address;
-    }
-}
-my $display = $Address || $User->RealName || $User->Name;
+my $display = $User ? ($User->RealName || $User->Name) : $Address->address;
    $display = $m->interp->apply_escapes( $display, 'h' )
         unless $ARGS{'NoEscape'};
 </%INIT>

commit ac4a4a38f651750d06c647b7a7bdd425792c458d
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Mon Dec 10 17:16:17 2012 -0800

    Move ShowUser* components into RT::User
    
    These formatters generally deal in just text, not HTML, and they can't
    be used by other library code when written in Mason.

diff --git a/docs/UPGRADING-4.2 b/docs/UPGRADING-4.2
index 43a9305..637f96b 100644
--- a/docs/UPGRADING-4.2
+++ b/docs/UPGRADING-4.2
@@ -22,3 +22,14 @@ UPGRADING FROM RT 4.0.0 and greater
 * MakeClicky handlers added via a callback are now passed an "object" key in
   the parameter hash instead of "ticket".  The object may be any RT::Record
   subclass.
+
+* ShowUser handlers (/Elements/ShowUser*) have moved out of Mason components
+  and into RT::User methods.  Any custom username formats will need to be
+  reimplemented as RT::User methods.  Renaming should follow that of the core
+  components:
+
+        /Elements/ShowUserConcise => RT::User->_FormatUserConcise
+        /Elements/ShowUserVerbose => RT::User->_FormatUserVerbose
+
+  The _FormatUser* methods are passed a hash containing the keys User and
+  Address, which have the same properties as before.
diff --git a/lib/RT/User.pm b/lib/RT/User.pm
index 176d30c..cf31492 100644
--- a/lib/RT/User.pm
+++ b/lib/RT/User.pm
@@ -66,6 +66,7 @@ package RT::User;
 use strict;
 use warnings;
 
+use Scalar::Util qw(blessed);
 
 use base 'RT::Record';
 
@@ -1538,9 +1539,120 @@ Return the friendly name
 
 sub FriendlyName {
     my $self = shift;
-    return $self->RealName if defined($self->RealName);
-    return $self->Name if defined($self->Name);
-    return "";
+    return $self->RealName if defined $self->RealName and length $self->RealName;
+    return $self->Name;
+}
+
+=head2 Format
+
+Class or object method.
+
+Returns a string describing a user in the current user's preferred format.
+
+May be invoked in three ways:
+
+    $UserObj->Format;
+    RT::User->Format( User => $UserObj );   # same as above
+    RT::User->Format( Address => $AddressObj, CurrentUser => $CurrentUserObj );
+
+Possible arguments are:
+
+=over
+
+=item User
+
+An L<RT::User> object representing the user to format.  Preferred to Address.
+
+=item Address
+
+An L<Email::Address> object representing the user address to format.  Address
+will be used to lookup an L<RT::User> if possible.
+
+=item CurrentUser
+
+Required when Format is called as a class method with an Address argument.
+Otherwise, this argument is ignored in preference to the CurrentUser of the
+involved L<RT::User> object.
+
+=item Format
+
+Specifies the format to use, overriding any set from the config or current
+user's preferences.
+
+=back
+
+=cut
+
+sub Format {
+    my $self = shift;
+    my %args = (
+        User        => undef,
+        Address     => undef,
+        CurrentUser => undef,
+        Format      => undef,
+        @_
+    );
+
+    if (blessed($self) and $self->id) {
+        @args{"User", "CurrentUser"} = ($self, $self->CurrentUser);
+    }
+    elsif ($args{User} and $args{User}->id) {
+        $args{CurrentUser} = $args{User}->CurrentUser;
+    }
+    elsif ($args{Address} and $args{CurrentUser}) {
+        $args{User} = RT::User->new( $args{CurrentUser} );
+        $args{User}->LoadByEmail( $args{Address}->address );
+        if ($args{User}->id) {
+            delete $args{Address};
+        } else {
+            delete $args{User};
+        }
+    }
+    else {
+        RT->Logger->warning("Invalid arguments to RT::User->Format at @{[join '/', caller]}");
+        return "";
+    }
+
+    $args{Format} ||= RT->Config->Get("UsernameFormat", $args{CurrentUser});
+    $args{Format} =~ s/[^A-Za-z0-9_]+//g;
+
+    my $method    = "_FormatUser" . ucfirst lc $args{Format};
+    my $formatter = $self->can($method);
+
+    unless ($formatter) {
+        RT->Logger->error(
+            "Either system config or user #" . $args{CurrentUser}->id .
+            " picked UsernameFormat $args{Format}, but RT::User->$method doesn't exist"
+        );
+        $formatter = $self->can("_FormatUserConcise");
+    }
+    return $formatter->( $self, map { $_ => $args{$_} } qw(User Address) );
+}
+
+sub _FormatUserConcise {
+    my $self = shift;
+    my %args = @_;
+    return $args{User} ? $args{User}->FriendlyName : $args{Address}->address;
+}
+
+sub _FormatUserVerbose {
+    my $self = shift;
+    my %args = @_;
+    my ($user, $address) = @args{"User", "Address"};
+
+    my $email   = '';
+    my $phrase  = '';
+    my $comment = '';
+
+    if ($user) {
+        $email   = $user->EmailAddress || '';
+        $phrase  = $user->RealName  if $user->RealName and lc $user->RealName ne lc $email;
+        $comment = $user->Name      if lc $user->Name ne lc $email;
+    } else {
+        ($email, $phrase, $comment) = (map { $address->$_ } "address", "phrase", "comment");
+    }
+
+    return join " ", grep { $_ } ($phrase || $comment || ''), ($email ? "<$email>" : "");
 }
 
 =head2 PreferredKey
diff --git a/share/html/Elements/ShowUser b/share/html/Elements/ShowUser
index 386bb2a..f456af6 100644
--- a/share/html/Elements/ShowUser
+++ b/share/html/Elements/ShowUser
@@ -49,27 +49,20 @@
 # $User is an RT::User object
 # $Address is Email::Address object
 
-my $comp = '/Elements/ShowUser'. ucfirst lc $style;
-unless ( RT::Interface::Web->ComponentPathIsSafe($comp) and $m->comp_exists( $comp ) ) {
-    $RT::Logger->error(
-        'Either system config or user #'
-        . $session{'CurrentUser'}->id
-        . ' picked UsernameFormat '. $style
-        . ', but '. $comp . "doesn't exist"
-    );
-    $comp = '/Elements/ShowUserConcise';
-}
+my $display = RT::User->Format(
+    User        => $User,
+    Address     => $Address,
+    CurrentUser => $session{CurrentUser},
+    Format      => $style,
+);
 
-if (not $User and $Address) {
-    $User = RT::User->new( $session{'CurrentUser'} );
-    $User->LoadByEmail( $Address->address );
-    undef $User unless $User->id;
-}
-return $m->comp( $comp, User => $User, Address => $Address, NoEscape => $NoEscape );
+$display = $m->interp->apply_escapes($display, 'h')
+    unless $NoEscape;
 </%INIT>
 <%ARGS>
 $User => undef
 $Address => undef
 $NoEscape => 0
-$style => RT->Config->Get('UsernameFormat', $session{'CurrentUser'})
+$style => undef
 </%ARGS>
+<% $display |n %>\
diff --git a/share/html/Elements/ShowUserConcise b/share/html/Elements/ShowUserConcise
deleted file mode 100644
index 8002fa0..0000000
--- a/share/html/Elements/ShowUserConcise
+++ /dev/null
@@ -1,57 +0,0 @@
-%# BEGIN BPS TAGGED BLOCK {{{
-%#
-%# COPYRIGHT:
-%#
-%# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
-%#                                          <sales at bestpractical.com>
-%#
-%# (Except where explicitly superseded by other copyright notices)
-%#
-%#
-%# LICENSE:
-%#
-%# This work is made available to you under the terms of Version 2 of
-%# the GNU General Public License. A copy of that license should have
-%# been provided with this software, but in any event can be snarfed
-%# from www.gnu.org.
-%#
-%# This work is distributed in the hope that it will be useful, but
-%# WITHOUT ANY WARRANTY; without even the implied warranty of
-%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-%# General Public License for more details.
-%#
-%# 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/licenses/old-licenses/gpl-2.0.html.
-%#
-%#
-%# CONTRIBUTION SUBMISSION POLICY:
-%#
-%# (The following paragraph is not intended to limit the rights granted
-%# to you to modify and distribute this software under the terms of
-%# the GNU General Public License and is only of importance to you if
-%# you choose to contribute your changes and enhancements to the
-%# community by submitting them to Best Practical Solutions, LLC.)
-%#
-%# By intentionally submitting any modifications, corrections or
-%# derivatives to this work, or any other work intended for use with
-%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
-%# you are the copyright holder for those contributions and you grant
-%# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
-%# royalty-free, perpetual, license to use, copy, create derivative
-%# works based on those contributions, and sublicense and distribute
-%# those contributions and any derivatives thereof.
-%#
-%# END BPS TAGGED BLOCK }}}
-<% $display |n %>\
-<%ARGS>
-$User => undef
-$Address => undef
-</%ARGS>
-<%INIT>
-my $display = $User ? ($User->RealName || $User->Name) : $Address->address;
-   $display = $m->interp->apply_escapes( $display, 'h' )
-        unless $ARGS{'NoEscape'};
-</%INIT>
diff --git a/share/html/Elements/ShowUserVerbose b/share/html/Elements/ShowUserVerbose
deleted file mode 100644
index 6c3c509..0000000
--- a/share/html/Elements/ShowUserVerbose
+++ /dev/null
@@ -1,70 +0,0 @@
-%# BEGIN BPS TAGGED BLOCK {{{
-%#
-%# COPYRIGHT:
-%#
-%# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
-%#                                          <sales at bestpractical.com>
-%#
-%# (Except where explicitly superseded by other copyright notices)
-%#
-%#
-%# LICENSE:
-%#
-%# This work is made available to you under the terms of Version 2 of
-%# the GNU General Public License. A copy of that license should have
-%# been provided with this software, but in any event can be snarfed
-%# from www.gnu.org.
-%#
-%# This work is distributed in the hope that it will be useful, but
-%# WITHOUT ANY WARRANTY; without even the implied warranty of
-%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-%# General Public License for more details.
-%#
-%# 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/licenses/old-licenses/gpl-2.0.html.
-%#
-%#
-%# CONTRIBUTION SUBMISSION POLICY:
-%#
-%# (The following paragraph is not intended to limit the rights granted
-%# to you to modify and distribute this software under the terms of
-%# the GNU General Public License and is only of importance to you if
-%# you choose to contribute your changes and enhancements to the
-%# community by submitting them to Best Practical Solutions, LLC.)
-%#
-%# By intentionally submitting any modifications, corrections or
-%# derivatives to this work, or any other work intended for use with
-%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
-%# you are the copyright holder for those contributions and you grant
-%# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
-%# royalty-free, perpetual, license to use, copy, create derivative
-%# works based on those contributions, and sublicense and distribute
-%# those contributions and any derivatives thereof.
-%#
-%# END BPS TAGGED BLOCK }}}
-<% $display |n %>\
-<%INIT>
-my $phrase = '';
-my $address = '';
-my $comment = '';
-
-if ($User) {
-    $address = $User->EmailAddress;
-    $phrase  = $User->RealName if $User->RealName && lc $User->RealName ne lc $address;
-    $comment = $User->Name if lc $User->Name ne lc $address;
-} else {
-    $address = $Address;
-}
-
-my $display = ($phrase || $comment || '' ) . ($address ?  ' <'.$address.'>' : '');
-
-$display = $m->interp->apply_escapes( $display, 'h' )
-    unless $ARGS{'NoEscape'};
-</%INIT>
-<%ARGS>
-$User => undef
-$Address => undef
-</%ARGS>

commit 2fc92598674235a2be45463f5dc1744f1cc83029
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Mon Dec 10 17:21:31 2012 -0800

    Add a callback to ShowUser to allow for HTML injection into the format

diff --git a/share/html/Elements/ShowUser b/share/html/Elements/ShowUser
index f456af6..84a1810 100644
--- a/share/html/Elements/ShowUser
+++ b/share/html/Elements/ShowUser
@@ -56,6 +56,14 @@ my $display = RT::User->Format(
     Format      => $style,
 );
 
+$m->callback(
+    ARGSRef         => \%ARGS,
+    User            => $User,
+    Address         => $Address,
+    NoEscape        => \$NoEscape,
+    CallbackName    => 'Modify',
+);
+
 $display = $m->interp->apply_escapes($display, 'h')
     unless $NoEscape;
 </%INIT>

commit c3ef8c709c475a96b6576e1549fb405494ab9429
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Mon Dec 10 17:36:15 2012 -0800

    Replace some calls to /Elements/ShowUser with Format in RT::User
    
    Calls which aren't in full HTML contexts should call the method to avoid
    any HTML.  This includes most loc strings, <option> contents, RSS
    elements, and autocomplete results.  Almost any call to ShowUser which
    sets NoEscape to a true value should probably be using $User->Format
    instead.

diff --git a/share/html/Dashboards/Elements/SelectPrivacy b/share/html/Dashboards/Elements/SelectPrivacy
index 523790b..d428d22 100644
--- a/share/html/Dashboards/Elements/SelectPrivacy
+++ b/share/html/Dashboards/Elements/SelectPrivacy
@@ -60,11 +60,11 @@ foreach my $object (@Objects) {
     if (ref($object) eq 'RT::User') {
         $label = $object->id == $session{'CurrentUser'}->Id
                     ? loc("My dashboards")
-                    : loc("[_1]'s dashboards", $m->scomp('/Elements/ShowUser', User => $object));
+                    : loc("[_1]'s dashboards", $object->Format);
     } else {
-        $label = loc("[_1]'s dashboards", $m->interp->apply_escapes($object->Name, 'h'));
+        $label = loc("[_1]'s dashboards", $object->Name);
     }
 </%perl>
-<option <%$selected|n%> value="<%$privacy%>"><% $label |n %></option>
+<option <%$selected|n%> value="<%$privacy%>"><% $label %></option>
 % }
 </select>
diff --git a/share/html/Elements/SelectOwnerDropdown b/share/html/Elements/SelectOwnerDropdown
index 5dd6429..96a2c63 100644
--- a/share/html/Elements/SelectOwnerDropdown
+++ b/share/html/Elements/SelectOwnerDropdown
@@ -50,8 +50,8 @@
 <option value=""<% !$Default ? qq[ selected="selected"] : '' |n %>><%$DefaultLabel |n%></option>
 %}
 % $Default = 0 unless defined $Default && $Default =~ /^\d+$/;
-% my @formatednames = sort {lc $a->[1] cmp lc $b->[1]} map {[$_, $m->scomp('/Elements/ShowUser', User => $_)]} grep { $_->id != RT->Nobody->id } @users;
-% my $nobody = [RT->Nobody, $m->scomp('/Elements/ShowUser', User => RT->Nobody)];
+% my @formatednames = sort {lc $a->[1] cmp lc $b->[1]} map {[$_, $_->Format]} grep { $_->id != RT->Nobody->id } @users;
+% my $nobody = [RT->Nobody, RT->Nobody->Format(CurrentUser => $session{CurrentUser})];
 % unshift @formatednames, $nobody;
 %foreach my $UserRef ( @formatednames)  {
 %my $User = $UserRef->[0];
@@ -61,7 +61,7 @@
 %} elsif ($ValueAttribute eq 'Name') {
     value="<%$User->Name%>"
 %}
-><% $UserRef->[1] |n %></option>
+><% $UserRef->[1] %></option>
 %}
 </select>
 <%INIT>
diff --git a/share/html/Helpers/Autocomplete/Owners b/share/html/Helpers/Autocomplete/Owners
index 1d065f2..a9b53e4 100644
--- a/share/html/Helpers/Autocomplete/Owners
+++ b/share/html/Helpers/Autocomplete/Owners
@@ -117,7 +117,7 @@ foreach my $spec (map { [split /\-/, $_, 2] } split /\|/, $limit) {
         next if $user_uniq_hash{ $User->Id };
         $user_uniq_hash{ $User->Id() } = [
             $User,
-            $m->scomp('/Elements/ShowUser', User => $User, NoEscape => 1)
+            $User->Format,
         ];
     }
 }
@@ -127,7 +127,7 @@ my $nobody = qr/^n(?:o(?:b(?:o(?:d(?:y)?)?)?)?)?$/i;
 if ( not $user_uniq_hash{RT->Nobody->id} and $term =~ $nobody ) {
     $user_uniq_hash{RT->Nobody->id} = [
         RT->Nobody,
-        $m->scomp('/Elements/ShowUser', User => RT->Nobody, NoEscape => 1)
+        RT->Nobody->Format,
     ];
 }
 
diff --git a/share/html/Helpers/Autocomplete/Users b/share/html/Helpers/Autocomplete/Users
index c2b92c1..799d5d9 100644
--- a/share/html/Helpers/Autocomplete/Users
+++ b/share/html/Helpers/Autocomplete/Users
@@ -123,9 +123,7 @@ while ( my $user = $users->Next ) {
     next if $user->id == RT->SystemUser->id
          or $user->id == RT->Nobody->id;
 
-    my $formatted = $m->scomp('/Elements/ShowUser', User => $user, NoEscape => 1);
-    $formatted =~ s/\n//g;
-    my $suggestion = { label => $formatted, value => $user->$return };
+    my $suggestion = { label => $user->Format, value => $user->$return };
     $m->callback( CallbackName => "ModifySuggestion", suggestion => $suggestion, user => $user );
     push @suggestions, $suggestion;
 }
diff --git a/share/html/Search/Elements/ResultsRSSView b/share/html/Search/Elements/ResultsRSSView
index 5033c8c..bb74f58 100644
--- a/share/html/Search/Elements/ResultsRSSView
+++ b/share/html/Search/Elements/ResultsRSSView
@@ -119,7 +119,7 @@ $r->content_type('application/rss+xml');
 
 
     while ( my $Ticket = $Tickets->Next()) {
-        my $creator_str = $m->scomp('/Elements/ShowUser', User => $Ticket->CreatorObj);
+        my $creator_str = $Ticket->CreatorObj->Format;
         $creator_str =~ s/[\r\n]//g;
         $rss->add_item(
           title       =>  $Ticket->Subject || loc('No Subject'),
diff --git a/share/html/Search/Elements/SearchPrivacy b/share/html/Search/Elements/SearchPrivacy
index f36c1c8..f897e2e 100644
--- a/share/html/Search/Elements/SearchPrivacy
+++ b/share/html/Search/Elements/SearchPrivacy
@@ -53,9 +53,9 @@ my $label;
 if (ref($Object) eq 'RT::User') {
     $label = $Object->id == $session{'CurrentUser'}->Id
                 ? loc("My saved searches")
-                : loc("[_1]'s saved searches", $m->scomp('/Elements/ShowUser', User => $Object));
+                : loc("[_1]'s saved searches", $Object->Format);
 } else {
-    $label = loc("[_1]'s saved searches", $m->interp->apply_escapes($Object->Name, 'h'));
+    $label = loc("[_1]'s saved searches", $Object->Name);
 }
 </%init>
-<% $label |n %>\
+<% $label %>\
diff --git a/share/html/Ticket/Update.html b/share/html/Ticket/Update.html
index 5734f95..f5cf78e 100644
--- a/share/html/Ticket/Update.html
+++ b/share/html/Ticket/Update.html
@@ -119,7 +119,7 @@
                 Name         => "Owner",
                 TicketObj    => $TicketObj,
                 QueueObj     => $TicketObj->QueueObj,
-                DefaultLabel => loc("[_1] (Unchanged)", $m->scomp('/Elements/ShowUser', User => $TicketObj->OwnerObj)),
+                DefaultLabel => loc("[_1] (Unchanged)", $TicketObj->OwnerObj->Format),
                 Default      => $ARGS{'Owner'}
             }
         },
diff --git a/share/html/m/ticket/reply b/share/html/m/ticket/reply
index 18587bc..2b4cd72 100644
--- a/share/html/m/ticket/reply
+++ b/share/html/m/ticket/reply
@@ -70,7 +70,7 @@
     Name         => "Owner",
     TicketObj    => $t,
     QueueObj     => $t->QueueObj,
-    DefaultLabel => loc("[_1] (Unchanged)", $m->scomp('/Elements/ShowUser', User => $t->OwnerObj)),
+    DefaultLabel => loc("[_1] (Unchanged)", $t->OwnerObj->Format),
     Default      => $ARGS{'Owner'}
 &>
 </div></div>

commit d0e98d40c4cb0dd27d343d67f3cf816902ebf838
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Mon Dec 10 17:38:03 2012 -0800

    Show all users in history using the current user's preferred format

diff --git a/lib/RT/Transaction.pm b/lib/RT/Transaction.pm
index 89e0129..e9934d3 100644
--- a/lib/RT/Transaction.pm
+++ b/lib/RT/Transaction.pm
@@ -720,13 +720,21 @@ sub _ProcessReturnValues {
     },
     "Forward Transaction" => sub {
         my $self = shift;
+        my $recipients = join ", ", map {
+            RT::User->Format( Address => $_, CurrentUser => $self->CurrentUser )
+        } RT::EmailParser->ParseEmailAddress($self->Data);
+
         return ( "Forwarded [_3]Transaction #[_1][_4] to [_2]", #loc
-            $self->Field, $self->Data,
+            $self->Field, $recipients,
             [\'<a href="#txn-', $self->Field, \'">'], \'</a>');
     },
     "Forward Ticket" => sub {
         my $self = shift;
-        return ( "Forwarded Ticket to [_1]", $self->Data ); #loc
+        my $recipients = join ", ", map {
+            RT::User->Format( Address => $_, CurrentUser => $self->CurrentUser )
+        } RT::EmailParser->ParseEmailAddress($self->Data);
+
+        return ( "Forwarded Ticket to [_1]", $recipients ); #loc
     },
     CommentEmailRecord => sub {
         my $self = shift;
@@ -784,31 +792,31 @@ sub _ProcessReturnValues {
         my $New = RT::User->new( $self->CurrentUser );
         $New->Load( $self->NewValue );
 
-        return ("Owner forcibly changed from [_1] to [_2]" , $Old->Name , $New->Name); #loc
+        return ("Owner forcibly changed from [_1] to [_2]", $Old->Format, $New->Format); #loc
     },
     Steal => sub {
         my $self = shift;
         my $Old = RT::User->new( $self->CurrentUser );
         $Old->Load( $self->OldValue );
-        return ("Stolen from [_1]",  $Old->Name);   #loc
+        return ("Stolen from [_1]", $Old->Format);   #loc
     },
     Give => sub {
         my $self = shift;
         my $New = RT::User->new( $self->CurrentUser );
         $New->Load( $self->NewValue );
-        return ( "Given to [_1]",  $New->Name );    #loc
+        return ( "Given to [_1]", $New->Format );    #loc
     },
     AddWatcher => sub {
         my $self = shift;
         my $principal = RT::Principal->new($self->CurrentUser);
         $principal->Load($self->NewValue);
-        return ( "[_1] [_2] added", $self->loc($self->Field), $principal->Object->Name);    #loc
+        return ( "[_1] [_2] added", $self->loc($self->Field), $principal->Object->Format);    #loc
     },
     DelWatcher => sub {
         my $self = shift;
         my $principal = RT::Principal->new($self->CurrentUser);
         $principal->Load($self->OldValue);
-        return ( "[_1] [_2] deleted", $self->loc($self->Field), $principal->Object->Name);  #loc
+        return ( "[_1] [_2] deleted", $self->loc($self->Field), $principal->Object->Format);  #loc
     },
     Subject => sub {
         my $self = shift;
@@ -945,25 +953,26 @@ sub _ProcessReturnValues {
                     return ("Taken");   #loc
                 }
                 else {
-                    return ( "Given to [_1]",  $New->Name );    #loc
+                    return ( "Given to [_1]", $New->Format );    #loc
                 }
             }
             else {
                 if ( $New->id == $self->Creator ) {
-                    return ("Stolen from [_1]",  $Old->Name);   #loc
+                    return ("Stolen from [_1]",  $Old->Format );   #loc
                 }
                 elsif ( $Old->id == $self->Creator ) {
                     if ( $New->id == RT->Nobody->id ) {
                         return ("Untaken"); #loc
                     }
                     else {
-                        return ( "Given to [_1]", $New->Name ); #loc
+                        return ( "Given to [_1]", $New->Format ); #loc
                     }
                 }
                 else {
                     return (
                         "Owner forcibly changed from [_1] to [_2]", #loc
-                        $Old->Name, $New->Name );
+                        $Old->Format, $New->Format
+                    );
                 }
             }
         }

commit d16457df051f14e1fb079e4fdb22d61fc545f1db
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Tue Dec 11 17:06:26 2012 -0800

    Wrap mentioned users in history with an identifying <span>
    
    This helps future extensions customize the history display of users.

diff --git a/lib/RT/Transaction.pm b/lib/RT/Transaction.pm
index e9934d3..1972067 100644
--- a/lib/RT/Transaction.pm
+++ b/lib/RT/Transaction.pm
@@ -677,6 +677,16 @@ sub _ProcessReturnValues {
     } @values;
 }
 
+sub _FormatUser {
+    my $self = shift;
+    my $user = shift;
+    return [
+        \'<span class="user" data-user-id="', $user->id, \'">',
+        $user->Format,
+        \'</span>'
+    ];
+}
+
 %_BriefDescriptions = (
     Create => sub {
         my $self = shift;
@@ -792,31 +802,32 @@ sub _ProcessReturnValues {
         my $New = RT::User->new( $self->CurrentUser );
         $New->Load( $self->NewValue );
 
-        return ("Owner forcibly changed from [_1] to [_2]", $Old->Format, $New->Format); #loc
+        return ("Owner forcibly changed from [_1] to [_2]", #loc
+                map { $self->_FormatUser($_) } $Old, $New);
     },
     Steal => sub {
         my $self = shift;
         my $Old = RT::User->new( $self->CurrentUser );
         $Old->Load( $self->OldValue );
-        return ("Stolen from [_1]", $Old->Format);   #loc
+        return ("Stolen from [_1]", $self->_FormatUser($Old));   #loc
     },
     Give => sub {
         my $self = shift;
         my $New = RT::User->new( $self->CurrentUser );
         $New->Load( $self->NewValue );
-        return ( "Given to [_1]", $New->Format );    #loc
+        return ( "Given to [_1]", $self->_FormatUser($New));    #loc
     },
     AddWatcher => sub {
         my $self = shift;
         my $principal = RT::Principal->new($self->CurrentUser);
         $principal->Load($self->NewValue);
-        return ( "[_1] [_2] added", $self->loc($self->Field), $principal->Object->Format);    #loc
+        return ( "[_1] [_2] added", $self->loc($self->Field), $self->_FormatUser($principal->Object));    #loc
     },
     DelWatcher => sub {
         my $self = shift;
         my $principal = RT::Principal->new($self->CurrentUser);
         $principal->Load($self->OldValue);
-        return ( "[_1] [_2] deleted", $self->loc($self->Field), $principal->Object->Format);  #loc
+        return ( "[_1] [_2] deleted", $self->loc($self->Field), $self->_FormatUser($principal->Object));  #loc
     },
     Subject => sub {
         my $self = shift;
@@ -953,25 +964,25 @@ sub _ProcessReturnValues {
                     return ("Taken");   #loc
                 }
                 else {
-                    return ( "Given to [_1]", $New->Format );    #loc
+                    return ( "Given to [_1]", $self->_FormatUser($New) );    #loc
                 }
             }
             else {
                 if ( $New->id == $self->Creator ) {
-                    return ("Stolen from [_1]",  $Old->Format );   #loc
+                    return ("Stolen from [_1]",  $self->_FormatUser($Old) );   #loc
                 }
                 elsif ( $Old->id == $self->Creator ) {
                     if ( $New->id == RT->Nobody->id ) {
                         return ("Untaken"); #loc
                     }
                     else {
-                        return ( "Given to [_1]", $New->Format ); #loc
+                        return ( "Given to [_1]", $self->_FormatUser($New) ); #loc
                     }
                 }
                 else {
                     return (
                         "Owner forcibly changed from [_1] to [_2]", #loc
-                        $Old->Format, $New->Format
+                        map { $self->_FormatUser($_) } $Old, $New
                     );
                 }
             }

commit c92e61628daed52f89faa49e204d2d467f876a80
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Tue Dec 11 18:59:10 2012 -0800

    Normalize forward recipients before sending and adjust tests to match reality
    
    None of the usual parsing and normalization of email recipients was done
    when forwarding tickets or transactions.  Use RT::EmailParser's
    ParseEmailAddress method to convert to Email::Address objects
    (effectively a split), then reformat and join back together.  This
    ensures domain-less usernames are supported in forwards just like
    elsewhere.  Importantly, this change also ensures the transaction
    recording the forward action has a Data column which is guaranteed
    parseable.
    
    The forwarding tests previously tested a domain-less user in the same
    field as a full email address, which is not supported by RT's email
    parsing and would likely never work as expected with a real MTA.  Switch
    to testing domain-less users are parsed correctly when in their own
    recipient field.
    
    These bugs were uncovered by RT::Transaction's new parsing of $txn->Data
    for generating history descriptions.

diff --git a/lib/RT/Interface/Email.pm b/lib/RT/Interface/Email.pm
index 1c7f9b7..b10322e 100644
--- a/lib/RT/Interface/Email.pm
+++ b/lib/RT/Interface/Email.pm
@@ -638,6 +638,9 @@ sub ForwardTransaction {
     my $txn = shift;
     my %args = ( To => '', Cc => '', Bcc => '', @_ );
 
+    $args{$_} = join ", ", map { $_->format } RT::EmailParser->ParseEmailAddress($args{$_} || '')
+        for qw(To Cc Bcc);
+
     my $entity = $txn->ContentAsMIME;
 
     my ( $ret, $msg ) = SendForward( %args, Entity => $entity, Transaction => $txn );
@@ -665,6 +668,9 @@ sub ForwardTicket {
     my $ticket = shift;
     my %args = ( To => '', Cc => '', Bcc => '', @_ );
 
+    $args{$_} = join ", ", map { $_->format } RT::EmailParser->ParseEmailAddress($args{$_} || '')
+        for qw(To Cc Bcc);
+
     my $txns = $ticket->Transactions;
     $txns->Limit(
         FIELD    => 'Type',
diff --git a/t/web/ticket_forward.t b/t/web/ticket_forward.t
index 3aceaa4..7a7d8d1 100644
--- a/t/web/ticket_forward.t
+++ b/t/web/ticket_forward.t
@@ -36,19 +36,22 @@ diag "Forward Ticket" if $ENV{TEST_VERBOSE};
     $m->submit_form(
         form_name => 'ForwardMessage',
         fields    => {
-            To => 'rt-test, rt-to at example.com',
-            Cc => 'rt-cc at example.com',
+            To  => 'rt-to at example.com, rt-too at example.com',
+            Cc  => 'rt-cc at example.com',
+            Bcc => 'root',
         },
         button => 'ForwardAndReturn'
     );
     $m->content_contains( 'Sent email successfully', 'sent mail msg' );
     $m->content_contains(
-        'Forwarded Ticket to rt-test, rt-to at example.com, rt-cc at example.com',
+        'Forwarded Ticket to rt-to at example.com, rt-too at example.com, rt-cc at example.com, Enoch Root',
         'txn msg' );
     my ($mail) = RT::Test->fetch_caught_mails;
     like( $mail, qr!Subject: test forward!,           'Subject field' );
-    like( $mail, qr!To: rt-test, rt-to\@example.com!, 'To field' );
+    like( $mail, qr!To: .*?rt-to\@example.com!i,      'To field' );
+    like( $mail, qr!To: .*?rt-too\@example.com!i,     'To field' );
     like( $mail, qr!Cc: rt-cc\@example.com!i,         'Cc field' );
+    like( $mail, qr!Bcc: "root" <root\@localhost>!i,  'Bcc field' );
     like( $mail, qr!This is a forward of ticket!,     'content' );
     like( $mail, qr!this is an attachment!,           'att content' );
     like( $mail, qr!$att_name!,                       'att file name' );
@@ -60,22 +63,23 @@ diag "Forward Transaction" if $ENV{TEST_VERBOSE};
     $m->submit_form(
         form_name => 'ForwardMessage',
         fields    => {
-            To  => 'rt-test, rt-to at example.com',
+            To  => 'rt-to at example.com, rt-too at example.com',
             Cc  => 'rt-cc at example.com',
-            Bcc => 'rt-bcc at example.com'
+            Bcc => 'root'
         },
         button => 'ForwardAndReturn'
     );
     $m->content_contains( 'Sent email successfully', 'sent mail msg' );
     $m->content_like(
-qr/Forwarded .*?Transaction #\d+.*? to rt-test, rt-to\@example.com, rt-cc\@example.com, rt-bcc\@example.com/,
+qr/Forwarded .*?Transaction #\d+.*? to rt-to\@example.com, rt-too\@example.com, rt-cc\@example.com, Enoch Root/,
         'txn msg'
     );
     my ($mail) = RT::Test->fetch_caught_mails;
     like( $mail, qr!Subject: test forward!,            'Subject field' );
-    like( $mail, qr!To: rt-test, rt-to\@example.com!,  'To field' );
+    like( $mail, qr!To: .*rt-to\@example.com!i,        'To field' );
+    like( $mail, qr!To: .*rt-too\@example.com!i,       'To field' );
     like( $mail, qr!Cc: rt-cc\@example.com!i,          'Cc field' );
-    like( $mail, qr!Bcc: rt-bcc\@example.com!i,        'Bcc field' );
+    like( $mail, qr!Bcc: "root" <root\@localhost>!i,   'Bcc field' );
     like( $mail, qr!This is a forward of transaction!, 'content' );
     like( $mail, qr!$att_name!,                        'att file name' );
     like( $mail, qr!this is an attachment!,            'att content' );

commit 0f1c6f74ca70bade62df9745ad2a15e6e872c26f
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Wed Dec 12 13:37:00 2012 -0800

    Don't distinguish between visited and unvisited links in transaction descriptions

diff --git a/share/html/NoAuth/css/base/history.css b/share/html/NoAuth/css/base/history.css
index acb8771..9a2a430 100644
--- a/share/html/NoAuth/css/base/history.css
+++ b/share/html/NoAuth/css/base/history.css
@@ -114,6 +114,10 @@ div.history-container {
  font-weight: bold;
 }
 
+.transaction .description a:visited {
+    color: inherit;
+}
+
 .transaction span.time-taken {
  margin-left: 1em;
 }

-----------------------------------------------------------------------


More information about the Rt-commit mailing list