1 package Koha::REST::V1::ERM::EUsage::UsageDataProviders;
3 # Copyright 2023 PTFS Europe
5 # This file is part of Koha.
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
22 use MIME::Base64 qw( decode_base64 );
23 use Mojo::Base 'Mojolicious::Controller';
25 use Koha::ERM::EUsage::UsageDataProviders;
26 use Koha::ERM::EUsage::MonthlyUsages;
27 use Koha::ERM::EUsage::CounterFiles;
29 use Scalar::Util qw( blessed );
30 use Try::Tiny qw( catch try );
41 my $c = shift->openapi->valid_input or return;
44 my $usage_data_providers_set = Koha::ERM::EUsage::UsageDataProviders->new;
45 my $usage_data_providers = $c->objects->search($usage_data_providers_set);
46 # if ( $c->validation->output->{"x-koha-embed"}[0]
47 # && $c->validation->output->{"x-koha-embed"}[0] eq 'counter_files' )
49 foreach my $provider (@$usage_data_providers) {
50 my $title_dates = _get_earliest_and_latest_dates(
52 $provider->{erm_usage_data_provider_id}
54 $provider->{earliest_title} =
55 $title_dates->{earliest_date}
56 ? $title_dates->{earliest_date}
58 $provider->{latest_title} =
59 $title_dates->{latest_date}
60 ? $title_dates->{latest_date}
63 my $platform_dates = _get_earliest_and_latest_dates(
65 $provider->{erm_usage_data_provider_id}
67 $provider->{earliest_platform} =
68 $platform_dates->{earliest_date}
69 ? $platform_dates->{earliest_date}
71 $provider->{latest_platform} =
72 $platform_dates->{latest_date}
73 ? $platform_dates->{latest_date}
76 my $item_dates = _get_earliest_and_latest_dates(
78 $provider->{erm_usage_data_provider_id}
80 $provider->{earliest_item} =
81 $item_dates->{earliest_date}
82 ? $item_dates->{earliest_date}
84 $provider->{latest_item} =
85 $item_dates->{latest_date} ? $item_dates->{latest_date} : '';
87 my $database_dates = _get_earliest_and_latest_dates(
89 $provider->{erm_usage_data_provider_id}
91 $provider->{earliest_database} =
92 $database_dates->{earliest_date}
93 ? $database_dates->{earliest_date}
95 $provider->{latest_database} =
96 $database_dates->{latest_date}
97 ? $database_dates->{latest_date}
100 my @last_run = Koha::ERM::EUsage::CounterFiles->search(
102 usage_data_provider_id => $provider->{erm_usage_data_provider_id},
104 { columns => [ { date_uploaded => { max => "date_uploaded" } }, ] }
106 $provider->{last_run} = $last_run[0][0]->{date_uploaded} ? $last_run[0][0]->{date_uploaded} : '';
111 return $c->render( status => 200, openapi => $usage_data_providers );
113 $c->unhandled_exception($_);
120 Controller function that handles retrieving a single Koha::ERM::EUsage::UsageDataProvider object
125 my $c = shift->openapi->valid_input or return;
128 my $usage_data_provider_id = $c->validation->param('erm_usage_data_provider_id');
129 my $usage_data_provider = $c->objects->find(
130 Koha::ERM::EUsage::UsageDataProviders->search,
131 $usage_data_provider_id
134 unless ($usage_data_provider) {
137 openapi => { error => "Usage data provider not found" }
143 openapi => $usage_data_provider
146 $c->unhandled_exception($_);
152 Controller function that handles adding a new Koha::ERM::EUsage::UsageDataProvider object
157 my $c = shift->openapi->valid_input or return;
160 Koha::Database->new->schema->txn_do(
163 my $body = $c->validation->param('body');
165 my $usage_data_provider = Koha::ERM::EUsage::UsageDataProvider->new_from_api($body)->store;
167 $c->res->headers->location(
168 $c->req->url->to_string . '/' . $usage_data_provider->erm_usage_data_provider_id );
171 openapi => $usage_data_provider->to_api
177 my $to_api_mapping = Koha::ERM::EUsage::UsageDataProvider->new->to_api_mapping;
180 if ( $_->isa('Koha::Exceptions::Object::DuplicateID') ) {
183 openapi => { error => $_->error, conflict => $_->duplicate_id }
185 } elsif ( $_->isa('Koha::Exceptions::Object::FKConstraint') ) {
188 openapi => { error => "Given " . $to_api_mapping->{ $_->broken_fk } . " does not exist" }
190 } elsif ( $_->isa('Koha::Exceptions::BadParameter') ) {
193 openapi => { error => "Given " . $to_api_mapping->{ $_->parameter } . " does not exist" }
195 } elsif ( $_->isa('Koha::Exceptions::PayloadTooLarge') ) {
198 openapi => { error => $_->error }
203 $c->unhandled_exception($_);
209 Controller function that handles updating a Koha::ERM::EUsage::UsageDataProvider object
214 my $c = shift->openapi->valid_input or return;
216 my $usage_data_provider_id = $c->validation->param('erm_usage_data_provider_id');
217 my $usage_data_provider = Koha::ERM::EUsage::UsageDataProviders->find($usage_data_provider_id);
219 unless ($usage_data_provider) {
222 openapi => { error => "Usage data provider not found" }
227 Koha::Database->new->schema->txn_do(
230 my $body = $c->validation->param('body');
232 $usage_data_provider->set_from_api($body)->store;
234 $c->res->headers->location(
235 $c->req->url->to_string . '/' . $usage_data_provider->erm_usage_data_provider_id );
238 openapi => $usage_data_provider->to_api
243 my $to_api_mapping = Koha::ERM::EUsage::UsageDataProvider->new->to_api_mapping;
246 if ( $_->isa('Koha::Exceptions::Object::FKConstraint') ) {
249 openapi => { error => "Given " . $to_api_mapping->{ $_->broken_fk } . " does not exist" }
251 } elsif ( $_->isa('Koha::Exceptions::BadParameter') ) {
254 openapi => { error => "Given " . $to_api_mapping->{ $_->parameter } . " does not exist" }
256 } elsif ( $_->isa('Koha::Exceptions::PayloadTooLarge') ) {
259 openapi => { error => $_->error }
264 $c->unhandled_exception($_);
273 my $c = shift->openapi->valid_input or return;
275 my $usage_data_provider_id = $c->validation->param('erm_usage_data_provider_id');
276 my $usage_data_provider = Koha::ERM::EUsage::UsageDataProviders->find($usage_data_provider_id);
277 unless ($usage_data_provider) {
280 openapi => { error => "Usage data provider not found" }
285 $usage_data_provider->delete;
291 $c->unhandled_exception($_);
295 =head3 process_COUNTER_file
297 Controller function that handles processing of the COUNTER file
298 It will->enqueue_counter_file_processing_job for its respective usage data provider
302 sub process_COUNTER_file {
303 my $c = shift->openapi->valid_input or return;
306 Koha::Database->new->schema->txn_do(
309 my $body = $c->validation->param('body');
312 defined( $body->{file_content} )
313 ? decode_base64( $body->{file_content} )
316 # Validate the file_content without storing, it'll throw an exception if fail
317 my $counter_file_validation = Koha::ERM::EUsage::CounterFile->new( { file_content => $file_content } );
318 $counter_file_validation->validate;
320 # Validation was successful, enqueue the job
322 Koha::ERM::EUsage::UsageDataProviders->find( $c->validation->param('erm_usage_data_provider_id') );
324 my $jobs = $udprovider->enqueue_counter_file_processing_job(
326 file_content => $file_content,
332 openapi => { jobs => [ @{$jobs} ] }
338 my $to_api_mapping = Koha::ERM::EUsage::CounterFile->new->to_api_mapping;
341 if ( $_->isa('Koha::Exceptions::Object::DuplicateID') ) {
344 openapi => { error => $_->error, conflict => $_->duplicate_id }
346 } elsif ( $_->isa('Koha::Exceptions::Object::FKConstraint') ) {
349 openapi => { error => "Given " . $to_api_mapping->{ $_->broken_fk } . " does not exist" }
351 } elsif ( $_->isa('Koha::Exceptions::BadParameter') ) {
354 openapi => { error => "Given " . $to_api_mapping->{ $_->parameter } . " does not exist" }
356 } elsif ( $_->isa('Koha::Exceptions::PayloadTooLarge') ) {
359 openapi => { error => $_->error }
361 } elsif ( $_->isa('Koha::Exceptions::ERM::EUsage::CounterFile::UnsupportedRelease') ) {
364 openapi => { error => $_->description }
369 $c->unhandled_exception($_);
373 =head3 process_SUSHI_response
375 Controller function that handles processing of the SUSHI response
376 It will ->enqueue_sushi_harvest_jobs for this usage data provider
380 sub process_SUSHI_response {
381 my $c = shift->openapi->valid_input or return;
383 my $body = $c->validation->param('body');
384 my $begin_date = $body->{begin_date};
385 my $end_date = $body->{end_date};
387 unless ( $begin_date lt $end_date ) {
390 openapi => { error => "Begin date must be before end date" }
394 my $udprovider = Koha::ERM::EUsage::UsageDataProviders->find( $c->validation->param('erm_usage_data_provider_id') );
396 unless ($udprovider) {
399 openapi => { error => "Usage data provider not found" }
404 my $jobs = $udprovider->enqueue_sushi_harvest_jobs(
406 begin_date => $begin_date,
407 end_date => $end_date
413 openapi => { jobs => [ @{$jobs} ] }
416 $c->unhandled_exception($_);
420 =head3 test_connection
424 sub test_connection {
425 my $c = shift->openapi->valid_input or return;
427 my $udprovider = Koha::ERM::EUsage::UsageDataProviders->find( $c->validation->param('erm_usage_data_provider_id') );
429 unless ($udprovider) {
432 openapi => { error => "Usage data provider not found" }
436 my $service_active = $udprovider->test_connection;
439 openapi => $service_active
442 $c->unhandled_exception($_);
446 =head3 _get_earliest_and_latest_dates
450 sub _get_earliest_and_latest_dates {
451 my ( $report_type, $id ) = @_;
453 my @years = Koha::ERM::EUsage::MonthlyUsages->search(
455 usage_data_provider_id => $id,
456 report_type => { -like => "%$report_type%" }
460 { earliestYear => { min => "year" } },
461 { latestYear => { max => "year" } },
465 if ( $years[0][0]->{earliestYear} ) {
466 my @earliest_month = Koha::ERM::EUsage::MonthlyUsages->search(
468 usage_data_provider_id => $id,
469 report_type => { -like => "%$report_type%" },
470 year => $years[0][0]->{earliestYear},
472 { columns => [ { month => { min => "month" } }, ] }
474 my @latest_month = Koha::ERM::EUsage::MonthlyUsages->search(
476 usage_data_provider_id => $id,
477 report_type => { -like => "%$report_type%" },
478 year => $years[0][0]->{latestYear},
480 { columns => [ { month => { max => "month" } }, ] }
483 $earliest_month[0][0]->{month} =
484 _format_month("0$earliest_month[0][0]->{month}");
485 $latest_month[0][0]->{month} =
486 _format_month("0$latest_month[0][0]->{month}");
488 my $earliest_date = "$years[0][0]->{earliestYear}-$earliest_month[0][0]->{month}";
489 my $latest_date = "$years[0][0]->{latestYear}-$latest_month[0][0]->{month}";
492 earliest_date => $earliest_date,
493 latest_date => $latest_date,
510 $month = length($month) eq 2 ? $month : "0$month";