[Bps-public-commit] RT-Extension-MandatoryOnTransition branch, master, updated. 0.09_01-24-g8891d72

Shawn Moore shawn at bestpractical.com
Mon Jul 11 16:23:16 EDT 2016


The branch, master has been updated
       via  8891d7203fd9be3afeb9874c9281e1349debe32b (commit)
       via  8225344896e1805863e259c045a1ca7e5458782d (commit)
       via  5861a66f9606b6aa09c9447a9665bac58025d3ca (commit)
       via  ff535764efd0e3c58e828168320a218b64ae8b4b (commit)
       via  fc8347f1ea9678f83936e9f27c9e4b0b4ec12458 (commit)
       via  da5daf3335ea12119c225472fe92f2f7b828d399 (commit)
       via  6d1615ddf25a3a4eaa16c2501748bceafa7fc34d (commit)
       via  83ef77a91649dc9001a2761e738a7a77527b53db (commit)
       via  babe91626fdd3c8463117ec31bcc2e10612ea23d (commit)
       via  022d05548787501a0ae3a6175c30ce4fccd2e247 (commit)
       via  2f48cf42006a6c6a6fdd1c4b62520531e52c8583 (commit)
      from  9c271bd4aebc6c1f824372d226b9403170334319 (commit)

Summary of changes:
 Changes                                           |   3 +
 README                                            |  31 +++++
 lib/RT/Extension/MandatoryOnTransition.pm         | 133 +++++++++++++++++-----
 lib/RT/Extension/MandatoryOnTransition/Test.pm.in |   5 +-
 xt/basic.t                                        |  69 ++++++++++-
 xt/required_fields.t                              |  21 +++-
 6 files changed, 227 insertions(+), 35 deletions(-)

- Log -----------------------------------------------------------------
commit 2f48cf42006a6c6a6fdd1c4b62520531e52c8583
Author: Jim Brandt <jbrandt at bestpractical.com>
Date:   Fri Jun 17 16:18:34 2016 -0400

    Remove config check for ARRAY before adding new HASH config option
    
    This check looks for a specific type of data in the config,
    but the new feature for checking specific values needs a
    hash reference. Adding hash would then make this check
    restrict almost nothing, so remove it.

diff --git a/lib/RT/Extension/MandatoryOnTransition.pm b/lib/RT/Extension/MandatoryOnTransition.pm
index 6222d17..5f6616c 100644
--- a/lib/RT/Extension/MandatoryOnTransition.pm
+++ b/lib/RT/Extension/MandatoryOnTransition.pm
@@ -165,31 +165,6 @@ If you're just using this module on your own RT instance, you should stop
 reading now.  You don't need to know about the implementation details unless
 you're writing a patch against this extension.
 
-=cut
-
-$RT::Config::META{'MandatoryOnTransition'} = {
-    Type            => 'HASH',
-    PostLoadCheck   => sub {
-        # Normalize field list to always be arrayref
-        my $self = shift;
-        my %config = $self->Get('MandatoryOnTransition');
-        for my $transitions (values %config) {
-            for (keys %$transitions) {
-                next if ref $transitions->{$_} eq 'ARRAY';
-
-                if (ref $transitions->{$_}) {
-                    RT->Logger->error("%MandatoryOnTransition definition '$_' must be a single field name or an array ref of field names.  Ignoring.");
-                    delete $transitions->{$_};
-                    next;
-                }
-
-                $transitions->{$_} = [ $transitions->{$_} ];
-            }
-        }
-        $self->Set(MandatoryOnTransition => %config);
-    },
-};
-
 =head2 Package variables
 
 =over 4

commit 022d05548787501a0ae3a6175c30ce4fccd2e247
Author: Jim Brandt <jbrandt at bestpractical.com>
Date:   Fri Jun 17 16:22:13 2016 -0400

    Allow rules to require or restrict specific values on transition
    
    Add configuration and functionality to require specific values
    for transitions or restrict specific values.

diff --git a/README b/README
index f879b29..1ea76f0 100644
--- a/README
+++ b/README
@@ -106,6 +106,7 @@ CONFIGURATION
     The fallback for queues without specific rules is specified with '*'
     where the queue name would normally be.
 
+  Requiring Any Value
     Below is an example which requires 1) time worked and filling in a
     custom field named Resolution before resolving tickets in the Helpdesk
     queue and 2) a Category selection before resolving tickets in every
@@ -123,6 +124,28 @@ CONFIGURATION
     The transition syntax is similar to that found in RT's Lifecycles. See
     perldoc /opt/rt4/etc/RT_Config.pm.
 
+  Requiring or Restricting Specific Values
+    Sometimes you want to restrict a transition if a field has a specific
+    value (maybe a ticket can't be resolved if System Status = down) or
+    require a specific value to to allow a transition (ticket can't be
+    resolved unless System Status = normal). To enforce specific values, you
+    can add the following:
+
+        Set( %MandatoryOnTransition,
+            Helpdesk => {
+                '* -> resolved' => ['TimeWorked', 'CF.Some Field1', 'CF.Some Field2'],
+                'CF.Test Field2' => { transition => '* -> resolved', must_be => ['normal', 'restored'] },
+                'CF.Test Field3' => { transition => '* -> resolved', must_not_be => ['reduced', 'down']}
+            },
+        );
+
+    This will then enforce both that the value is set and that it either has
+    one of the required values on the configured transition or does not have
+    one of the restricted values.
+
+    Note that you need to specify the transition the rule applies to since a
+    given queue configuration could have multiple transition rules.
+
   $ShowAllCustomFieldsOnMandatoryUpdate
     By default, this extension shows only the mandatory fields on the update
     page to make it easy for users to fill them out when completing an
diff --git a/lib/RT/Extension/MandatoryOnTransition.pm b/lib/RT/Extension/MandatoryOnTransition.pm
index 5f6616c..b073ffd 100644
--- a/lib/RT/Extension/MandatoryOnTransition.pm
+++ b/lib/RT/Extension/MandatoryOnTransition.pm
@@ -134,6 +134,8 @@ status C<to>.
 The fallback for queues without specific rules is specified with C<'*'> where
 the queue name would normally be.
 
+=head2 Requiring Any Value
+
 Below is an example which requires 1) time worked and filling in a custom field
 named Resolution before resolving tickets in the Helpdesk queue and 2) a
 Category selection before resolving tickets in every other queue.
@@ -150,6 +152,29 @@ Category selection before resolving tickets in every other queue.
 The transition syntax is similar to that found in RT's Lifecycles.  See
 C<perldoc /opt/rt4/etc/RT_Config.pm>.
 
+=head2 Requiring or Restricting Specific Values
+
+Sometimes you want to restrict a transition if a field has a specific
+value (maybe a ticket can't be resolved if System Status = down) or
+require a specific value to to allow a transition (ticket can't be
+resolved unless System Status = normal). To enforce specific values, you
+can add the following:
+
+    Set( %MandatoryOnTransition,
+        Helpdesk => {
+            '* -> resolved' => ['TimeWorked', 'CF.Some Field1', 'CF.Some Field2'],
+            'CF.Test Field2' => { transition => '* -> resolved', must_be => ['normal', 'restored'] },
+            'CF.Test Field3' => { transition => '* -> resolved', must_not_be => ['reduced', 'down']}
+        },
+    );
+
+This will then enforce both that the value is set and that it either has
+one of the required values on the configured transition or does
+not have one of the restricted values.
+
+Note that you need to specify the transition the rule applies to
+since a given queue configuration could have multiple transition rules.
+
 =head2 C<$ShowAllCustomFieldsOnMandatoryUpdate>
 
 By default, this extension shows only the mandatory fields on the update page
@@ -272,7 +297,25 @@ sub RequiredFields {
     my @cfs  =  map { /^CF\.(.+)$/i; $1; }
                grep { /^CF\./i } @$required;
 
-    return (\@core, \@cfs);
+    # Pull out an must be or must not be rules
+    my %cf_must_values = ();
+    foreach my $cf (@cfs){
+        if ( $config{"CF.$cf"} ){
+            my $transition = $config{"CF.$cf"}->{'transition'};
+            unless ( $transition ){
+                RT->Logger->error("No transition defined in must be or must not be rules for $cf");
+                next;
+            }
+
+            if ( $transition eq "$from -> $to"
+                 || $transition eq "* -> $to"
+                 || $transition eq "$from -> *" ) {
+
+                $cf_must_values{$cf} = $config{"CF.$cf"};
+            }
+        }
+    }
+    return (\@core, \@cfs, \%cf_must_values);
 }
 
 =head3 CheckMandatoryFields
@@ -325,7 +368,7 @@ sub CheckMandatoryFields {
         return \@errors;
     }
 
-    my ($core, $cfs) = $self->RequiredFields(
+    my ($core, $cfs, $must_values) = $self->RequiredFields(
         Ticket  => $args{'Ticket'},
         Queue   => $args{'Queue'} ? $args{'Queue'}->Name : undef,
         From    => $args{'From'},
@@ -401,6 +444,39 @@ sub CheckMandatoryFields {
             $value = ($ARGSRef->{"${arg}s-Magic"} and exists $ARGSRef->{"${arg}s"}) ? $ARGSRef->{$arg . "s"} : $ARGSRef->{$arg};
         }
 
+        # Check for specific values
+        if ( exists $must_values->{$cf->Name} ){
+            my $cf_value = $value;
+            # Fetch the current value if we didn't receive a new one
+            $cf_value = $args{'Ticket'}->FirstCustomFieldValue($cf->Name)
+                unless defined $cf_value;
+
+            if ( exists $must_values->{$cf->Name}{'must_be'} ){
+                # OK if it's defined and is one of the specified values
+                next if defined $cf_value and grep { $cf_value eq $_ } @{$must_values->{$cf->Name}{'must_be'}};
+                my $valid_values = join ", ", @{$must_values->{$cf->Name}{'must_be'}};
+                my $one_of = '';
+                $one_of = " one of:" if @{$must_values->{$cf->Name}{'must_be'}} > 1;
+                push @errors,
+                  $CurrentUser->loc("[_1] must be$one_of [_3] when changing Status to [_2]",
+                                    $cf->Name, $CurrentUser->loc($ARGSRef->{Status}), $valid_values);
+                next;
+            }
+
+            if ( exists $must_values->{$cf->Name}{'must_not_be'} ){
+                # OK if it's defined and _not_ in the list
+                next if defined $cf_value and !grep { $cf_value eq $_ } @{$must_values->{$cf->Name}{'must_not_be'}};
+                my $valid_values = join ", ", @{$must_values->{$cf->Name}{'must_not_be'}};
+                my $one_of = '';
+                $one_of = " one of:" if @{$must_values->{$cf->Name}{'must_not_be'}} > 1;
+                push @errors,
+                  $CurrentUser->loc("[_1] must not be$one_of [_3] when changing Status to [_2]",
+                                    $cf->Name, $CurrentUser->loc($ARGSRef->{Status}), $valid_values);
+                next;
+            }
+        }
+
+        # Check for any value
         next if defined $value and length $value;
 
         # Is there a current value?  (Particularly important for Date/Datetime CFs

commit babe91626fdd3c8463117ec31bcc2e10612ea23d
Author: Jim Brandt <jbrandt at bestpractical.com>
Date:   Fri Jun 17 16:23:50 2016 -0400

    Add tests for new must_be and must_not_be features

diff --git a/lib/RT/Extension/MandatoryOnTransition/Test.pm.in b/lib/RT/Extension/MandatoryOnTransition/Test.pm.in
index 41ae190..1757bb1 100644
--- a/lib/RT/Extension/MandatoryOnTransition/Test.pm.in
+++ b/lib/RT/Extension/MandatoryOnTransition/Test.pm.in
@@ -36,8 +36,9 @@ Set( %MandatoryOnTransition,
         'open -> resolved' => [qw(TimeWorked TimeTaken)]
     },
     'General' => {
-        '* -> resolved' => ['TimeWorked', 'TimeTaken', 'CF.Test Field']
-    },
+        '* -> resolved' => ['TimeWorked', 'TimeTaken', 'CF.Test Field', 'CF.Test Field3', 'CF.Test Field4'],
+        'CF.Test Field3' => { transition => '* -> resolved', must_be => ['normal', 'restored'] },
+        'CF.Test Field4' => { transition => '* -> resolved', must_not_be => ['down', 'reduced'] } },
 );
 CONFIG
 
diff --git a/xt/basic.t b/xt/basic.t
index 285eda6..3823fe6 100644
--- a/xt/basic.t
+++ b/xt/basic.t
@@ -42,6 +42,38 @@ ok( $id2, $msg );
 $cf2->AddValue( Name => 'blue' );
 $cf2->AddValue( Name => 'green' );
 
+my $cf3 = RT::CustomField->new($RT::SystemUser);
+my $id3;
+diag "Create custom field for must have values";
+( $id3, $msg ) = $cf3->Create(
+    Name      => 'Test Field3',
+    Type      => 'Select',
+    LookupType => 'RT::Queue-RT::Ticket',
+    MaxValues => '1',
+    Queue     => 'General',
+);
+
+ok( $id3, $msg );
+$cf3->AddValue( Name => 'normal' );
+$cf3->AddValue( Name => 'restored' );
+$cf3->AddValue( Name => 'other' );
+
+my $cf4 = RT::CustomField->new($RT::SystemUser);
+my $id4;
+diag "Create custom field for must not have values";
+( $id4, $msg ) = $cf4->Create(
+    Name      => 'Test Field4',
+    Type      => 'Select',
+    LookupType => 'RT::Queue-RT::Ticket',
+    MaxValues => '1',
+    Queue     => 'General',
+);
+
+ok( $id4, $msg );
+$cf4->AddValue( Name => 'normal' );
+$cf4->AddValue( Name => 'down' );
+$cf4->AddValue( Name => 'reduced' );
+
 diag "Try a resolve without TimeWorked";
 {
     my $t = RT::Test->create_ticket(
@@ -62,13 +94,30 @@ diag "Try a resolve without TimeWorked";
                           'Submit resolve with no Time Worked');
     $m->content_contains('Time Worked is required when changing Status to resolved');
     $m->content_contains('Test Field is required when changing Status to resolved');
+    $m->content_contains('Test Field3 must be one of: normal, restored when changing Status to resolved');
 
     $m->submit_form_ok( { form_name => 'TicketUpdate',
                           fields => { UpdateTimeWorked => 10,
-                                    'Object-RT::Ticket-' . $t->id . "-CustomField-$id-Values" => 'foo'},
+                                    'Object-RT::Ticket-' . $t->id . "-CustomField-$id-Values" => 'foo',
+                                    'Object-RT::Ticket-' . $t->id . "-CustomField-$id3-Values" => 'other',
+                                    'Object-RT::Ticket-' . $t->id . "-CustomField-$id4-Values" => 'down',},
+
                           button => 'SubmitTicket',
                         }, 'Submit resolve with Time Worked and Test Field');
 
+    $m->content_contains('Test Field3 must be one of: normal, restored when changing Status to resolved');
+    $m->content_contains('Test Field4 must not be one of: down, reduced when changing Status to resolved');
+
+    $m->submit_form_ok( { form_name => 'TicketUpdate',
+                          fields => { UpdateTimeWorked => 10,
+                                    'Object-RT::Ticket-' . $t->id . "-CustomField-$id-Values" => 'foo',
+                                    'Object-RT::Ticket-' . $t->id . "-CustomField-$id3-Values" => 'normal',
+                                    'Object-RT::Ticket-' . $t->id . "-CustomField-$id4-Values" => 'normal',},
+
+                          button => 'SubmitTicket',
+                        }, 'Submit resolve with Time Worked and Test Field');
+
+
     if ( $RT::VERSION =~ /^4\.0\.\d+/ ){
         $m->content_contains("TimeWorked changed from (no value) to '10'");
     }
@@ -106,10 +155,26 @@ diag "Try a resolve without TimeWorked in mobile interface";
 
     $m->content_contains('Time Worked is required when changing Status to resolved');
     $m->content_contains('Test Field is required when changing Status to resolved');
+    $m->content_contains('Test Field3 must be one of: normal, restored when changing Status to resolved');
 
     $m->submit_form_ok( { form_number => 1,
                           fields => { UpdateTimeWorked => 10,
-                                    'Object-RT::Ticket-' . $ticket_id . "-CustomField-$id-Values" => 'foo'},
+                                    'Object-RT::Ticket-' . $ticket_id . "-CustomField-$id-Values" => 'foo',
+                                    'Object-RT::Ticket-' . $ticket_id . "-CustomField-$id3-Values" => 'other',
+                                    'Object-RT::Ticket-' . $ticket_id . "-CustomField-$id4-Values" => 'down',},
+
+                          button => 'SubmitTicket',
+                        }, 'Submit resolve with Time Worked and Test Field');
+
+    $m->content_contains('Test Field3 must be one of: normal, restored when changing Status to resolved');
+    $m->content_contains('Test Field4 must not be one of: down, reduced when changing Status to resolved');
+
+    $m->submit_form_ok( { form_number => 1,
+                          fields => { UpdateTimeWorked => 10,
+                                    'Object-RT::Ticket-' . $ticket_id . "-CustomField-$id-Values" => 'foo',
+                                    'Object-RT::Ticket-' . $ticket_id . "-CustomField-$id3-Values" => 'normal',
+                                    'Object-RT::Ticket-' . $ticket_id . "-CustomField-$id4-Values" => 'normal',},
+
                           button => 'SubmitTicket',
                         }, 'Submit resolve with Time Worked and Test Field');
 
diff --git a/xt/required_fields.t b/xt/required_fields.t
index d5d7f63..3c7a91d 100644
--- a/xt/required_fields.t
+++ b/xt/required_fields.t
@@ -1,7 +1,7 @@
 use strict;
 use warnings;
 
-use RT::Extension::MandatoryOnTransition::Test tests => 13;
+use RT::Extension::MandatoryOnTransition::Test tests => undef;
 
 use_ok('RT::Extension::MandatoryOnTransition');
 
@@ -13,7 +13,8 @@ diag "Test RequiredFields without a ticket";
                        );
     is( $core->[0], 'TimeWorked', 'Got TimeWorked for required core');
 
-    ($core, $cf) = RT::Extension::MandatoryOnTransition->RequiredFields(
+    my $must_values;
+    ($core, $cf, $must_values) = RT::Extension::MandatoryOnTransition->RequiredFields(
                            From => "''",
                            To   => 'resolved',
                            Queue => 'General',
@@ -21,6 +22,12 @@ diag "Test RequiredFields without a ticket";
 
     is( $core->[0], 'TimeWorked', 'Got TimeWorked for required core');
     is( $cf->[0], 'Test Field', 'Got Test Field for required custom field');
+
+    is( (ref $must_values->{'Test Field2'}), 'HASH', 'Got a hash for Test Field2 must values');
+    is( (ref $must_values->{'Test Field2'}{'must_be'}), 'ARRAY', 'Got an array for must be values');
+    is( (ref $must_values->{'Test Field2'}{'must_not_be'}), 'ARRAY', 'Got an array for must not be values');
+    is( $must_values->{'Test Field2'}{'must_be'}->[0], 'normal', "First must be value is 'normal'");
+    is( $must_values->{'Test Field2'}{'must_not_be'}->[0], 'down', "First must not be value is 'down'");
 }
 
 diag "Test RequiredFields with a ticket";
@@ -33,11 +40,19 @@ diag "Test RequiredFields with a ticket";
 
     ok( $t->id, 'Created test ticket: ' . $t->id);
 
-    my ($core, $cf) = RT::Extension::MandatoryOnTransition->RequiredFields(
+    my ($core, $cf, $must_values) = RT::Extension::MandatoryOnTransition->RequiredFields(
                            Ticket => $t,
                            To   => 'resolved',
                        );
 
     is( $core->[0], 'TimeWorked', 'Got TimeWorked for required core');
     is( $cf->[0], 'Test Field', 'Got Test Field for required custom field');
+
+    is( (ref $must_values->{'Test Field2'}), 'HASH', 'Got a hash for Test Field2 must values');
+    is( (ref $must_values->{'Test Field2'}{'must_be'}), 'ARRAY', 'Got an array for must be values');
+    is( (ref $must_values->{'Test Field2'}{'must_not_be'}), 'ARRAY', 'Got an array for must not be values');
+    is( $must_values->{'Test Field2'}{'must_be'}->[0], 'normal', "First must be value is 'normal'");
+    is( $must_values->{'Test Field2'}{'must_not_be'}->[0], 'down', "First must not be value is 'down'");
 }
+
+done_testing;

commit 83ef77a91649dc9001a2761e738a7a77527b53db
Author: Jim Brandt <jbrandt at bestpractical.com>
Date:   Thu Jun 23 09:52:32 2016 -0400

    Update test to match test config changes

diff --git a/xt/required_fields.t b/xt/required_fields.t
index 3c7a91d..8d91b81 100644
--- a/xt/required_fields.t
+++ b/xt/required_fields.t
@@ -23,11 +23,11 @@ diag "Test RequiredFields without a ticket";
     is( $core->[0], 'TimeWorked', 'Got TimeWorked for required core');
     is( $cf->[0], 'Test Field', 'Got Test Field for required custom field');
 
-    is( (ref $must_values->{'Test Field2'}), 'HASH', 'Got a hash for Test Field2 must values');
-    is( (ref $must_values->{'Test Field2'}{'must_be'}), 'ARRAY', 'Got an array for must be values');
-    is( (ref $must_values->{'Test Field2'}{'must_not_be'}), 'ARRAY', 'Got an array for must not be values');
-    is( $must_values->{'Test Field2'}{'must_be'}->[0], 'normal', "First must be value is 'normal'");
-    is( $must_values->{'Test Field2'}{'must_not_be'}->[0], 'down', "First must not be value is 'down'");
+    is( (ref $must_values->{'Test Field3'}), 'HASH', 'Got a hash for Test Field3 must values');
+    is( (ref $must_values->{'Test Field3'}{'must_be'}), 'ARRAY', 'Got an array for must be values');
+    is( (ref $must_values->{'Test Field4'}{'must_not_be'}), 'ARRAY', 'Got an array for must not be values');
+    is( $must_values->{'Test Field3'}{'must_be'}->[0], 'normal', "First must be value is 'normal'");
+    is( $must_values->{'Test Field4'}{'must_not_be'}->[0], 'down', "First must not be value is 'down'");
 }
 
 diag "Test RequiredFields with a ticket";
@@ -48,11 +48,11 @@ diag "Test RequiredFields with a ticket";
     is( $core->[0], 'TimeWorked', 'Got TimeWorked for required core');
     is( $cf->[0], 'Test Field', 'Got Test Field for required custom field');
 
-    is( (ref $must_values->{'Test Field2'}), 'HASH', 'Got a hash for Test Field2 must values');
-    is( (ref $must_values->{'Test Field2'}{'must_be'}), 'ARRAY', 'Got an array for must be values');
-    is( (ref $must_values->{'Test Field2'}{'must_not_be'}), 'ARRAY', 'Got an array for must not be values');
-    is( $must_values->{'Test Field2'}{'must_be'}->[0], 'normal', "First must be value is 'normal'");
-    is( $must_values->{'Test Field2'}{'must_not_be'}->[0], 'down', "First must not be value is 'down'");
+    is( (ref $must_values->{'Test Field3'}), 'HASH', 'Got a hash for Test Field3 must values');
+    is( (ref $must_values->{'Test Field3'}{'must_be'}), 'ARRAY', 'Got an array for must be values');
+    is( (ref $must_values->{'Test Field4'}{'must_not_be'}), 'ARRAY', 'Got an array for must not be values');
+    is( $must_values->{'Test Field3'}{'must_be'}->[0], 'normal', "First must be value is 'normal'");
+    is( $must_values->{'Test Field4'}{'must_not_be'}->[0], 'down', "First must not be value is 'down'");
 }
 
 done_testing;

commit 6d1615ddf25a3a4eaa16c2501748bceafa7fc34d
Author: Jim Brandt <jbrandt at bestpractical.com>
Date:   Thu Jun 23 10:59:49 2016 -0400

    Fix incorrect sample configuration

diff --git a/README b/README
index 1ea76f0..8ff74b2 100644
--- a/README
+++ b/README
@@ -128,14 +128,14 @@ CONFIGURATION
     Sometimes you want to restrict a transition if a field has a specific
     value (maybe a ticket can't be resolved if System Status = down) or
     require a specific value to to allow a transition (ticket can't be
-    resolved unless System Status = normal). To enforce specific values, you
+    resolved unless a problem was fixed). To enforce specific values, you
     can add the following:
 
         Set( %MandatoryOnTransition,
             Helpdesk => {
-                '* -> resolved' => ['TimeWorked', 'CF.Some Field1', 'CF.Some Field2'],
-                'CF.Test Field2' => { transition => '* -> resolved', must_be => ['normal', 'restored'] },
-                'CF.Test Field3' => { transition => '* -> resolved', must_not_be => ['reduced', 'down']}
+                '* -> resolved' => ['TimeWorked', 'CF.Resolution', 'CF.System Status'],
+                'CF.Resolution' => { transition => '* -> resolved', must_be => ['fixed', 'not an issue'] },
+                'CF.System Status' => { transition => '* -> resolved', must_not_be => ['reduced', 'down']}
             },
         );
 
diff --git a/lib/RT/Extension/MandatoryOnTransition.pm b/lib/RT/Extension/MandatoryOnTransition.pm
index b073ffd..49c043b 100644
--- a/lib/RT/Extension/MandatoryOnTransition.pm
+++ b/lib/RT/Extension/MandatoryOnTransition.pm
@@ -157,14 +157,14 @@ C<perldoc /opt/rt4/etc/RT_Config.pm>.
 Sometimes you want to restrict a transition if a field has a specific
 value (maybe a ticket can't be resolved if System Status = down) or
 require a specific value to to allow a transition (ticket can't be
-resolved unless System Status = normal). To enforce specific values, you
+resolved unless a problem was fixed). To enforce specific values, you
 can add the following:
 
     Set( %MandatoryOnTransition,
         Helpdesk => {
-            '* -> resolved' => ['TimeWorked', 'CF.Some Field1', 'CF.Some Field2'],
-            'CF.Test Field2' => { transition => '* -> resolved', must_be => ['normal', 'restored'] },
-            'CF.Test Field3' => { transition => '* -> resolved', must_not_be => ['reduced', 'down']}
+            '* -> resolved' => ['TimeWorked', 'CF.Resolution', 'CF.System Status'],
+            'CF.Resolution' => { transition => '* -> resolved', must_be => ['fixed', 'not an issue'] },
+            'CF.System Status' => { transition => '* -> resolved', must_not_be => ['reduced', 'down']}
         },
     );
 

commit da5daf3335ea12119c225472fe92f2f7b828d399
Author: Jim Brandt <jbrandt at bestpractical.com>
Date:   Thu Jun 23 11:16:23 2016 -0400

    Clean up must values with temp arrays

diff --git a/lib/RT/Extension/MandatoryOnTransition.pm b/lib/RT/Extension/MandatoryOnTransition.pm
index 49c043b..c6f97ef 100644
--- a/lib/RT/Extension/MandatoryOnTransition.pm
+++ b/lib/RT/Extension/MandatoryOnTransition.pm
@@ -303,7 +303,7 @@ sub RequiredFields {
         if ( $config{"CF.$cf"} ){
             my $transition = $config{"CF.$cf"}->{'transition'};
             unless ( $transition ){
-                RT->Logger->error("No transition defined in must be or must not be rules for $cf");
+                RT->Logger->error("No transition defined in must_be or must_not_be rules for $cf");
                 next;
             }
 
@@ -452,11 +452,13 @@ sub CheckMandatoryFields {
                 unless defined $cf_value;
 
             if ( exists $must_values->{$cf->Name}{'must_be'} ){
+                my @must_be = @{$must_values->{$cf->Name}{'must_be'}};
+
                 # OK if it's defined and is one of the specified values
-                next if defined $cf_value and grep { $cf_value eq $_ } @{$must_values->{$cf->Name}{'must_be'}};
-                my $valid_values = join ", ", @{$must_values->{$cf->Name}{'must_be'}};
+                next if defined $cf_value and grep { $cf_value eq $_ } @must_be;
+                my $valid_values = join ", ", @must_be;
                 my $one_of = '';
-                $one_of = " one of:" if @{$must_values->{$cf->Name}{'must_be'}} > 1;
+                $one_of = " one of:" if @must_be > 1;
                 push @errors,
                   $CurrentUser->loc("[_1] must be$one_of [_3] when changing Status to [_2]",
                                     $cf->Name, $CurrentUser->loc($ARGSRef->{Status}), $valid_values);
@@ -464,11 +466,13 @@ sub CheckMandatoryFields {
             }
 
             if ( exists $must_values->{$cf->Name}{'must_not_be'} ){
+                my @must_not_be = @{$must_values->{$cf->Name}{'must_not_be'}};
+
                 # OK if it's defined and _not_ in the list
-                next if defined $cf_value and !grep { $cf_value eq $_ } @{$must_values->{$cf->Name}{'must_not_be'}};
-                my $valid_values = join ", ", @{$must_values->{$cf->Name}{'must_not_be'}};
+                next if defined $cf_value and !grep { $cf_value eq $_ } @must_not_be;
+                my $valid_values = join ", ", @must_not_be;
                 my $one_of = '';
-                $one_of = " one of:" if @{$must_values->{$cf->Name}{'must_not_be'}} > 1;
+                $one_of = " one of:" if @must_not_be > 1;
                 push @errors,
                   $CurrentUser->loc("[_1] must not be$one_of [_3] when changing Status to [_2]",
                                     $cf->Name, $CurrentUser->loc($ARGSRef->{Status}), $valid_values);

commit fc8347f1ea9678f83936e9f27c9e4b0b4ec12458
Author: Jim Brandt <jbrandt at bestpractical.com>
Date:   Thu Jun 23 11:22:46 2016 -0400

    Add some new items to todo list

diff --git a/README b/README
index 8ff74b2..51fce9e 100644
--- a/README
+++ b/README
@@ -238,6 +238,14 @@ TODO
     Enforcement on other update pages
             SelfService - can't do it without patches to <form> POST + additional callbacks
 
+    Full Validation of Configuration
+            Check that all CFs are actually CFs applied to the indicated queues (or global). Also
+            validate additional CF's with "must" configuration are defined in a transition.
+
+    Allow empty values in "must" configuration
+            When defining a list of "must be" or "must not be" values, there may be use cases where
+            an empty value could be valid. Provide a way to specify and allow this.
+
 AUTHOR
     Best Practical Solutions, LLC <modules at bestpractical.com>
 
diff --git a/lib/RT/Extension/MandatoryOnTransition.pm b/lib/RT/Extension/MandatoryOnTransition.pm
index c6f97ef..7182188 100644
--- a/lib/RT/Extension/MandatoryOnTransition.pm
+++ b/lib/RT/Extension/MandatoryOnTransition.pm
@@ -527,6 +527,16 @@ sub Config {
 
     SelfService - can't do it without patches to <form> POST + additional callbacks
 
+=item Full Validation of Configuration
+
+    Check that all CFs are actually CFs applied to the indicated queues (or global). Also
+    validate additional CF's with "must" configuration are defined in a transition.
+
+=item Allow empty values in "must" configuration
+
+    When defining a list of "must be" or "must not be" values, there may be use cases where
+    an empty value could be valid. Provide a way to specify and allow this.
+
 =back
 
 =head1 AUTHOR

commit ff535764efd0e3c58e828168320a218b64ae8b4b
Author: Jim Brandt <jbrandt at bestpractical.com>
Date:   Thu Jun 23 11:43:06 2016 -0400

    Confirm Ticket is available before calling methods

diff --git a/lib/RT/Extension/MandatoryOnTransition.pm b/lib/RT/Extension/MandatoryOnTransition.pm
index 7182188..3600661 100644
--- a/lib/RT/Extension/MandatoryOnTransition.pm
+++ b/lib/RT/Extension/MandatoryOnTransition.pm
@@ -297,7 +297,7 @@ sub RequiredFields {
     my @cfs  =  map { /^CF\.(.+)$/i; $1; }
                grep { /^CF\./i } @$required;
 
-    # Pull out an must be or must not be rules
+    # Pull out any must_be or must_not_be rules
     my %cf_must_values = ();
     foreach my $cf (@cfs){
         if ( $config{"CF.$cf"} ){
@@ -447,9 +447,11 @@ sub CheckMandatoryFields {
         # Check for specific values
         if ( exists $must_values->{$cf->Name} ){
             my $cf_value = $value;
-            # Fetch the current value if we didn't receive a new one
-            $cf_value = $args{'Ticket'}->FirstCustomFieldValue($cf->Name)
-                unless defined $cf_value;
+
+            if ( not defined $cf_value and $args{'Ticket'} ){
+                # Fetch the current value if we didn't receive a new one
+                $cf_value = $args{'Ticket'}->FirstCustomFieldValue($cf->Name);
+            }
 
             if ( exists $must_values->{$cf->Name}{'must_be'} ){
                 my @must_be = @{$must_values->{$cf->Name}{'must_be'}};

commit 5861a66f9606b6aa09c9447a9665bac58025d3ca
Author: Jim Brandt <jbrandt at bestpractical.com>
Date:   Thu Jun 23 11:59:45 2016 -0400

    Update error messages for proper localization

diff --git a/lib/RT/Extension/MandatoryOnTransition.pm b/lib/RT/Extension/MandatoryOnTransition.pm
index 3600661..2f7b6d6 100644
--- a/lib/RT/Extension/MandatoryOnTransition.pm
+++ b/lib/RT/Extension/MandatoryOnTransition.pm
@@ -459,11 +459,16 @@ sub CheckMandatoryFields {
                 # OK if it's defined and is one of the specified values
                 next if defined $cf_value and grep { $cf_value eq $_ } @must_be;
                 my $valid_values = join ", ", @must_be;
-                my $one_of = '';
-                $one_of = " one of:" if @must_be > 1;
-                push @errors,
-                  $CurrentUser->loc("[_1] must be$one_of [_3] when changing Status to [_2]",
-                                    $cf->Name, $CurrentUser->loc($ARGSRef->{Status}), $valid_values);
+                if ( @must_be > 1 ){
+                    push @errors,
+                        $CurrentUser->loc("[_1] must be one of: [_3] when changing Status to [_2]",
+                        $cf->Name, $CurrentUser->loc($ARGSRef->{Status}), $valid_values);
+                }
+                else{
+                    push @errors,
+                        $CurrentUser->loc("[_1] must be [_3] when changing Status to [_2]",
+                        $cf->Name, $CurrentUser->loc($ARGSRef->{Status}), $valid_values);
+                }
                 next;
             }
 
@@ -473,11 +478,16 @@ sub CheckMandatoryFields {
                 # OK if it's defined and _not_ in the list
                 next if defined $cf_value and !grep { $cf_value eq $_ } @must_not_be;
                 my $valid_values = join ", ", @must_not_be;
-                my $one_of = '';
-                $one_of = " one of:" if @must_not_be > 1;
-                push @errors,
-                  $CurrentUser->loc("[_1] must not be$one_of [_3] when changing Status to [_2]",
-                                    $cf->Name, $CurrentUser->loc($ARGSRef->{Status}), $valid_values);
+                if ( @must_not_be > 1 ){
+                    push @errors,
+                        $CurrentUser->loc("[_1] must not be one of: [_3] when changing Status to [_2]",
+                        $cf->Name, $CurrentUser->loc($ARGSRef->{Status}), $valid_values);
+                }
+                else{
+                    push @errors,
+                        $CurrentUser->loc("[_1] must not be [_3] when changing Status to [_2]",
+                        $cf->Name, $CurrentUser->loc($ARGSRef->{Status}), $valid_values);
+                }
                 next;
             }
         }

commit 8225344896e1805863e259c045a1ca7e5458782d
Merge: 9c271bd 5861a66
Author: Shawn M Moore <shawn at bestpractical.com>
Date:   Mon Jul 11 20:23:01 2016 +0000

    Merge branch 'must-and-must-not-be'


commit 8891d7203fd9be3afeb9874c9281e1349debe32b
Author: Shawn M Moore <shawn at bestpractical.com>
Date:   Mon Jul 11 20:22:39 2016 +0000

    0.11 releng

diff --git a/Changes b/Changes
index 855d476..63016a6 100644
--- a/Changes
+++ b/Changes
@@ -1,3 +1,6 @@
+0.11 2016-06-30
+ - Allow rules to require or restrict specific values on transition
+
 0.10 2016-04-02
  - Updates to run on RT 4.4 (tests)
  - Fix bug where non-mandatory fields were displayed on update
diff --git a/lib/RT/Extension/MandatoryOnTransition.pm b/lib/RT/Extension/MandatoryOnTransition.pm
index da59988..4a8feb6 100644
--- a/lib/RT/Extension/MandatoryOnTransition.pm
+++ b/lib/RT/Extension/MandatoryOnTransition.pm
@@ -2,7 +2,7 @@ use strict;
 use warnings;
 package RT::Extension::MandatoryOnTransition;
 
-our $VERSION = '0.10';
+our $VERSION = '0.11';
 
 =head1 NAME
 

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


More information about the Bps-public-commit mailing list