[Bps-public-commit] rt-extension-rest2 branch, request-fields, created. 1.06-20-gda38e33

? sunnavy sunnavy at bestpractical.com
Thu May 23 12:25:24 EDT 2019


The branch, request-fields has been created
        at  da38e3349532bff6b7d285eec08b54ee115a943e (commit)

- Log -----------------------------------------------------------------
commit 7f25f77baa2c979c1c186a66c93438ac58483d7f
Author: Andrew Ruthven <puck at catalystcloud.nz>
Date:   Thu Jun 28 06:55:03 2018 +0000

    Allow specifying additional fields to return in search results

diff --git a/lib/RT/Extension/REST2.pm b/lib/RT/Extension/REST2.pm
index 826d5ab..a5c699b 100644
--- a/lib/RT/Extension/REST2.pm
+++ b/lib/RT/Extension/REST2.pm
@@ -618,6 +618,13 @@ the query parameters C<page> and C<per_page>.  The default page size is 20
 items, but it may be increased up to 100 (or decreased if desired).  Page
 numbers start at 1.
 
+=head2 Fields
+
+When fetching search results you can include additional fields by adding
+a query parameter C<fields> which is a comma seperated list of fields
+to include. You must use the camel case version of the name as included
+in the results for the actual item.
+
 =head2 Authentication Methods
 
 Authentication should B<always> be done over HTTPS/SSL for
diff --git a/lib/RT/Extension/REST2/Resource/Collection.pm b/lib/RT/Extension/REST2/Resource/Collection.pm
index e29ab9b..c83bc4a 100644
--- a/lib/RT/Extension/REST2/Resource/Collection.pm
+++ b/lib/RT/Extension/REST2/Resource/Collection.pm
@@ -54,10 +54,20 @@ sub serialize {
     my $self = shift;
     my $collection = $self->collection;
     my @results;
+    my @fields = defined $self->request->param('fields') ? split(/,/, $self->request->param('fields')) : ();
 
     while (my $item = $collection->Next) {
-        # TODO: Allow selection of desired fields
-        push @results, expand_uid( $item->UID );
+        my $result = expand_uid( $item->UID );
+
+        # Allow selection of desired fields
+        if ($result) {
+            for my $field (@fields) {
+                if ($item->_Accessible($field, 'read')) {
+                   $result->{$field} = $item->$field;
+                }
+            }
+        }
+        push @results, $result;
     }
     return {
         count       => scalar(@results)         + 0,

commit 5dc3e3150281fa8ab7793f892601649f7149245c
Author: Andrew Ruthven <puck at catalystcloud.nz>
Date:   Fri Jun 29 03:12:28 2018 +0000

    Improve specifying fields for collection results
    
    If it's an object, use expand_uid, if a datetime or timestamp,
    format it nicely.

diff --git a/lib/RT/Extension/REST2/Resource/Collection.pm b/lib/RT/Extension/REST2/Resource/Collection.pm
index c83bc4a..6d64569 100644
--- a/lib/RT/Extension/REST2/Resource/Collection.pm
+++ b/lib/RT/Extension/REST2/Resource/Collection.pm
@@ -10,7 +10,7 @@ extends 'RT::Extension::REST2::Resource';
 use Scalar::Util qw( blessed );
 use Web::Machine::FSM::States qw( is_status_code );
 use Module::Runtime qw( require_module );
-use RT::Extension::REST2::Util qw( serialize_record expand_uid );
+use RT::Extension::REST2::Util qw( serialize_record expand_uid format_datetime );
 
 has 'collection_class' => (
     is  => 'ro',
@@ -62,8 +62,20 @@ sub serialize {
         # Allow selection of desired fields
         if ($result) {
             for my $field (@fields) {
-                if ($item->_Accessible($field, 'read')) {
-                   $result->{$field} = $item->$field;
+                if ($item->_Accessible($field => 'read')) {
+                    if ($item->_Accessible($field => 'type') =~ /(datetime|timestamp)/i) {
+                        $result->{$field} = format_datetime($item->$field);
+                    } elsif ($item->can($field . 'Obj')) {
+                        my $method = $field . 'Obj';
+                        my $obj = $item->$method;
+                        if ($obj->can('UID')) {
+                            $result->{$field} = expand_uid( $obj->UID );
+                        } else {
+                            $result->{$field} = $obj;
+                        }
+                    } else {
+                        $result->{$field} = $item->$field;
+                    }
                 }
             }
         }
diff --git a/lib/RT/Extension/REST2/Util.pm b/lib/RT/Extension/REST2/Util.pm
index 9b52319..e814c1c 100644
--- a/lib/RT/Extension/REST2/Util.pm
+++ b/lib/RT/Extension/REST2/Util.pm
@@ -18,6 +18,7 @@ use Sub::Exporter -setup => {
         escape_uri
         query_string
         custom_fields_for
+        format_datetime
     ]]
 };
 

commit aab7cf97c4997bb53b33242164a3365ad2fbb734
Author: Andrew Ruthven <puck at catalystcloud.nz>
Date:   Fri Jun 29 08:53:56 2018 +0000

    Allow JSON API syntax to specify fields from child blocks to be included.
    
    See: http://jsonapi.org/examples/#sparse-fieldsets

diff --git a/lib/RT/Extension/REST2.pm b/lib/RT/Extension/REST2.pm
index a5c699b..7b24ea4 100644
--- a/lib/RT/Extension/REST2.pm
+++ b/lib/RT/Extension/REST2.pm
@@ -625,6 +625,46 @@ a query parameter C<fields> which is a comma seperated list of fields
 to include. You must use the camel case version of the name as included
 in the results for the actual item.
 
+You can use additional fields parameters to expand child blocks, for
+example (line wrapping inserted for readability):
+
+    XX_RT_URL_XX/REST/2.0/tickets
+      ?fields=Owner,Status,Created,Subject,Queue
+      &fields[Queue]=Name,Description
+
+Says that in the result set for tickets, the extra fields for Owner, Status,
+Created, Subject and Queue should be included. But in addition, for the Queue
+block, also include Name and Description. The results would be similar to
+this (only one ticket is displayed):
+
+   "items" : [
+      {
+         "Subject" : "Sample Ticket",
+         "id" : "2",
+         "type" : "ticket",
+         "Owner" : {
+            "id" : "root",
+            "_url" : "XX_RT_URL_XX/REST/2.0/user/root",
+            "type" : "user"
+         },
+         "_url" : "XX_RT_URL_XX/REST/2.0/ticket/2",
+         "Status" : "resolved",
+         "Created" : "2018-06-29:10:25Z",
+         "Queue" : {
+            "id" : "1",
+            "type" : "queue",
+            "Name" : "General",
+            "Description" : "The default queue",
+            "_url" : "XX_RT_URL_XX/REST/2.0/queue/1"
+         }
+      }
+      { … },
+      …
+   ],
+
+If the user performing the query doesn't have rights to view the record
+(or sub record), then the empty string or an empty hash will be returned.
+
 =head2 Authentication Methods
 
 Authentication should B<always> be done over HTTPS/SSL for
diff --git a/lib/RT/Extension/REST2/Resource/Collection.pm b/lib/RT/Extension/REST2/Resource/Collection.pm
index 6d64569..a93002a 100644
--- a/lib/RT/Extension/REST2/Resource/Collection.pm
+++ b/lib/RT/Extension/REST2/Resource/Collection.pm
@@ -62,21 +62,8 @@ sub serialize {
         # Allow selection of desired fields
         if ($result) {
             for my $field (@fields) {
-                if ($item->_Accessible($field => 'read')) {
-                    if ($item->_Accessible($field => 'type') =~ /(datetime|timestamp)/i) {
-                        $result->{$field} = format_datetime($item->$field);
-                    } elsif ($item->can($field . 'Obj')) {
-                        my $method = $field . 'Obj';
-                        my $obj = $item->$method;
-                        if ($obj->can('UID')) {
-                            $result->{$field} = expand_uid( $obj->UID );
-                        } else {
-                            $result->{$field} = $obj;
-                        }
-                    } else {
-                        $result->{$field} = $item->$field;
-                    }
-                }
+                my $field_result = $self->expand_field($item, $field);
+                $result->{$field} = $field_result if defined $field_result;
             }
         }
         push @results, $result;
@@ -90,6 +77,48 @@ sub serialize {
     };
 }
 
+# Used in Serialize to allow additional fields to be selected ala JSON API on:
+# http://jsonapi.org/examples/
+sub expand_field {
+    my $self  = shift;
+    my $item  = shift;
+    my $field = shift;
+    my $param_prefix = shift || 'fields';
+
+    my ($result, $obj);
+    if ($item->can('_Accessible') && $item->_Accessible($field => 'read')) {
+        # RT::Record derived object, so we can check access permissions.
+
+        if ($item->_Accessible($field => 'type') =~ /(datetime|timestamp)/i) {
+            $result = format_datetime($item->$field);
+        } elsif ($item->can($field . 'Obj')) {
+            my $method = $field . 'Obj';
+            $obj = $item->$method;
+            if ($obj->can('UID')) {
+                $result = expand_uid( $obj->UID );
+            } else {
+                $result = {};
+            }
+        } else {
+            $result = $item->$field;
+        }
+    }
+
+    $result //= '';
+
+    if (defined $obj && defined $result) {
+        my $param_field = $param_prefix . '[' . $field . ']';
+        my @subfields = split(/,/, $self->request->param($param_field) || '');
+
+        for my $subfield (@subfields) {
+            my $subfield_result = $self->expand_field($obj, $subfield, $param_field);
+            $result->{$subfield} = $subfield_result if defined $subfield_result;
+        }
+    }
+
+    return $result;
+}
+
 # XXX TODO: Bulk update via DELETE/PUT on a collection resource?
 
 sub charsets_provided { [ 'utf-8' ] }

commit 785266122b5c39c495c4c9caf8cd0f933b61cfa9
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Tue May 14 23:28:07 2019 +0800

    Add tests for the additional fields support in search results

diff --git a/xt/queues.t b/xt/queues.t
index 2209766..faf744d 100644
--- a/xt/queues.t
+++ b/xt/queues.t
@@ -242,5 +242,70 @@ my ($features_url, $features_id);
     like($queue->{_url}, qr{$rest_base_path/queue/$features_id$});
 }
 
-done_testing;
+# id > 0 (finds new Features queue but not disabled Bugs queue), include Name field
+{
+    my $res = $mech->post_json("$rest_base_path/queues?fields=Name",
+        [{ field => 'id', operator => '>', value => 0 }],
+        'Authorization' => $auth,
+    );
+    is($res->code, 200);
+
+    my $content = $mech->json_response;
+    is(scalar @{$content->{items}}, 1);
+
+    my $queue = $content->{items}->[0];
+    is($queue->{Name}, 'Features');
+    is(scalar keys %$queue, 4);
+}
+
+
+# all queues, basic fields
+{
+    my $res = $mech->post_json("$rest_base_path/queues/all",
+        [],
+        'Authorization' => $auth,
+    );
+    is($res->code, 200);
+
+    my $content = $mech->json_response;
+    is(scalar @{$content->{items}}, 1);
+
+    my $queue = $content->{items}->[0];
+    is(scalar keys %$queue, 3);
+}
 
+# all queues, basic fields plus Name
+{
+    my $res = $mech->post_json("$rest_base_path/queues/all?fields=Name",
+        [],
+        'Authorization' => $auth,
+    );
+    is($res->code, 200);
+
+    my $content = $mech->json_response;
+    is(scalar @{$content->{items}}, 1);
+
+    my $queue = $content->{items}->[0];
+    is(scalar keys %$queue, 4);
+    is($queue->{Name}, 'Features');
+}
+
+# all queues, basic fields plus Name, Lifecycle. Lifecycle should be empty
+# string as we don't allow returning it.
+{
+    my $res = $mech->post_json("$rest_base_path/queues/all?fields=Name,Lifecycle",
+        [],
+        'Authorization' => $auth,
+    );
+    is($res->code, 200);
+
+    my $content = $mech->json_response;
+    is(scalar @{$content->{items}}, 1);
+
+    my $queue = $content->{items}->[0];
+    is(scalar keys %$queue, 5);
+    is($queue->{Name}, 'Features');
+    is_deeply($queue->{Lifecycle}, {}, 'Lifecycle is empty');
+}
+
+done_testing;
diff --git a/xt/tickets.t b/xt/tickets.t
index 645b225..9dd6619 100644
--- a/xt/tickets.t
+++ b/xt/tickets.t
@@ -134,6 +134,65 @@ my ($ticket_url, $ticket_id);
     is($ticket->{type}, 'ticket');
     is($ticket->{id}, 1);
     like($ticket->{_url}, qr{$rest_base_path/ticket/1$});
+    is(scalar keys %$ticket, 3);
+}
+
+# Ticket Search - Fields
+{
+    my $res = $mech->get("$rest_base_path/tickets?query=id>0&fields=Status,Subject",
+        'Authorization' => $auth,
+    );
+    is($res->code, 200);
+    my $content = $mech->json_response;
+    is(scalar @{$content->{items}}, 1);
+
+    my $ticket = $content->{items}->[0];
+    is($ticket->{Subject}, 'Ticket creation using REST');
+    is($ticket->{Status}, 'new');
+    is(scalar keys %$ticket, 5);
+}
+
+# Ticket Search - Fields, sub objects, no right to see Queues
+{
+    my $res = $mech->get("$rest_base_path/tickets?query=id>0&fields=Status,Owner,Queue&fields[Queue]=Name,Description&fields[Owner]=Name",
+        'Authorization' => $auth,
+    );
+    is($res->code, 200);
+    my $content = $mech->json_response;
+    is(scalar @{$content->{items}}, 1);
+
+    my $ticket = $content->{items}->[0];
+
+    is($ticket->{Status}, 'new');
+    is($ticket->{Queue}{Name}, '');
+    is($ticket->{Queue}{id}, '1');
+    is($ticket->{Queue}{type}, 'queue');
+    like($ticket->{Queue}{_url}, qr[$rest_base_path/queue/1$]);
+    is($ticket->{Owner}{Name}, 'Nobody');
+    is(scalar keys %$ticket, 6);
+}
+
+# Ticket Search - Fields, sub objects with SeeQueue right
+{
+    $user->PrincipalObj->GrantRight( Right => 'SeeQueue' );
+
+    my $res = $mech->get("$rest_base_path/tickets?query=id>0&fields=Status,Owner,Queue&fields[Queue]=Name,Description&fields[Owner]=Name",
+        'Authorization' => $auth,
+    );
+    is($res->code, 200);
+    my $content = $mech->json_response;
+    is(scalar @{$content->{items}}, 1);
+
+    my $ticket = $content->{items}->[0];
+
+    is($ticket->{Status}, 'new');
+    is($ticket->{Queue}{Name}, 'General');
+    is($ticket->{Queue}{Description}, 'The default queue');
+    is($ticket->{Queue}{id}, '1');
+    is($ticket->{Queue}{type}, 'queue');
+    like($ticket->{Queue}{_url}, qr[$rest_base_path/queue/1$]);
+    is($ticket->{Owner}{Name}, 'Nobody');
+    is(scalar keys %$ticket, 6);
 }
 
 # Ticket Update

commit daad7cd9d02368dfcc4d847d38f4d59f988b6eec
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Thu May 23 16:26:20 2019 +0800

    Move expand_field to parent class so we can call it in other resources.

diff --git a/lib/RT/Extension/REST2/Resource.pm b/lib/RT/Extension/REST2/Resource.pm
index 4e34614..d9ce9ea 100644
--- a/lib/RT/Extension/REST2/Resource.pm
+++ b/lib/RT/Extension/REST2/Resource.pm
@@ -5,6 +5,7 @@ use warnings;
 use Moose;
 use MooseX::NonMoose;
 use namespace::autoclean;
+use RT::Extension::REST2::Util qw(expand_uid format_datetime );
 
 extends 'Web::Machine::Resource';
 
@@ -20,6 +21,48 @@ sub _build_current_user {
     $_[0]->request->env->{"rt.current_user"} || RT::CurrentUser->new;
 }
 
+# Used in Serialize to allow additional fields to be selected ala JSON API on:
+# http://jsonapi.org/examples/
+sub expand_field {
+    my $self  = shift;
+    my $item  = shift;
+    my $field = shift;
+    my $param_prefix = shift || 'fields';
+
+    my ($result, $obj);
+    if ($item->can('_Accessible') && $item->_Accessible($field => 'read')) {
+        # RT::Record derived object, so we can check access permissions.
+
+        if ($item->_Accessible($field => 'type') =~ /(datetime|timestamp)/i) {
+            $result = format_datetime($item->$field);
+        } elsif ($item->can($field . 'Obj')) {
+            my $method = $field . 'Obj';
+            $obj = $item->$method;
+            if ($obj->can('UID')) {
+                $result = expand_uid( $obj->UID );
+            } else {
+                $result = {};
+            }
+        } else {
+            $result = $item->$field;
+        }
+    }
+
+    $result //= '';
+
+    if (defined $obj && defined $result) {
+        my $param_field = $param_prefix . '[' . $field . ']';
+        my @subfields = split(/,/, $self->request->param($param_field) || '');
+
+        for my $subfield (@subfields) {
+            my $subfield_result = $self->expand_field($obj, $subfield, $param_field);
+            $result->{$subfield} = $subfield_result if defined $subfield_result;
+        }
+    }
+
+    return $result;
+}
+
 __PACKAGE__->meta->make_immutable;
 
 1;
diff --git a/lib/RT/Extension/REST2/Resource/Collection.pm b/lib/RT/Extension/REST2/Resource/Collection.pm
index a93002a..f646885 100644
--- a/lib/RT/Extension/REST2/Resource/Collection.pm
+++ b/lib/RT/Extension/REST2/Resource/Collection.pm
@@ -77,48 +77,6 @@ sub serialize {
     };
 }
 
-# Used in Serialize to allow additional fields to be selected ala JSON API on:
-# http://jsonapi.org/examples/
-sub expand_field {
-    my $self  = shift;
-    my $item  = shift;
-    my $field = shift;
-    my $param_prefix = shift || 'fields';
-
-    my ($result, $obj);
-    if ($item->can('_Accessible') && $item->_Accessible($field => 'read')) {
-        # RT::Record derived object, so we can check access permissions.
-
-        if ($item->_Accessible($field => 'type') =~ /(datetime|timestamp)/i) {
-            $result = format_datetime($item->$field);
-        } elsif ($item->can($field . 'Obj')) {
-            my $method = $field . 'Obj';
-            $obj = $item->$method;
-            if ($obj->can('UID')) {
-                $result = expand_uid( $obj->UID );
-            } else {
-                $result = {};
-            }
-        } else {
-            $result = $item->$field;
-        }
-    }
-
-    $result //= '';
-
-    if (defined $obj && defined $result) {
-        my $param_field = $param_prefix . '[' . $field . ']';
-        my @subfields = split(/,/, $self->request->param($param_field) || '');
-
-        for my $subfield (@subfields) {
-            my $subfield_result = $self->expand_field($obj, $subfield, $param_field);
-            $result->{$subfield} = $subfield_result if defined $subfield_result;
-        }
-    }
-
-    return $result;
-}
-
 # XXX TODO: Bulk update via DELETE/PUT on a collection resource?
 
 sub charsets_provided { [ 'utf-8' ] }

commit 4f7e086429ea94cc904c81f4521eef2f481a0563
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Thu May 23 16:35:31 2019 +0800

    Show plain column value if the corresponding ...Obj is not an RT::Record
    
    We use UID method to expand RT::Record objects. But not all the ...Obj
    methods return RT::Record objects. Take LifecycleObj for example,
    previously it returned an empty hash, which is not useful. Instead, we
    can return the plain column value(like "default" Lifecycle) for cases
    like this.
    
    Code is also re-arranged to make the logic a bit more clear.

diff --git a/lib/RT/Extension/REST2.pm b/lib/RT/Extension/REST2.pm
index 7b24ea4..d678a84 100644
--- a/lib/RT/Extension/REST2.pm
+++ b/lib/RT/Extension/REST2.pm
@@ -663,7 +663,7 @@ this (only one ticket is displayed):
    ],
 
 If the user performing the query doesn't have rights to view the record
-(or sub record), then the empty string or an empty hash will be returned.
+(or sub record), then the empty string will be returned.
 
 =head2 Authentication Methods
 
diff --git a/lib/RT/Extension/REST2/Resource.pm b/lib/RT/Extension/REST2/Resource.pm
index d9ce9ea..d7e611c 100644
--- a/lib/RT/Extension/REST2/Resource.pm
+++ b/lib/RT/Extension/REST2/Resource.pm
@@ -29,7 +29,7 @@ sub expand_field {
     my $field = shift;
     my $param_prefix = shift || 'fields';
 
-    my ($result, $obj);
+    my $result;
     if ($item->can('_Accessible') && $item->_Accessible($field => 'read')) {
         # RT::Record derived object, so we can check access permissions.
 
@@ -37,30 +37,22 @@ sub expand_field {
             $result = format_datetime($item->$field);
         } elsif ($item->can($field . 'Obj')) {
             my $method = $field . 'Obj';
-            $obj = $item->$method;
-            if ($obj->can('UID')) {
-                $result = expand_uid( $obj->UID );
-            } else {
-                $result = {};
+            my $obj = $item->$method;
+            if ( $obj->can('UID') and $result = expand_uid( $obj->UID ) ) {
+                my $param_field = $param_prefix . '[' . $field . ']';
+                my @subfields = split( /,/, $self->request->param($param_field) || '' );
+
+                for my $subfield (@subfields) {
+                    my $subfield_result = $self->expand_field( $obj, $subfield, $param_field );
+                    $result->{$subfield} = $subfield_result if defined $subfield_result;
+                }
             }
-        } else {
-            $result = $item->$field;
         }
-    }
-
-    $result //= '';
 
-    if (defined $obj && defined $result) {
-        my $param_field = $param_prefix . '[' . $field . ']';
-        my @subfields = split(/,/, $self->request->param($param_field) || '');
-
-        for my $subfield (@subfields) {
-            my $subfield_result = $self->expand_field($obj, $subfield, $param_field);
-            $result->{$subfield} = $subfield_result if defined $subfield_result;
-        }
+        $result //= $item->$field;
     }
 
-    return $result;
+    return $result // '';
 }
 
 __PACKAGE__->meta->make_immutable;
diff --git a/xt/queues.t b/xt/queues.t
index faf744d..a8396b2 100644
--- a/xt/queues.t
+++ b/xt/queues.t
@@ -305,7 +305,7 @@ my ($features_url, $features_id);
     my $queue = $content->{items}->[0];
     is(scalar keys %$queue, 5);
     is($queue->{Name}, 'Features');
-    is_deeply($queue->{Lifecycle}, {}, 'Lifecycle is empty');
+    is_deeply($queue->{Lifecycle}, 'default', 'Lifecycle is default');
 }
 
 done_testing;

commit 18a9d56ebc36abb40b433e49ae76eedfd79606f0
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Thu May 23 22:31:52 2019 +0800

    Support additional fields for single object URI
    
    Take /ticket/:id for example, as it already contains all the ticket
    fields by default, we only need to handle additional child blocks, e.g
    /ticket/1?fields[Queue]=Name,Lifecycle

diff --git a/lib/RT/Extension/REST2.pm b/lib/RT/Extension/REST2.pm
index d678a84..c3bfeee 100644
--- a/lib/RT/Extension/REST2.pm
+++ b/lib/RT/Extension/REST2.pm
@@ -665,6 +665,12 @@ this (only one ticket is displayed):
 If the user performing the query doesn't have rights to view the record
 (or sub record), then the empty string will be returned.
 
+For single object URLs like /ticket/:id, as it already contains all the
+fields by default, parameter "fields" is not needed, but you can still
+use additional fields parameters to expand child blocks:
+
+    XX_RT_URL_XX/REST/2.0/ticket/1?fields[Queue]=Name,Description
+
 =head2 Authentication Methods
 
 Authentication should B<always> be done over HTTPS/SSL for
diff --git a/lib/RT/Extension/REST2/Resource/Record/Readable.pm b/lib/RT/Extension/REST2/Resource/Record/Readable.pm
index 6eeb50a..bd9b151 100644
--- a/lib/RT/Extension/REST2/Resource/Record/Readable.pm
+++ b/lib/RT/Extension/REST2/Resource/Record/Readable.pm
@@ -21,6 +21,22 @@ sub serialize {
     my $record = $self->record;
     my $data = serialize_record($record);
 
+    for my $field (keys %$data) {
+        my $result = $data->{$field};
+        if ($record->can($field . 'Obj')) {
+            my $method = $field . 'Obj';
+            my $obj = $record->$method;
+            my $param_field = "fields[$field]";
+            my @subfields = split(/,/, $self->request->param($param_field) || '');
+
+            for my $subfield (@subfields) {
+                my $subfield_result = $self->expand_field($obj, $subfield, $param_field);
+                $result->{$subfield} = $subfield_result if defined $subfield_result;
+            }
+        }
+        $data->{$field} = $result;
+    }
+
     if ($self->does('RT::Extension::REST2::Resource::Record::Hypermedia')) {
         $data->{_hyperlinks} = $self->hypermedia_links;
     }

commit da38e3349532bff6b7d285eec08b54ee115a943e
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Thu May 23 22:43:36 2019 +0800

    Test additional fields support for /ticket/:id

diff --git a/xt/tickets.t b/xt/tickets.t
index 9dd6619..695d9a4 100644
--- a/xt/tickets.t
+++ b/xt/tickets.t
@@ -100,6 +100,8 @@ my ($ticket_url, $ticket_id);
     is($queue->{id}, 1);
     is($queue->{type}, 'queue');
     like($queue->{_url}, qr{$rest_base_path/queue/1$});
+    ok(!exists $queue->{Name}, 'queue name is absent');
+    ok(!exists $queue->{Lifecycle}, 'queue lifecycle is absent');
 
     my $owner = $content->{Owner};
     is($owner->{id}, 'Nobody');
@@ -117,6 +119,42 @@ my ($ticket_url, $ticket_id);
     like($updated_by->{_url}, qr{$rest_base_path/user/test$});
 }
 
+# Ticket display with additional fields
+{
+    my $res = $mech->get($ticket_url . '?fields[Queue]=Name,Lifecycle',
+        'Authorization' => $auth,
+    );
+    is($res->code, 200);
+
+    my $content = $mech->json_response;
+    is($content->{id}, $ticket_id);
+
+    my $queue = $content->{Queue};
+    is($queue->{id},   1);
+    is($queue->{type}, 'queue');
+    like($queue->{_url}, qr{$rest_base_path/queue/1$});
+    is($queue->{Name},      '', 'empty queue name');
+    is($queue->{Lifecycle}, '', 'empty queue lifecycle');
+
+    $user->PrincipalObj->GrantRight(Right => 'SeeQueue');
+
+    $res = $mech->get($ticket_url . '?fields[Queue]=Name,Lifecycle',
+        'Authorization' => $auth,);
+    is($res->code, 200);
+
+    $content = $mech->json_response;
+    is($content->{id}, $ticket_id);
+
+    $queue = $content->{Queue};
+    is($queue->{id},   1);
+    is($queue->{type}, 'queue');
+    like($queue->{_url}, qr{$rest_base_path/queue/1$});
+    is($queue->{Name},      'General', 'queue name');
+    is($queue->{Lifecycle}, 'default', 'queue lifecycle');
+
+    $user->PrincipalObj->RevokeRight(Right => 'SeeQueue');
+}
+
 # Ticket Search
 {
     my $res = $mech->get("$rest_base_path/tickets?query=id>0",

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


More information about the Bps-public-commit mailing list