From 26f3ca8d88486e5948c400f0d19d8c5bdf392d2e Mon Sep 17 00:00:00 2001 From: Tomas Cohen Arazi Date: Tue, 29 Aug 2017 16:52:48 -0300 Subject: [PATCH] Bug 19196: Add Koha::REST::Plugin::Pagination This patch introduces a Mojolicious plugin to be used on the REST api. It adds a helper method: add_pagination_headers ====================== When used, it adds a _Link_ header to the reponse with the calculated values for pagination, and X-Total-Count containing the total results like this: my $params = $c->validation->output; my $patrons = Koha::Patrons->search; my $count = $patrons->count; $c->add_pagination_headers({ total => $count, params => $params )}; To test: - Run: $ sudo koha-shell kohadev k$ cd kohaclone k$ prove t/Koha/REST/Plugin/Pagination.t => SUCCESS: Tests pass! - Sign off :-D Sponsored-by: ByWater solutions Sponsored-by: Camden County Edit: I fixed a mistake on the POD (tcohen) Signed-off-by: Kyle M Hall Signed-off-by: Lari Taskula Signed-off-by: Jonathan Druart --- Koha/REST/Plugin/Pagination.pm | 143 +++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 Koha/REST/Plugin/Pagination.pm diff --git a/Koha/REST/Plugin/Pagination.pm b/Koha/REST/Plugin/Pagination.pm new file mode 100644 index 0000000000..8b09dd1c84 --- /dev/null +++ b/Koha/REST/Plugin/Pagination.pm @@ -0,0 +1,143 @@ +package Koha::REST::Plugin::Pagination; + +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use Mojo::Base 'Mojolicious::Plugin'; + +=head1 NAME + +Koha::REST::Plugin::Pagination + +=head1 API + +=head2 Mojolicious::Plugin methods + +=head3 register + +=cut + +sub register { + my ( $self, $app ) = @_; + +=head2 Helper methods + +=head3 add_pagination_headers + + my $patrons = Koha::Patrons->search( ... ); + $c->add_pagination_headers({ + total => $patrons->count, + params => { + page => ... + per_page => ... + ... + } + }); + +Adds a Link header to the response message $c carries, following RFC5988, including +the following relation types: 'prev', 'next', 'first' and 'last'. +It also adds X-Total-Count, containing the total results count. + +=cut + + $app->helper( + 'add_pagination_headers' => sub { + my ( $c, $args ) = @_; + + my $total = $args->{total}; + my $req_page = $args->{params}->{page}; + my $per_page = $args->{params}->{per_page}; + + my $pages = int $total / $per_page; + $pages++ + if $total % $per_page > 0; + + my @links; + + if ( $pages > 1 and $req_page > 1 ) { # Previous exists? + push @links, + _build_link( + $c, + { page => $req_page - 1, + per_page => $per_page, + rel => 'prev', + params => $args->{params} + } + ); + } + + if ( $pages > 1 and $req_page < $pages ) { # Next exists? + push @links, + _build_link( + $c, + { page => $req_page + 1, + per_page => $per_page, + rel => 'next', + params => $args->{params} + } + ); + } + + push @links, + _build_link( $c, + { page => 1, per_page => $per_page, rel => 'first', params => $args->{params} } ); + push @links, + _build_link( $c, + { page => $pages, per_page => $per_page, rel => 'last', params => $args->{params} } ); + + # Add Link header + $c->res->headers->add( 'Link' => join( ',', @links ) ); + + # Add X-Total-Count header + $c->res->headers->add( 'X-Total-Count' => $total ); + return $c; + } + ); +} + +=head2 Internal methods + +=head3 _build_link + + my $link = _build_link( $c, { page => 1, per_page => 5, rel => 'prev' }); + +Returns a string, suitable for using in Link headers following RFC5988. + +=cut + +sub _build_link { + my ( $c, $args ) = @_; + + my $params = $args->{params}; + + $params->{page} = $args->{page}; + $params->{per_page} = $args->{per_page}; + + my $link = '<' + . $c->req->url->clone->query( + $params + )->to_abs + . '>; rel="' + . $args->{rel} . '"'; + + # TODO: Find a better solution for this horrible (but needed) fix + $link =~ s|api/v1/app\.pl/||; + + return $link; +} + +1; -- 2.39.5