From b7aebb337ed010828f4ae1667218ffccd6a44e47 Mon Sep 17 00:00:00 2001 From: Matt Blenkinsop Date: Thu, 24 Aug 2023 14:09:57 +0000 Subject: [PATCH] Bug 34587: Add integration with the counter registry API The counter registry offers an API that provides SUSHI information for each provider. This will be incredibly useful for creating new providers as we can use the correct information from the registry for harvesting urls etc. This reduces the risk of user input errors when creating providers and gives greater reliability to the data required to successfully harvest from the SUSHI API Signed-off-by: Jessica Zairo Signed-off-by: Michaela Sieber Signed-off-by: Nick Clemens Signed-off-by: Tomas Cohen Arazi --- Koha/REST/V1/ERM/CounterRegistry.pm | 114 ++++++++ Koha/REST/V1/ERM/SushiServices.pm | 102 +++++++ .../definitions/erm_counter_registry.yaml | 57 ++++ .../definitions/erm_sushi_service.yaml | 114 ++++++++ .../swagger/paths/erm_counter_registries.yaml | 45 +++ api/v1/swagger/paths/erm_sushi_services.yaml | 45 +++ api/v1/swagger/swagger.yaml | 8 + .../UsageStatisticsDataProvidersFormAdd.vue | 256 +++++++++++++++++- .../prog/js/vue/fetch/erm-api-client.js | 19 ++ 9 files changed, 752 insertions(+), 8 deletions(-) create mode 100644 Koha/REST/V1/ERM/CounterRegistry.pm create mode 100644 Koha/REST/V1/ERM/SushiServices.pm create mode 100644 api/v1/swagger/definitions/erm_counter_registry.yaml create mode 100644 api/v1/swagger/definitions/erm_sushi_service.yaml create mode 100644 api/v1/swagger/paths/erm_counter_registries.yaml create mode 100644 api/v1/swagger/paths/erm_sushi_services.yaml diff --git a/Koha/REST/V1/ERM/CounterRegistry.pm b/Koha/REST/V1/ERM/CounterRegistry.pm new file mode 100644 index 0000000000..ca56256b83 --- /dev/null +++ b/Koha/REST/V1/ERM/CounterRegistry.pm @@ -0,0 +1,114 @@ +package Koha::REST::V1::ERM::CounterRegistry; + +# Copyright 2023 PTFS Europe + +# 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 HTTP::Request; +use LWP::UserAgent; +use Scalar::Util qw( blessed ); +use JSON qw( from_json decode_json encode_json ); +use Try::Tiny qw( catch try ); + +use Koha::Exceptions; + +=head1 API + +=head2 Methods + +=head3 list + +=cut + +sub list { + my $c = shift->openapi->valid_input or return; + + my $args = $c->validation->output; + my $json = JSON->new; + + my @query_params_array = + map { $_ ? $json->decode($_) : () } @{ $args->{q} }; + my $search_string = $query_params_array[0]->{name}; + + my $url = 'https://registry.projectcounter.org/api/v1/platform/'; + my $request = HTTP::Request->new( + GET => $url, + ); + + my $ua = LWP::UserAgent->new; + my $response = $ua->simple_request($request); + + if ( $response->code >= 400 ) { + my $result = decode_json( $response->decoded_content ); + my $message; + if ( ref($result) eq 'ARRAY' ) { + for my $r (@$result) { + $message .= $r->{message}; + } + } + else { + $message = $result->{message} || $result->{Message} || q{}; + if ( $result->{errors} ) { + for my $e ( @{ $result->{errors} } ) { + $message .= $e->{message}; + } + } + } + warn sprintf "ERROR - Counter registry API %s returned %s - %s\n", $url, + $response->code, $message; + if ( $response->code == 404 ) { + Koha::Exceptions::ObjectNotFound->throw($message); + } + elsif ( $response->code == 401 ) { + Koha::Exceptions::Authorization::Unauthorized->throw($message); + } + else { + die sprintf + "ERROR requesting Counter registry API\n%s\ncode %s: %s\n", $url, + $response->code, + $message; + } + } + elsif ( $response->code == 204 ) { # No content + return; + } + + my $result = decode_json( $response->decoded_content ); + + my @counter_5_supporting_platforms; + foreach my $platform (@$result) { + my $name_check = index( lc $platform->{name}, lc $search_string ); + my @services = grep { $_->{counter_release} eq '5' } + @{ $platform->{sushi_services} }; + if ( scalar(@services) > 0 + && $name_check != -1 + && scalar( @{ $platform->{reports} } ) > 0 ) + { + $platform->{sushi_services} = \@services; + push @counter_5_supporting_platforms, $platform; + } + } + + return $c->render( + status => 200, + openapi => \@counter_5_supporting_platforms + ); +} + +1; diff --git a/Koha/REST/V1/ERM/SushiServices.pm b/Koha/REST/V1/ERM/SushiServices.pm new file mode 100644 index 0000000000..ae322001e4 --- /dev/null +++ b/Koha/REST/V1/ERM/SushiServices.pm @@ -0,0 +1,102 @@ +package Koha::REST::V1::ERM::SushiServices; + +# Copyright 2023 PTFS Europe + +# 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 HTTP::Request; +use LWP::UserAgent; +use Scalar::Util qw( blessed ); +use JSON qw( from_json decode_json encode_json ); +use Try::Tiny qw( catch try ); + +use Koha::Exceptions; + +=head1 API + +=head2 Methods + +=head3 get + +=cut + +sub get { + my $c = shift->openapi->valid_input or return; + + my $args = $c->validation->output; + my $json = JSON->new; + + my @query_params_array = + map { $_ ? $json->decode($_) : () } @{ $args->{q} }; + + my $service_url = $query_params_array[0]->{url}; + + my $request = HTTP::Request->new( + GET => $service_url + ); + + my $ua = LWP::UserAgent->new; + my $response = $ua->simple_request($request); + + if ( $response->code >= 400 ) { + my $result = decode_json( $response->decoded_content ); + my $message; + if ( ref($result) eq 'ARRAY' ) { + for my $r (@$result) { + $message .= $r->{message}; + } + } + else { + $message = $result->{message} || $result->{Message} || q{}; + if ( $result->{errors} ) { + for my $e ( @{ $result->{errors} } ) { + $message .= $e->{message}; + } + } + } + warn sprintf "ERROR - Counter registry API %s returned %s - %s\n", + $service_url, + $response->code, $message; + if ( $response->code == 404 ) { + Koha::Exceptions::ObjectNotFound->throw($message); + } + elsif ( $response->code == 401 ) { + Koha::Exceptions::Authorization::Unauthorized->throw($message); + } + else { + die sprintf + "ERROR requesting Counter registry API\n%s\ncode %s: %s\n", + $service_url, + $response->code, + $message; + } + } + elsif ( $response->code == 204 ) { # No content + return; + } + + my $result = decode_json( $response->decoded_content ); + + return $c->render( + status => 200, + openapi => $result + ); +} + +1; diff --git a/api/v1/swagger/definitions/erm_counter_registry.yaml b/api/v1/swagger/definitions/erm_counter_registry.yaml new file mode 100644 index 0000000000..93c8ac4942 --- /dev/null +++ b/api/v1/swagger/definitions/erm_counter_registry.yaml @@ -0,0 +1,57 @@ +--- +type: object +properties: + id: + description: internally assigned identifier + type: string + name: + description: name of the platform + type: string + abbrev: + description: abbrev of the platform + type: + - string + - "null" + content_provider_name: + description: current content_provider_name of the platform + type: + - string + - "null" + host_types: + description: host_types for the platform + type: array + items: + type: object + address: + description: current address of the platform + type: + - string + - "null" + address_country: + description: current address country of the platform + type: + - object + - string + website: + description: current website of the platform + type: + - string + - "null" + contact: + description: current contact of the platform + type: + - object + - "null" + reports: + description: reports for the platform + type: array + items: + type: object + sushi_services: + description: sushi_services for the platform + type: array + items: + type: object + +additionalProperties: false + diff --git a/api/v1/swagger/definitions/erm_sushi_service.yaml b/api/v1/swagger/definitions/erm_sushi_service.yaml new file mode 100644 index 0000000000..e6f0b6895d --- /dev/null +++ b/api/v1/swagger/definitions/erm_sushi_service.yaml @@ -0,0 +1,114 @@ +--- +type: object +properties: + id: + description: internally assigned identifier + type: string + data_host: + description: data_host of the sushi service + type: + - string + - "null" + counter_release: + description: counter_release of the sushi service + type: + - string + - "null" + contact: + description: contact for the sushi service + type: array + items: + type: object + url: + description: url of the sushi service + type: + - string + - "null" + customer_id_info: + description: customer_id_info of the sushi service + type: + - string + - "null" + requestor_id_required: + description: is requestor_id required + type: + - boolean + - "null" + requestor_id_info: + description: requestor_id_info of the sushi service + type: + - string + - "null" + api_key_required: + description: is api_key required + type: + - boolean + - "null" + api_key_info: + description: api_key_info of the sushi service + type: + - string + - "null" + platform_specific_info: + description: platform_specific_info of the sushi service + type: + - string + - "null" + platform_attr_required: + description: is platform_attr required + type: + - boolean + - "null" + credentials_auto_expire: + description: do the credentials expire + type: + - boolean + - "null" + credentials_auto_expire_info: + description: credentials_auto_expire_info of the sushi service + type: + - string + - "null" + request_volume_limits_applied: + description: are limits applied + type: + - boolean + - "null" + request_volume_limits_info: + description: request_volume_limits_info of the sushi service + type: + - string + - "null" + ip_address_authorization: + description: is ip address auth required + type: + - boolean + - "null" + ip_address_authorization_info: + description: ip_address_authorization_info of the sushi service + type: + - string + - "null" + customizations_in_place: + description: are any customizations in place + type: + - boolean + - "null" + customizations_info: + description: customizations_info of the sushi service + type: + - string + - "null" + notification_count: + description: notification count + type: + - integer + - "null" + notifications_url: + description: notifications_url of the sushi service + type: + - string + - "null" + +additionalProperties: false + diff --git a/api/v1/swagger/paths/erm_counter_registries.yaml b/api/v1/swagger/paths/erm_counter_registries.yaml new file mode 100644 index 0000000000..948143db10 --- /dev/null +++ b/api/v1/swagger/paths/erm_counter_registries.yaml @@ -0,0 +1,45 @@ +--- +/erm/counter_registry: + get: + x-mojo-to: ERM::CounterRegistry#list + operationId: listCounterRegisteredPlatforms + tags: + - erm_counter_registry + summary: List platforms currently registered with the counter registry + produces: + - application/json + parameters: + - $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" + responses: + 200: + description: A list of counter registered platforms + schema: + items: + $ref: "../swagger.yaml#/definitions/erm_counter_registry" + type: array + 400: + description: Bad request + schema: + $ref: "../swagger.yaml#/definitions/error" + 403: + description: Access forbidden + 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: + erm: 1 \ No newline at end of file diff --git a/api/v1/swagger/paths/erm_sushi_services.yaml b/api/v1/swagger/paths/erm_sushi_services.yaml new file mode 100644 index 0000000000..31d32f8393 --- /dev/null +++ b/api/v1/swagger/paths/erm_sushi_services.yaml @@ -0,0 +1,45 @@ +--- +/erm/sushi_service: + get: + x-mojo-to: ERM::SushiServices#get + operationId: getSushiService + tags: + - erm_sushi_service + summary: Get the details for a sushi service from the counter registry + produces: + - application/json + parameters: + - $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" + responses: + 200: + description: A sushi service + schema: + items: + $ref: "../swagger.yaml#/definitions/erm_sushi_service" + type: object + 400: + description: Bad request + schema: + $ref: "../swagger.yaml#/definitions/error" + 403: + description: Access forbidden + 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: + erm: 1 \ No newline at end of file diff --git a/api/v1/swagger/swagger.yaml b/api/v1/swagger/swagger.yaml index b8445cc9be..9f067d3f3c 100644 --- a/api/v1/swagger/swagger.yaml +++ b/api/v1/swagger/swagger.yaml @@ -42,6 +42,8 @@ definitions: $ref: ./definitions/erm_agreement.yaml erm_counter_file: $ref: ./definitions/erm_counter_file.yaml + erm_counter_registry: + $ref: ./definitions/erm_counter_registry.yaml erm_counter_log: $ref: ./definitions/erm_counter_log.yaml erm_custom_report: @@ -56,6 +58,8 @@ definitions: $ref: ./definitions/erm_eholdings_resource.yaml erm_license: $ref: ./definitions/erm_license.yaml + erm_sushi_service: + $ref: ./definitions/erm_sushi_service.yaml erm_usage_data_provider: $ref: ./definitions/erm_usage_data_provider.yaml erm_usage_database: @@ -271,6 +275,8 @@ paths: $ref: "./paths/erm_counter_files.yaml#/~1erm~1counter_files~1{erm_counter_files_id}" "/erm/counter_files/{erm_counter_files_id}/file/content": $ref: "./paths/erm_counter_files.yaml#/~1erm~1counter_files~1{erm_counter_files_id}~1file~1content" + /erm/counter_registry: + $ref: ./paths/erm_counter_registries.yaml#/~1erm~1counter_registry /erm/default_usage_reports: $ref: ./paths/erm_default_usage_reports.yaml#/~1erm~1default_usage_reports "/erm/default_usage_reports/{erm_default_usage_report_id}": @@ -305,6 +311,8 @@ paths: $ref: ./paths/erm_licenses.yaml#/~1erm~1licenses "/erm/licenses/{license_id}": $ref: "./paths/erm_licenses.yaml#/~1erm~1licenses~1{license_id}" + /erm/sushi_service: + $ref: ./paths/erm_sushi_services.yaml#/~1erm~1sushi_service /erm/usage_data_providers: $ref: ./paths/erm_usage_data_providers.yaml#/~1erm~1usage_data_providers "/erm/usage_data_providers/{erm_usage_data_provider_id}": diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/UsageStatisticsDataProvidersFormAdd.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/UsageStatisticsDataProvidersFormAdd.vue index f50c7c995e..3bd8db0344 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/UsageStatisticsDataProvidersFormAdd.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/UsageStatisticsDataProvidersFormAdd.vue @@ -22,12 +22,55 @@ >{{ $__("Data provider name") }}: + + + + + {{ $__("Required") }} +
  • @@ -51,6 +95,7 @@ label="description" :reduce="status => status.value" :options="statuses" + :disabled="!selected_provider && !manual_form" />
  • @@ -78,6 +125,7 @@
  • @@ -91,12 +139,29 @@ v-model="usage_data_provider.report_types" label="description" :reduce="av => av.value" - :options="av_report_types" + :options="valid_report_types" multiple + :disabled="!selected_provider && !manual_form" :required=" !usage_data_provider.report_types.length " > +