View | Details | Raw Unified | Return to bug 33080
Collapse All | Expand All

(-)a/Koha/REST/Plugin/Objects.pm (-26 / +27 lines)
Lines 44-50 sub register { Link Here
44
Performs a database search using given Koha::Objects object and the $id.
44
Performs a database search using given Koha::Objects object and the $id.
45
45
46
Returns I<undef> if no object is found or the I<API representation> of
46
Returns I<undef> if no object is found or the I<API representation> of
47
the requested object. It passes through any embeds if specified.
47
the requested object including any embeds specified in the request.
48
48
49
=cut
49
=cut
50
50
Lines 65-74 the requested object. It passes through any embeds if specified. Link Here
65
    . . .
65
    . . .
66
    return $c->render({ status => 200, openapi => $patron_rs->to_api });
66
    return $c->render({ status => 200, openapi => $patron_rs->to_api });
67
67
68
Returns the passed Koha::Objects resultset filtered to the passed $id and
68
Returns the passed Koha::Object result filtered to the passed $id and
69
with any embeds requested by the api applied.
69
with any embeds requested by the api applied.
70
70
71
The resultset can then be used for further processing.
71
The result object can then be used for further processing.
72
72
73
=cut
73
=cut
74
74
Lines 102-109 The resultset can then be used for further processing. Link Here
102
Performs a database search using given Koha::Objects object with any api
102
Performs a database search using given Koha::Objects object with any api
103
query parameters applied.
103
query parameters applied.
104
104
105
Returns an arrayref of the hashrefs representing the resulting objects
105
Returns an arrayref of I<API representations> of the requested objects
106
for API rendering.
106
including any embeds specified in the request.
107
107
108
Warning: this helper adds pagination headers to the calling controller, and thus
108
Warning: this helper adds pagination headers to the calling controller, and thus
109
shouldn't be called twice in it.
109
shouldn't be called twice in it.
Lines 114-135 shouldn't be called twice in it. Link Here
114
        'objects.search' => sub {
114
        'objects.search' => sub {
115
            my ( $c, $result_set ) = @_;
115
            my ( $c, $result_set ) = @_;
116
116
117
            return $c->objects->to_api( $c->objects->search_rs($result_set) );
117
            # Generate the resultset using the HTTP request information
118
            my $objects_rs = $c->objects->search_rs($result_set);
119
120
            # Add pagination headers
121
            $c->add_pagination_headers();
122
123
            return $c->objects->to_api($objects_rs);
118
        }
124
        }
119
    );
125
    );
120
126
121
=head3 objects.search_rs
127
=head3 objects.search_rs
122
128
123
    my $patrons_rs = Koha::Patrons->new;
129
    my $patrons_object = Koha::Patrons->new;
124
    my $patrons_rs = $c->objects->search_rs( $patrons_rs );
130
    my $patrons_rs = $c->objects->search_rs( $patrons_object );
125
    . . .
131
    . . .
126
    return $c->render({ status => 200, openapi => $patrons_rs->to_api });
132
    return $c->render({ status => 200, openapi => $patrons_rs->to_api });
127
133
128
Returns the passed Koha::Objects resultset filtered as requested by the api query
134
Returns the passed Koha::Objects resultset filtered as requested by the api query
129
parameters and with requested embeds applied.
135
parameters and with requested embeds applied.
130
136
131
Warning: this helper adds pagination headers to the calling controller, and thus
137
Warning: this helper stashes base values for the pagination headers to the calling
132
shouldn't be called twice in it.
138
controller, and thus shouldn't be called twice in it.
133
139
134
=cut
140
=cut
135
141
Lines 155-163 shouldn't be called twice in it. Link Here
155
161
156
            # If no pagination parameters are passed, default
162
            # If no pagination parameters are passed, default
157
            $reserved_params->{_per_page} //=
163
            $reserved_params->{_per_page} //=
158
              C4::Context->preference('RESTdefaultPageSize');
164
              C4::Context->preference('RESTdefaultPageSize') // 20;
159
            $reserved_params->{_page} //= 1;
165
            $reserved_params->{_page} //= 1;
160
166
167
            $c->stash('koha.pagination.page'     => $reserved_params->{_page});
168
            $c->stash('koha.pagination.per_page' => $reserved_params->{_per_page});
169
161
            unless ( $reserved_params->{_per_page} == -1 ) {
170
            unless ( $reserved_params->{_per_page} == -1 ) {
162
171
163
                # Merge pagination into query attributes
172
                # Merge pagination into query attributes
Lines 244-266 shouldn't be called twice in it. Link Here
244
            $result_set = $result_set->search_limited,
253
            $result_set = $result_set->search_limited,
245
              if $result_set->can('search_limited');
254
              if $result_set->can('search_limited');
246
255
247
            # Perform search
256
            $c->stash('koha.pagination.base_total'   => $result_set->count);
248
            my $objects = $result_set->search( $filtered_params, $attributes );
257
            $c->stash('koha.pagination.query_params' => $args);
249
            my $total   = $result_set->search->count;
250
258
251
            $c->add_pagination_headers(
259
            # Generate the resultset
252
                {
260
            my $objects_rs = $result_set->search( $filtered_params, $attributes );
253
                    total => (
261
            # Stash the page total if requires, total otherwise
254
                          $objects->is_paged
262
            $c->stash('koha.pagination.total' => $objects_rs->is_paged ? $objects_rs->pager->total_entries : $objects_rs->count);
255
                        ? $objects->pager->total_entries
256
                        : $objects->count
257
                    ),
258
                    base_total => $total,
259
                    params     => $args,
260
                }
261
            );
262
263
263
            return $objects;
264
            return $objects_rs;
264
        }
265
        }
265
    );
266
    );
266
267
(-)a/Koha/REST/Plugin/Pagination.pm (-23 / +56 lines)
Lines 38-58 sub register { Link Here
38
38
39
=head3 add_pagination_headers
39
=head3 add_pagination_headers
40
40
41
    my $patrons = Koha::Patrons->search( ... );
41
    $c->add_pagination_headers();
42
    $c->add_pagination_headers({
42
    $c->add_pagination_headers(
43
        total  => $patrons->count,
43
        {
44
        params => {
44
            base_total   => $base_total,
45
            _page     => ...
45
            page         => $page,
46
            _per_page => ...
46
            per_page     => $per_page,
47
            ...
47
            query_params => $query_params,
48
            total        => $total,
48
        }
49
        }
49
    });
50
    );
51
52
Adds RFC5988 compliant I<Link> headers for pagination to the response message carried
53
by our controller.
54
55
Additionally, it also adds the customer I<X-Total-Count> header containing the total results
56
count, and I<X-Base-Total-Count> header containing the total of the non-filtered results count.
57
58
Optionally accepts the any of the following parameters to override the values stored in the
59
stash by the I<search_rs> helper.
60
61
=over
62
63
=item base_total
64
65
Total records for the search domain (e.g. all patron records, filtered only by visibility)
50
66
51
Adds a Link header to the response message $c carries, following RFC5988, including
67
=item page
52
the following relation types: 'prev', 'next', 'first' and 'last'.
53
It also adds X-Total-Count containing the total results count, and X-Base-Total-Count containing the total of the non-filtered results count.
54
68
55
If page size is omitted, it defaults to the value of the RESTdefaultPageSize syspref.
69
The requested page number, usually extracted from the request query.
70
See I<objects.search_rs> for more information.
71
72
=item per_page
73
74
The requested maximum results per page, usually extracted from the request query.
75
See I<objects.search_rs> for more information.
76
77
=item query_params
78
79
The request query, usually extracted from the request query and used to build the I<Link> headers.
80
See I<objects.search_rs> for more information.
81
82
=item total
83
84
Total records for the search with filters applied.
85
86
=back
56
87
57
=cut
88
=cut
58
89
Lines 60-70 If page size is omitted, it defaults to the value of the RESTdefaultPageSize sys Link Here
60
        'add_pagination_headers' => sub {
91
        'add_pagination_headers' => sub {
61
            my ( $c, $args ) = @_;
92
            my ( $c, $args ) = @_;
62
93
63
            my $total    = $args->{total};
94
            my $base_total = $args->{base_total} // $c->stash('koha.pagination.base_total');
64
            my $base_total = $args->{base_total};
95
            my $req_page   = $args->{page}         // $c->stash('koha.pagination.page')     // 1;
65
            my $req_page = $args->{params}->{_page} // 1;
96
            my $per_page   = $args->{per_page}     // $c->stash('koha.pagination.per_page') // C4::Context->preference('RESTdefaultPageSize') // 20;
66
            my $per_page = $args->{params}->{_per_page} //
97
            my $params     = $args->{query_params} // $c->stash('koha.pagination.query_params');
67
                            C4::Context->preference('RESTdefaultPageSize') // 20;
98
            my $total      = $args->{total}        // $c->stash('koha.pagination.total');
68
99
69
            my $pages;
100
            my $pages;
70
            if ( $per_page == -1 ) {
101
            if ( $per_page == -1 ) {
Lines 86-92 If page size is omitted, it defaults to the value of the RESTdefaultPageSize sys Link Here
86
                    {   page     => $req_page - 1,
117
                    {   page     => $req_page - 1,
87
                        per_page => $per_page,
118
                        per_page => $per_page,
88
                        rel      => 'prev',
119
                        rel      => 'prev',
89
                        params   => $args->{params}
120
                        params   => $params
90
                    }
121
                    }
91
                    );
122
                    );
92
            }
123
            }
Lines 98-114 If page size is omitted, it defaults to the value of the RESTdefaultPageSize sys Link Here
98
                    {   page     => $req_page + 1,
129
                    {   page     => $req_page + 1,
99
                        per_page => $per_page,
130
                        per_page => $per_page,
100
                        rel      => 'next',
131
                        rel      => 'next',
101
                        params   => $args->{params}
132
                        params   => $params
102
                    }
133
                    }
103
                    );
134
                    );
104
            }
135
            }
105
136
106
            push @links,
137
            push @links,
107
                _build_link( $c,
138
                _build_link( $c,
108
                { page => 1, per_page => $per_page, rel => 'first', params => $args->{params} } );
139
                { page => 1, per_page => $per_page, rel => 'first', params => $params } );
109
            push @links,
140
            push @links,
110
                _build_link( $c,
141
                _build_link( $c,
111
                { page => $pages, per_page => $per_page, rel => 'last', params => $args->{params} } );
142
                { page => $pages, per_page => $per_page, rel => 'last', params => $params } );
112
143
113
            # Add Link header
144
            # Add Link header
114
            foreach my $link (@links) {
145
            foreach my $link (@links) {
Lines 116-123 If page size is omitted, it defaults to the value of the RESTdefaultPageSize sys Link Here
116
            }
147
            }
117
148
118
            # Add X-Total-Count header
149
            # Add X-Total-Count header
119
            $c->res->headers->add( 'X-Total-Count' => $total );
150
            $c->res->headers->add( 'X-Total-Count'      => $total );
120
            $c->res->headers->add( 'X-Base-Total-Count' => $base_total ) if defined $base_total;
151
            $c->res->headers->add( 'X-Base-Total-Count' => $base_total )
152
              if defined $base_total;
153
121
            return $c;
154
            return $c;
122
        }
155
        }
123
    );
156
    );
(-)a/t/Koha/REST/Plugin/Pagination.t (-69 / +58 lines)
Lines 20-29 use Modern::Perl; Link Here
20
# Dummy app for testing the plugin
20
# Dummy app for testing the plugin
21
use Mojolicious::Lite;
21
use Mojolicious::Lite;
22
22
23
use Koha::Patrons;
24
25
use t::lib::TestBuilder;
26
23
app->log->level('error');
27
app->log->level('error');
24
28
25
plugin 'Koha::REST::Plugin::Pagination';
29
plugin 'Koha::REST::Plugin::Pagination';
26
30
31
my $schema = Koha::Database->new->schema;
32
my $builder = t::lib::TestBuilder->new;
33
34
$schema->storage->txn_begin;
35
36
# Add 10 known 'Jonathan' patrons
37
my @patron_ids;
38
for my $i ( 1 .. 10 ) {
39
    push @patron_ids, $builder->build_object({ class => 'Koha::Patrons', value => { firstname => 'Jonathan' } })->id;
40
}
41
# Add two non-Jonathans
42
push @patron_ids, $builder->build_object({ class => 'Koha::Patrons' })->id;
43
push @patron_ids, $builder->build_object({ class => 'Koha::Patrons' })->id;
44
27
# For add_pagination_headers()
45
# For add_pagination_headers()
28
46
29
get '/empty' => sub {
47
get '/empty' => sub {
Lines 33-51 get '/empty' => sub { Link Here
33
51
34
get '/pagination_headers' => sub {
52
get '/pagination_headers' => sub {
35
    my $c = shift;
53
    my $c = shift;
36
    $c->add_pagination_headers({ total => 10, base_total => 12, params => { _page => 2, _per_page => 3, firstname => 'Jonathan' } });
37
    $c->render( json => { ok => 1 }, status => 200 );
38
};
39
54
40
get '/pagination_headers_first_page' => sub {
55
    my $args = $c->req->params->to_hash;
41
    my $c = shift;
56
42
    $c->add_pagination_headers({ total => 10, base_total => 12, params => { _page => 1, _per_page => 3, firstname => 'Jonathan' } });
57
    my $result_set = Koha::Patrons->search(
43
    $c->render( json => { ok => 1 }, status => 200 );
58
        { borrowernumber => \@patron_ids }
44
};
59
    );
60
61
    my $rows = ($args->{_per_page}) ?
62
                        ( $args->{_per_page} == -1 ) ?  undef : $args->{_per_page}
63
                        : C4::Context->preference('RESTdefaultPageSize');
64
65
    my $objects_rs = $result_set->search( { firstname => 'Jonathan' } ,{ page => $args->{_page} // 1, rows => $rows });
66
67
    $c->stash('koha.pagination.page'         => $args->{_page});
68
    $c->stash('koha.pagination.per_page'     => $args->{_per_page});
69
    $c->stash('koha.pagination.base_total'   => $result_set->count);
70
    $c->stash('koha.pagination.query_params' => $args);
71
    $c->stash('koha.pagination.total'        => $objects_rs->is_paged ? $objects_rs->pager->total_entries : $objects_rs->count);
72
73
    $c->add_pagination_headers;
45
74
46
get '/pagination_headers_last_page' => sub {
47
    my $c = shift;
48
    $c->add_pagination_headers({ total => 10, base_total => 12, params => { _page => 4, _per_page => 3, firstname => 'Jonathan' } });
49
    $c->render( json => { ok => 1 }, status => 200 );
75
    $c->render( json => { ok => 1 }, status => 200 );
50
};
76
};
51
77
Lines 58-99 get '/dbic_merge_pagination' => sub { Link Here
58
    $c->render( json => $filter, status => 200 );
84
    $c->render( json => $filter, status => 200 );
59
};
85
};
60
86
61
get '/pagination_headers_without_page_size' => sub {
62
    my $c = shift;
63
    $c->add_pagination_headers({ total => 10, base_total => 12, params => { _page => 2, firstname => 'Jonathan' } });
64
    $c->render( json => { ok => 1 }, status => 200 );
65
};
66
67
get '/pagination_headers_without_page' => sub {
68
    my $c = shift;
69
    $c->add_pagination_headers({ total => 10, base_total => 12, params => { _per_page => 3, firstname => 'Jonathan' } });
70
    $c->render( json => { ok => 1 }, status => 200 );
71
};
72
73
get '/pagination_headers_with_minus_one' => sub {
74
    my $c = shift;
75
    $c->add_pagination_headers(
76
        {
77
            total => 10,
78
            base_total => 12,
79
            params => { _per_page => -1, firstname => 'Jonathan' }
80
        }
81
    );
82
    $c->render( json => { ok => 1 }, status => 200 );
83
};
84
85
get '/pagination_headers_with_minus_one_and_invalid_page' => sub {
86
    my $c = shift;
87
    $c->add_pagination_headers(
88
        {
89
            total  => 10,
90
            base_total => 12,
91
            params => { page => 100, _per_page => -1, firstname => 'Jonathan' }
92
        }
93
    );
94
    $c->render( json => { ok => 1 }, status => 200 );
95
};
96
97
# The tests
87
# The tests
98
88
99
use Test::More tests => 2;
89
use Test::More tests => 2;
Lines 109-122 subtest 'add_pagination_headers() tests' => sub { Link Here
109
99
110
    $t->get_ok('/empty')
100
    $t->get_ok('/empty')
111
      ->status_is( 200 )
101
      ->status_is( 200 )
112
      ->header_is( 'X-Total-Count' => undef, 'X-Total-Count is undefined' )
102
      ->header_is( 'X-Total-Count'      => undef, 'X-Total-Count is undefined' )
113
      ->header_is( 'X-Base-Total-Count' => undef, 'X-Base-Total-Count is undefined' )
103
      ->header_is( 'X-Base-Total-Count' => undef, 'X-Base-Total-Count is undefined' )
114
      ->header_is( 'Link'          => undef, 'Link is undefined' );
104
      ->header_is( 'Link'               => undef, 'Link is undefined' );
115
105
116
    $t->get_ok('/pagination_headers')
106
    $t->get_ok('/pagination_headers?firstname=Jonathan&_page=2&_per_page=3')
117
      ->status_is( 200 )
107
      ->status_is( 200 )
118
      ->header_is( 'X-Total-Count' => 10, 'X-Total-Count contains the passed value' )
108
      ->header_is( 'X-Total-Count' => 10, 'X-Total-Count correctly set' )
119
      ->header_is( 'X-Base-Total-Count' => 12, 'X-Base-Total-Count contains the passed value' )
109
      ->header_is( 'X-Base-Total-Count' => 12, 'X-Base-Total-Count correctly set' )
120
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*_per_page=3.*>; rel="prev",/ )
110
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*_per_page=3.*>; rel="prev",/ )
121
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*_page=1.*>; rel="prev",/ )
111
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*_page=1.*>; rel="prev",/ )
122
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*firstname=Jonathan.*>; rel="prev",/ )
112
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*firstname=Jonathan.*>; rel="prev",/ )
Lines 130-139 subtest 'add_pagination_headers() tests' => sub { Link Here
130
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*_page=4.*>; rel="last"/ )
120
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*_page=4.*>; rel="last"/ )
131
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*firstname=Jonathan.*>; rel="last"/ );
121
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*firstname=Jonathan.*>; rel="last"/ );
132
122
133
    $t->get_ok('/pagination_headers_first_page')
123
    $t->get_ok('/pagination_headers?firstname=Jonathan&_page=1&_per_page=3')
134
      ->status_is( 200 )
124
      ->status_is( 200 )
135
      ->header_is( 'X-Total-Count' => 10, 'X-Total-Count contains the passed value' )
125
      ->header_is( 'X-Total-Count' => 10, 'X-Total-Count correctly set' )
136
      ->header_is( 'X-Base-Total-Count' => 12, 'X-Base-Total-Count contains the passed value' )
126
      ->header_is( 'X-Base-Total-Count' => 12, 'X-Base-Total-Count correctly set' )
137
      ->header_unlike( 'Link' => qr/<http:\/\/.*\?.*>; rel="prev",/ )
127
      ->header_unlike( 'Link' => qr/<http:\/\/.*\?.*>; rel="prev",/ )
138
      ->header_like(   'Link' => qr/<http:\/\/.*\?.*_per_page=3.*>; rel="next",/ )
128
      ->header_like(   'Link' => qr/<http:\/\/.*\?.*_per_page=3.*>; rel="next",/ )
139
      ->header_like(   'Link' => qr/<http:\/\/.*\?.*_page=2.*>; rel="next",/ )
129
      ->header_like(   'Link' => qr/<http:\/\/.*\?.*_page=2.*>; rel="next",/ )
Lines 145-154 subtest 'add_pagination_headers() tests' => sub { Link Here
145
      ->header_like(   'Link' => qr/<http:\/\/.*\?.*_page=4.*>; rel="last"/ )
135
      ->header_like(   'Link' => qr/<http:\/\/.*\?.*_page=4.*>; rel="last"/ )
146
      ->header_like(   'Link' => qr/<http:\/\/.*\?.*firstname=Jonathan.*>; rel="last"/ );
136
      ->header_like(   'Link' => qr/<http:\/\/.*\?.*firstname=Jonathan.*>; rel="last"/ );
147
137
148
    $t->get_ok('/pagination_headers_last_page')
138
    $t->get_ok('/pagination_headers?firstname=Jonathan&_page=4&_per_page=3')
149
      ->status_is( 200 )
139
      ->status_is( 200 )
150
      ->header_is( 'X-Total-Count' => 10, 'X-Total-Count contains the passed value' )
140
      ->header_is( 'X-Total-Count' => 10, 'X-Total-Count correctly set' )
151
      ->header_is( 'X-Base-Total-Count' => 12, 'X-Base-Total-Count contains the passed value' )
141
      ->header_is( 'X-Base-Total-Count' => 12, 'X-Base-Total-Count correctly set' )
152
      ->header_like(   'Link' => qr/<http:\/\/.*\?.*_per_page=3.*>; rel="prev",/ )
142
      ->header_like(   'Link' => qr/<http:\/\/.*\?.*_per_page=3.*>; rel="prev",/ )
153
      ->header_like(   'Link' => qr/<http:\/\/.*\?.*_page=3.*>; rel="prev",/ )
143
      ->header_like(   'Link' => qr/<http:\/\/.*\?.*_page=3.*>; rel="prev",/ )
154
      ->header_like(   'Link' => qr/<http:\/\/.*\?.*firstname=Jonathan.*>; rel="prev",/ )
144
      ->header_like(   'Link' => qr/<http:\/\/.*\?.*firstname=Jonathan.*>; rel="prev",/ )
Lines 161-170 subtest 'add_pagination_headers() tests' => sub { Link Here
161
      ->header_like(   'Link' => qr/<http:\/\/.*\?.*firstname=Jonathan.*>; rel="last"/ );
151
      ->header_like(   'Link' => qr/<http:\/\/.*\?.*firstname=Jonathan.*>; rel="last"/ );
162
152
163
    t::lib::Mocks::mock_preference('RESTdefaultPageSize', 3);
153
    t::lib::Mocks::mock_preference('RESTdefaultPageSize', 3);
164
    $t->get_ok('/pagination_headers_without_page_size')
154
    $t->get_ok('/pagination_headers?firstname=Jonathan&_page=2')
165
      ->status_is( 200 )
155
      ->status_is( 200 )
166
      ->header_is( 'X-Total-Count' => 10, 'X-Total-Count contains the passed value' )
156
      ->header_is( 'X-Total-Count' => 10, 'X-Total-Count correctly set' )
167
      ->header_is( 'X-Base-Total-Count' => 12, 'X-Base-Total-Count contains the passed value' )
157
      ->header_is( 'X-Base-Total-Count' => 12, 'X-Base-Total-Count correctly set' )
168
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*per_page=3.*>; rel="prev",/ )
158
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*per_page=3.*>; rel="prev",/ )
169
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*page=1.*>; rel="prev",/ )
159
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*page=1.*>; rel="prev",/ )
170
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*firstname=Jonathan.*>; rel="prev",/ )
160
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*firstname=Jonathan.*>; rel="prev",/ )
Lines 178-192 subtest 'add_pagination_headers() tests' => sub { Link Here
178
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*page=4.*>; rel="last"/ )
168
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*page=4.*>; rel="last"/ )
179
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*firstname=Jonathan.*>; rel="last"/ );
169
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*firstname=Jonathan.*>; rel="last"/ );
180
170
181
    $t->get_ok('/pagination_headers_without_page')
171
    $t->get_ok('/pagination_headers?firstname=Jonathan&_per_page=3')
182
      ->status_is( 200 )
172
      ->status_is( 200 )
183
      ->header_is( 'X-Total-Count' => 10, 'X-Total-Count header present, even without page param' )
173
      ->header_is( 'X-Total-Count' => 10, 'X-Total-Count header present, even without page param' )
184
      ->header_is( 'X-Base-Total-Count' => 12, 'X-Base-Total-Count contains the passed value' )
174
      ->header_is( 'X-Base-Total-Count' => 12, 'X-Base-Total-Count correctly set' )
185
      ->header_unlike( 'Link' => qr/<http:\/\/.*\?.*per_page=3.*>; rel="prev",/, 'First page, no previous' )
175
      ->header_unlike( 'Link' => qr/<http:\/\/.*\?.*per_page=3.*>; rel="prev",/, 'First page, no previous' )
186
      ->header_unlike( 'Link' => qr/<http:\/\/.*\?.*page=1.*>; rel="prev",/, 'First page, no previous' )
176
      ->header_unlike( 'Link' => qr/<http:\/\/.*\?.*page=1.*>; rel="prev",/, 'First page, no previous' )
187
      ->header_unlike( 'Link' => qr/<http:\/\/.*\?.*firstname=Jonathan.*>; rel="prev",/, 'First page, no previous' )
177
      ->header_unlike( 'Link' => qr/<http:\/\/.*\?.*firstname=Jonathan.*>; rel="prev",/, 'First page, no previous' )
188
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*per_page=3.*>; rel="next",/ )
178
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*per_page=3.*>; rel="next",/ )
189
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*page=3.*>; rel="next",/ )
179
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*page=2.*>; rel="next",/ )
190
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*firstname=Jonathan.*>; rel="next",/ )
180
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*firstname=Jonathan.*>; rel="next",/ )
191
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*per_page=3.*>; rel="first",/ )
181
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*per_page=3.*>; rel="first",/ )
192
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*page=1.*>; rel="first",/ )
182
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*page=1.*>; rel="first",/ )
Lines 195-204 subtest 'add_pagination_headers() tests' => sub { Link Here
195
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*page=4.*>; rel="last"/ )
185
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*page=4.*>; rel="last"/ )
196
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*firstname=Jonathan.*>; rel="last"/ );
186
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*firstname=Jonathan.*>; rel="last"/ );
197
187
198
    $t->get_ok('/pagination_headers_with_minus_one')
188
    $t->get_ok('/pagination_headers?firstname=Jonathan&_per_page=-1')
199
      ->status_is( 200 )
189
      ->status_is( 200 )
200
      ->header_is( 'X-Total-Count' => 10, 'X-Total-Count header present, with per_page=-1' )
190
      ->header_is( 'X-Total-Count' => 10, 'X-Total-Count header present, with per_page=-1' )
201
      ->header_is( 'X-Base-Total-Count' => 12, 'X-Base-Total-Count contains the passed value' )
191
      ->header_is( 'X-Base-Total-Count' => 12, 'X-Base-Total-Count correctly set' )
202
      ->header_unlike( 'Link' => qr/<http:\/\/.*\?.*per_page=-1.*>; rel="prev",/, 'First page, no previous' )
192
      ->header_unlike( 'Link' => qr/<http:\/\/.*\?.*per_page=-1.*>; rel="prev",/, 'First page, no previous' )
203
      ->header_unlike( 'Link' => qr/<http:\/\/.*\?.*page=1.*>; rel="prev",/, 'First page, no previous' )
193
      ->header_unlike( 'Link' => qr/<http:\/\/.*\?.*page=1.*>; rel="prev",/, 'First page, no previous' )
204
      ->header_unlike( 'Link' => qr/<http:\/\/.*\?.*firstname=Jonathan.*>; rel="prev",/, 'First page, no previous' )
194
      ->header_unlike( 'Link' => qr/<http:\/\/.*\?.*firstname=Jonathan.*>; rel="prev",/, 'First page, no previous' )
Lines 210-219 subtest 'add_pagination_headers() tests' => sub { Link Here
210
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*page=1.*>; rel="last"/ )
200
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*page=1.*>; rel="last"/ )
211
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*firstname=Jonathan.*>; rel="last"/ );
201
      ->header_like( 'Link' => qr/<http:\/\/.*\?.*firstname=Jonathan.*>; rel="last"/ );
212
202
213
    $t->get_ok('/pagination_headers_with_minus_one_and_invalid_page')
203
    $t->get_ok('/pagination_headers?firstname=Jonathan&_per_page=-1&_page=100')
214
      ->status_is( 200 )
204
      ->status_is( 200 )
215
      ->header_is( 'X-Total-Count' => 10, 'X-Total-Count header present, with per_page=-1' )
205
      ->header_is( 'X-Total-Count' => 10, 'X-Total-Count header present, with per_page=-1' )
216
      ->header_is( 'X-Base-Total-Count' => 12, 'X-Base-Total-Count contains the passed value' )
206
      ->header_is( 'X-Base-Total-Count' => 12, 'X-Base-Total-Count correctly set' )
217
      ->header_unlike( 'Link' => qr/<http:\/\/.*\?.*per_page=-1.*>; rel="prev",/, 'First page, no previous' )
207
      ->header_unlike( 'Link' => qr/<http:\/\/.*\?.*per_page=-1.*>; rel="prev",/, 'First page, no previous' )
218
      ->header_unlike( 'Link' => qr/<http:\/\/.*\?.*page=1.*>; rel="prev",/, 'First page, no previous' )
208
      ->header_unlike( 'Link' => qr/<http:\/\/.*\?.*page=1.*>; rel="prev",/, 'First page, no previous' )
219
      ->header_unlike( 'Link' => qr/<http:\/\/.*\?.*firstname=Jonathan.*>; rel="prev",/, 'First page, no previous' )
209
      ->header_unlike( 'Link' => qr/<http:\/\/.*\?.*firstname=Jonathan.*>; rel="prev",/, 'First page, no previous' )
220
- 

Return to bug 33080