[Rt-commit] rt branch, 4.4/custom-role-sort-order, created. rt-4.4.4-411-g26c2125b8e

? sunnavy sunnavy at bestpractical.com
Wed May 5 14:53:18 EDT 2021


The branch, 4.4/custom-role-sort-order has been created
        at  26c2125b8e53ebe58c662c0bcd928a44ce7e9d21 (commit)

- Log -----------------------------------------------------------------
commit 8b87cf76d4827dd9e069ab0206e30465dbc35c44
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Sat Feb 22 02:30:16 2020 +0800

    Support to set sort order of applied custom roles
    
    This is quite like custom fields but simpler mainly because custom roles
    are only applied at queue level.
    
    The code is originally from custom fields' corresponding pages with the
    following differences:
    
    * No globally applied custom roles
    
    There is no corresponding /Admin/Global/CustomRoles.html and we also
    don't need to consider ObjectCustomRoles with ObjectId=0
    
    * No spearate right like "AssignCustomRoles"
    
    Current AddToObject/RemoveFromObject methods check "AdminCustomRoles"
    right, we stick to that on new page too.
    
    As there is no queue-level "AdminCustomRoles", we don't need to set
    specified queue as context object.
    
    * Params ObjectType/SubType are dropped
    
    * AddToObject/RemoveFromObject are called a bit differently
    
    The API is different from custom field
    
    * A bit code style cleanup

diff --git a/lib/RT/CustomRoles.pm b/lib/RT/CustomRoles.pm
index cca57926c0..669d0d88a0 100644
--- a/lib/RT/CustomRoles.pm
+++ b/lib/RT/CustomRoles.pm
@@ -172,6 +172,29 @@ sub ApplySortOrder {
     } );
 }
 
+=head2 LimitToNotAdded
+
+Takes either list of object ids or nothing. Limits collection
+to custom roles to listed objects or any corespondingly.
+
+=cut
+
+sub LimitToNotAdded {
+    my $self = shift;
+    return RT::ObjectCustomRoles->new( $self->CurrentUser )->LimitTargetToNotAdded( $self => @_ );
+}
+
+=head2 LimitToAdded
+
+Limits collection to custom roles to listed objects or any corespondingly.
+
+=cut
+
+sub LimitToAdded {
+    my $self = shift;
+    return RT::ObjectCustomRoles->new( $self->CurrentUser )->LimitTargetToAdded( $self => @_ );
+}
+
 RT::Base->_ImportOverlays();
 
 1;
diff --git a/share/html/Admin/Elements/EditCustomRoles b/share/html/Admin/Elements/EditCustomRoles
new file mode 100644
index 0000000000..2ab7cc38cb
--- /dev/null
+++ b/share/html/Admin/Elements/EditCustomRoles
@@ -0,0 +1,170 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2019 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 }}}
+<& /Elements/ListActions, actions => \@results &>
+
+<form action="<%RT->Config->Get('WebPath')%><% $m->request_comp->path |n %>" method="post" name="EditCustomRoles">
+<input type="hidden" class="hidden" name="id" value="<% $id %>" />
+
+<h2><&|/l&>Selected Custom Roles</&></h2>
+<& /Elements/CollectionList,
+    %ARGS,
+    Collection    => $added_crs,
+    Rows          => 0,
+    Page          => 1,
+    Format        => $format,
+    DisplayFormat => $display_format,
+    AllowSorting  => 0,
+    ShowEmpty     => 0,
+    PassArguments => [
+        qw(Page Order OrderBy id),
+    ],
+&>
+
+<h2><&|/l&>Unselected Custom Roles</&></h2>
+<& /Elements/CollectionList,
+    OrderBy       => 'Name',
+    Order         => 'ASC',
+    %ARGS,
+    Collection    => $not_added_crs,
+    Rows          => $rows,
+    Format        => $format,
+    DisplayFormat => "'__CheckBox.{AddCustomRole}__',". $format,
+    AllowSorting  => 1,
+    ShowEmpty     => 0,
+    PassArguments => [
+        qw(Page Order OrderBy id),
+    ],
+&>
+
+<& /Elements/Submit, Name => 'UpdateCRs' &>
+</form>
+
+
+<%INIT>
+my $id = $Object->Id or Abort( loc("Invalid object") );
+
+if ( !$Object->CurrentUserHasRight('AdminCustomRoles') ) {
+    $m->out( '<p><i>', loc('(No custom roles)'), '</i></p>' );
+    return;
+}
+
+my @results;
+
+## deal with moving sortorder of custom roles
+if ( $MoveCustomRoleUp ) {
+    my $record = RT::ObjectCustomRole->new( $session{'CurrentUser'} );
+    $record->LoadByCols( ObjectId => $id, CustomRole => $MoveCustomRoleUp );
+    unless ( $record->id ) {
+        push @results, loc("Custom role #[_1] is not applied to this object", $MoveCustomRoleUp);
+        last;
+    }
+
+    my ( $status, $msg ) = $record->MoveUp;
+    push @results, $msg;
+}
+if ( $MoveCustomRoleDown ) {
+    my $record = RT::ObjectCustomRole->new( $session{'CurrentUser'} );
+    $record->LoadByCols( ObjectId => $id, CustomRole => $MoveCustomRoleDown );
+    unless ( $record->id ) {
+        push @results, loc("Custom role #[_1] is not applied to this object", $MoveCustomRoleDown);
+        last;
+    }
+
+    my ( $status, $msg ) = $record->MoveDown;
+    push @results, $msg;
+}
+
+if ( $UpdateCRs ) {
+    for my $cr_id ( @AddCustomRole ) {
+        my $cr = RT::CustomRole->new( $session{'CurrentUser'} );
+        $cr->Load( $cr_id );
+        unless ( $cr->id ) {
+            push @results, loc("Couldn't load CustomRole #[_1]", $cr_id);
+            next;
+        }
+        my ( $status, $msg ) = $cr->AddToObject($id);
+        push @results, $msg;
+    }
+    for my $cr_id ( @RemoveCustomRole ) {
+        my $cr = RT::CustomRole->new( $session{'CurrentUser'} );
+        $cr->Load( $cr_id );
+        unless ( $cr->id ) {
+            push @results, loc("Couldn't load CustomRole #[_1]", $cr_id);
+            next;
+        }
+        my ( $status, $msg ) = $cr->RemoveFromObject($id);
+        push @results, $msg;
+    }
+}
+
+$m->callback( CallbackName => 'UpdateExtraFields', Results => \@results, Object => $Object, %ARGS );
+
+my $added_crs = RT::CustomRoles->new( $session{'CurrentUser'} );
+$added_crs->LimitToObjectId($id);
+$added_crs->ApplySortOrder;
+
+my $not_added_crs = RT::CustomRoles->new( $session{'CurrentUser'} );
+$not_added_crs->LimitToNotAdded( $id );
+
+my $format = RT->Config->Get('AdminSearchResultFormat')->{'CustomRoles'};
+my $rows = RT->Config->Get('AdminSearchResultRows')->{'CustomRoles'} || 50;
+
+my $display_format = $id
+            ? ("'__RemoveCheckBox.{$id}__',". $format .", '__MoveCR.{$id}__'")
+            : ("'__CheckBox.{RemoveCustomRole}__',". $format .", '__MoveCR.{$id}__'");
+$m->callback( CallbackName => 'EditDisplayFormat', DisplayFormat => \$display_format, id => $id );
+
+</%INIT>
+<%ARGS>
+$Object
+$UpdateCRs           => undef
+ at RemoveCustomRole   => ()
+ at AddCustomRole      => ()
+$MoveCustomRoleUp   => undef
+$MoveCustomRoleDown => undef
+</%ARGS>
diff --git a/share/html/Elements/RT__CustomRole/ColumnMap b/share/html/Admin/Queues/CustomRoles.html
similarity index 56%
copy from share/html/Elements/RT__CustomRole/ColumnMap
copy to share/html/Admin/Queues/CustomRoles.html
index 63ef10bf5f..9ae98488f5 100644
--- a/share/html/Elements/RT__CustomRole/ColumnMap
+++ b/share/html/Admin/Queues/CustomRoles.html
@@ -45,66 +45,16 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<%ARGS>
-$Name => undef
-$Attr => undef
-$GenericMap => {}
-</%ARGS>
-<%ONCE>
-my $COLUMN_MAP = {
-    Disabled => {
-        title     => 'Status', # loc
-        attribute => 'Disabled',
-        value     => sub { return $_[0]->Disabled ? $_[0]->loc('Disabled') : $_[0]->loc('Enabled') },
-    },
-
-    map(
-        { my $c = $_; $c => {
-            title     => $c, attribute => $c,
-            value     => sub { return $_[0]->$c() },
-        } }
-        qw(Name Description EntryHint)
-    ),
-
-    MaxValues => {
-        title     => 'Number', # loc
-        attribute => 'MaxValues',
-        value     => sub {
-            my $v = $_[0]->MaxValues;
-            return !$v ? $_[0]->loc('Multiple') : $v == 1 ? $_[0]->loc('Single') : $v;
-        },
-    },
-
-    AddedTo => {
-        title     => 'Added', # loc
-        value     => sub {
-            my $collection = $_[0]->AddedTo;
-            return '' unless $collection;
-
-            $collection->RowsPerPage(10);
+<& /Admin/Elements/Header, Title => $title &>
+<& /Elements/Tabs &>
+<& /Admin/Elements/EditCustomRoles, %ARGS, title => $title, Object => $Object &>
 
-            my $found = 0;
-            my $res = '';
-            while ( my $record = $collection->Next ) {
-                $res .= ', ' if $res;
-
-                my $id = '';
-                $id = $record->Name if $record->_Accessible('Name','read');
-                $id ||= "#". $record->id;
-                $res .= $id;
-
-                $found++;
-            }
-            $res .= ', ...' if $found >= 10;
-            return $res;
-        },
-
-    },
-};
-
-</%ONCE>
 <%INIT>
-$m->callback( GenericMap => $GenericMap, COLUMN_MAP => $COLUMN_MAP, CallbackName => 'ColumnMap', CallbackOnce => 1 );
-return GetColumnMapEntry( Map => $COLUMN_MAP, Name => $Name, Attribute => $Attr );
+my $Object = RT::Queue->new($session{'CurrentUser'});
+$Object->Load($id) || Abort( loc( "Couldn't load object [_1]", $id ) );
+my $title = loc( 'Custom Roles for queue [_1]', $Object->Name );
 </%INIT>
 
+<%ARGS>
+$id => undef
+</%ARGS>
diff --git a/share/html/Elements/RT__CustomRole/ColumnMap b/share/html/Elements/RT__CustomRole/ColumnMap
index 63ef10bf5f..31f8d25efb 100644
--- a/share/html/Elements/RT__CustomRole/ColumnMap
+++ b/share/html/Elements/RT__CustomRole/ColumnMap
@@ -100,6 +100,58 @@ my $COLUMN_MAP = {
         },
 
     },
+    RemoveCheckBox => {
+        title => sub {
+            my $name = 'RemoveCustomRole';
+            my $checked = $DECODED_ARGS->{ $name .'All' }? 'checked="checked"': '';
+
+            return \qq{<input type="checkbox" name="}, $name, \qq{All" value="1" $checked
+                              onclick="setCheckbox(this, },
+                              $m->interp->apply_escapes($name,'j'),
+                              \qq{)" />};
+        },
+        value => sub {
+            my $id   = $_[0]->id;
+            my $name = 'RemoveCustomRole';
+            my $arg  = $DECODED_ARGS->{$name};
+
+            my $checked = '';
+            if ( $arg && ref $arg ) {
+                $checked = 'checked="checked"' if grep $_ == $id, @$arg;
+            }
+            elsif ( $arg ) {
+                $checked = 'checked="checked"' if $arg == $id;
+            }
+            return \qq{<input type="checkbox" name="}, $name, \qq{" value="$id" $checked />}
+        },
+    },
+    MoveCR => {
+        title => 'Move',
+        value => sub {
+            return '' unless $_[0]->IsAdded( $_[2] );
+
+            my $id      = $_[0]->id;
+            my $name = 'MoveCustomRole';
+            my $args = $m->caller_args( 1 );
+            my @pass = ref $args->{'PassArguments'}
+                ? @{$args->{'PassArguments'}}
+                : ($args->{'PassArguments'});
+            my %pass = map { $_ => $args->{$_} } grep exists $args->{$_}, @pass;
+
+            my $uri = RT->Config->Get('WebPath') . $m->request_path;
+
+            my @res = (
+                \'<a href="',
+                $uri .'?'. $m->comp("/Elements/QueryString", %pass, MoveCustomRoleUp => $id ),
+                \'">', loc('~[Up~]'), \'</a>',
+                \' <a href="',
+                $uri .'?'. $m->comp("/Elements/QueryString", %pass, MoveCustomRoleDown => $id ),
+                \'">', loc('~[Down~]'), \'</a>'
+            );
+
+            return @res;
+        },
+    },
 };
 
 </%ONCE>
diff --git a/share/html/Elements/Tabs b/share/html/Elements/Tabs
index 4d91c5b0df..ae86de4298 100644
--- a/share/html/Elements/Tabs
+++ b/share/html/Elements/Tabs
@@ -364,6 +364,7 @@ my $build_admin_menu = sub {
                 my $txn_cfs = $cfs->child( 'transactions' => title => loc('Transactions'),
                     path => '/Admin/Queues/CustomFields.html?SubType=RT::Ticket-RT::Transaction&id='.$id );
 
+                $queue->child( 'custom-roles' => title => loc('Custom Roles'), path => "/Admin/Queues/CustomRoles.html?id=".$id );
                 $queue->child( 'group-rights' => title => loc('Group Rights'), path => "/Admin/Queues/GroupRights.html?id=".$id );
                 $queue->child( 'user-rights' => title => loc('User Rights'), path => "/Admin/Queues/UserRights.html?id=" . $id );
                 $queue->child( 'history' => title => loc('History'), path => "/Admin/Queues/History.html?id=" . $id );

commit 6f4651be57584065f36c9cb44f4f6665fa9b01da
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Sat Feb 22 03:05:33 2020 +0800

    Show custom roles in correct order on queue watcher and ticket pages
    
    _ROLES has all the custom roles, but we can't set sort order there as
    they are at the level of class instead of object where sort order really
    applies.
    
    We need to find out the sort order at object level, thus the "Roles"
    call on an object could return roles in correct order.

diff --git a/lib/RT/Record/Role/Roles.pm b/lib/RT/Record/Role/Roles.pm
index 9dcd141726..da8dc508a3 100644
--- a/lib/RT/Record/Role/Roles.pm
+++ b/lib/RT/Record/Role/Roles.pm
@@ -282,6 +282,15 @@ sub Roles {
     return   map { $_->[0] }
             sort {   $a->[1]{SortOrder} <=> $b->[1]{SortOrder}
                   or $a->[0] cmp $b->[0] }
+            map {
+                if ( ref $self && $self->Id && $_->[0] =~ /^RT::CustomRole-(\d+)/ ) {
+                    my $id  = $1;
+                    my $ocr = RT::ObjectCustomRole->new( $self->CurrentUser );
+                    $ocr->LoadByCols( ObjectId => $self->Id, CustomRole => $id );
+                    $_->[1]{SortOrder} = $ocr->SortOrder if $ocr->Id;
+                }
+                $_;
+            }
             grep {
                 my $ok = 1;
                 for my $k (keys %attr) {

commit 26c2125b8e53ebe58c662c0bcd928a44ce7e9d21
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Sat Feb 22 03:53:47 2020 +0800

    Test sort order of custom roles
    
    This is originally from t/customfields/sort_order.t, with a few
    necessary changes to make it work for custom roles and also a tiny bit
    code tweak.

diff --git a/t/customroles/sort_order.t b/t/customroles/sort_order.t
new file mode 100644
index 0000000000..e9ea6c94cf
--- /dev/null
+++ b/t/customroles/sort_order.t
@@ -0,0 +1,69 @@
+use strict;
+use warnings;
+
+use RT::Test tests => undef;
+
+my $queue_name = "CRSortQueue-$$";
+my $queue = RT::Test->load_or_create_queue( Name => $queue_name );
+
+diag "create multiple CRs: B, A and C";
+
+for my $name (qw/B A C/) {
+    my $cr = RT::CustomRole->new( RT->SystemUser );
+    my ( $ret, $msg ) = $cr->Create( Name => "CR $name", );
+    ok( $ret, "Custom Role $name created" );
+    ( $ret, $msg ) = $cr->AddToObject( $queue->id );
+    ok( $ret, "Added $name to $queue_name: $msg" );
+}
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+ok( $m->login(), 'Logged in' );
+
+diag "reorder CRs: C, A and B";
+{
+    $m->get_ok('/Admin/Queues/');
+    $m->follow_link_ok( { text => $queue->id } );
+    $m->follow_link_ok( { id   => 'page-custom-roles' } );
+    my @tmp = ( $m->content =~ /(CR [ABC])/g );
+    is_deeply( \@tmp, [ 'CR B', 'CR A', 'CR C' ], 'Order on admin page' );
+
+    $m->follow_link_ok( { text => '[Up]', n => 3 } );
+    $m->follow_link_ok( { text => '[Up]', n => 2 } );
+    $m->follow_link_ok( { text => '[Up]', n => 3 } );
+
+    @tmp = ( $m->content =~ /(CR [ABC])/g );
+    is_deeply( \@tmp, [ 'CR C', 'CR A', 'CR B' ], 'Order on updated admin page' );
+}
+
+diag "check ticket create, display and edit pages";
+{
+    $m->submit_form_ok(
+        {   form_name => "CreateTicketInQueue",
+            fields    => { Queue => $queue->Name },
+        },
+        'Get ticket create page'
+    );
+
+    my @tmp = ( $m->content =~ /(CR [ABC])/g );
+    is_deeply( \@tmp, [ 'CR C', 'CR A', 'CR B' ], 'Order on ticket create page' );
+
+    $m->submit_form_ok(
+        {   form_name => "TicketCreate",
+            fields    => { Subject => 'test' },
+        },
+        'Submit ticket create form'
+    );
+    my ($tid) = ( $m->content =~ /Ticket (\d+) created/i );
+    ok $tid, "Created a ticket succesfully";
+
+    @tmp = ( $m->content =~ /(CR [ABC])/g );
+    is_deeply( \@tmp, [ 'CR C', 'CR A', 'CR B' ], 'Order on ticket display page' );
+    $m->follow_link_ok( { text => 'People' } );
+
+    @tmp = ( $m->content =~ /(CR [ABC])/g );
+
+    # 3 "WatcherTypeEmail1" select boxes and 1 "Current watchers"
+    is_deeply( \@tmp, [ ( 'CR C', 'CR A', 'CR B' ) x 4 ], 'Order on ticket people page' );
+}
+
+done_testing;

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


More information about the rt-commit mailing list