Bugzilla – Attachment 137189 Details for
Bug 17170
Add the ability to create 'saved searches' for use as filters when searching the catalog
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 17170: Add API route for SearchFilters
Bug-17170-Add-API-route-for-SearchFilters.patch (text/plain), 29.44 KB, created by
Michal Urban
on 2022-07-05 20:10:05 UTC
(
hide
)
Description:
Bug 17170: Add API route for SearchFilters
Filename:
MIME Type:
Creator:
Michal Urban
Created:
2022-07-05 20:10:05 UTC
Size:
29.44 KB
patch
obsolete
>From 1129022ef4244c50a2fb66a2f717ed9f9e7f96f7 Mon Sep 17 00:00:00 2001 >From: Nick Clemens <nick@bywatersolutions.com> >Date: Thu, 16 Sep 2021 15:54:19 +0000 >Subject: [PATCH] Bug 17170: Add API route for SearchFilters > >This adds the API routes and tests >--- > Koha/REST/V1/SearchFilter.pm | 153 ++++++++ > api/v1/swagger/definitions.yaml | 65 ++++ > api/v1/swagger/definitions/search_filter.yaml | 33 ++ > api/v1/swagger/paths/search_filters.yaml | 226 +++++++++++ > api/v1/swagger/swagger.yaml | 12 + > t/db_dependent/api/v1/search_filters.t | 353 ++++++++++++++++++ > t/lib/TestBuilder.pm | 4 + > 7 files changed, 846 insertions(+) > create mode 100644 Koha/REST/V1/SearchFilter.pm > create mode 100644 api/v1/swagger/definitions.yaml > create mode 100644 api/v1/swagger/definitions/search_filter.yaml > create mode 100644 api/v1/swagger/paths/search_filters.yaml > create mode 100755 t/db_dependent/api/v1/search_filters.t > >diff --git a/Koha/REST/V1/SearchFilter.pm b/Koha/REST/V1/SearchFilter.pm >new file mode 100644 >index 0000000000..05c72e7e9b >--- /dev/null >+++ b/Koha/REST/V1/SearchFilter.pm >@@ -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; >diff --git a/api/v1/swagger/definitions.yaml b/api/v1/swagger/definitions.yaml >new file mode 100644 >index 0000000000..015aefd59e >--- /dev/null >+++ b/api/v1/swagger/definitions.yaml >@@ -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 >diff --git a/api/v1/swagger/definitions/search_filter.yaml b/api/v1/swagger/definitions/search_filter.yaml >new file mode 100644 >index 0000000000..a60e3f0ad4 >--- /dev/null >+++ b/api/v1/swagger/definitions/search_filter.yaml >@@ -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 >diff --git a/api/v1/swagger/paths/search_filters.yaml b/api/v1/swagger/paths/search_filters.yaml >new file mode 100644 >index 0000000000..5aa61e7350 >--- /dev/null >+++ b/api/v1/swagger/paths/search_filters.yaml >@@ -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 >diff --git a/api/v1/swagger/swagger.yaml b/api/v1/swagger/swagger.yaml >index f020ee427a..04b6dc4eee 100644 >--- a/api/v1/swagger/swagger.yaml >+++ b/api/v1/swagger/swagger.yaml >@@ -62,6 +62,8 @@ definitions: > $ref: ./definitions/renewals.yaml > return_claim: > $ref: ./definitions/return_claim.yaml >+ search_filter: >+ $ref: ./definitions/search_filter.yaml > smtp_server: > $ref: ./definitions/smtp_server.yaml > suggestion: >@@ -91,6 +93,10 @@ paths: > $ref: ./paths/advancededitormacros.yaml#/~1advanced_editor~1macros > /advanced_editor/macros/shared: > $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}": > $ref: "./paths/advancededitormacros.yaml#/~1advanced_editor~1macros~1shared~1{advancededitormacro_id}" > "/advanced_editor/macros/{advancededitormacro_id}": >@@ -395,6 +401,12 @@ parameters: > name: x-koha-request-id > required: false > type: integer >+ search_filter_id_pp: >+ name: search_filter_id >+ in: path >+ description: Search filter internal identifier >+ required: true >+ type: integer > seen_pp: > description: Item was seen flag > in: query >diff --git a/t/db_dependent/api/v1/search_filters.t b/t/db_dependent/api/v1/search_filters.t >new file mode 100755 >index 0000000000..c0b1bb705a >--- /dev/null >+++ b/t/db_dependent/api/v1/search_filters.t >@@ -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; >diff --git a/t/lib/TestBuilder.pm b/t/lib/TestBuilder.pm >index 86a793f1b9..9a8d5f27d9 100644 >--- a/t/lib/TestBuilder.pm >+++ b/t/lib/TestBuilder.pm >@@ -609,6 +609,10 @@ sub _gen_default_values { > status => 'staged', > import_error => undef > }, >+ SearchFilter => { >+ opac => 1, >+ staff_client => 1 >+ }, > }; > } > >-- >2.25.1
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 17170
:
133263
|
133264
|
133265
|
133266
|
133267
|
133268
|
133269
|
133270
|
133361
|
133376
|
137027
|
137028
|
137029
|
137030
|
137031
|
137032
|
137033
|
137034
|
137035
|
137036
|
137186
|
137187
|
137188
|
137189
|
137190
|
137191
|
137192
|
137193
|
137194
|
137195
|
137808
|
137809
|
137810
|
137811
|
137812
|
137813
|
137814
|
137815
|
137816
|
137817
|
138505
|
138506
|
138507
|
138508
|
138509
|
138510
|
138511
|
138512
|
138513
|
138514
|
139948
|
139949
|
139950
|
139951
|
139952
|
139953
|
139954
|
139955
|
139956
|
139957
|
141228
|
141229
|
141230
|
141231
|
141232
|
141233
|
141234
|
141235
|
141236
|
141237
|
141316
|
141317
|
141318
|
141319
|
141320
|
141321
|
141322
|
141323
|
141324
|
141325
|
141326
|
141327
|
141328
|
141348
|
141349
|
141350
|
141351
|
141352
|
141353
|
141354
|
141355
|
141356
|
141357
|
141358
|
141359
|
141360
|
141422
|
141423
|
141424
|
141425
|
141426
|
141427
|
141428
|
141429
|
141430
|
141431
|
141432
|
141433
|
141434
|
141435
|
141436
|
141437
|
141438
|
141461
|
141462
|
142365
|
142367
|
142368
|
142369
|
142370
|
142371
|
142372
|
142373
|
142374
|
142375
|
142376
|
142377
|
142378
|
142379
|
142380
|
142381
|
142382
|
142383
|
142384
|
142385
|
142494
|
142498