Bug 17170: Add API route for SearchFilters
This adds the API routes and tests Sponsored-by: Sponsored by: Round Rock Public Library [https://www.roundrocktexas.gov/departments/library/] Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com> Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
This commit is contained in:
parent
b306b1d4ca
commit
adf252d96c
7 changed files with 846 additions and 0 deletions
153
Koha/REST/V1/SearchFilter.pm
Normal file
153
Koha/REST/V1/SearchFilter.pm
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
package Koha::REST::V1::SearchFilter;
|
||||||
|
|
||||||
|
# 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, see <http://www.gnu.org/licenses>.
|
||||||
|
|
||||||
|
use Modern::Perl;
|
||||||
|
|
||||||
|
use Mojo::Base 'Mojolicious::Controller';
|
||||||
|
use Koha::SearchFilters;
|
||||||
|
|
||||||
|
use Try::Tiny qw( catch try );
|
||||||
|
|
||||||
|
=head1 Name
|
||||||
|
|
||||||
|
Koha::REST::V1::SearchFilters
|
||||||
|
|
||||||
|
=head1 API
|
||||||
|
|
||||||
|
=head2 Methods
|
||||||
|
|
||||||
|
=head3 list
|
||||||
|
|
||||||
|
Controller function that handles listing Koha::SearchFilter objects
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub list {
|
||||||
|
my $c = shift->openapi->valid_input or return;
|
||||||
|
return try {
|
||||||
|
my $filters_set = Koha::SearchFilters->search({});
|
||||||
|
my $filters = $c->objects->search( $filters_set );
|
||||||
|
return $c->render(
|
||||||
|
status => 200,
|
||||||
|
openapi => $filters
|
||||||
|
);
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
$c->unhandled_exception($_);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
=head3 get
|
||||||
|
|
||||||
|
Controller function that handles retrieving a single Koha::AdvancedEditorMacro
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub get {
|
||||||
|
my $c = shift->openapi->valid_input or return;
|
||||||
|
my $filter = Koha::SearchFilters->find({
|
||||||
|
id => $c->validation->param('search_filter_id'),
|
||||||
|
});
|
||||||
|
unless ($filter) {
|
||||||
|
return $c->render( status => 404,
|
||||||
|
openapi => { error => "Search filter not found" } );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $c->render( status => 200, openapi => $filter->to_api );
|
||||||
|
}
|
||||||
|
|
||||||
|
=head3 add
|
||||||
|
|
||||||
|
Controller function that handles adding a new Koha::SearchFilter object
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub add {
|
||||||
|
my $c = shift->openapi->valid_input or return;
|
||||||
|
|
||||||
|
return try {
|
||||||
|
my $filter = Koha::SearchFilter->new_from_api( $c->validation->param('body') );
|
||||||
|
$filter->store->discard_changes;
|
||||||
|
$c->res->headers->location( $c->req->url->to_string . '/' . $filter->id );
|
||||||
|
return $c->render(
|
||||||
|
status => 201,
|
||||||
|
openapi => $filter->to_api
|
||||||
|
);
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
if ( blessed $_ and $_->isa('Koha::Exceptions::Object::DuplicateID') ) {
|
||||||
|
return $c->render(
|
||||||
|
status => 409,
|
||||||
|
openapi => { error => $_->error, conflict => $_->duplicate_id }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$c->unhandled_exception($_);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
=head3 update
|
||||||
|
|
||||||
|
Controller function that handles updating a Koha::SearchFilter object
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub update {
|
||||||
|
my $c = shift->openapi->valid_input or return;
|
||||||
|
|
||||||
|
my $filter = Koha::SearchFilters->find( $c->validation->param('search_filter_id') );
|
||||||
|
|
||||||
|
if ( not defined $filter ) {
|
||||||
|
return $c->render( status => 404,
|
||||||
|
openapi => { error => "Object not found" } );
|
||||||
|
}
|
||||||
|
|
||||||
|
return try {
|
||||||
|
my $params = $c->req->json;
|
||||||
|
$filter->set_from_api( $params );
|
||||||
|
$filter->store->discard_changes;
|
||||||
|
return $c->render( status => 200, openapi => $filter->to_api );
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
$c->unhandled_exception($_);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
=head3 delete
|
||||||
|
|
||||||
|
Controller function that handles deleting a Koha::SearchFilter object
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub delete {
|
||||||
|
my $c = shift->openapi->valid_input or return;
|
||||||
|
|
||||||
|
my $filter = Koha::SearchFilters->find( $c->validation->param('search_filter_id') );
|
||||||
|
if ( not defined $filter ) {
|
||||||
|
return $c->render( status => 404,
|
||||||
|
openapi => { error => "Object not found" } );
|
||||||
|
}
|
||||||
|
|
||||||
|
return try {
|
||||||
|
$filter->delete;
|
||||||
|
return $c->render( status => 204, openapi => q{} );
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
$c->unhandled_exception($_);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
65
api/v1/swagger/definitions.yaml
Normal file
65
api/v1/swagger/definitions.yaml
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
---
|
||||||
|
account_line:
|
||||||
|
$ref: definitions/account_line.yaml
|
||||||
|
advancededitormacro:
|
||||||
|
$ref: definitions/advancededitormacro.yaml
|
||||||
|
allows_renewal:
|
||||||
|
$ref: definitions/allows_renewal.yaml
|
||||||
|
basket:
|
||||||
|
$ref: definitions/basket.yaml
|
||||||
|
cashup:
|
||||||
|
$ref: definitions/cashup.yaml
|
||||||
|
checkout:
|
||||||
|
$ref: definitions/checkout.yaml
|
||||||
|
checkouts:
|
||||||
|
$ref: definitions/checkouts.yaml
|
||||||
|
circ-rule-kind:
|
||||||
|
$ref: definitions/circ-rule-kind.yaml
|
||||||
|
city:
|
||||||
|
$ref: definitions/city.yaml
|
||||||
|
error:
|
||||||
|
$ref: definitions/error.yaml
|
||||||
|
fund:
|
||||||
|
$ref: definitions/fund.yaml
|
||||||
|
hold:
|
||||||
|
$ref: definitions/hold.yaml
|
||||||
|
holds:
|
||||||
|
$ref: definitions/holds.yaml
|
||||||
|
ill_backend:
|
||||||
|
$ref: definitions/ill_backend.yaml
|
||||||
|
ill_backends:
|
||||||
|
$ref: definitions/ill_backends.yaml
|
||||||
|
import_batch_profile:
|
||||||
|
$ref: definitions/import_batch_profile.yaml
|
||||||
|
import_batch_profiles:
|
||||||
|
$ref: definitions/import_batch_profiles.yaml
|
||||||
|
invoice:
|
||||||
|
$ref: definitions/invoice.yaml
|
||||||
|
item:
|
||||||
|
$ref: definitions/item.yaml
|
||||||
|
library:
|
||||||
|
$ref: definitions/library.yaml
|
||||||
|
order:
|
||||||
|
$ref: definitions/order.yaml
|
||||||
|
patron:
|
||||||
|
$ref: definitions/patron.yaml
|
||||||
|
patron_account_credit:
|
||||||
|
$ref: definitions/patron_account_credit.yaml
|
||||||
|
patron_balance:
|
||||||
|
$ref: definitions/patron_balance.yaml
|
||||||
|
patron_extended_attribute:
|
||||||
|
$ref: definitions/patron_extended_attribute.yaml
|
||||||
|
quote:
|
||||||
|
$ref: definitions/quote.yaml
|
||||||
|
return_claim:
|
||||||
|
$ref: definitions/return_claim.yaml
|
||||||
|
smtp_server:
|
||||||
|
$ref: definitions/smtp_server.yaml
|
||||||
|
suggestion:
|
||||||
|
$ref: definitions/suggestion.yaml
|
||||||
|
search_filter:
|
||||||
|
$ref: definitions/search_filter.yaml
|
||||||
|
transfer_limit:
|
||||||
|
$ref: definitions/transfer_limit.yaml
|
||||||
|
vendor:
|
||||||
|
$ref: definitions/vendor.yaml
|
33
api/v1/swagger/definitions/search_filter.yaml
Normal file
33
api/v1/swagger/definitions/search_filter.yaml
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
---
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
search_filter_id:
|
||||||
|
type: integer
|
||||||
|
description: internally assigned search filter identifier
|
||||||
|
readOnly: true
|
||||||
|
name:
|
||||||
|
description: filter name
|
||||||
|
type: string
|
||||||
|
filter_query:
|
||||||
|
description: filter query part
|
||||||
|
type:
|
||||||
|
- string
|
||||||
|
- 'null'
|
||||||
|
filter_limits:
|
||||||
|
description: filter limits part
|
||||||
|
type:
|
||||||
|
- string
|
||||||
|
- 'null'
|
||||||
|
opac:
|
||||||
|
description: visible on opac
|
||||||
|
type:
|
||||||
|
- boolean
|
||||||
|
- 'null'
|
||||||
|
staff_client:
|
||||||
|
description: visible in staff client
|
||||||
|
type:
|
||||||
|
- boolean
|
||||||
|
- 'null'
|
||||||
|
additionalProperties: false
|
||||||
|
required:
|
||||||
|
- name
|
226
api/v1/swagger/paths/search_filters.yaml
Normal file
226
api/v1/swagger/paths/search_filters.yaml
Normal file
|
@ -0,0 +1,226 @@
|
||||||
|
---
|
||||||
|
"/search_filters":
|
||||||
|
get:
|
||||||
|
x-mojo-to: SearchFilter#list
|
||||||
|
operationId: listFilters
|
||||||
|
tags:
|
||||||
|
- search_filters
|
||||||
|
summary: List search filters
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- name: name
|
||||||
|
in: query
|
||||||
|
description: Case insensitive search on filter name
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
- name: filter_query
|
||||||
|
in: query
|
||||||
|
description: Search on filter query part
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
- name: filter_limits
|
||||||
|
in: query
|
||||||
|
description: Search on filter limits
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
- name: opac
|
||||||
|
in: query
|
||||||
|
description: Display in OPAC
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
- name: staff_client
|
||||||
|
in: query
|
||||||
|
description: Display on staff client
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
- $ref: "../swagger.yaml#/parameters/match"
|
||||||
|
- $ref: "../swagger.yaml#/parameters/order_by"
|
||||||
|
- $ref: "../swagger.yaml#/parameters/page"
|
||||||
|
- $ref: "../swagger.yaml#/parameters/per_page"
|
||||||
|
- $ref: "../swagger.yaml#/parameters/q_param"
|
||||||
|
- $ref: "../swagger.yaml#/parameters/q_body"
|
||||||
|
- $ref: "../swagger.yaml#/parameters/q_header"
|
||||||
|
- $ref: "../swagger.yaml#/parameters/request_id_header"
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: A list of search filters
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "../swagger.yaml#/definitions/search_filter"
|
||||||
|
'403':
|
||||||
|
description: Access forbidden
|
||||||
|
schema:
|
||||||
|
$ref: "../swagger.yaml#/definitions/error"
|
||||||
|
'500':
|
||||||
|
description: Internal error
|
||||||
|
schema:
|
||||||
|
$ref: "../swagger.yaml#/definitions/error"
|
||||||
|
'503':
|
||||||
|
description: Under maintenance
|
||||||
|
schema:
|
||||||
|
$ref: "../swagger.yaml#/definitions/error"
|
||||||
|
x-koha-authorization:
|
||||||
|
permissions:
|
||||||
|
parameters: manage_search_filters
|
||||||
|
post:
|
||||||
|
x-mojo-to: SearchFilter#add
|
||||||
|
operationId: addSearchFilter
|
||||||
|
tags:
|
||||||
|
- search_filters
|
||||||
|
summary: Add search filter
|
||||||
|
parameters:
|
||||||
|
- name: body
|
||||||
|
in: body
|
||||||
|
description: A JSON object containing informations about the new search filter
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: "../swagger.yaml#/definitions/search_filter"
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
'201':
|
||||||
|
description: Search filter added
|
||||||
|
schema:
|
||||||
|
$ref: "../swagger.yaml#/definitions/search_filter"
|
||||||
|
'401':
|
||||||
|
description: Authentication required
|
||||||
|
schema:
|
||||||
|
$ref: "../swagger.yaml#/definitions/error"
|
||||||
|
'403':
|
||||||
|
description: Access forbidden
|
||||||
|
schema:
|
||||||
|
$ref: "../swagger.yaml#/definitions/error"
|
||||||
|
"409":
|
||||||
|
description: Conflict in creating the resource
|
||||||
|
schema:
|
||||||
|
$ref: ../swagger.yaml#/definitions/error
|
||||||
|
'500':
|
||||||
|
description: Internal error
|
||||||
|
schema:
|
||||||
|
$ref: "../swagger.yaml#/definitions/error"
|
||||||
|
'503':
|
||||||
|
description: Under maintenance
|
||||||
|
schema:
|
||||||
|
$ref: "../swagger.yaml#/definitions/error"
|
||||||
|
x-koha-authorization:
|
||||||
|
permissions:
|
||||||
|
parameters: manage_search_filters
|
||||||
|
"/search_filters/{search_filter_id}":
|
||||||
|
get:
|
||||||
|
x-mojo-to: SearchFilter#get
|
||||||
|
operationId: getSearchFilter
|
||||||
|
tags:
|
||||||
|
- search_filters
|
||||||
|
summary: Get search filter
|
||||||
|
parameters:
|
||||||
|
- $ref: "../swagger.yaml#/parameters/search_filter_id_pp"
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: A search filter
|
||||||
|
schema:
|
||||||
|
$ref: "../swagger.yaml#/definitions/search_filter"
|
||||||
|
'403':
|
||||||
|
description: Access forbidden
|
||||||
|
schema:
|
||||||
|
$ref: "../swagger.yaml#/definitions/error"
|
||||||
|
'404':
|
||||||
|
description: SearchFilter not found
|
||||||
|
schema:
|
||||||
|
$ref: "../swagger.yaml#/definitions/error"
|
||||||
|
'500':
|
||||||
|
description: Internal error
|
||||||
|
schema:
|
||||||
|
$ref: "../swagger.yaml#/definitions/error"
|
||||||
|
'503':
|
||||||
|
description: Under maintenance
|
||||||
|
schema:
|
||||||
|
$ref: "../swagger.yaml#/definitions/error"
|
||||||
|
x-koha-authorization:
|
||||||
|
permissions:
|
||||||
|
parameters: manage_search_filters
|
||||||
|
put:
|
||||||
|
x-mojo-to: SearchFilter#update
|
||||||
|
operationId: updateSearchFilter
|
||||||
|
tags:
|
||||||
|
- search_filters
|
||||||
|
summary: Update search filter
|
||||||
|
parameters:
|
||||||
|
- $ref: "../swagger.yaml#/parameters/search_filter_id_pp"
|
||||||
|
- name: body
|
||||||
|
in: body
|
||||||
|
description: A search filter object
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: "../swagger.yaml#/definitions/search_filter"
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: An search_filter
|
||||||
|
schema:
|
||||||
|
$ref: "../swagger.yaml#/definitions/search_filter"
|
||||||
|
'401':
|
||||||
|
description: Authentication required
|
||||||
|
schema:
|
||||||
|
$ref: "../swagger.yaml#/definitions/error"
|
||||||
|
'403':
|
||||||
|
description: Access forbidden
|
||||||
|
schema:
|
||||||
|
$ref: "../swagger.yaml#/definitions/error"
|
||||||
|
'404':
|
||||||
|
description: Search filter not found
|
||||||
|
schema:
|
||||||
|
$ref: "../swagger.yaml#/definitions/error"
|
||||||
|
'500':
|
||||||
|
description: Internal error
|
||||||
|
schema:
|
||||||
|
$ref: "../swagger.yaml#/definitions/error"
|
||||||
|
'503':
|
||||||
|
description: Under maintenance
|
||||||
|
schema:
|
||||||
|
$ref: "../swagger.yaml#/definitions/error"
|
||||||
|
x-koha-authorization:
|
||||||
|
permissions:
|
||||||
|
parameters: manage_search_filters
|
||||||
|
delete:
|
||||||
|
x-mojo-to: SearchFilter#delete
|
||||||
|
operationId: deleteSearchFilter
|
||||||
|
tags:
|
||||||
|
- macros
|
||||||
|
summary: Delete search filter
|
||||||
|
parameters:
|
||||||
|
- $ref: "../swagger.yaml#/parameters/search_filter_id_pp"
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
'204':
|
||||||
|
description: Searc filter deleted
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
'401':
|
||||||
|
description: Authentication required
|
||||||
|
schema:
|
||||||
|
$ref: "../swagger.yaml#/definitions/error"
|
||||||
|
'403':
|
||||||
|
description: Access forbidden
|
||||||
|
schema:
|
||||||
|
$ref: "../swagger.yaml#/definitions/error"
|
||||||
|
'404':
|
||||||
|
description: Search filter not found
|
||||||
|
schema:
|
||||||
|
$ref: "../swagger.yaml#/definitions/error"
|
||||||
|
'500':
|
||||||
|
description: Internal error
|
||||||
|
schema:
|
||||||
|
$ref: "../swagger.yaml#/definitions/error"
|
||||||
|
'503':
|
||||||
|
description: Under maintenance
|
||||||
|
schema:
|
||||||
|
$ref: "../swagger.yaml#/definitions/error"
|
||||||
|
x-koha-authorization:
|
||||||
|
permissions:
|
||||||
|
parameters: manage_search_filters
|
|
@ -68,6 +68,8 @@ definitions:
|
||||||
$ref: ./definitions/renewals.yaml
|
$ref: ./definitions/renewals.yaml
|
||||||
return_claim:
|
return_claim:
|
||||||
$ref: ./definitions/return_claim.yaml
|
$ref: ./definitions/return_claim.yaml
|
||||||
|
search_filter:
|
||||||
|
$ref: ./definitions/search_filter.yaml
|
||||||
smtp_server:
|
smtp_server:
|
||||||
$ref: ./definitions/smtp_server.yaml
|
$ref: ./definitions/smtp_server.yaml
|
||||||
suggestion:
|
suggestion:
|
||||||
|
@ -97,6 +99,10 @@ paths:
|
||||||
$ref: ./paths/advancededitormacros.yaml#/~1advanced_editor~1macros
|
$ref: ./paths/advancededitormacros.yaml#/~1advanced_editor~1macros
|
||||||
/advanced_editor/macros/shared:
|
/advanced_editor/macros/shared:
|
||||||
$ref: ./paths/advancededitormacros.yaml#/~1advanced_editor~1macros~1shared
|
$ref: ./paths/advancededitormacros.yaml#/~1advanced_editor~1macros~1shared
|
||||||
|
/search_filters:
|
||||||
|
$ref: ./paths/search_filters.yaml#/~1search_filters
|
||||||
|
"/search_filters/{search_filter_id}":
|
||||||
|
$ref: "./paths/search_filters.yaml#/~1search_filters~1{search_filter_id}"
|
||||||
"/advanced_editor/macros/shared/{advancededitormacro_id}":
|
"/advanced_editor/macros/shared/{advancededitormacro_id}":
|
||||||
$ref: "./paths/advancededitormacros.yaml#/~1advanced_editor~1macros~1shared~1{advancededitormacro_id}"
|
$ref: "./paths/advancededitormacros.yaml#/~1advanced_editor~1macros~1shared~1{advancededitormacro_id}"
|
||||||
"/advanced_editor/macros/{advancededitormacro_id}":
|
"/advanced_editor/macros/{advancededitormacro_id}":
|
||||||
|
@ -427,6 +433,12 @@ parameters:
|
||||||
name: x-koha-request-id
|
name: x-koha-request-id
|
||||||
required: false
|
required: false
|
||||||
type: integer
|
type: integer
|
||||||
|
search_filter_id_pp:
|
||||||
|
name: search_filter_id
|
||||||
|
in: path
|
||||||
|
description: Search filter internal identifier
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
seen_pp:
|
seen_pp:
|
||||||
description: Item was seen flag
|
description: Item was seen flag
|
||||||
in: query
|
in: query
|
||||||
|
|
353
t/db_dependent/api/v1/search_filters.t
Executable file
353
t/db_dependent/api/v1/search_filters.t
Executable file
|
@ -0,0 +1,353 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
|
||||||
|
# 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, see <http://www.gnu.org/licenses>.
|
||||||
|
|
||||||
|
use Modern::Perl;
|
||||||
|
|
||||||
|
use Test::More tests => 5;
|
||||||
|
use Test::Mojo;
|
||||||
|
use Test::Warn;
|
||||||
|
|
||||||
|
use t::lib::TestBuilder;
|
||||||
|
use t::lib::Mocks;
|
||||||
|
|
||||||
|
use Koha::SearchFilters;
|
||||||
|
use Koha::Database;
|
||||||
|
|
||||||
|
my $schema = Koha::Database->new->schema;
|
||||||
|
my $builder = t::lib::TestBuilder->new;
|
||||||
|
|
||||||
|
t::lib::Mocks::mock_preference( 'RESTBasicAuth', 1 );
|
||||||
|
|
||||||
|
my $t = Test::Mojo->new('Koha::REST::V1');
|
||||||
|
|
||||||
|
$schema->storage->txn_begin;
|
||||||
|
|
||||||
|
subtest 'list() tests' => sub {
|
||||||
|
plan tests => 10;
|
||||||
|
|
||||||
|
Koha::SearchFilters->search()->delete();
|
||||||
|
|
||||||
|
my $patron_1 = $builder->build_object({
|
||||||
|
class => 'Koha::Patrons',
|
||||||
|
value => { flags => 3 }
|
||||||
|
});
|
||||||
|
my $password = 'thePassword123';
|
||||||
|
$patron_1->set_password({ password => $password, skip_validation => 1 });
|
||||||
|
my $userid = $patron_1->userid;
|
||||||
|
|
||||||
|
# Create test context
|
||||||
|
my $search_filter_1 = $builder->build_object({ class => 'Koha::SearchFilters', value =>
|
||||||
|
{
|
||||||
|
name => 'Test1',
|
||||||
|
query => 'kw:this',
|
||||||
|
limits => 'mc-itype,phr:BK',
|
||||||
|
opac => 1,
|
||||||
|
staff_client => 1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
my $search_filter_2 = $builder->build_object({ class => 'Koha::SearchFilters', value =>
|
||||||
|
{
|
||||||
|
name => 'Test2',
|
||||||
|
query => 'kw:that',
|
||||||
|
limits => 'mc-itype,phr:BK',
|
||||||
|
opac => 0,
|
||||||
|
staff_client => 1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
my $search_filter_3 = $builder->build_object({ class => 'Koha::SearchFilters', value =>
|
||||||
|
{
|
||||||
|
name => 'Test3',
|
||||||
|
query => 'kw:any',
|
||||||
|
limits => 'mc-itype,phr:CD',
|
||||||
|
opac => 0,
|
||||||
|
staff_client => 0
|
||||||
|
}
|
||||||
|
});
|
||||||
|
my $search_filter_4 = $builder->build_object({ class => 'Koha::SearchFilters', value =>
|
||||||
|
{
|
||||||
|
name => 'Test4',
|
||||||
|
query => 'kw:some',
|
||||||
|
limits => 'mc-itype,phr:CD',
|
||||||
|
opac => 1,
|
||||||
|
staff_client => 0
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
# Make sure we are returned with the correct amount of macros
|
||||||
|
$t->get_ok( "//$userid:$password@/api/v1/search_filters" )
|
||||||
|
->status_is( 200, 'SWAGGER3.2.2' )
|
||||||
|
->json_has('/0/search_filter_id')
|
||||||
|
->json_has('/1/search_filter_id')
|
||||||
|
->json_has('/2/search_filter_id')
|
||||||
|
->json_has('/3/search_filter_id');
|
||||||
|
|
||||||
|
subtest 'query parameters' => sub {
|
||||||
|
|
||||||
|
plan tests => 12;
|
||||||
|
$t->get_ok("//$userid:$password@/api/v1/search_filters?name=" . $search_filter_2->name)
|
||||||
|
->status_is(200)
|
||||||
|
->json_is( [ $search_filter_2->to_api ] );
|
||||||
|
$t->get_ok("//$userid:$password@/api/v1/search_filters?name=NotAName")
|
||||||
|
->status_is(200)
|
||||||
|
->json_is( [ ] );
|
||||||
|
$t->get_ok("//$userid:$password@/api/v1/search_filters?filter_query=kw:any")
|
||||||
|
->status_is(200)
|
||||||
|
->json_is( [ $search_filter_3->to_api ] );
|
||||||
|
$t->get_ok("//$userid:$password@/api/v1/search_filters?filter_limits=mc-itype,phr:BK")
|
||||||
|
->status_is(200)
|
||||||
|
->json_is( [ $search_filter_1->to_api, $search_filter_2->to_api ] );
|
||||||
|
};
|
||||||
|
|
||||||
|
# Warn on unsupported query parameter
|
||||||
|
$t->get_ok( "//$userid:$password@/api/v1/search_filters?filter_blah=blah" )
|
||||||
|
->status_is(400)
|
||||||
|
->json_is( [{ path => '/query/filter_blah', message => 'Malformed query string'}] );
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
subtest 'get() tests' => sub {
|
||||||
|
|
||||||
|
plan tests => 9;
|
||||||
|
|
||||||
|
my $patron = $builder->build_object({
|
||||||
|
class => 'Koha::Patrons',
|
||||||
|
value => { flags => 3 }
|
||||||
|
});
|
||||||
|
my $password = 'thePassword123';
|
||||||
|
$patron->set_password({ password => $password, skip_validation => 1 });
|
||||||
|
my $userid = $patron->userid;
|
||||||
|
|
||||||
|
my $search_filter_1 = $builder->build_object( { class => 'Koha::SearchFilters' } );
|
||||||
|
my $search_filter_2 = $builder->build_object( { class => 'Koha::SearchFilters' } );
|
||||||
|
my $search_filter_3 = $builder->build_object( { class => 'Koha::SearchFilters' } );
|
||||||
|
|
||||||
|
$t->get_ok( "//$userid:$password@/api/v1/search_filters/" . $search_filter_1->id )
|
||||||
|
->status_is( 200, 'Filter retrieved correctly' )
|
||||||
|
->json_is( $search_filter_1->to_api );
|
||||||
|
|
||||||
|
my $non_existent_code = $search_filter_1->id;
|
||||||
|
$search_filter_1->delete;
|
||||||
|
|
||||||
|
$t->get_ok( "//$userid:$password@/api/v1/search_filters/" . $non_existent_code )
|
||||||
|
->status_is(404)
|
||||||
|
->json_is( '/error' => 'Search filter not found' );
|
||||||
|
|
||||||
|
$patron->flags(4)->store;
|
||||||
|
$t->get_ok( "//$userid:$password/api/v1/search_filters/" . $search_filter_2->id )
|
||||||
|
->status_is( 401, 'Cannot search filters without permission' )
|
||||||
|
->json_is( '/error' => 'Authentication failure.' );
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
subtest 'add() tests' => sub {
|
||||||
|
|
||||||
|
plan tests => 17;
|
||||||
|
|
||||||
|
my $authorized_patron = $builder->build_object({
|
||||||
|
class => 'Koha::Patrons',
|
||||||
|
value => { flags => 0 }
|
||||||
|
});
|
||||||
|
$builder->build({
|
||||||
|
source => 'UserPermission',
|
||||||
|
value => {
|
||||||
|
borrowernumber => $authorized_patron->borrowernumber,
|
||||||
|
module_bit => 3,
|
||||||
|
code => 'manage_search_filters',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
my $password = 'thePassword123';
|
||||||
|
$authorized_patron->set_password({ password => $password, skip_validation => 1 });
|
||||||
|
my $auth_userid = $authorized_patron->userid;
|
||||||
|
|
||||||
|
my $unauthorized_patron = $builder->build_object({
|
||||||
|
class => 'Koha::Patrons',
|
||||||
|
value => { flags => 0 }
|
||||||
|
});
|
||||||
|
$unauthorized_patron->set_password({ password => $password, skip_validation => 1 });
|
||||||
|
my $unauth_userid = $unauthorized_patron->userid;
|
||||||
|
|
||||||
|
my $search_filter = $builder->build_object({ class => 'Koha::SearchFilters' });
|
||||||
|
my $search_filter_values = $search_filter->to_api;
|
||||||
|
delete $search_filter_values->{search_filter_id};
|
||||||
|
$search_filter->delete;
|
||||||
|
|
||||||
|
# Unauthorized attempt to write
|
||||||
|
$t->post_ok( "//$unauth_userid:$password@/api/v1/search_filters" => json => $search_filter_values )
|
||||||
|
->status_is(403);
|
||||||
|
|
||||||
|
# Authorized attempt to write invalid data
|
||||||
|
my $search_filter_with_invalid_field = { %$search_filter_values };
|
||||||
|
$search_filter_with_invalid_field->{'coffee_filter'} = 'Chemex';
|
||||||
|
|
||||||
|
$t->post_ok( "//$auth_userid:$password@/api/v1/search_filters" => json => $search_filter_with_invalid_field )
|
||||||
|
->status_is(400)
|
||||||
|
->json_is(
|
||||||
|
"/errors" => [
|
||||||
|
{
|
||||||
|
message => "Properties not allowed: coffee_filter.",
|
||||||
|
path => "/body"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
# Authorized attempt to write
|
||||||
|
$t->post_ok( "//$auth_userid:$password@/api/v1/search_filters" => json => $search_filter_values )
|
||||||
|
->status_is( 201, 'SWAGGER3.2.1' )
|
||||||
|
->json_has( '/search_filter_id', 'We generated a new id' )
|
||||||
|
->json_is( '/name' => $search_filter_values->{name}, 'The name matches what we supplied' )
|
||||||
|
->json_is( '/query' => $search_filter_values->{query}, 'The query matches what we supplied' )
|
||||||
|
->json_is( '/limits' => $search_filter_values->{limits}, 'The limits match what we supplied' )
|
||||||
|
->json_is( '/opac' => $search_filter_values->{opac}, 'The limits match what we supplied' )
|
||||||
|
->json_is( '/staff_client' => $search_filter_values->{staff_client}, 'The limits match what we supplied' )
|
||||||
|
->header_like( Location => qr|^\/api\/v1\/search_filters\/d*|, 'Correct location' );
|
||||||
|
|
||||||
|
# save the library_id
|
||||||
|
my $search_filter_id = 999;
|
||||||
|
|
||||||
|
# Authorized attempt to create with existing id
|
||||||
|
$search_filter_values->{search_filter_id} = $search_filter_id;
|
||||||
|
|
||||||
|
$t->post_ok( "//$auth_userid:$password@/api/v1/search_filters" => json => $search_filter_values )
|
||||||
|
->status_is(400)
|
||||||
|
->json_is( '/errors' => [
|
||||||
|
{
|
||||||
|
message => "Read-only.",
|
||||||
|
path => "/body/search_filter_id"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
subtest 'update() tests' => sub {
|
||||||
|
plan tests => 15;
|
||||||
|
|
||||||
|
my $authorized_patron = $builder->build_object({
|
||||||
|
class => 'Koha::Patrons',
|
||||||
|
value => { flags => 0 }
|
||||||
|
});
|
||||||
|
$builder->build({
|
||||||
|
source => 'UserPermission',
|
||||||
|
value => {
|
||||||
|
borrowernumber => $authorized_patron->borrowernumber,
|
||||||
|
module_bit => 3,
|
||||||
|
code => 'manage_search_filters',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
my $password = 'thePassword123';
|
||||||
|
$authorized_patron->set_password({ password => $password, skip_validation => 1 });
|
||||||
|
my $auth_userid = $authorized_patron->userid;
|
||||||
|
|
||||||
|
my $unauthorized_patron = $builder->build_object({
|
||||||
|
class => 'Koha::Patrons',
|
||||||
|
value => { flags => 0 }
|
||||||
|
});
|
||||||
|
$unauthorized_patron->set_password({ password => $password, skip_validation => 1 });
|
||||||
|
my $unauth_userid = $unauthorized_patron->userid;
|
||||||
|
|
||||||
|
my $search_filter = $builder->build_object({ class => 'Koha::SearchFilters' });
|
||||||
|
my $search_filter_id = $search_filter->id;
|
||||||
|
my $search_filter_values = $search_filter->to_api;
|
||||||
|
delete $search_filter_values->{search_filter_id};
|
||||||
|
|
||||||
|
# Unauthorized attempt to update
|
||||||
|
$t->put_ok( "//$unauth_userid:$password@/api/v1/search_filters/$search_filter_id"
|
||||||
|
=> json => { name => 'New unauthorized name change' } )
|
||||||
|
->status_is(403);
|
||||||
|
|
||||||
|
my $search_filter_update = {
|
||||||
|
name => "Filter update",
|
||||||
|
filter_query => "ti:The hobbit",
|
||||||
|
filter_limits => "mc-ccode:fantasy",
|
||||||
|
};
|
||||||
|
|
||||||
|
my $test = $t->put_ok( "//$auth_userid:$password@/api/v1/search_filters/$search_filter_id" => json => $search_filter_update )
|
||||||
|
->status_is(200, 'Authorized user can update a macro')
|
||||||
|
->json_is( '/search_filter_id' => $search_filter_id, 'We get back the id' )
|
||||||
|
->json_is( '/name' => $search_filter_update->{name}, 'We get back the name' )
|
||||||
|
->json_is( '/filter_query' => $search_filter_update->{filter_query}, 'We get back our query' )
|
||||||
|
->json_is( '/filter_limits' => $search_filter_update->{filter_limits}, 'We get back our limits' )
|
||||||
|
->json_is( '/opac' => 1, 'We get back our opac visibility unchanged' )
|
||||||
|
->json_is( '/staff_client' => 1, 'We get back our staff client visibility unchanged' );
|
||||||
|
|
||||||
|
# Authorized attempt to write invalid data
|
||||||
|
my $search_filter_with_invalid_field = { %$search_filter_update };
|
||||||
|
$search_filter_with_invalid_field->{'coffee_filter'} = 'Chemex';
|
||||||
|
|
||||||
|
$t->put_ok( "//$auth_userid:$password@/api/v1/search_filters/$search_filter_id" => json => $search_filter_with_invalid_field )
|
||||||
|
->status_is(400)
|
||||||
|
->json_is(
|
||||||
|
"/errors" => [
|
||||||
|
{
|
||||||
|
message => "Properties not allowed: coffee_filter.",
|
||||||
|
path => "/body"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
my $non_existent_macro = $builder->build_object({class => 'Koha::SearchFilters'});
|
||||||
|
my $non_existent_code = $non_existent_macro->id;
|
||||||
|
$non_existent_macro->delete;
|
||||||
|
|
||||||
|
$t->put_ok("//$auth_userid:$password@/api/v1/search_filters/$non_existent_code" => json => $search_filter_update)
|
||||||
|
->status_is(404);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
subtest 'delete() tests' => sub {
|
||||||
|
plan tests => 4;
|
||||||
|
|
||||||
|
my $authorized_patron = $builder->build_object({
|
||||||
|
class => 'Koha::Patrons',
|
||||||
|
value => { flags => 0 }
|
||||||
|
});
|
||||||
|
$builder->build({
|
||||||
|
source => 'UserPermission',
|
||||||
|
value => {
|
||||||
|
borrowernumber => $authorized_patron->borrowernumber,
|
||||||
|
module_bit => 3,
|
||||||
|
code => 'manage_search_filters',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
my $password = 'thePassword123';
|
||||||
|
$authorized_patron->set_password({ password => $password, skip_validation => 1 });
|
||||||
|
my $auth_userid = $authorized_patron->userid;
|
||||||
|
|
||||||
|
my $unauthorized_patron = $builder->build_object({
|
||||||
|
class => 'Koha::Patrons',
|
||||||
|
value => { flags => 0 }
|
||||||
|
});
|
||||||
|
$unauthorized_patron->set_password({ password => $password, skip_validation => 1 });
|
||||||
|
my $unauth_userid = $unauthorized_patron->userid;
|
||||||
|
|
||||||
|
my $search_filter = $builder->build_object({ class => 'Koha::SearchFilters' });
|
||||||
|
my $search_filter_2 = $builder->build_object({ class => 'Koha::SearchFilters' });
|
||||||
|
my $search_filter_id = $search_filter->id;
|
||||||
|
my $search_filter_2_id = $search_filter_2->id;
|
||||||
|
|
||||||
|
# Unauthorized attempt to delete
|
||||||
|
$t->delete_ok( "//$unauth_userid:$password@/api/v1/search_filters/$search_filter_2_id")
|
||||||
|
->status_is(403, "Cannot delete search filter without permission");
|
||||||
|
|
||||||
|
$t->delete_ok( "//$auth_userid:$password@/api/v1/search_filters/$search_filter_id")
|
||||||
|
->status_is( 204, 'Can delete search filter with permission');
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
$schema->storage->txn_rollback;
|
|
@ -628,6 +628,10 @@ sub _gen_default_values {
|
||||||
status => 'staged',
|
status => 'staged',
|
||||||
import_error => undef
|
import_error => undef
|
||||||
},
|
},
|
||||||
|
SearchFilter => {
|
||||||
|
opac => 1,
|
||||||
|
staff_client => 1
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue