1 package Koha
::REST
::V1
::Patrons
;
3 # This file is part of Koha.
5 # Koha is free software; you can redistribute it and/or modify it under the
6 # terms of the GNU General Public License as published by the Free Software
7 # Foundation; either version 3 of the License, or (at your option) any later
10 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
11 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License along
15 # with Koha; if not, write to the Free Software Foundation, Inc.,
16 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 use Mojo
::Base
'Mojolicious::Controller';
22 use C4
::Members
qw( AddMember ModMember );
25 use Scalar
::Util
qw(blessed);
30 Koha::REST::V1::Patrons
38 Controller function that handles listing Koha::Patron objects
43 my $c = shift->openapi->valid_input or return;
47 my $args = $c->validation->output;
48 my ( $params, $reserved_params ) = $c->extract_reserved_params( $args );
50 # Merge sorting into query attributes
51 $c->dbic_merge_sorting({ attributes
=> $attributes, params
=> $reserved_params });
53 # Merge pagination into query attributes
54 $c->dbic_merge_pagination({ filter
=> $attributes, params
=> $reserved_params });
56 my $restricted = $args->{restricted
};
58 $params = _to_model
($params)
60 # deal with string params
61 $params = $c->build_query_params( $params, $reserved_params );
63 # translate 'restricted' => 'debarred'
64 $params->{debarred
} = { '!=' => undef }
67 my $patrons = Koha
::Patrons
->search( $params, $attributes );
68 if ( $patrons->is_paged ) {
69 $c->add_pagination_headers(
71 total
=> $patrons->pager->total_entries,
76 my @patrons = $patrons->as_list;
77 @patrons = map { _to_api
( $_->TO_JSON ) } @patrons;
78 return $c->render( status
=> 200, openapi
=> \
@patrons );
81 if ( $_->isa('DBIx::Class::Exception') ) {
84 openapi
=> { error
=> $_->{msg
} }
90 openapi
=> { error
=> "Something went wrong, check the logs." }
99 Controller function that handles retrieving a single Koha::Patron object
104 my $c = shift->openapi->valid_input or return;
106 my $patron_id = $c->validation->param('patron_id');
107 my $patron = Koha
::Patrons
->find($patron_id);
110 return $c->render( status
=> 404, openapi
=> { error
=> "Patron not found." } );
113 return $c->render( status
=> 200, openapi
=> _to_api
( $patron->TO_JSON ) );
118 Controller function that handles adding a new Koha::Patron object
123 my $c = shift->openapi->valid_input or return;
127 my $body = _to_model
( $c->validation->param('body') );
129 # TODO: Use AddMember until it has been moved to Koha-namespace
130 my $patron_id = AddMember
( %{ _to_model
($body) } );
131 my $patron = _to_api
( Koha
::Patrons
->find($patron_id)->TO_JSON );
133 return $c->render( status
=> 201, openapi
=> $patron );
136 unless ( blessed
$_ && $_->can('rethrow') ) {
139 openapi
=> { error
=> "Something went wrong, check Koha logs for details." }
142 if ( $_->isa('Koha::Exceptions::Object::DuplicateID') ) {
145 openapi
=> { error
=> $_->error, conflict
=> $_->duplicate_id }
148 elsif ( $_->isa('Koha::Exceptions::Object::FKConstraint') ) {
153 . $Koha::REST
::V1
::Patrons
::to_api_mapping
->{ $_->broken_fk }
158 elsif ( $_->isa('Koha::Exceptions::BadParameter') ) {
163 . $Koha::REST
::V1
::Patrons
::to_api_mapping
->{ $_->parameter }
171 openapi
=> { error
=> "Something went wrong, check Koha logs for details." }
180 Controller function that handles updating a Koha::Patron object
185 my $c = shift->openapi->valid_input or return;
187 my $patron_id = $c->validation->param('patron_id');
188 my $patron = Koha
::Patrons
->find( $patron_id );
193 openapi
=> { error
=> "Patron not found" }
198 my $body = _to_model
($c->validation->param('body'));
200 ## TODO: Use ModMember until it has been moved to Koha-namespace
201 # Add borrowernumber to $body, as required by ModMember
202 $body->{borrowernumber
} = $patron_id;
204 if ( ModMember
(%$body) ) {
205 # Fetch the updated Koha::Patron object
206 $patron->discard_changes;
207 return $c->render( status
=> 200, openapi
=> $patron );
213 error
=> 'Something went wrong, check Koha logs for details.'
219 unless ( blessed
$_ && $_->can('rethrow') ) {
223 error
=> "Something went wrong, check Koha logs for details."
227 if ( $_->isa('Koha::Exceptions::Object::DuplicateID') ) {
230 openapi
=> { error
=> $_->error, conflict
=> $_->duplicate_id }
233 elsif ( $_->isa('Koha::Exceptions::Object::FKConstraint') ) {
236 openapi
=> { error
=> "Given " .
237 $Koha::REST
::V1
::Patrons
::to_api_mapping
->{$_->broken_fk}
238 . " does not exist" }
241 elsif ( $_->isa('Koha::Exceptions::MissingParameter') ) {
245 error
=> "Missing mandatory parameter(s)",
246 parameters
=> $_->parameter
250 elsif ( $_->isa('Koha::Exceptions::BadParameter') ) {
254 error
=> "Invalid parameter(s)",
255 parameters
=> $_->parameter
259 elsif ( $_->isa('Koha::Exceptions::NoChanges') ) {
262 openapi
=> { error
=> "No changes have been made" }
270 "Something went wrong, check Koha logs for details."
279 Controller function that handles deleting a Koha::Patron object
284 my $c = shift->openapi->valid_input or return;
289 $patron = Koha
::Patrons
->find( $c->validation->param('patron_id') );
291 # check if loans, reservations, debarrment, etc. before deletion!
292 my $res = $patron->delete;
293 return $c->render( status
=> 200, openapi
=> {} );
299 openapi
=> { error
=> "Patron not found" }
307 "Something went wrong, check Koha logs for details."
316 Helper function that maps unblessed Koha::Patron objects into REST api
323 my $patron_id = $patron->{ borrowernumber
};
326 foreach my $column ( keys %{ $Koha::REST
::V1
::Patrons
::to_api_mapping
} ) {
327 my $mapped_column = $Koha::REST
::V1
::Patrons
::to_api_mapping
->{$column};
328 if ( exists $patron->{ $column }
329 && defined $mapped_column )
332 $patron->{ $mapped_column } = delete $patron->{ $column };
334 elsif ( exists $patron->{ $column }
335 && !defined $mapped_column )
338 delete $patron->{ $column };
342 # Calculate the 'restricted' field
343 my $patron_obj = Koha
::Patrons
->find( $patron_id );
344 $patron->{ restricted
} = ($patron_obj->is_debarred) ? Mojo
::JSON
->true : Mojo
::JSON
->false;
351 Helper function that maps REST api objects into Koha::Patron
359 foreach my $attribute ( keys %{ $Koha::REST
::V1
::Patrons
::to_model_mapping
} ) {
360 my $mapped_attribute = $Koha::REST
::V1
::Patrons
::to_model_mapping
->{$attribute};
361 if ( exists $patron->{ $attribute }
362 && defined $mapped_attribute )
365 $patron->{ $mapped_attribute } = delete $patron->{ $attribute };
367 elsif ( exists $patron->{ $attribute }
368 && !defined $mapped_attribute )
370 # key => undef / to be deleted
371 delete $patron->{ $attribute };
375 # TODO: Get rid of this once write operations are based on Koha::Patron
376 if ( exists $patron->{lost
} ) {
377 $patron->{lost
} = ($patron->{lost
}) ?
1 : 0;
380 if ( exists $patron->{ gonenoaddress
} ) {
381 $patron->{gonenoaddress
} = ($patron->{gonenoaddress
}) ?
1 : 0;
387 =head2 Global variables
389 =head3 $to_api_mapping
393 our $to_api_mapping = {
394 borrowernotes
=> 'staff_notes',
395 borrowernumber
=> 'patron_id',
396 branchcode
=> 'library_id',
397 categorycode
=> 'category_id',
398 checkprevcheckout
=> 'check_previous_checkout',
399 contactfirstname
=> undef, # Unused
400 contactname
=> undef, # Unused
401 contactnote
=> 'altaddress_notes',
402 contacttitle
=> undef, # Unused
403 dateenrolled
=> 'date_enrolled',
404 dateexpiry
=> 'expiry_date',
405 dateofbirth
=> 'date_of_birth',
406 debarred
=> undef, # replaced by 'restricted'
407 debarredcomment
=> undef, # calculated, API consumers will use /restrictions instead
408 emailpro
=> 'secondary_email',
409 flags
=> undef, # permissions manipulation handled in /permissions
410 gonenoaddress
=> 'incorrect_address',
411 guarantorid
=> 'guarantor_id',
412 lastseen
=> 'last_seen',
413 lost
=> 'patron_card_lost',
414 opacnote
=> 'opac_notes',
415 othernames
=> 'other_name',
416 password
=> undef, # password manipulation handled in /password
417 phonepro
=> 'secondary_phone',
418 relationship
=> 'relationship_type',
420 smsalertnumber
=> 'sms_number',
421 sort1
=> 'statistics_1',
422 sort2
=> 'statistics_2',
423 streetnumber
=> 'street_number',
424 streettype
=> 'street_type',
425 zipcode
=> 'postal_code',
426 B_address
=> 'altaddress_address',
427 B_address2
=> 'altaddress_address2',
428 B_city
=> 'altaddress_city',
429 B_country
=> 'altaddress_country',
430 B_email
=> 'altaddress_email',
431 B_phone
=> 'altaddress_phone',
432 B_state
=> 'altaddress_state',
433 B_streetnumber
=> 'altaddress_street_number',
434 B_streettype
=> 'altaddress_street_type',
435 B_zipcode
=> 'altaddress_postal_code',
436 altcontactaddress1
=> 'altcontact_address',
437 altcontactaddress2
=> 'altcontact_address2',
438 altcontactaddress3
=> 'altcontact_city',
439 altcontactcountry
=> 'altcontact_country',
440 altcontactfirstname
=> 'altcontact_firstname',
441 altcontactphone
=> 'altcontact_phone',
442 altcontactsurname
=> 'altcontact_surname',
443 altcontactstate
=> 'altcontact_state',
444 altcontactzipcode
=> 'altcontact_postal_code'
447 =head3 $to_model_mapping
451 our $to_model_mapping = {
452 altaddress_notes
=> 'contactnote',
453 category_id
=> 'categorycode',
454 check_previous_checkout
=> 'checkprevcheckout',
455 date_enrolled
=> 'dateenrolled',
456 date_of_birth
=> 'dateofbirth',
457 expiry_date
=> 'dateexpiry',
459 guarantor_id
=> 'guarantorid',
460 incorrect_address
=> 'gonenoaddress',
461 last_seen
=> 'lastseen',
462 library_id
=> 'branchcode',
463 opac_notes
=> 'opacnote',
464 other_name
=> 'othernames',
465 patron_card_lost
=> 'lost',
466 patron_id
=> 'borrowernumber',
467 postal_code
=> 'zipcode',
468 relationship_type
=> 'relationship',
470 secondary_email
=> 'emailpro',
471 secondary_phone
=> 'phonepro',
472 sms_number
=> 'smsalertnumber',
473 staff_notes
=> 'borrowernotes',
474 statistics_1
=> 'sort1',
475 statistics_2
=> 'sort2',
476 street_number
=> 'streetnumber',
477 street_type
=> 'streettype',
478 altaddress_address
=> 'B_address',
479 altaddress_address2
=> 'B_address2',
480 altaddress_city
=> 'B_city',
481 altaddress_country
=> 'B_country',
482 altaddress_email
=> 'B_email',
483 altaddress_phone
=> 'B_phone',
484 altaddress_state
=> 'B_state',
485 altaddress_street_number
=> 'B_streetnumber',
486 altaddress_street_type
=> 'B_streettype',
487 altaddress_postal_code
=> 'B_zipcode',
488 altcontact_firstname
=> 'altcontactfirstname',
489 altcontact_surname
=> 'altcontactsurname',
490 altcontact_address
=> 'altcontactaddress1',
491 altcontact_address2
=> 'altcontactaddress2',
492 altcontact_city
=> 'altcontactaddress3',
493 altcontact_state
=> 'altcontactstate',
494 altcontact_postal_code
=> 'altcontactzipcode',
495 altcontact_country
=> 'altcontactcountry',
496 altcontact_phone
=> 'altcontactphone'