|
Lines 11-19
package Koha::REST::V1::Suggestions;
Link Here
|
| 11 |
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR |
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. |
12 |
# A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
| 13 |
# |
13 |
# |
| 14 |
# You should have received a copy of the GNU General Public License along |
14 |
# You should have received a copy of the GNU General Public License |
| 15 |
# with Koha; if not, write to the Free Software Foundation, Inc., |
15 |
# along with Koha; if not, see <http:°www.gnu.org/licenses>. |
| 16 |
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
|
|
| 17 |
|
16 |
|
| 18 |
use Modern::Perl; |
17 |
use Modern::Perl; |
| 19 |
|
18 |
|
|
Lines 28-94
use Koha::Suggestions;
Link Here
|
| 28 |
|
27 |
|
| 29 |
use Koha::ItemTypes; |
28 |
use Koha::ItemTypes; |
| 30 |
use Koha::Libraries; |
29 |
use Koha::Libraries; |
|
|
30 |
use Koha::DateUtils; |
| 31 |
use List::MoreUtils qw/any/; |
31 |
use List::MoreUtils qw/any/; |
| 32 |
|
32 |
|
| 33 |
use Try::Tiny; |
33 |
use Try::Tiny; |
| 34 |
|
34 |
|
| 35 |
sub list { |
35 |
=head1 NAME |
| 36 |
my $c = shift->openapi->valid_input or return; |
|
|
| 37 |
|
36 |
|
| 38 |
my $suggestions; |
37 |
Koha::REST::V1::Suggestion |
| 39 |
my $filter; |
|
|
| 40 |
my $args = $c->validation->output; |
| 41 |
|
38 |
|
| 42 |
for my $filter_param ( keys %$args ) { |
39 |
=head1 API |
| 43 |
$filter->{$filter_param} = { LIKE => $args->{$filter_param} . '%' }; |
40 |
|
| 44 |
} |
41 |
=head2 Methods |
|
|
42 |
|
| 43 |
=head3 list |
| 44 |
|
| 45 |
List Koha::Suggestion objects |
| 46 |
|
| 47 |
=cut |
| 48 |
|
| 49 |
sub list { |
| 50 |
my $c = shift->openapi->valid_input or return; |
| 45 |
|
51 |
|
| 46 |
return try { |
52 |
return try { |
| 47 |
$suggestions = Koha::Suggestions->search($filter, \&_to_model, \&_to_api); |
53 |
my $suggestion_set = Koha::Suggestions->new; |
| 48 |
return $c->render( status => 200, openapi => $suggestions ); |
54 |
my $suggestions = $c->objects->search( $suggestion_set ); |
|
|
55 |
return $c->render( |
| 56 |
status => 200, |
| 57 |
openapi => $suggestions |
| 58 |
); |
| 49 |
} |
59 |
} |
| 50 |
catch { |
60 |
catch { |
| 51 |
if ( $_->isa('DBIx::Class::Exception') ) { |
61 |
$c->unhandled_exception($_); |
| 52 |
return $c->render( status => 500, openapi => { error => $_->{msg} } ); |
|
|
| 53 |
} |
| 54 |
else { |
| 55 |
return $c->render( status => 500, openapi => { error => 'Something went wrong, check the logs.' } ); |
| 56 |
} |
| 57 |
}; |
62 |
}; |
| 58 |
} |
63 |
} |
| 59 |
|
64 |
|
|
|
65 |
=head3 get |
| 66 |
|
| 67 |
Controller function that handles retrieving a single Koha::Suggestion object |
| 68 |
|
| 69 |
=cut |
| 70 |
|
| 60 |
sub get { |
71 |
sub get { |
| 61 |
my $c = shift->openapi->valid_input or return; |
72 |
my $c = shift->openapi->valid_input or return; |
| 62 |
my $args = $c->validation->output; |
|
|
| 63 |
|
73 |
|
| 64 |
my $suggestion = Koha::Suggestions->find($args->{suggestionid}); |
74 |
return try { |
| 65 |
unless ($suggestion) { |
75 |
my $suggestion_id = $c->validation->param('suggestion_id'); |
| 66 |
return $c->render( status => 404, openapi => {error => 'Suggestion not found'}); |
76 |
my $suggestion = Koha::Suggestions->find($suggestion_id); |
| 67 |
} |
77 |
|
|
|
78 |
unless ($suggestion) { |
| 79 |
return $c->render( status => 404, openapi => { error => "Suggestion not found." } ); |
| 80 |
} |
| 68 |
|
81 |
|
| 69 |
return $c->render( status => 200, openapi => $suggestion->unblessed ); |
82 |
return $c->render( status => 200, openapi => $suggestion->to_api ); |
|
|
83 |
} |
| 84 |
catch { |
| 85 |
$c->unhandled_exception($_); |
| 86 |
}; |
| 70 |
} |
87 |
} |
| 71 |
|
88 |
|
|
|
89 |
=head3 add |
| 90 |
|
| 91 |
Controller function that handles adding a new Koha::Suggestion object |
| 92 |
|
| 93 |
=cut |
| 94 |
|
| 72 |
sub add { |
95 |
sub add { |
| 73 |
my $c = shift->openapi->valid_input or return; |
96 |
my $c = shift->openapi->valid_input or return; |
| 74 |
my $args = $c->validation->output; |
97 |
my $params = $c->validation->param('body'); |
| 75 |
|
98 |
$params->{'date_created'} = dt_from_string(); |
| 76 |
my $suggestion = Koha::Suggestion->new( $args->{body} ); |
99 |
$params->{'status'} = 'ASKED' unless defined $params->{'status'}; |
| 77 |
|
100 |
|
| 78 |
return try { |
101 |
return try { |
| 79 |
$suggestion->store; |
102 |
my $suggestion = Koha::Suggestion->new_from_api( $params )->store; |
| 80 |
return $c->render( status => 200, openapi => $suggestion->unblessed ); |
103 |
$c->res->headers->location( $c->req->url->to_string . '/' . $suggestion->suggestionid ); |
|
|
104 |
return $c->render( |
| 105 |
status => 201, |
| 106 |
openapi => $suggestion->to_api |
| 107 |
); |
| 81 |
} |
108 |
} |
| 82 |
catch { |
109 |
catch { |
| 83 |
if ( $_->isa('DBIx::Class::Exception') ) { |
110 |
|
| 84 |
return $c->render( status => 500, openapi => { error => $_->msg } ); |
111 |
my $to_api_mapping = Koha::Suggestion->new->to_api_mapping; |
|
|
112 |
|
| 113 |
unless ( blessed $_ && $_->can('rethrow') ) { |
| 114 |
return $c->render( |
| 115 |
status => 500, |
| 116 |
openapi => { error => "Something went wrong, check Koha logs for details." } |
| 117 |
); |
| 118 |
} |
| 119 |
if ( $_->isa('Koha::Exceptions::Object::DuplicateID') ) { |
| 120 |
return $c->render( |
| 121 |
status => 409, |
| 122 |
openapi => { error => $_->error, conflict => $_->duplicate_id } |
| 123 |
); |
| 124 |
} |
| 125 |
elsif ( $_->isa('Koha::Exceptions::Object::FKConstraint') ) { |
| 126 |
return $c->render( |
| 127 |
status => 400, |
| 128 |
openapi => { |
| 129 |
error => "Given " |
| 130 |
. $to_api_mapping->{ $_->broken_fk } |
| 131 |
. " does not exist" |
| 132 |
} |
| 133 |
); |
| 134 |
} |
| 135 |
elsif ( $_->isa('Koha::Exceptions::BadParameter') ) { |
| 136 |
return $c->render( |
| 137 |
status => 400, |
| 138 |
openapi => { |
| 139 |
error => "Given " |
| 140 |
. $to_api_mapping->{ $_->parameter } |
| 141 |
. " does not exist" |
| 142 |
} |
| 143 |
); |
| 85 |
} |
144 |
} |
| 86 |
else { |
145 |
else { |
| 87 |
return $c->render( status => 500, openapi => { error => 'Something went wrong, check the logs.' } ); |
146 |
$c->unhandled_exception($_); |
| 88 |
} |
147 |
} |
| 89 |
} |
148 |
}; |
| 90 |
} |
149 |
} |
| 91 |
|
150 |
|
|
|
151 |
=head3 update |
| 152 |
|
| 153 |
Controller function that handles modifying Koha::Suggestion object |
| 154 |
|
| 155 |
=cut |
| 156 |
|
| 92 |
sub update { |
157 |
sub update { |
| 93 |
my $c = shift->openapi->valid_input or return; |
158 |
my $c = shift->openapi->valid_input or return; |
| 94 |
|
159 |
|
|
Lines 98-117
sub update {
Link Here
|
| 98 |
|
163 |
|
| 99 |
return try { |
164 |
return try { |
| 100 |
|
165 |
|
| 101 |
$suggestion = Koha::Suggestions->find( $args->{suggestionid} ); |
166 |
$suggestion = Koha::Suggestions->find( $args->{suggestion_id} ); |
| 102 |
|
167 |
|
| 103 |
my $body = $args->{body}; |
168 |
my $body = $args->{body}; |
| 104 |
|
169 |
|
| 105 |
# Remove unchaned fields so that we can use our body validation from the add subroutine |
170 |
# Remove unchaned fields so that we can use our body validation from the add subroutine |
| 106 |
foreach my $param ( keys %{ $body } ) { |
171 |
foreach my $param ( keys %{ $body } ) { |
| 107 |
if (exists $body->{$param}) { |
172 |
if (exists $body->{$param}) { |
| 108 |
delete $body->{$param} if $body->{$param} eq $suggestion->unblessed->{$param}; |
173 |
delete $body->{$param} if $body->{$param} eq $suggestion->to_api->{$param}; |
| 109 |
} |
174 |
} |
| 110 |
} |
175 |
} |
| 111 |
|
176 |
|
| 112 |
$suggestion->set( $body ); |
177 |
$suggestion->set_from_api( $body ); |
| 113 |
$suggestion->store(); |
178 |
$suggestion->store(); |
| 114 |
return $c->render( status => 200, openapi => $suggestion->unblessed ); |
179 |
return $c->render( status => 200, openapi => $suggestion->to_api ); |
| 115 |
} |
180 |
} |
| 116 |
catch { |
181 |
catch { |
| 117 |
if ( not defined $suggestion ) { |
182 |
if ( not defined $suggestion ) { |
|
Lines 127-132
sub update {
Link Here
|
| 127 |
|
192 |
|
| 128 |
} |
193 |
} |
| 129 |
|
194 |
|
|
|
195 |
=head3 delete |
| 196 |
|
| 197 |
Controller function that handles removing a Koha::Suggestion object |
| 198 |
|
| 199 |
=cut |
| 200 |
|
| 130 |
sub delete { |
201 |
sub delete { |
| 131 |
my $c = shift->openapi->valid_input or return; |
202 |
my $c = shift->openapi->valid_input or return; |
| 132 |
|
203 |
|
|
Lines 135-141
sub delete {
Link Here
|
| 135 |
my $suggestion; |
206 |
my $suggestion; |
| 136 |
|
207 |
|
| 137 |
return try { |
208 |
return try { |
| 138 |
$suggestion = Koha::Suggestions->find( $args->{suggestionid} ); |
209 |
$suggestion = Koha::Suggestions->find( $args->{suggestion_id} ); |
| 139 |
$suggestion->delete; |
210 |
$suggestion->delete; |
| 140 |
return $c->render( status => 200, openapi => '' ); |
211 |
return $c->render( status => 200, openapi => '' ); |
| 141 |
} |
212 |
} |
|
Lines 175-185
sub _validate_body {
Link Here
|
| 175 |
|
246 |
|
| 176 |
foreach my $param ( keys %{ $body } ) { |
247 |
foreach my $param ( keys %{ $body } ) { |
| 177 |
unless (any { /^$param$/ } @allowed_fields) { |
248 |
unless (any { /^$param$/ } @allowed_fields) { |
| 178 |
# Ouch ! User trying to edit field he has no rights to edit! |
249 |
# Ouch ! User trying to edit field they has no rights to edit! |
| 179 |
my $verb = 'specified '; |
250 |
my $verb = 'specified '; |
| 180 |
return $c->render( status => 403 , openapi => { |
251 |
return $c->render( status => 403 , openapi => { |
| 181 |
error => 'You ' . $verb . $param . ', but allowed fields are only ' . join(', ', @allowed_fields)} |
252 |
error => 'You ' . $verb . $param . ', but allowed fields are only ' . join(', ', @allowed_fields)} |
| 182 |
); |
253 |
); |
| 183 |
} |
254 |
} |
| 184 |
} |
255 |
} |
| 185 |
} |
256 |
} |
|
Lines 187-193
sub _validate_body {
Link Here
|
| 187 |
# Set user's branchcode if not specified (after validation input, because user does not |
258 |
# Set user's branchcode if not specified (after validation input, because user does not |
| 188 |
# necessarily have rights to choose a branchcode) |
259 |
# necessarily have rights to choose a branchcode) |
| 189 |
if ( not exists $body->{branchcode} ) { |
260 |
if ( not exists $body->{branchcode} ) { |
| 190 |
$body->{branchcode} = C4::Context->userenv->{branch}; |
261 |
$body->{branchcode} = C4::Context->userenv->{branch}; |
| 191 |
} |
262 |
} |
| 192 |
|
263 |
|
| 193 |
# Is suggester anonymous? |
264 |
# Is suggester anonymous? |
|
Lines 221-241
sub _validate_body {
Link Here
|
| 221 |
if ( exists $body->{itemtype} ) { |
292 |
if ( exists $body->{itemtype} ) { |
| 222 |
my @item_types = map {$_->unblessed->{itemtype}} Koha::ItemTypes->search; |
293 |
my @item_types = map {$_->unblessed->{itemtype}} Koha::ItemTypes->search; |
| 223 |
return $c->render( status => 400 , openapi => {error => 'itemtype must be one of ' . join(', ', @item_types)} ) |
294 |
return $c->render( status => 400 , openapi => {error => 'itemtype must be one of ' . join(', ', @item_types)} ) |
| 224 |
unless grep(/^$body->{itemtype}$/, @item_types); |
295 |
unless grep(/^$body->{itemtype}$/, @item_types); |
| 225 |
} |
296 |
} |
| 226 |
|
297 |
|
| 227 |
# Check branchcode is valid |
298 |
# Check branchcode is valid |
| 228 |
if ( exists $body->{branchcode} ) { |
299 |
if ( exists $body->{branchcode} ) { |
| 229 |
my @branch_codes = map {$_->unblessed->{branchcode}} Koha::Libraries->search; |
300 |
my @branch_codes = map {$_->unblessed->{branchcode}} Koha::Libraries->search; |
| 230 |
return $c->render( status => 400 , openapi => {error => 'branchcode must be one of ' . join(', ', @branch_codes)} ) |
301 |
return $c->render( status => 400 , openapi => {error => 'branchcode must be one of ' . join(', ', @branch_codes)} ) |
| 231 |
unless grep(/^$body->{branchcode}$/, @branch_codes); |
302 |
unless grep(/^$body->{branchcode}$/, @branch_codes); |
| 232 |
} |
303 |
} |
| 233 |
|
304 |
|
| 234 |
# Check patron reason is valid |
305 |
# Check patron reason is valid |
| 235 |
if ( exists $body->{patronreason} ) { |
306 |
if ( exists $body->{patronreason} ) { |
| 236 |
my @authorized_values = map { $_->{authorised_value} } @{ C4::Koha::GetAuthorisedValues('OPAC_SUG') }; |
307 |
my @authorized_values = map { $_->{authorised_value} } @{ C4::Koha::GetAuthorisedValues('OPAC_SUG') }; |
| 237 |
return $c->render( status => 400, openapi => {error => 'patronreason must be one of ' . join(', ', @authorized_values)} ) |
308 |
return $c->render( status => 400, openapi => {error => 'patronreason must be one of ' . join(', ', @authorized_values)} ) |
| 238 |
unless grep(/^$body->{patronreason}$/, @authorized_values); |
309 |
unless grep(/^$body->{patronreason}$/, @authorized_values); |
| 239 |
} |
310 |
} |
| 240 |
|
311 |
|
| 241 |
# Check suggestedby patron exists |
312 |
# Check suggestedby patron exists |
|
Lines 253-390
sub _validate_body {
Link Here
|
| 253 |
# Everything's fine .. |
324 |
# Everything's fine .. |
| 254 |
return 0; |
325 |
return 0; |
| 255 |
} |
326 |
} |
| 256 |
=head3 _to_api |
|
|
| 257 |
|
| 258 |
Helper function that maps unblessed Koha::Suggestion objects into REST api |
| 259 |
attribute names. |
| 260 |
|
| 261 |
=cut |
| 262 |
|
| 263 |
sub _to_api { |
| 264 |
my $suggestion = shift; |
| 265 |
|
| 266 |
# Rename attributes |
| 267 |
foreach my $column ( keys %{ $Koha::REST::V1::Suggestions::to_api_mapping } ) { |
| 268 |
my $mapped_column = $Koha::REST::V1::Suggestions::to_api_mapping->{$column}; |
| 269 |
if ( exists $suggestion->{ $column } |
| 270 |
&& defined $mapped_column ) |
| 271 |
{ |
| 272 |
# key != undef |
| 273 |
$suggestion->{ $mapped_column } = delete $suggestion->{ $column }; |
| 274 |
} |
| 275 |
elsif ( exists $suggestion->{ $column } |
| 276 |
&& !defined $mapped_column ) |
| 277 |
{ |
| 278 |
# key == undef |
| 279 |
delete $suggestion->{ $column }; |
| 280 |
} |
| 281 |
} |
| 282 |
|
| 283 |
return $suggestion; |
| 284 |
} |
| 285 |
|
| 286 |
=head3 _to_model |
| 287 |
|
| 288 |
Helper function that maps REST api objects into Koha::Suggestion |
| 289 |
attribute names. |
| 290 |
|
| 291 |
=cut |
| 292 |
|
| 293 |
sub _to_model { |
| 294 |
my $suggestion = shift; |
| 295 |
|
| 296 |
foreach my $attribute ( keys %{ $Koha::REST::V1::Suggestions::to_model_mapping } ) { |
| 297 |
my $mapped_attribute = $Koha::REST::V1::Suggestions::to_model_mapping->{$attribute}; |
| 298 |
if ( exists $suggestion->{ $attribute } |
| 299 |
&& defined $mapped_attribute ) |
| 300 |
{ |
| 301 |
# key => !undef |
| 302 |
$suggestion->{ $mapped_attribute } = delete $suggestion->{ $attribute }; |
| 303 |
} |
| 304 |
elsif ( exists $suggestion->{ $attribute } |
| 305 |
&& !defined $mapped_attribute ) |
| 306 |
{ |
| 307 |
# key => undef / to be deleted |
| 308 |
delete $suggestion->{ $attribute }; |
| 309 |
} |
| 310 |
} |
| 311 |
|
| 312 |
return $suggestion; |
| 313 |
} |
| 314 |
|
| 315 |
=head2 Global variables |
| 316 |
|
| 317 |
=head3 $to_api_mapping |
| 318 |
|
| 319 |
=cut |
| 320 |
|
| 321 |
our $to_api_mapping = { |
| 322 |
suggestionid => 'suggestion_id', |
| 323 |
suggestedby => 'suggested_by', |
| 324 |
suggesteddate => 'suggestion_date', |
| 325 |
managedby => 'managed_by', |
| 326 |
manageddate => 'managed_date', |
| 327 |
accepteddate => 'accepted_date', |
| 328 |
rejectedby => 'rejected_by', |
| 329 |
rejectiondate => 'rejected_date', |
| 330 |
STATUS => 'status', |
| 331 |
note => 'note', |
| 332 |
author => 'author', |
| 333 |
title => 'title', |
| 334 |
copyrightdate => 'copyright_date', |
| 335 |
publishercode => 'publisher_code', |
| 336 |
date => 'date_created', |
| 337 |
volumedesc => 'volume_desc', |
| 338 |
publicationyear => 'publication_year', |
| 339 |
place => 'publication_place', |
| 340 |
isbn => 'isbn', |
| 341 |
biblionumber => 'biblio_id', |
| 342 |
reason => 'reason', |
| 343 |
patronreason => 'patron_reason', |
| 344 |
budgetid => 'budget_id', |
| 345 |
branchcode => 'library_id', |
| 346 |
collectiontitle => 'collection_title', |
| 347 |
itemtype => 'item_type', |
| 348 |
quantity => 'quantity', |
| 349 |
currency => 'currency', |
| 350 |
price => 'item_price', |
| 351 |
total => 'total_price' |
| 352 |
}; |
| 353 |
|
| 354 |
=head3 $to_model_mapping |
| 355 |
|
| 356 |
=cut |
| 357 |
|
| 358 |
our $to_model_mapping = { |
| 359 |
suggestion_id => 'suggestionid', |
| 360 |
suggested_by => 'suggestedby', |
| 361 |
suggestion_date => 'suggesteddate', |
| 362 |
managed_by => 'managedby', |
| 363 |
managed_date => 'manageddate', |
| 364 |
accepted_date => 'accepteddate', |
| 365 |
rejected_by => 'rejectedby', |
| 366 |
rejected_date => 'rejectiondate', |
| 367 |
status => 'STATUS', |
| 368 |
note => 'note', |
| 369 |
author => 'author', |
| 370 |
title => 'title', |
| 371 |
copyright_date => 'copyrightdate', |
| 372 |
publisher_code => 'publishercode', |
| 373 |
date_created => 'date', |
| 374 |
volume_desc => 'volumedesc', |
| 375 |
publication_year => 'publicationyear', |
| 376 |
publication_place => 'place', |
| 377 |
isbn => 'isbn', |
| 378 |
biblio_id => 'biblionumber', |
| 379 |
reason => 'reason', |
| 380 |
patron_reason => 'patronreason', |
| 381 |
budget_id => 'budgetid', |
| 382 |
library_id => 'branchcode', |
| 383 |
collection_title => 'collectiontitle', |
| 384 |
item_type => 'itemtype', |
| 385 |
quantity => 'quantity', |
| 386 |
currency => 'currency', |
| 387 |
item_price => 'price', |
| 388 |
total_price => 'total' |
| 389 |
}; |
| 390 |
1; |
327 |
1; |