diff --git a/Koha/REST/V1/Patrons/Image.pm b/Koha/REST/V1/Patrons/Image.pm new file mode 100644 index 0000000000..3cba4612a9 --- /dev/null +++ b/Koha/REST/V1/Patrons/Image.pm @@ -0,0 +1,74 @@ +package Koha::REST::V1::Patrons::Image; + +# 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 . + +use Modern::Perl; + +use Mojo::Base 'Mojolicious::Controller'; + +use Koha::Patrons; + +use Try::Tiny qw( catch try ); + +use MIME::Base64 qw( encode_base64 ); + +=head1 NAME + +Koha::REST::V1::Patrons::Image + +=head1 API + +=head2 Methods + +=head3 get + +Controller method that gets a patron's image + +=cut + +sub get { + my $c = shift->openapi->valid_input or return; + + my $patron = Koha::Patrons->find( $c->param('patron_id') ); + + unless ($patron) { + return $c->render( + status => 404, + openapi => { error => "Patron not found." } + ); + } + + return try { + my $image = $patron->image; + + unless ($image) { + return $c->render( + status => 404, + openapi => { error => "Patron image not found." } + ); + } + + return $c->render( + status => 200, + format => "png", # currently all patron images are converted to png upon upload + data => $image->imagefile + ); + } catch { + $c->unhandled_exception($_); + }; +} + +1; diff --git a/api/v1/swagger/paths/patrons_image.yaml b/api/v1/swagger/paths/patrons_image.yaml new file mode 100644 index 0000000000..38fb7b6b90 --- /dev/null +++ b/api/v1/swagger/paths/patrons_image.yaml @@ -0,0 +1,42 @@ +--- +"/patrons/{patron_id}/default_image": + get: + x-mojo-to: Patrons::Image#get + operationId: getPatronImage + tags: + - patrons + summary: Get image of a patron + parameters: + - $ref: "../swagger.yaml#/parameters/patron_id_pp" + produces: + - image/png + responses: + "200": + description: Patron's image + "401": + description: Authentication required + schema: + $ref: "../swagger.yaml#/definitions/error" + "403": + description: Access forbidden + schema: + $ref: "../swagger.yaml#/definitions/error" + "404": + description: Patron not found + schema: + $ref: "../swagger.yaml#/definitions/error" + "500": + description: | + Internal server error. Possible `error_code` attribute values: + + * `internal_server_error` + schema: + $ref: "../swagger.yaml#/definitions/error" + "503": + description: Under maintenance + schema: + $ref: "../swagger.yaml#/definitions/error" + x-koha-authorization: + permissions: + - borrowers: "list_borrowers" + - borrowers: "edit_borrowers" diff --git a/api/v1/swagger/swagger.yaml b/api/v1/swagger/swagger.yaml index 4c35664630..70e80c81ff 100644 --- a/api/v1/swagger/swagger.yaml +++ b/api/v1/swagger/swagger.yaml @@ -565,6 +565,8 @@ paths: $ref: "./paths/patrons_hold_groups.yaml#/~1patrons~1{patron_id}~1hold_groups~1{hold_group_id}~1cancel" "/patrons/{patron_id}/checkouts": $ref: "./paths/patrons_checkouts.yaml#/~1patrons~1{patron_id}~1checkouts" + "/patrons/{patron_id}/default_image": + $ref: "./paths/patrons_image.yaml#/~1patrons~1{patron_id}~1default_image" "/patrons/{patron_id}/password": $ref: "./paths/patrons_password.yaml#/~1patrons~1{patron_id}~1password" "/patrons/{patron_id}/password/expiration_date": diff --git a/t/db_dependent/api/v1/patron_images.t b/t/db_dependent/api/v1/patron_images.t new file mode 100755 index 0000000000..eb00276d59 --- /dev/null +++ b/t/db_dependent/api/v1/patron_images.t @@ -0,0 +1,96 @@ +#!/usr/bin/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 . + +use Modern::Perl; + +use Test::NoWarnings; +use Test::More tests => 2; +use Test::Mojo; + +use t::lib::TestBuilder; +use t::lib::Mocks; + +use Koha::Patrons; + +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'); + +subtest 'Image tests' => sub { + + plan tests => 16; + + $schema->storage->txn_begin; + + my $privileged_patron = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 1 } + } + ); + my $password = 'thePassword123'; + $privileged_patron->set_password( { password => $password, skip_validation => 1 } ); + my $userid = $privileged_patron->userid; + my $borrowernumber = $privileged_patron->borrowernumber; + + $t->get_ok("//$userid:$password@/api/v1/patrons/$borrowernumber/default_image") + ->status_is(404) + ->json_is( '/error' => 'Patron image not found.' ); + + my $non_existent_patron = $builder->build_object( { class => 'Koha::Patrons' } ); + my $non_existent_patron_borrower_number = $non_existent_patron->borrowernumber; + $non_existent_patron->delete; + + $t->get_ok( "//$userid:$password@/api/v1/patrons/" . $non_existent_patron_borrower_number . '/checkouts' ) + ->status_is(404) + ->json_is( '/error' => 'Patron not found' ); + + my $new_image = Koha::Patron::Image->new( + { + borrowernumber => $privileged_patron->borrowernumber, + mimetype => 'image/png', + imagefile => 'lot of binary content', + } + )->store; + + $t->get_ok("//$userid:$password@/api/v1/patrons/$borrowernumber/default_image") + ->status_is(200) + ->content_type_is('image/png') + ->content_is('lot of binary content'); + + my $unauthorized_patron = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 0 } + } + ); + my $unauthorized_password = 'thePassword456'; + + $unauthorized_patron->set_password( { password => $unauthorized_password, skip_validation => 1 } ); + my $unauthorized_userid = $unauthorized_patron->userid; + + $t->get_ok( "//$unauthorized_userid:$unauthorized_password@/api/v1/patrons/" . $borrowernumber . "/default_image" ) + ->status_is(403) + ->json_is( '/error' => "Authorization failure. Missing required permission(s)." ); + + $t->get_ok( "//@/api/v1/patrons/" . $borrowernumber . "/default_image" ) + ->status_is(401) + ->json_is( '/error' => 'Authentication failure.' ); +};