[Bps-public-commit] rt-extension-rest2 branch, custom-field-handling-improvements, created. 1.07-2-gde47b37
Aaron Trevena
ast at bestpractical.com
Fri Feb 28 05:06:43 EST 2020
The branch, custom-field-handling-improvements has been created
at de47b37ac89fa2312cf50e57a1c042172608e9e4 (commit)
- Log -----------------------------------------------------------------
commit 0f2f2b6f79b30bf22f82351897b1207b947259ee
Author: Andrew Ruthven <puck at catalystcloud.nz>
Date: Fri Feb 28 10:05:04 2020 +0000
Treat CustomFields in a manner that is more consistent to other object types
diff --git a/Changes b/Changes
index c756d8c..e6c887b 100644
--- a/Changes
+++ b/Changes
@@ -1,5 +1,8 @@
Revision history for RT-Extension-REST2
+Unreleased
+ - Return more information about CustomFields when returning ticket
+
1.07 2019-05-24
- Accept 'Content' as a parameter on create. The documentation previously showed
this in examples, but it wasn't yet supported. Now it works as documented.
diff --git a/lib/RT/Extension/REST2/Util.pm b/lib/RT/Extension/REST2/Util.pm
index e814c1c..2474e83 100644
--- a/lib/RT/Extension/REST2/Util.pm
+++ b/lib/RT/Extension/REST2/Util.pm
@@ -115,8 +115,13 @@ sub serialize_record {
if (my $cfs = custom_fields_for($record)) {
my %values;
while (my $cf = $cfs->Next) {
- my $key = $cf->Id;
- my $values = $values{$key} ||= [];
+ if (! defined $values{$cf->Id}) {
+ $values{$cf->Id} = {
+ %{ expand_uid($cf->UID) },
+ name => $cf->Name,
+ values => [],
+ };
+ }
my $ocfvs = $cf->ValuesForObject( $record );
my $type = $cf->Type;
while (my $ocfv = $ocfvs->Next) {
@@ -131,11 +136,11 @@ sub serialize_record {
_url => RT::Extension::REST2->base_uri . "/download/cf/" . $ocfv->id,
};
}
- push @$values, $content;
+ push @{ $values{$cf->Id}{values} }, $content;
}
}
- $data{CustomFields} = \%values;
+ push @{ $data{CustomFields} }, values %values;
}
return \%data;
}
commit de47b37ac89fa2312cf50e57a1c042172608e9e4
Author: Andrew Ruthven <puck at catalystcloud.nz>
Date: Fri Feb 28 10:05:39 2020 +0000
New and updated Tests for CustomFields handling
diff --git a/xt/asset-customfields.t b/xt/asset-customfields.t
index 499c400..3003665 100644
--- a/xt/asset-customfields.t
+++ b/xt/asset-customfields.t
@@ -96,10 +96,15 @@ my ($asset_url, $asset_id);
is($content->{id}, $asset_id);
is($content->{Status}, 'new');
is($content->{Name}, 'Asset creation using REST');
- is_deeply($content->{'CustomFields'}, {}, 'Asset custom field not present');
+ is_deeply($content->{'CustomFields'}, [], 'Asset custom field not present');
is_deeply([grep { $_->{ref} eq 'customfield' } @{ $content->{'_hyperlinks'} }], [], 'No CF hypermedia');
}
+my $no_asset_cf_values = bag(
+ { name => 'Single', id => $single_cf_id, type => 'customfield', _url => ignore(), values => [] },
+ { name => 'Multi', id => $multi_cf_id, type => 'customfield', _url => ignore(), values => [] },
+);
+
# Rights Test - With ShowAsset and SeeCustomField
{
$user->PrincipalObj->GrantRight( Right => 'SeeCustomField');
@@ -113,7 +118,9 @@ my ($asset_url, $asset_id);
is($content->{id}, $asset_id);
is($content->{Status}, 'new');
is($content->{Name}, 'Asset creation using REST');
- is_deeply($content->{CustomFields}, { $single_cf_id => [], $multi_cf_id => [] }, 'No asset custom field values');
+ cmp_deeply($content->{CustomFields}, $no_asset_cf_values, 'No asset custom field values');
+
+
cmp_deeply(
[grep { $_->{ref} eq 'customfield' } @{ $content->{'_hyperlinks'} }],
[{
@@ -198,7 +205,7 @@ my ($asset_url, $asset_id);
my $content = $mech->json_response;
is($content->{Name}, 'Asset update using REST');
is($content->{Status}, 'allocated');
- is_deeply($content->{CustomFields}, { $single_cf_id => [], $multi_cf_id => [] }, 'No update to CF');
+ cmp_deeply($content->{CustomFields}, $no_asset_cf_values, 'No update to CF');
}
# Asset Update with ModifyCustomField
@@ -223,10 +230,15 @@ my ($asset_url, $asset_id);
);
is($res->code, 200);
+ my $modified_asset_cf_values = bag(
+ { name => 'Single', id => $single_cf_id, type => 'customfield', _url => ignore(), values => ['Modified CF'] },
+ { name => 'Multi', id => $multi_cf_id, type => 'customfield', _url => ignore(), values => [] },
+ );
+
my $content = $mech->json_response;
is($content->{Name}, 'More updates using REST');
is($content->{Status}, 'in-use');
- is_deeply($content->{CustomFields}, { $single_cf_id => ['Modified CF'], $multi_cf_id => [] }, 'New CF value');
+ cmp_deeply($content->{CustomFields}, $modified_asset_cf_values, 'New CF value');
# make sure changing the CF doesn't add a second OCFV
$payload->{CustomFields}{$single_cf_id} = 'Modified Again';
@@ -242,8 +254,13 @@ my ($asset_url, $asset_id);
);
is($res->code, 200);
+ $modified_asset_cf_values = bag(
+ { name => 'Single', id => $single_cf_id, type => 'customfield', _url => ignore(), values => ['Modified Again'] },
+ { name => 'Multi', id => $multi_cf_id, type => 'customfield', _url => ignore(), values => [] },
+ );
+
$content = $mech->json_response;
- is_deeply($content->{CustomFields}, { $single_cf_id => ['Modified Again'], $multi_cf_id => [] }, 'New CF value');
+ cmp_deeply($content->{CustomFields}, $modified_asset_cf_values, 'New CF value');
# stop changing the CF, change something else, make sure CF sticks around
delete $payload->{CustomFields}{$single_cf_id};
@@ -261,7 +278,7 @@ my ($asset_url, $asset_id);
is($res->code, 200);
$content = $mech->json_response;
- is_deeply($content->{CustomFields}, { $single_cf_id => ['Modified Again'], $multi_cf_id => [] }, 'Same CF value');
+ cmp_deeply($content->{CustomFields}, $modified_asset_cf_values, 'Same CF value');
}
# Asset Creation with ModifyCustomField
@@ -290,11 +307,16 @@ my ($asset_url, $asset_id);
);
is($res->code, 200);
+ my $asset_cf_values = bag(
+ { name => 'Single', id => $single_cf_id, type => 'customfield', _url => ignore(), values => ['Hello world!'] },
+ { name => 'Multi', id => $multi_cf_id, type => 'customfield', _url => ignore(), values => [] },
+ );
+
my $content = $mech->json_response;
is($content->{id}, $asset_id);
is($content->{Status}, 'new');
is($content->{Name}, 'Asset creation using REST');
- is_deeply($content->{'CustomFields'}{$single_cf_id}, ['Hello world!'], 'Asset custom field');
+ cmp_deeply($content->{'CustomFields'}, $asset_cf_values, 'Asset custom field');
}
# Asset Creation for multi-value CF
@@ -330,7 +352,12 @@ for my $value (
is($content->{Name}, 'Multi-value CF');
my $output = ref($value) ? $value : [$value]; # scalar input comes out as array reference
- is_deeply($content->{'CustomFields'}, { $multi_cf_id => $output, $single_cf_id => [] }, 'Asset custom field');
+ my $asset_cf_values = bag(
+ { name => 'Single', id => $single_cf_id, type => 'customfield', _url => ignore(), values => [] },
+ { name => 'Multi', id => $multi_cf_id, type => 'customfield', _url => ignore(), values => $output },
+ );
+
+ cmp_deeply($content->{'CustomFields'}, $asset_cf_values, 'Asset custom field');
}
{
@@ -359,8 +386,13 @@ for my $value (
is($res->code, 200);
my $content = $mech->json_response;
- my @values = sort @{ $content->{CustomFields}{$multi_cf_id} };
- is_deeply(\@values, $output, $name || 'New CF value');
+ my $values;
+ for my $cf (@{ $content->{CustomFields} }) {
+ next unless $cf->{id} == $multi_cf_id;
+
+ $values = [ sort @{ $cf->{values} } ];
+ }
+ cmp_deeply($values, $output, $name || 'New CF value');
}
# starting point: ['multiple', 'values'],
diff --git a/xt/ticket-customfields.t b/xt/ticket-customfields.t
index 5e8174f..949253b 100644
--- a/xt/ticket-customfields.t
+++ b/xt/ticket-customfields.t
@@ -91,10 +91,15 @@ my ($ticket_url, $ticket_id);
is($content->{Type}, 'ticket');
is($content->{Status}, 'new');
is($content->{Subject}, 'Ticket creation using REST');
- is_deeply($content->{'CustomFields'}, {}, 'Ticket custom field not present');
+ is_deeply($content->{'CustomFields'}, [], 'Ticket custom field not present');
is_deeply([grep { $_->{ref} eq 'customfield' } @{ $content->{'_hyperlinks'} }], [], 'No CF hypermedia');
}
+my $no_ticket_cf_values = bag(
+ { name => 'Single', id => $single_cf_id, type => 'customfield', _url => ignore(), values => [] },
+ { name => 'Multi', id => $multi_cf_id, type => 'customfield', _url => ignore(), values => [] },
+);
+
# Rights Test - With ShowTicket and SeeCustomField
{
$user->PrincipalObj->GrantRight( Right => 'SeeCustomField');
@@ -109,7 +114,7 @@ my ($ticket_url, $ticket_id);
is($content->{Type}, 'ticket');
is($content->{Status}, 'new');
is($content->{Subject}, 'Ticket creation using REST');
- is_deeply($content->{CustomFields}, { $single_cf_id => [], $multi_cf_id => [] }, 'No ticket custom field values');
+ cmp_deeply($content->{CustomFields}, $no_ticket_cf_values, 'No ticket custom field values');
cmp_deeply(
[grep { $_->{ref} eq 'customfield' } @{ $content->{'_hyperlinks'} }],
[{
@@ -194,7 +199,7 @@ my ($ticket_url, $ticket_id);
my $content = $mech->json_response;
is($content->{Subject}, 'Ticket update using REST');
is($content->{Priority}, 42);
- is_deeply($content->{CustomFields}, { $single_cf_id => [], $multi_cf_id => [] }, 'No update to CF');
+ cmp_deeply($content->{CustomFields}, $no_ticket_cf_values, 'No update to CF');
}
# Ticket Update with ModifyCustomField
@@ -219,10 +224,15 @@ my ($ticket_url, $ticket_id);
);
is($res->code, 200);
+ my $modified_single_cf_value = bag(
+ { name => 'Single', id => $single_cf_id, type => 'customfield', _url => ignore(), values => ['Modified CF'] },
+ { name => 'Multi', id => $multi_cf_id, type => 'customfield', _url => ignore(), values => [] },
+ );
+
my $content = $mech->json_response;
is($content->{Subject}, 'More updates using REST');
is($content->{Priority}, 43);
- is_deeply($content->{CustomFields}, { $single_cf_id => ['Modified CF'], $multi_cf_id => [] }, 'New CF value');
+ cmp_deeply($content->{CustomFields}, $modified_single_cf_value, 'New CF value');
# make sure changing the CF doesn't add a second OCFV
$payload->{CustomFields}{$single_cf_id} = 'Modified Again';
@@ -238,8 +248,13 @@ my ($ticket_url, $ticket_id);
);
is($res->code, 200);
+ my $modified_again_single_cf_value = bag(
+ { name => 'Single', id => $single_cf_id, type => 'customfield', _url => ignore(), values => ['Modified Again'] },
+ { name => 'Multi', id => $multi_cf_id, type => 'customfield', _url => ignore(), values => [] },
+ );
+
$content = $mech->json_response;
- is_deeply($content->{CustomFields}, { $single_cf_id => ['Modified Again'], $multi_cf_id => [] }, 'New CF value');
+ cmp_deeply($content->{CustomFields}, $modified_again_single_cf_value, 'New CF value');
# stop changing the CF, change something else, make sure CF sticks around
delete $payload->{CustomFields}{$single_cf_id};
@@ -257,7 +272,7 @@ my ($ticket_url, $ticket_id);
is($res->code, 200);
$content = $mech->json_response;
- is_deeply($content->{CustomFields}, { $single_cf_id => ['Modified Again'], $multi_cf_id => [] }, 'Same CF value');
+ cmp_deeply($content->{CustomFields}, $modified_again_single_cf_value, 'Same CF value');
}
# Ticket Creation with ModifyCustomField
@@ -289,12 +304,17 @@ my ($ticket_url, $ticket_id);
);
is($res->code, 200);
+ my $ticket_cf_value = bag(
+ { name => 'Single', id => $single_cf_id, type => 'customfield', _url => ignore(), values => ['Hello world!'] },
+ { name => 'Multi', id => $multi_cf_id, type => 'customfield', _url => ignore(), values => [] },
+ );
+
my $content = $mech->json_response;
is($content->{id}, $ticket_id);
is($content->{Type}, 'ticket');
is($content->{Status}, 'new');
is($content->{Subject}, 'Ticket creation using REST');
- is_deeply($content->{'CustomFields'}{$single_cf_id}, ['Hello world!'], 'Ticket custom field');
+ cmp_deeply($content->{CustomFields}, $ticket_cf_value, 'Ticket custom field');
}
# Ticket Creation for multi-value CF
@@ -331,7 +351,11 @@ for my $value (
is($content->{Subject}, 'Multi-value CF');
my $output = ref($value) ? $value : [$value]; # scalar input comes out as array reference
- is_deeply($content->{'CustomFields'}, { $multi_cf_id => $output, $single_cf_id => [] }, 'Ticket custom field');
+ my $ticket_cf_value = bag(
+ { name => 'Single', id => $single_cf_id, type => 'customfield', _url => ignore(), values => [] },
+ { name => 'Multi', id => $multi_cf_id, type => 'customfield', _url => ignore(), values => $output },
+ );
+ cmp_deeply($content->{'CustomFields'}, $ticket_cf_value, 'Ticket custom field');
}
{
@@ -359,9 +383,13 @@ for my $value (
);
is($res->code, 200);
+ my $ticket_cf_value = bag(
+ { name => 'Single', id => $single_cf_id, type => 'customfield', _url => ignore(), values => [] },
+ { name => 'Multi', id => $multi_cf_id, type => 'customfield', _url => ignore(), values => bag(@$output) },
+ );
+
my $content = $mech->json_response;
- my @values = sort @{ $content->{CustomFields}{$multi_cf_id} };
- is_deeply(\@values, $output, $name || 'New CF value');
+ cmp_deeply($content->{'CustomFields'}, $ticket_cf_value, $name || 'New CF value');
}
# starting point: ['multiple', 'values'],
diff --git a/xt/ticket-customroles.t b/xt/ticket-customroles.t
index 9ccfcdf..a2bc034 100644
--- a/xt/ticket-customroles.t
+++ b/xt/ticket-customroles.t
@@ -505,7 +505,7 @@ $user->PrincipalObj->GrantRight( Right => $_ )
id => $group->Id,
Name => 'Watcher Group',
Domain => 'UserDefined',
- CustomFields => {},
+ CustomFields => [],
Members => [{
type => 'user',
id => 'multi at example.com',
diff --git a/xt/ticket-watchers.t b/xt/ticket-watchers.t
index 1ceae9f..e6bf631 100644
--- a/xt/ticket-watchers.t
+++ b/xt/ticket-watchers.t
@@ -570,7 +570,7 @@ $user->PrincipalObj->GrantRight( Right => $_ )
id => $group->Id,
Name => 'Watcher Group',
Domain => 'UserDefined',
- CustomFields => {},
+ CustomFields => [],
Members => [{
type => 'user',
id => 'admincc at example.com',
diff --git a/xt/user-customfields.t b/xt/user-customfields.t
index 7d277c5..d46a1c0 100644
--- a/xt/user-customfields.t
+++ b/xt/user-customfields.t
@@ -1,6 +1,7 @@
use strict;
use warnings;
use RT::Extension::REST2::Test tests => undef;
+use Test::Deep;
my $mech = RT::Extension::REST2::Test->mech;
@@ -11,6 +12,7 @@ my $user = RT::Extension::REST2::Test->user;
my $single_cf = RT::CustomField->new( RT->SystemUser );
my ($ok, $msg) = $single_cf->Create( Name => 'Freeform', Type => 'FreeformSingle', LookupType => RT::User->CustomFieldLookupType );
ok($ok, $msg);
+my $single_cf_id = $single_cf->Id();
my $ocf = RT::ObjectCustomField->new( RT->SystemUser );
( $ok, $msg ) = $ocf->Add( CustomField => $single_cf->id, ObjectId => 0 );
ok($ok, "Applied globally" );
@@ -18,6 +20,7 @@ ok($ok, "Applied globally" );
my $multi_cf = RT::CustomField->new( RT->SystemUser );
($ok, $msg) = $multi_cf->Create( Name => 'Multi', Type => 'FreeformMultiple', LookupType => RT::User->CustomFieldLookupType );
ok($ok, $msg);
+my $multi_cf_id = $multi_cf->Id();
$ocf = RT::ObjectCustomField->new( RT->SystemUser );
( $ok, $msg ) = $ocf->Add( CustomField => $multi_cf->id, ObjectId => 0 );
ok($ok, "Applied globally" );
@@ -65,7 +68,7 @@ my ($user_url, $user_id);
is($content->{id}, $user_id);
is($content->{EmailAddress}, 'user1 at example.com');
is($content->{Name}, 'user1');
- is_deeply($content->{'CustomFields'}, {}, 'User custom field not present');
+ is_deeply($content->{'CustomFields'}, [], 'User custom field not present');
# can fetch user by name too
$res = $mech->get("$rest_base_path/user/user1",
@@ -76,6 +79,11 @@ my ($user_url, $user_id);
is_deeply($mech->json_response, $content, 'requesting user by name is same as user by id');
}
+my $no_user_cf_values = bag(
+ { name => 'Freeform', id => $single_cf_id, type => 'customfield', _url => ignore(), values => [] },
+ { name => 'Multi', id => $multi_cf_id, type => 'customfield', _url => ignore(), values => [] },
+);
+
# Rights Test - With SeeCustomField
{
$user->PrincipalObj->GrantRight( Right => 'SeeCustomField');
@@ -89,7 +97,7 @@ my ($user_url, $user_id);
is($content->{id}, $user_id);
is($content->{EmailAddress}, 'user1 at example.com');
is($content->{Name}, 'user1');
- is_deeply($content->{'CustomFields'}, { $single_cf->Id => [], $multi_cf->Id => [] }, 'User custom field not present');
+ cmp_deeply($content->{'CustomFields'}, $no_user_cf_values, 'User custom field not present');
}
# User Update without ModifyCustomField
@@ -117,7 +125,7 @@ my ($user_url, $user_id);
is($content->{id}, $user_id);
is($content->{EmailAddress}, 'user1 at example.com');
is($content->{Name}, 'User1');
- is_deeply($content->{CustomFields}, { $single_cf->Id => [], $multi_cf->Id => [] }, 'No update to CF');
+ cmp_deeply($content->{'CustomFields'}, $no_user_cf_values, 'User custom field not present');
}
# User Update with ModifyCustomField
@@ -126,7 +134,7 @@ my ($user_url, $user_id);
my $payload = {
EmailAddress => 'user1+rt at example.com',
CustomFields => {
- $single_cf->Id => 'Modified CF',
+ $single_cf_id => 'Modified CF',
},
};
my $res = $mech->put_json($user_url,
@@ -143,7 +151,12 @@ my ($user_url, $user_id);
my $content = $mech->json_response;
is($content->{EmailAddress}, 'user1+rt at example.com');
- is_deeply($content->{CustomFields}, { $single_cf->Id => ['Modified CF'], $multi_cf->Id => [] }, 'New CF value');
+
+ my $set_user_cf_values = bag(
+ { name => 'Freeform', id => $single_cf_id, type => 'customfield', _url => ignore(), values => ['Modified CF'] },
+ { name => 'Multi', id => $multi_cf_id, type => 'customfield', _url => ignore(), values => [] },
+ );
+ cmp_deeply($content->{'CustomFields'}, $set_user_cf_values, 'New CF value');
# make sure changing the CF doesn't add a second OCFV
$payload->{CustomFields}{$single_cf->Id} = 'Modified Again';
@@ -160,7 +173,12 @@ my ($user_url, $user_id);
is($res->code, 200);
$content = $mech->json_response;
- is_deeply($content->{CustomFields}, { $single_cf->Id => ['Modified Again'], $multi_cf->Id => [] }, 'New CF value');
+
+ $set_user_cf_values = bag(
+ { name => 'Freeform', id => $single_cf_id, type => 'customfield', _url => ignore(), values => ['Modified Again'] },
+ { name => 'Multi', id => $multi_cf_id, type => 'customfield', _url => ignore(), values => [] },
+ );
+ cmp_deeply($content->{'CustomFields'}, $set_user_cf_values, 'New CF value');
# stop changing the CF, change something else, make sure CF sticks around
delete $payload->{CustomFields}{$single_cf->Id};
@@ -178,7 +196,7 @@ my ($user_url, $user_id);
is($res->code, 200);
$content = $mech->json_response;
- is_deeply($content->{CustomFields}, { $single_cf->Id => ['Modified Again'], $multi_cf->Id => [] }, 'Same CF value');
+ cmp_deeply($content->{'CustomFields'}, $set_user_cf_values, 'Same CF value');
}
# User Creation with ModifyCustomField
@@ -209,7 +227,12 @@ my ($user_url, $user_id);
my $content = $mech->json_response;
is($content->{id}, $user_id);
is($content->{Name}, 'user2');
- is_deeply($content->{'CustomFields'}{$single_cf->Id}, ['Hello world!'], 'User custom field');
+
+ my $set_user_cf_values = bag(
+ { name => 'Freeform', id => $single_cf_id, type => 'customfield', _url => ignore(), values => ['Hello world!'] },
+ { name => 'Multi', id => $multi_cf_id, type => 'customfield', _url => ignore(), values => [] },
+ );
+ cmp_deeply($content->{'CustomFields'}, $set_user_cf_values, 'User custom field');
}
# User Creation for multi-value CF
@@ -241,7 +264,11 @@ for my $value (
my $content = $mech->json_response;
is($content->{id}, $user_id);
my $output = ref($value) ? $value : [$value]; # scalar input comes out as array reference
- is_deeply($content->{'CustomFields'}, { $multi_cf->Id => $output, $single_cf->Id => [] }, 'User custom field');
+ my $set_user_cf_values = bag(
+ { name => 'Freeform', id => $single_cf_id, type => 'customfield', _url => ignore(), values => [] },
+ { name => 'Multi', id => $multi_cf_id, type => 'customfield', _url => ignore(), values => $output },
+ );
+ cmp_deeply($content->{'CustomFields'}, $set_user_cf_values, 'User custom field');
}
done_testing;
-----------------------------------------------------------------------
More information about the Bps-public-commit
mailing list