[Bps-public-commit] RT-Extension-MandatoryOnTransition branch, support-coreroles-and-customroles, created. 0.17-5-gb060515
Craig Kaiser
craig at bestpractical.com
Fri Jan 11 11:40:43 EST 2019
The branch, support-coreroles-and-customroles has been created
at b06051524b7dca2ff8655f85baf6c9911147ee01 (commit)
- Log -----------------------------------------------------------------
commit fa95e1a61afd063b9b70eb7e6c16bec0960d30f9
Author: Craig Kaiser <craig at bestpractical.com>
Date: Fri Jan 4 11:11:15 2019 -0500
Support customroles for mandatoryontransition conditions
Use the syntax 'CustomRole.MyRole' to set mandatory conditions for
customrole values.
diff --git a/lib/RT/Extension/MandatoryOnTransition.pm b/lib/RT/Extension/MandatoryOnTransition.pm
index d238c18..ac96bbd 100644
--- a/lib/RT/Extension/MandatoryOnTransition.pm
+++ b/lib/RT/Extension/MandatoryOnTransition.pm
@@ -127,7 +127,7 @@ config option. This option takes the generic form of:
Set( %MandatoryOnTransition,
'QueueName' => {
- 'from -> to' => [ 'BasicField', 'CF.MyField', ],
+ 'from -> to' => [ 'BasicField', 'CF.MyField', 'CustomRole.MyRole' ],
},
);
@@ -146,10 +146,11 @@ Category selection before resolving tickets in every other queue.
Set( %MandatoryOnTransition,
Helpdesk => {
- '* -> resolved' => ['TimeWorked', 'CF.Resolution'],
+ '* -> resolved' => ['TimeWorked', 'CF.Resolution', 'CustomRole.Analyst'],
},
'*' => {
'* -> resolved' => ['CF.Category'],
+ 'CustomRole.Analyst' => {transition => '* -> open', group => 'Engineering'},
},
);
@@ -340,6 +341,8 @@ sub RequiredFields {
my @core = grep { !/^CF\./i && $core_supported{$_} } @$required;
my @cfs = map { /^CF\.(.+)$/i; $1; }
grep { /^CF\./i } @$required;
+ my @roles = map { /^(:?[CustomRole\.]?.+)$/i; $1; }
+ grep { /^CustomRole\./i } @$required;
# Pull out any must_be or must_not_be rules
my %cf_must_values = ();
@@ -359,7 +362,25 @@ sub RequiredFields {
}
}
}
- return (\@core, \@cfs, \%cf_must_values);
+
+ my %role_group_values;
+ foreach my $role (@roles){
+ if ( $config{$role} ){
+ my $transition = $config{$role}->{'transition'};
+ unless ( $transition ){
+ RT->Logger->error("No transition defined in group rules for $role");
+ next;
+ }
+
+ if ( $transition eq "$from -> $to"
+ || $transition eq "* -> $to"
+ || $transition eq "$from -> *" ) {
+
+ $role_group_values{$role} = $config{$role};
+ }
+ }
+ }
+ return (\@core, \@cfs, \@roles, \%cf_must_values, \%role_group_values);
}
=head3 CheckMandatoryFields
@@ -412,13 +433,15 @@ sub CheckMandatoryFields {
}
# Some convenience variables set depending on what gets passed
- my ($CFs, $CurrentUser);
+ my ($CFs, $CRs, $CurrentUser);
if ( $args{'Ticket'} ){
$CFs = $args{'Ticket'}->CustomFields;
+ $CRs = $args{'Ticket'}->QueueObj->CustomRoles;
$CurrentUser = $args{'Ticket'}->CurrentUser();
}
elsif ( $args{'Queue'} ){
$CFs = $args{'Queue'}->TicketCustomFields;
+ $CRs = $args{'Queue'}->CustomRoles;
$CurrentUser = $args{'Queue'}->CurrentUser();
}
else{
@@ -426,15 +449,14 @@ sub CheckMandatoryFields {
return \@errors;
}
- my ($core, $cfs, $must_values) = $self->RequiredFields(
+ my ($core, $cfs, $roles, $cf_must_values, $role_group_values) = $self->RequiredFields(
Ticket => $args{'Ticket'},
Queue => $args{'Queue'} ? $args{'Queue'}->Name : undef,
From => $args{'From'},
To => $args{'To'},
NewQueue => $$ARGSRef{'Queue'},
);
-
- return \@errors unless @$core or @$cfs;
+ return \@errors unless @$core or @$cfs or $roles;
my $transition = ($args{'From'} ||'') ne ($args{'To'} || '') ? 'Status' : 'Queue';
@@ -500,6 +522,47 @@ sub CheckMandatoryFields {
$label, $CurrentUser->loc($transition), $CurrentUser->loc($field_label{$transition}));
}
+ if ( @$roles ) {
+ foreach my $role (@$roles) {
+ my $role_values;
+ my $role_arg = $role;
+ my $role_full = $role;
+
+ if ( not $CRs ){
+ $RT::Logger->error("Custom Roles object required to process mandatory custom roles");
+ return \@errors;
+ }
+ $role =~ qr/^CustomRole\.(.+)$/i;
+ $role = $1;
+
+ my $role_object = RT::CustomRole->new($args{Ticket}->CurrentUser);
+
+ my ($ret, $msg) = $role_object->Load($role);
+ push @errors, $CurrentUser->loc("Failed to load customrole $role: $msg") unless $ret;
+ return \@errors unless $ret;
+
+ $role_arg = 'RT::CustomRole-' . $role_object->Id;
+
+ ($ret, $msg) = $role_values = $args{Ticket}->RoleGroup($role_object->GroupType);
+ push @errors, $CurrentUser->loc("$msg") unless $ret;
+ return \@errors unless $ret;
+
+ my @role_values;
+ my @row_input_id = grep $role_arg eq $ARGSRef->{$_}, keys %{$ARGSRef};
+ if ( @row_input_id ) {
+ map {push @role_values, $ARGSRef->{"WatcherAddressEmail$_"} } grep { $_ =~ qr/WatcherTypeEmail(.+)/ } @row_input_id;
+ }
+
+ my @temp_array = $role_values->MemberEmailAddresses;
+ push @role_values, @temp_array if scalar @temp_array;
+
+ if ( not scalar @role_values ) {
+ push @errors, "Requires value for $role to perform action.";
+ return \@errors;
+ }
+ return \@errors if scalar @errors;
+ }
+
return \@errors unless @$cfs;
if ( not $CFs ){
@@ -565,7 +628,7 @@ sub CheckMandatoryFields {
}
# Check for specific values
- if ( exists $must_values->{$cf->Name} ){
+ if ( exists $cf_must_values->{$cf->Name} ){
my $cf_value = $value;
if ( not defined $cf_value and $args{'Ticket'} ){
@@ -574,8 +637,8 @@ sub CheckMandatoryFields {
$cf_value = $args{'Ticket'}->FirstCustomFieldValue($cf->Name);
}
- if ( exists $must_values->{$cf->Name}{'must_be'} ){
- my @must_be = @{$must_values->{$cf->Name}{'must_be'}};
+ if ( exists $cf_must_values->{$cf->Name}{'must_be'} ){
+ my @must_be = @{$cf_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_be;
@@ -593,8 +656,8 @@ sub CheckMandatoryFields {
next;
}
- if ( exists $must_values->{$cf->Name}{'must_not_be'} ){
- my @must_not_be = @{$must_values->{$cf->Name}{'must_not_be'}};
+ if ( exists $cf_must_values->{$cf->Name}{'must_not_be'} ){
+ my @must_not_be = @{$cf_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_not_be;
commit 78217ccbe6f4d6e004f69f34a435b8304c759262
Author: Craig Kaiser <craig at bestpractical.com>
Date: Fri Jan 11 11:29:59 2019 -0500
Support core roles for mandatoryontransation
diff --git a/lib/RT/Extension/MandatoryOnTransition.pm b/lib/RT/Extension/MandatoryOnTransition.pm
index ac96bbd..45a3733 100644
--- a/lib/RT/Extension/MandatoryOnTransition.pm
+++ b/lib/RT/Extension/MandatoryOnTransition.pm
@@ -342,7 +342,7 @@ sub RequiredFields {
my @cfs = map { /^CF\.(.+)$/i; $1; }
grep { /^CF\./i } @$required;
my @roles = map { /^(:?[CustomRole\.]?.+)$/i; $1; }
- grep { /^CustomRole\./i } @$required;
+ grep { /^CustomRole\.|^AdminCc|^Cc|^Requestor|^Owner/i } @$required;
# Pull out any must_be or must_not_be rules
my %cf_must_values = ();
@@ -528,24 +528,31 @@ sub CheckMandatoryFields {
my $role_arg = $role;
my $role_full = $role;
- if ( not $CRs ){
- $RT::Logger->error("Custom Roles object required to process mandatory custom roles");
- return \@errors;
- }
- $role =~ qr/^CustomRole\.(.+)$/i;
- $role = $1;
+ if ( $role =~ 'CustomRole.' ) {
+ if ( not $CRs ){
+ $RT::Logger->error("Custom Roles object required to process mandatory custom roles");
+ return \@errors;
+ }
+ $role =~ qr/^CustomRole\.(.+)$/i;
+ $role = $1;
- my $role_object = RT::CustomRole->new($args{Ticket}->CurrentUser);
+ my $role_object = RT::CustomRole->new($args{Ticket}->CurrentUser);
- my ($ret, $msg) = $role_object->Load($role);
- push @errors, $CurrentUser->loc("Failed to load customrole $role: $msg") unless $ret;
- return \@errors unless $ret;
+ my ($ret, $msg) = $role_object->Load($role);
+ push @errors, $CurrentUser->loc("Failed to load customrole $role: $msg") unless $ret;
+ return \@errors unless $ret;
- $role_arg = 'RT::CustomRole-' . $role_object->Id;
+ $role_arg = 'RT::CustomRole-' . $role_object->Id;
- ($ret, $msg) = $role_values = $args{Ticket}->RoleGroup($role_object->GroupType);
- push @errors, $CurrentUser->loc("$msg") unless $ret;
- return \@errors unless $ret;
+ ($ret, $msg) = $role_values = $args{Ticket}->RoleGroup($role_object->GroupType);
+ push @errors, $CurrentUser->loc("$msg") unless $ret;
+ return \@errors unless $ret;
+ } else {
+ $role_values = RT::Group->new($args{Ticket}->CurrentUser);
+ my ($ret, $msg) = $role_values->LoadRoleGroup(Object => $args{Ticket}, Name => $role);
+ push @errors, $CurrentUser->loc("Failed to load role $role for ticket: $msg") unless $ret;
+ return \@errors unless $ret;
+ }
my @role_values;
my @row_input_id = grep $role_arg eq $ARGSRef->{$_}, keys %{$ARGSRef};
commit 0fdd0606e37f9f66581fa6f5d236863bcac7fd63
Author: Craig Kaiser <craig at bestpractical.com>
Date: Fri Jan 4 14:33:30 2019 -0500
Allow group key to be set for roles
If a group key is set for a role it will be attempted
to be loaded and then check that a value for the
role is a member of the group.
diff --git a/lib/RT/Extension/MandatoryOnTransition.pm b/lib/RT/Extension/MandatoryOnTransition.pm
index 45a3733..a83b5cb 100644
--- a/lib/RT/Extension/MandatoryOnTransition.pm
+++ b/lib/RT/Extension/MandatoryOnTransition.pm
@@ -566,7 +566,30 @@ sub CheckMandatoryFields {
if ( not scalar @role_values ) {
push @errors, "Requires value for $role to perform action.";
return \@errors;
+ } elsif ( $role_group_values->{$role_full}->{group} ) {
+ my $group_name = $role_group_values->{$role_full}->{group};
+ my $group = RT::Group->new($args{Ticket}->CurrentUser);
+
+ my ($ret, $msg) = $group->LoadUserDefinedGroup($group_name);
+ push @errors, $CurrentUser->loc("Failed to load group: '$group_name' $msg") unless $ret;
+ return \@errors unless $ret;
+
+ my $has_valid_member;
+ my $user = RT::User->new($args{Ticket}->CurrentUser);
+
+ foreach my $member (@role_values) {
+ next if $has_valid_member;
+ ($ret, $msg) = $user->LoadByEmail($member);
+ RT::Logger->error($msg) unless $ret;
+ next unless $ret;
+
+ $has_valid_member = $group->HasMemberRecursively($user->Id);
+ }
+ push @errors, $CurrentUser->loc("User who is a member of $group_name is required for role: $role")
+ unless $has_valid_member;
+ return \@errors unless $has_valid_member;
}
+ }
return \@errors if scalar @errors;
}
commit 845bd08b125eb469f449c1e62c69dd4ff27802a3
Author: Craig Kaiser <craig at bestpractical.com>
Date: Mon Jan 7 08:37:09 2019 -0500
Move Owner code into the roles code block
Since owner is a ticket role it makes logical sense to move the code
handling the owner value on a ticket into the same code block as
the other role handling code.
diff --git a/lib/RT/Extension/MandatoryOnTransition.pm b/lib/RT/Extension/MandatoryOnTransition.pm
index a83b5cb..bc7488f 100644
--- a/lib/RT/Extension/MandatoryOnTransition.pm
+++ b/lib/RT/Extension/MandatoryOnTransition.pm
@@ -258,18 +258,16 @@ pair to %CORE_FOR_UPDATE and/or %CORE_FOR_CREATE.
=cut
-our @CORE_SUPPORTED = qw(Content TimeWorked TimeTaken Owner);
-our @CORE_TICKET = qw(TimeWorked Owner);
+our @CORE_SUPPORTED = qw(Content TimeWorked TimeTaken);
+our @CORE_TICKET = qw(TimeWorked);
our %CORE_FOR_UPDATE = (
TimeWorked => 'UpdateTimeWorked',
TimeTaken => 'UpdateTimeWorked',
- Content => 'UpdateContent',
- Owner => 'Owner',
+ Content => 'UpdateContent'
);
our %CORE_FOR_CREATE = (
TimeWorked => 'TimeWorked',
Content => 'Content',
- Owner => 'Owner',
);
=head2 Methods
@@ -479,36 +477,6 @@ sub CheckMandatoryFields {
: $CORE_FOR_CREATE{$field};
next unless $arg;
- if ($field eq 'Owner') {
- my $value;
-
- # There are 2 Owner fields on Jumbo page, copied the same handling from it.
- if (ref $ARGSRef->{$arg}) {
- foreach my $owner (@{$ARGSRef->{$arg}}) {
- if (defined($owner) && $owner =~ /\D/) {
- $value = $owner unless ($args{'Ticket'}->OwnerObj->Name eq $owner);
- }
- elsif (length $owner) {
- $value = $owner unless ($args{'Ticket'}->OwnerObj->id == $owner);
- }
- }
- }
- else {
- $value = $ARGSRef->{$arg};
- }
-
- if (($value || $args{'Ticket'}->$field()) == $RT::Nobody->id) {
- push @errors,
- $CurrentUser->loc(
- "[_1] is required when changing [_2] to [_3]",
- $field,
- $CurrentUser->loc($transition),
- $CurrentUser->loc($field_label{$transition})
- );
- next;
- }
- }
-
next if defined $ARGSRef->{$arg} and length $ARGSRef->{$arg};
# Do we have a value currently?
@@ -547,21 +515,49 @@ sub CheckMandatoryFields {
($ret, $msg) = $role_values = $args{Ticket}->RoleGroup($role_object->GroupType);
push @errors, $CurrentUser->loc("$msg") unless $ret;
return \@errors unless $ret;
+ } elsif ( $role =~ 'Owner' ) {
+ my $value;
+ foreach my $owner (@{$ARGSRef->{$role}}) {
+ if (defined($owner) && $owner =~ /\D/) {
+ $value = $owner unless ($args{'Ticket'}->OwnerObj->Name eq $owner);
+ }
+ elsif (length $owner) {
+ $value = $owner unless ($args{'Ticket'}->OwnerObj->id == $owner);
+ }
+ }
+ if (($value || $args{'Ticket'}->$role()) == $RT::Nobody->id) {
+ push @errors,
+ $CurrentUser->loc(
+ "[_1] is required when changing [_2] to [_3]",
+ $role,
+ $CurrentUser->loc($args{From}),
+ $CurrentUser->loc($args{To})
+ );
+ }
+ my $user = RT::User->new($args{Ticket}->CurrentUser);
+ my ($ret, $msg) = $user->Load($value);
+ push @errors, $CurrentUser->loc("$msg") unless $ret;
+ return \@errors unless $ret;
+
+ $role_values = $user->EmailAddress;
} else {
$role_values = RT::Group->new($args{Ticket}->CurrentUser);
my ($ret, $msg) = $role_values->LoadRoleGroup(Object => $args{Ticket}, Name => $role);
push @errors, $CurrentUser->loc("Failed to load role $role for ticket: $msg") unless $ret;
return \@errors unless $ret;
}
-
my @role_values;
my @row_input_id = grep $role_arg eq $ARGSRef->{$_}, keys %{$ARGSRef};
if ( @row_input_id ) {
map {push @role_values, $ARGSRef->{"WatcherAddressEmail$_"} } grep { $_ =~ qr/WatcherTypeEmail(.+)/ } @row_input_id;
}
- my @temp_array = $role_values->MemberEmailAddresses;
- push @role_values, @temp_array if scalar @temp_array;
+ if ( ref $role_values eq 'RT::Group' ) {
+ my @temp_array = $role_values->MemberEmailAddresses;
+ push @role_values, @temp_array if scalar @temp_array;
+ } else {
+ push @role_values, $role_values;
+ }
if ( not scalar @role_values ) {
push @errors, "Requires value for $role to perform action.";
commit b06051524b7dca2ff8655f85baf6c9911147ee01
Author: Craig Kaiser <craig at bestpractical.com>
Date: Fri Jan 11 11:37:10 2019 -0500
Update README
diff --git a/README b/README
index ad7e034..80db750 100644
--- a/README
+++ b/README
@@ -96,7 +96,7 @@ CONFIGURATION
Set( %MandatoryOnTransition,
'QueueName' => {
- 'from -> to' => [ 'BasicField', 'CF.MyField', ],
+ 'from -> to' => [ 'BasicField', 'CF.MyField', 'CustomRole.MyRole' ],
},
);
@@ -125,6 +125,18 @@ CONFIGURATION
The transition syntax is similar to that found in RT's Lifecycles. See
perldoc /opt/rt4/etc/RT_Config.pm.
+ Requiring role values
+ You can require any core or custom role on a RT::Ticket object, further
+ more you can require a 'group' category to check that at least one value
+ for that role is a member of the required group. In the below example we
+ require that the custom role 'customer' have a user value who is a
+ member of the group 'Customers' and the owner of the ticket must be a
+ member of the group 'Helpdesk'.
+
+ Set( %MandatoryOnTransition, 'General' => { 'CustomRole.customer' => {
+ transition => 'open -> *', group => 'Customers' }, 'Owner' => {
+ transition => 'open -> *', group => 'Helpdesk' }, }, );
+
Restrictions on Queue Transitions
The default behavior for MandatoryOnTransition operates on status
transitions, so a change from new to open or from open to resolved. It
diff --git a/lib/RT/Extension/MandatoryOnTransition.pm b/lib/RT/Extension/MandatoryOnTransition.pm
index bc7488f..d75f96a 100644
--- a/lib/RT/Extension/MandatoryOnTransition.pm
+++ b/lib/RT/Extension/MandatoryOnTransition.pm
@@ -146,17 +146,31 @@ Category selection before resolving tickets in every other queue.
Set( %MandatoryOnTransition,
Helpdesk => {
- '* -> resolved' => ['TimeWorked', 'CF.Resolution', 'CustomRole.Analyst'],
+ '* -> resolved' => ['TimeWorked', 'CF.Resolution'],
},
'*' => {
'* -> resolved' => ['CF.Category'],
- 'CustomRole.Analyst' => {transition => '* -> open', group => 'Engineering'},
},
);
The transition syntax is similar to that found in RT's Lifecycles. See
C<perldoc /opt/rt4/etc/RT_Config.pm>.
+=head2 Requiring role values
+
+You can require any core or custom role on a RT::Ticket object, further more
+you can require a 'group' category to check that at least one value for that
+role is a member of the required group. In the below example we require that
+the custom role 'customer' have a user value who is a member of the group 'Customers'
+and the owner of the ticket must be a member of the group 'Helpdesk'.
+
+Set( %MandatoryOnTransition,
+ 'General' => {
+ 'CustomRole.customer' => { transition => 'open -> *', group => 'Customers' },
+ 'Owner' => { transition => 'open -> *', group => 'Helpdesk' },
+ },
+);
+
=head2 Restrictions on Queue Transitions
The default behavior for C<MandatoryOnTransition> operates on status transitions,
-----------------------------------------------------------------------
More information about the Bps-public-commit
mailing list