[Rt-commit] rt branch, 5.0/rest2-efficiently-get-ticket-attachment-list, created. rt-5.0.0-53-gcc82acb804

Dianne Skoll dianne at bestpractical.com
Wed Oct 21 15:35:00 EDT 2020


The branch, 5.0/rest2-efficiently-get-ticket-attachment-list has been created
        at  cc82acb8044d3733d6211fca301701f427c17a8f (commit)

- Log -----------------------------------------------------------------
commit cc82acb8044d3733d6211fca301701f427c17a8f
Author: Dianne Skoll <dianne at bestpractical.com>
Date:   Fri Oct 16 14:50:57 2020 -0400

    Add the REST2 endpoint: GET /ticket/:id/attachments?field=F1,F2,...,Fn
    
    This endpoint returns a list of attachments associated with a ticket; the
    "fields" query parameter lets you select which fields to return for each
    attachment.

diff --git a/lib/RT/REST2.pm b/lib/RT/REST2.pm
index 1079f95cd6..5f9bf1ba9d 100644
--- a/lib/RT/REST2.pm
+++ b/lib/RT/REST2.pm
@@ -557,6 +557,9 @@ Below are some examples using the endpoints above.
     GET /transaction/:id/attachments
         get attachments for transaction
 
+    GET /ticket/:id/attachments
+        get attachments associated with a ticket
+
     GET /attachment/:id
         retrieve an attachment
 
diff --git a/lib/RT/REST2/Resource.pm b/lib/RT/REST2/Resource.pm
index 670cbb7eb0..e4746e0140 100644
--- a/lib/RT/REST2/Resource.pm
+++ b/lib/RT/REST2/Resource.pm
@@ -110,7 +110,8 @@ sub expand_field {
 
             push @{ $result }, values %values if %values;
         }
-
+    } elsif ($field eq 'ContentLength' && $item->can('ContentLength')) {
+        $result = $item->ContentLength;
     } elsif ($item->can('_Accessible') && $item->_Accessible($field => 'read')) {
         # RT::Record derived object, so we can check access permissions.
 
diff --git a/lib/RT/REST2/Resource/Attachments.pm b/lib/RT/REST2/Resource/Attachments.pm
index d098aaa01a..413bad0303 100644
--- a/lib/RT/REST2/Resource/Attachments.pm
+++ b/lib/RT/REST2/Resource/Attachments.pm
@@ -69,7 +69,38 @@ sub dispatch_rules {
             $txn->Load($match->pos(1));
             return { collection => $txn->Attachments };
         },
-    )
+    ),
+    Path::Dispatcher::Rule::Regex->new(
+        regex => qr{^/ticket/(\d+)/attachments/?$},
+        block => sub {
+            my ($match, $req) = @_;
+            return _get_ticket_attachments($match, $req);
+        },
+    ),
+}
+
+# Get a collection of attachments associated with a ticket This code
+# was put into a subroutine as it was a little long to put inline
+# above and maintain readability.
+
+sub _get_ticket_attachments
+{
+    my ($match, $req) = @_;
+
+    my $ticket = RT::Ticket->new($req->env->{"rt.current_user"});
+    my $id = $ticket->Load($match->pos(1));
+    my $attachments = RT::Attachments->new($req->env->{"rt.current_user"});
+
+    # Return empty list if no such ticket
+    return { collection => $attachments } unless $id;
+
+    # Explicitly check for permission to see the ticket.
+    # If we do not do that, we leak the total number of attachments
+    # even though the actual attachments themselves are not shown.
+    return { collection => $attachments } unless $ticket->CurrentUserHasRight('ShowTicket');
+
+    $attachments->LimitByTicket($id);
+    return { collection => $attachments };
 }
 
 __PACKAGE__->meta->make_immutable;
diff --git a/t/rest2/attachments.t b/t/rest2/attachments.t
index d7aa05fac7..416ea504e5 100644
--- a/t/rest2/attachments.t
+++ b/t/rest2/attachments.t
@@ -98,6 +98,60 @@ $image_content = MIME::Base64::encode_base64($image_content);
     ok(!$attachments->[3]->Subject);
 }
 
+# Check the GET /ticket/:id/attachments endpoint
+{
+    my $res = $mech->get(
+        "$rest_base_path/ticket/$ticket_id/attachments?fields=Subject,Filename,ContentType,ContentLength",
+        'Authorization' => $auth
+    );
+    is( $res->code, 200 );
+
+    cmp_deeply(
+        $mech->json_response,
+        {   per_page => 20,
+            pages    => 1,
+            total    => 4,
+            page     => 1,
+            count    => 4,
+            items    => [
+                {   type    => 'attachment',
+                    Subject => 'HTML comment with PNG image and text file',
+                    _url    => re(qr/^https?:/),
+                    ContentType   => 'multipart/mixed',
+                    ContentLength => 0,
+                    Filename      => '',
+                    id            => re(qr/^\d+$/)
+                },
+                {   type          => 'attachment',
+                    Subject       => '',
+                    _url          => re(qr/^https?:/),
+                    ContentType   => 'text/html',
+                    ContentLength => 31,
+                    Filename      => '',
+                    id            => re(qr/^\d+$/)
+                },
+                {   type          => 'attachment',
+                    Subject       => '',
+                    _url          => re(qr/^https?:/),
+                    ContentType   => 'image/png',
+                    ContentLength => 3929,
+                    Filename      => 'image.png',
+                    id            => re(qr/^\d+$/)
+                },
+                {   type          => 'attachment',
+                    Subject       => '',
+                    _url          => re(qr/^https?:/),
+                    ContentType   => 'text/plain',
+                    ContentLength => 19,
+                    Filename      => 'password',
+                    id            => re(qr/^\d+$/)
+                },
+            ]
+        },
+        'Got expected attachment list'
+    );
+}
+
 # Comment ticket with image attachment and no content through JSON Base64
 {
     my $payload = {

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


More information about the rt-commit mailing list