[Rt-commit] rt branch, 4.6/select-queue-in-ticket-create, created. rt-4.4.4-542-g927e511ff2

Aaron Trevena ast at bestpractical.com
Mon Dec 30 06:41:56 EST 2019


The branch, 4.6/select-queue-in-ticket-create has been created
        at  927e511ff24cb5bbadcb14c9f9ad795cb2bd4128 (commit)

- Log -----------------------------------------------------------------
commit eae4316bb170ec9f8198ec8442132ab5c3bc30ac
Author: Aaron Trevena <ast at bestpractical.com>
Date:   Mon Dec 30 10:52:18 2019 +0000

    Add Test::HTML::Form for testing

diff --git a/etc/cpanfile b/etc/cpanfile
index 8a542d2729..48aefa7774 100644
--- a/etc/cpanfile
+++ b/etc/cpanfile
@@ -128,6 +128,7 @@ on 'develop' => sub {
     requires 'Test::NoWarnings';
     requires 'Test::Pod';
     requires 'Test::Warn';
+    requires 'Test::HTML::Form', '>= 1.01';
     requires 'Test::WWW::Mechanize', '>= 1.30';
     requires 'Test::WWW::Mechanize::PSGI';
     requires 'WWW::Mechanize', '>= 1.52';
diff --git a/lib/RT/Test/Web.pm b/lib/RT/Test/Web.pm
index 2faecf20ab..d99f1a1cb2 100644
--- a/lib/RT/Test/Web.pm
+++ b/lib/RT/Test/Web.pm
@@ -485,6 +485,10 @@ sub DESTROY {
     }
 }
 
+sub decoded_content {
+   return shift->content(@_);
+}
+
 END {
     return if RT::Test->builder->{Original_Pid} != $$;
     if (defined $RT::Test::Web::INSTANCES and $RT::Test::Web::INSTANCES == 0 ) {
diff --git a/t/web/csrf.t b/t/web/csrf.t
index bdd895d92d..92eb34682c 100644
--- a/t/web/csrf.t
+++ b/t/web/csrf.t
@@ -2,6 +2,7 @@ use strict;
 use warnings;
 
 use RT::Test tests => undef;
+use Test::HTML::Form;
 
 my $ticket = RT::Ticket->new(RT::CurrentUser->new('root'));
 my ($ok, $msg) = $ticket->Create(Queue => 1, Owner => 'nobody', Subject => 'bad music');
@@ -173,8 +174,8 @@ $m->title_is('Configuration for queue test');
 $m->get_ok("/Ticket/Create.html?Queue=$other_queue_id&CSRF_Token=$token");
 $m->content_lacks("Possible cross-site request forgery");
 $m->title_is('Create a new ticket in General');
-$m->text_unlike(qr/Queue:\s*Other queue/);
-$m->text_like(qr/Queue:\s*General/);
+form_select_field_matches($m, { field_name => 'SelectedQueue', selected => 1, form_name => 'TicketCreate'}, 'Queue selection dropdown populated and pre-selected');
+
 
 # Ensure that file uploads work across the interstitial
 $m->delete_header('Referer');

commit 927e511ff24cb5bbadcb14c9f9ad795cb2bd4128
Author: Aaron Trevena <ast at bestpractical.com>
Date:   Mon Dec 30 11:21:59 2019 +0000

    Select Queue in Ticket Create page
    
    Allow Queue to be selected in the create ticket page, using defaults from configuration if none provided
    Added new tests for creating tickets with custom fields and lifecycles, and with or without queue specified
    Existing urls for queue creation will still work, and previous ticket create button and modal are possible by over-riding template
    Auto-complete lookup will be used if configured in place of selectbox in ticket create page in same way as previous modal

diff --git a/lib/RT/Interface/Web/MenuBuilder.pm b/lib/RT/Interface/Web/MenuBuilder.pm
index 101af440b0..9b7398bac9 100644
--- a/lib/RT/Interface/Web/MenuBuilder.pm
+++ b/lib/RT/Interface/Web/MenuBuilder.pm
@@ -93,7 +93,7 @@ sub BuildMainNav {
 
     my $home = $top->child( home => title => loc('Homepage'), path => '/' );
     $home->child( createticket => title => loc("Create Ticket"),
-                  path => "/Ticket/CreateInQueue.html" );
+                  path => "/Ticket/Create.html" );
 
     unless ($HTML::Mason::Commands::session{'dashboards_in_menu'}) {
         my $dashboards_in_menu = $current_user->UserObj->Preferences(
@@ -1277,7 +1277,7 @@ sub BuildSelfServiceNav {
 
 
     if ( $queue_count > 1 ) {
-        $top->child( new => title => loc('New ticket'), path => '/SelfService/CreateTicketInQueue.html' );
+        $top->child( new => title => loc('New ticket'), path => '/SelfService/CreateTicket.html' );
     } elsif ( $queue_id ) {
         $top->child( new => title => loc('New ticket'), path => '/SelfService/Create.html?Queue=' . $queue_id );
     }
diff --git a/share/html/Elements/CreateTicket b/share/html/Elements/CreateTicket
index a07a3f1a23..d7fd4d9b8e 100644
--- a/share/html/Elements/CreateTicket
+++ b/share/html/Elements/CreateTicket
@@ -55,19 +55,25 @@
 
 % my $button_start = '<input type="submit" class="button btn btn-primary form-control" value="';
 % my $button_start_modal = '<input type="submit" class="button btn btn-primary form-control ticket-create-modal" value="';
-% my $button_only_start_modal = '<input type="submit" class="btn btn-primary ticket-create-modal" value="';
+% my $button_only_start_modal = '<input type="submit" class="btn btn-primary ticket-create-modal" value="'; # not used, but left in place if users want later
+% my $button_only_start = '<input type="submit" class="btn btn-primary" value="';
 % my $button_end = '" />';
-% my $queue_selector = $m->scomp('/Elements/SelectNewTicketQueue', AutoSubmit => 1, SendTo => $SendTo, Placeholder => loc('Queue'), Hyperlink => $Hyperlink );
 
-% if ($Hyperlink) {
-<% $queue_selector |n %>
-% }
-% elsif ($ButtonOnly) {
+% if ($ButtonOnly) {
 <div class="create-ticket-button">
+% if ($ShowModal) {
 <&|/l_unsafe, $button_only_start_modal, $button_end &>[_1]Create new ticket[_2]</&>
+% } else {
+<&|/l_unsafe, $button_only_start, $button_end &>[_1]Create new ticket[_2]</&>
+% }
 </div>
 % }
 % else {
+%   my $queue_selector = $m->scomp('/Elements/SelectNewTicketQueue', AutoSubmit => 1, SendTo => $SendTo, Placeholder => loc('Queue'), Hyperlink => $Hyperlink );
+%   if ($Hyperlink) {
+<% $queue_selector |n %>
+%   }
+%   else {
 <div class="create-wide">
 <&|/l_unsafe, $button_start, $button_end, $queue_selector &>[_1]New ticket in[_2] [_3]</&>
 </div>
@@ -77,6 +83,7 @@
 <div class="create-narrow">
 <&|/l_unsafe, $button_start_modal, $button_end &>[_1]+[_2]</&>
 </div>
+%   }
 % }
 
 % $m->callback(CallbackName => 'BeforeFormEnd');
@@ -87,5 +94,6 @@ $SendTo => '/Ticket/Create.html',
 $IncludeExplanation => 0
 $Hyperlink => undef
 $ButtonOnly => undef
+$ShowModal => 0
 $FormName => 'CreateTicketInQueue'
 </%ARGS>
diff --git a/share/html/Elements/SelectObject b/share/html/Elements/SelectObject
index 37db75ea46..36149cff37 100644
--- a/share/html/Elements/SelectObject
+++ b/share/html/Elements/SelectObject
@@ -70,7 +70,11 @@
 %     }
 %     for my $object ($default_entry || (), @{$session{$cache_key}{objects}}) {
   <option value="<% ($NamedValues ? $object->{Name} : $object->{Id}) %>"\
-% if ($object->{Id} eq ($Default||'') || $object->{Name} eq ($Default||'')) {
+% if ($SelectedId) {
+%    if ($SelectedId eq $object->{Id} ) {
+ selected="selected"\
+%    }
+% } elsif ( $object->{Id} eq ($Default||'') || $object->{Name} eq ($Default||'')) {
  selected="selected"\
 % }
 ><%$object->{Name}%>\
@@ -91,6 +95,7 @@ $Verbose => undef
 $NamedValues => 0
 $DefaultLabel => "-"
 $Default => 0
+$SelectedId => undef
 $Lite => 0
 $OnChange => undef
 $Multiple => 0
@@ -101,6 +106,7 @@ $Hyperlink => undef
 $AccessKey => undef
 </%args>
 <%init>
+
 $ObjectType = "RT::$ObjectType" unless $ObjectType =~ /::/;
 $Class    ||= "select-" . CSSClass("\L$1") if $ObjectType =~ /RT::(.+)$/;
 
diff --git a/share/html/Elements/SelectQueue b/share/html/Elements/SelectQueue
index 412f95e2f5..05e9cc5e5b 100644
--- a/share/html/Elements/SelectQueue
+++ b/share/html/Elements/SelectQueue
@@ -45,6 +45,7 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
+<input type="hidden" name="queue-changed-reload" id="queue-changed-reload" value="0"/>
 %if (RT->Config->Get("AutocompleteQueues", $session{'CurrentUser'})) {
 <& SelectQueueAutocomplete, %ARGS, &>
 %} else {
@@ -54,13 +55,17 @@
     CheckRight       => $CheckQueueRight,
     ShowAll          => $ShowAllQueues,
     CacheNeedsUpdate => RT->System->QueueCacheNeedsUpdate,
+    SelectedId       => $SelectedId
     &>
 %}
 <%args>
 $CheckQueueRight => 'CreateTicket'
 $ShowAllQueues   => 1
 $AutoSubmit      => 0
+$SelectedId      => undef
+$QueueObj        => undef
 </%args>
 <%init>
-$ARGS{OnChange} = "jQuery(this).closest('form').submit();" if $AutoSubmit;
+$ARGS{OnChange} = "jQuery('#queue-changed-reload').val(1);jQuery('#queue-changed-reload').val(jQuery(this).children('option:selected').val());";
+$ARGS{OnChange} .= "jQuery(this).closest('form').submit();" if $AutoSubmit;
 </%init>
diff --git a/share/html/Ticket/Create.html b/share/html/Ticket/Create.html
index e65ac52c29..986e0718bc 100644
--- a/share/html/Ticket/Create.html
+++ b/share/html/Ticket/Create.html
@@ -49,7 +49,7 @@
     Title => $title,
     onload => "function () { hide('Ticket-Create-details') }" &>
 <& /Elements/Tabs &>
-    
+
 <& /Elements/ListActions, actions => \@results &>
 
 <form action="<% RT->Config->Get('WebPath') %>/Ticket/Create.html" method="post" enctype="multipart/form-data" name="TicketCreate">
@@ -80,10 +80,12 @@
         defaults => \%ARGS,
         fields  => [
             {   name => 'Queue',
-                comp => '/Ticket/Elements/ShowQueue',
+                comp => '/Elements/SelectQueue',
                 args => {
-                    QueueObj => $QueueObj,
-                    Wrap => 1,
+                    Wrap        => 1,
+                    SelectedId  => $Queue,
+                    AutoSubmit  => 1,
+                    Name        => 'SelectedQueue'
                 },
             },
             {   name => 'Status',
@@ -259,8 +261,8 @@
 <div class="row">
 <div class="boxcontainer col-md-6">
     <div class="ticket-info-basics">
-          <&| /Widgets/TitleBox, title => loc('The Basics'), 
-                title_class=> 'inverse',  
+          <&| /Widgets/TitleBox, title => loc('The Basics'),
+                title_class=> 'inverse',
                 color => "#993333" &>
 <div>
 
@@ -299,7 +301,7 @@
 <br />
 <div class="ticket-info-dates">
 <&|/Widgets/TitleBox, title => loc("Dates"),
-  title_class=> 'inverse',  
+  title_class=> 'inverse',
   color => "#663366" &>
 
 <div>
@@ -346,7 +348,38 @@
 
 <%INIT>
 $m->callback( CallbackName => "Init", ARGSRef => \%ARGS );
+
+# Queue is a hidden field and updated by javascript when changed in selectbox,
+# but we check the select field in case javascript disabled or incompatible with browser
 my $Queue = $ARGS{Queue};
+if ($ARGS{SelectedQueue}) {
+   $Queue = $ARGS{SelectedQueue};
+}
+
+# Use default queue from config site or user prefs if none provided
+unless ($Queue) {
+    $Queue = RT->Config->Get("DefaultQueue", $session{'CurrentUser'});
+    if (RT->Config->Get("RememberDefaultQueue", $session{'CurrentUser'})) {
+        if (my $session_default = $session{'DefaultQueue'}) {
+            $Queue = $session_default;
+        }
+    }
+}
+
+# pick first in list in normal order unless queue provided from form/url/defaults
+unless ($Queue) {
+    my $cache_key = SetObjectSessionCache(
+        ObjectType => 'Queue',
+        CheckRight => 1,
+        CacheNeedsUpdate => 0,
+     );
+
+     $Queue = $session{$cache_key}{objects}[0]->{Id};
+     if (not $Queue) {
+        Abort(loc("Queue [_1] could not be loaded.", ''), Code => HTTP::Status::HTTP_BAD_REQUEST);
+     }
+}
+
 $session{DefaultQueue} = $Queue;
 
 my $current_user = $session{'CurrentUser'};
@@ -487,14 +520,14 @@ if ( !exists $ARGS{'AddMoreAttach'} && ($ARGS{'id'}||'') eq 'new' ) {
 }
 
 my $skip_create = 0;
-$m->callback( CallbackName => 'BeforeCreate', ARGSRef => \%ARGS, skip_create => \$skip_create, 
+$m->callback( CallbackName => 'BeforeCreate', ARGSRef => \%ARGS, skip_create => \$skip_create,
               checks_failure => $checks_failure, results => \@results );
 
 $m->comp( '/Articles/Elements/CheckSkipCreate', ARGSRef => \%ARGS, skip_create => \$skip_create,
               checks_failure => $checks_failure, results => \@results );
 
 if ((!exists $ARGS{'AddMoreAttach'}) and (!exists $ARGS{'Go'}) and (defined($ARGS{'id'}) and $ARGS{'id'} eq 'new')) { # new ticket?
-    if ( !$checks_failure && !$skip_create ) {
+    if ( !$checks_failure && !$skip_create && !$ARGS{'queue-changed-reload'} ) {
         $m->comp('Display.html', %ARGS);
         $RT::Logger->crit("After display call; error is $@");
         $m->abort();
diff --git a/share/static/js/util.js b/share/static/js/util.js
index d9914c4efe..f54c129656 100644
--- a/share/static/js/util.js
+++ b/share/static/js/util.js
@@ -565,7 +565,7 @@ jQuery(function() {
         return false;
     });
 
-    jQuery("#home-createticket,.ticket-create-modal").click(function(ev){
+    jQuery(".ticket-create-modal").click(function(ev){
         ev.preventDefault();
         jQuery.get(
             RT.Config.WebHomePath + "/Helpers/CreateInQueue",
diff --git a/t/web/group_summary.t b/t/web/group_summary.t
index 22977b667c..3d55c2ce2f 100644
--- a/t/web/group_summary.t
+++ b/t/web/group_summary.t
@@ -29,7 +29,7 @@ diag( 'Group Summary access and ticket creation' );
 
     $m->submit_form_ok({ form_name => 'CreateTicket' },
                          "Submitted form to create ticket with group $group_id as Cc" );
-    like( $m->uri, qr{/Ticket/Create\.html\?AddGroupCc=$group_id&Queue=1$},
+    like( $m->uri, qr{/Ticket/Create\.html\?AddGroupCc=$group_id&queue-changed-reload=0&Queue=1$},
           "now on /Ticket/Create\.html with param AddGroupCc=$group_id" );
 
     my $subject = 'test AddGroupCc ticket';
diff --git a/t/web/ticket_create.t b/t/web/ticket_create.t
new file mode 100644
index 0000000000..b38307cee7
--- /dev/null
+++ b/t/web/ticket_create.t
@@ -0,0 +1,75 @@
+use strict;
+use warnings;
+use Test::HTML::Form;
+
+use RT::Test tests => undef;
+use RT::Lifecycle;
+
+# populate lifecycles
+my $lifecycles = RT->Config->Get('Lifecycles');
+RT->Config->Set( Lifecycles => %{$lifecycles},
+                 foo => {
+                     initial  => ['initial'],
+                     active   => ['open'],
+                     inactive => ['resolved'],
+                 }
+);
+RT::Lifecycle->FillCache();
+
+# populate test queues and test user
+my $queue1 = RT::Test->load_or_create_queue( Name => 'General' );
+my $queue2 = RT::Test->load_or_create_queue( Name => 'Specific' );
+my $queue3 = RT::Test->load_or_create_queue( Name => 'Bugs' );
+my $user = RT::Test->load_or_create_user(
+    Name     => 'user',
+    Password => 'password',
+);
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+
+#set up lifecycle for one of the queues
+ok $m->login;
+$m->get_ok( '/Admin/Queues/Modify.html?id='.$queue1->id );
+$m->form_name('ModifyQueue');
+$m->submit_form( fields => { Lifecycle => 'foo' } );
+
+# set up custom field
+my $cf = RT::Test->load_or_create_custom_field( Name => 'test_cf', Queue => $queue1->Name, Type => 'FreeformSingle' );
+my $cf_form_id = 'Object-RT::Ticket--CustomField-'.$cf->Id.'-Value';
+my $cf_test_value = "some string for test_cf $$";
+
+# load initial ticket create page without specifying queue
+# should have default queue with no custom fields
+note('load create ticket page with defaults');
+$m->get_ok( '/Ticket/Create.html', 'go to ticket create page with no queue id' );
+no_tag($m,'input',{ name => $cf_form_id }, 'no custom field');
+form_field_value_matches($m, 'Queue', $queue3->id, 'TicketCreate', 'queue id set in hidden field');
+form_select_field_matches($m, { field_name => 'SelectedQueue', selected => $queue3->id,
+                                form_name => 'TicketCreate'}, 'Queue selection dropdown populated');
+form_select_field_matches($m, { field_name => 'Status', selected => "new",
+                                form_name => 'TicketCreate'}, 'Status selection dropdown populated');
+
+# test ticket creation on reload from selected queue, specifying queue with custom fields
+note('reload ticket create page with selected queue');
+$m->get_ok( '/Ticket/Create.html?queue-changed-reload=1&Queue='.$queue1->id.'&SelectedQueue=' . $queue1->id,
+            'go to ticket create page' );
+
+form_select_field_matches($m, { field_name => 'SelectedQueue', selected => $queue1->id,
+                                form_name => 'TicketCreate'}, 'Queue selection dropdown populated and pre-selected');
+form_field_value_matches($m, 'Queue', $queue1->id, 'TicketCreate', 'queue id set in hidden field');
+form_field_value_matches($m, $cf_form_id, "", 'TicketCreate', 'custom field is present');
+
+my $form = $m->form_name('TicketCreate');
+my $status_input = $form->find_input('Status');
+is_deeply( [ $status_input->possible_values ], [ 'initial', 'open', 'resolved' ], 'status selectbox shows custom lifecycle for queue' );
+
+note('submit populated form');
+$m->submit_form( fields => { Subject => 'ticket foo', 'Queue' => $queue1->id, $cf_form_id => $cf_test_value } );
+$m->text_contains('test_cf', 'custom field populated in display');
+$m->text_contains($cf_test_value, 'custom field populated in display');
+
+my $ticket = RT::Test->last_ticket;
+ok( $ticket->id, 'ticket is created' );
+is($ticket->QueueObj->id, $queue1->id, 'Ticket created with correct queue');
+
+done_testing();

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


More information about the rt-commit mailing list