From ff070c185d341a2e554c4df982388fcbe5fd9c03 Mon Sep 17 00:00:00 2001 From: Jeff Davis Date: Tue, 7 Feb 2017 15:23:12 -0800 Subject: [PATCH] LP#1541559: ebook API handler for OverDrive Signed-off-by: Jeff Davis Signed-off-by: Kathy Lussier --- Open-ILS/src/perlmods/MANIFEST | 1 + .../OpenILS/Application/EbookAPI/OverDrive.pm | 561 ++++++++++++++++++ .../t/23-OpenILS-Application-EbookAPI.t | 3 +- Open-ILS/src/sql/Pg/950.data.seed-values.sql | 134 +++++ ...X.data.org-setting.ebook-api-overdrive.sql | 141 +++++ 5 files changed, 839 insertions(+), 1 deletion(-) create mode 100644 Open-ILS/src/perlmods/lib/OpenILS/Application/EbookAPI/OverDrive.pm create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.data.org-setting.ebook-api-overdrive.sql diff --git a/Open-ILS/src/perlmods/MANIFEST b/Open-ILS/src/perlmods/MANIFEST index 8de8df8f67..d3f1deb42c 100644 --- a/Open-ILS/src/perlmods/MANIFEST +++ b/Open-ILS/src/perlmods/MANIFEST @@ -41,6 +41,7 @@ lib/OpenILS/Application/Circ/Transit.pm lib/OpenILS/Application/Collections.pm lib/OpenILS/Application/EbookAPI.pm lib/OpenILS/Application/EbookAPI/Test.pm +lib/OpenILS/Application/EbookAPI/OverDrive.pm lib/OpenILS/Application/Fielder.pm lib/OpenILS/Application/PermaCrud.pm lib/OpenILS/Application/Proxy.pm diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/EbookAPI/OverDrive.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/EbookAPI/OverDrive.pm new file mode 100644 index 0000000000..6bb5be5a1d --- /dev/null +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/EbookAPI/OverDrive.pm @@ -0,0 +1,561 @@ +#!/usr/bin/perl + +# Copyright (C) 2015 BC Libraries Cooperative +# +# This program 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 2 +# of the License, or (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +package OpenILS::Application::EbookAPI::OverDrive; + +use strict; +use warnings; + +use OpenILS::Application; +use OpenILS::Application::EbookAPI; +use base qw/OpenILS::Application::EbookAPI/; +use OpenSRF::AppSession; +use OpenSRF::EX qw(:try); +use OpenSRF::Utils::SettingsClient; +use OpenSRF::Utils::Logger qw($logger); +use OpenSRF::Utils::Cache; +use OpenILS::Application::AppUtils; +use Data::Dumper; + +sub new { + my( $class, $args ) = @_; + $class = ref $class || $class; + return bless $args, $class; +} + +sub ou { + my $self = shift; + return $self->{ou}; +} + +sub vendor { + my $self = shift; + return $self->{vendor}; +} + +sub session_id { + my $self = shift; + return $self->{session_id}; +} + +sub account_id { + my $self = shift; + return $self->{account_id}; +} + +sub websiteid { + my $self = shift; + return $self->{websiteid}; +} + +sub authorizationname { + my $self = shift; + return $self->{authorizationname}; +} + +sub basic_token { + my $self = shift; + return $self->{basic_token}; +} + +sub bearer_token { + my $self = shift; + return $self->{bearer_token}; +} + +sub collection_token { + my $self = shift; + return $self->{collection_token}; +} + +sub granted_auth_uri { + my $self = shift; + return $self->{granted_auth_uri}; +} + +sub password_required { + my $self = shift; + return $self->{password_required}; +} + +sub patron_token { + my $self = shift; + return $self->{patron_token}; +} + +sub initialize { + my $self = shift; + my $ou = $self->{ou}; + + my $discovery_base_uri = OpenILS::Application::AppUtils->ou_ancestor_setting_value($ou, 'ebook_api.overdrive.discovery_base_uri'); + $self->{discovery_base_uri} = $discovery_base_uri || 'http://api.overdrive.com/v1'; + my $circulation_base_uri = OpenILS::Application::AppUtils->ou_ancestor_setting_value($ou, 'ebook_api.overdrive.circulation_base_uri'); + $self->{circulation_base_uri} = $circulation_base_uri || 'http://patron.api.overdrive.com/v1'; + + my $account_id = OpenILS::Application::AppUtils->ou_ancestor_setting_value($ou, 'ebook_api.overdrive.account_id'); + if ($account_id) { + $self->{account_id} = $account_id; + } else { + $logger->error("EbookAPI: no OverDrive account ID found for org unit $ou"); + return; + } + + my $websiteid = OpenILS::Application::AppUtils->ou_ancestor_setting_value($ou, 'ebook_api.overdrive.websiteid'); + if ($websiteid) { + $self->{websiteid} = $websiteid; + } else { + $logger->error("EbookAPI: no OverDrive website ID found for org unit $ou"); + return; + } + + my $authorizationname = OpenILS::Application::AppUtils->ou_ancestor_setting_value($ou, 'ebook_api.overdrive.authorizationname'); + if ($authorizationname) { + $self->{authorizationname} = $authorizationname; + } else { + $logger->error("EbookAPI: no OverDrive authorization name found for org unit $ou"); + return; + } + + my $basic_token = OpenILS::Application::AppUtils->ou_ancestor_setting_value($ou, 'ebook_api.overdrive.basic_token'); + if ($basic_token) { + $self->{basic_token} = $basic_token; + } else { + $logger->error("EbookAPI: no OverDrive basic token found for org unit $ou"); + return; + } + + my $granted_auth_uri = OpenILS::Application::AppUtils->ou_ancestor_setting_value($ou, 'ebook_api.overdrive.granted_auth_redirect_uri'); + if ($granted_auth_uri) { + $self->{granted_auth_uri} = $granted_auth_uri; + } + + my $password_required = OpenILS::Application::AppUtils->ou_ancestor_setting_value($ou, 'ebook_api.overdrive.password_required') || 0; + $self->{password_required} = $password_required; + + return $self; + +} + +# Wrapper method for HTTP requests. +sub handle_http_request { + my $self = shift; + my $req = shift; + + # Prep our request using defaults. + $req->{method} = 'GET' if (!$req->{method}); + $req = $self->set_http_headers($req); + + # Send the request. + my $res = $self->request($req, $self->{session_id}); + + $logger->info("EbookAPI: raw OverDrive HTTP response: " . Dumper $res); + + # A "401 Unauthorized" response means we need to re-auth our client or patron. + if (defined ($res) && $res->{status} =~ /^401/) { + $logger->info("EbookAPI: 401 response received from OverDrive, re-authorizing..."); + + # Always re-auth client to ensure we have an up-to-date client token. + $self->do_client_auth(); + + # If we're using a Circulation API, redo patron auth too. + my $circulation_base_uri = $self->{circulation_base_uri}; + if ($req->{uri} =~ /^$circulation_base_uri/) { + $self->do_patron_auth(); + } + + # Now we can update our headers with our fresh client/patron tokens + # and re-send our request. + $req = $self->set_http_headers($req); + return $self->request($req, $self->{session_id}); + } + + # For any non-401 response (including no response at all), + # just return whatever response we got (if any). + return $res; +} + +# Set the correct headers for our request. +# Authorization headers are determined by which API we're using: +# - Circulation APIs use a patron access token. +# - Discovery APIs use a regular access token. +# - For other APIs, fallback to our basic token. +sub set_http_headers { + my $self = shift; + my $req = shift; + $req->{headers} = {} if (!$req->{headers}); + if (!$req->{headers}->{Authorization}) { + my $auth_type; + my $token; + my $circulation_base_uri = $self->{circulation_base_uri}; + my $discovery_base_uri = $self->{discovery_base_uri}; + if ($req->{uri} =~ /^$circulation_base_uri/) { + $auth_type = 'Bearer'; + $token = $self->{patron_token}; + } elsif ($req->{uri} =~ /^$discovery_base_uri/) { + $auth_type = 'Bearer'; + $token = $self->{bearer_token}; + } else { + $auth_type = 'Basic'; + $token = $self->{basic_token}; + } + if (!$token) { + $logger->error("EbookAPI: unable to set HTTP Authorization header without token"); + $logger->error("EbookAPI: failed request: " . Dumper $req); + return; + } else { + $req->{headers}->{Authorization} = "$auth_type $token"; + } + } + return $req; +} + +# POST /token HTTP/1.1 +# Host: oauth.overdrive.com +# Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW +# +# grant_type=client_credentials +sub do_client_auth { + my $self = shift; + my $req = { + method => 'POST', + uri => 'https://oauth.overdrive.com/token', + headers => { + 'Authorization' => 'Basic ' . $self->{basic_token}, + 'Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8' + }, + content => 'grant_type=client_credentials' + }; + my $res = $self->request($req, $self->{session_id}); + + if (defined ($res)) { + if ($res->{content}->{access_token}) { + # save our access token for future use + $self->{bearer_token} = $res->{content}->{access_token}; + # use access token to grab other library info (e.g. collection token) + $self->get_library_info(); + return $res; + } else { + $logger->error("EbookAPI: bearer token not received from OverDrive API"); + $logger->error("EbookAPI: bad response: " . Dumper $res); + } + } else { + $logger->error("EbookAPI: no client authentication response from OverDrive API"); + } + return; +} + +sub do_patron_auth { + my $self = shift; + my @args = @_; + if ($self->{granted_auth_uri}) { + return $self->do_granted_patron_auth(@args); + } else { + return $self->do_basic_patron_auth(@args); + } +} + +# TODO +sub do_granted_patron_auth { +} + +# POST /patrontoken HTTP/1.1 +# Host: oauth-patron.overdrive.com +# Authorization: Basic {Base64-encoded string} +# Content-Type: application/x-www-form-urlencoded;charset=UTF-8 +# +# grant_type=password&username=1234567890&password=1234&scope=websiteid:12345 authorizationname:default +# OR: +# grant_type=password&username=1234567890&password=[ignore]&password_required=false&scope=websiteid:12345 authorizationname:default +sub do_basic_patron_auth { + my $self = shift; + my $barcode = shift; + + if ($barcode) { + if (!$self->{patron_barcode}) { + $self->{patron_barcode} = $barcode; + } elsif ($barcode ne $self->{patron_barcode}) { + $logger->error("EbookAPI: patron barcode in auth request does not match patron barcode for this session"); + return; + } + } else { + if (!$self->{patron_barcode}) { + $logger->error("EbookAPI: Cannot authenticate patron with unknown barcode"); + } else { + $barcode = $self->{patron_barcode}; + } + } + + # TODO handle cached/expired tokens? + # Making a request using an expired token will give a 401 Unauthorized error. + # Handle this appropriately. + + # request content is an ugly url-encoded string + my $pw = (defined $self->{patron_password}) ? $self->{patron_password} : ''; + my $content = 'grant_type=password'; + $content .= "&username=$barcode"; + if ($self->{password_required}) { + $content .= "&password=$pw"; + } else { + $content .= '&password=xxx&password_required=false' + } + $content .= '&scope=websiteid:' . $self->{websiteid} . ' authorizationname:' . $self->{authorizationname}; + + my $req = { + method => 'POST', + uri => 'https://oauth-patron.overdrive.com/patrontoken', + headers => { + 'Authorization' => 'Basic ' . $self->{basic_token}, + 'Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8' + }, + content => $content + }; + my $res = $self->request($req, $self->{session_id}); + + if (defined ($res)) { + if ($res->{content}->{access_token}) { + $self->{patron_token} = $res->{content}->{access_token}; + return $self->{patron_token}; + } else { + $logger->error("EbookAPI: patron access token not received from OverDrive API"); + } + } else { + $logger->error("EbookAPI: no patron authentication response from OverDrive API"); + } + return; +} + +# GET http://api.overdrive.com/v1/libraries/1225 +# User-Agent: {Your application} +# Authorization: Bearer {OAuth access token} +# Host: api.overdrive.com +sub get_library_info { + my $self = shift; + my $library_id = $self->{account_id}; + my $req = { + method => 'GET', + uri => $self->{discovery_base_uri} . "/libraries/$library_id" + }; + if (my $res = $self->handle_http_request($req, $self->{session_id})) { + $self->{collection_token} = $res->{content}->{collectionToken}; + return $self->{collection_token}; + } else { + $logger->error("EbookAPI: OverDrive Library Account API request failed"); + return; + } +} + +# GET http://api.overdrive.com/v1/collections/v1L1BYwAAAA2Q/products/76c1b7d0-17f4-4c05-8397-c66c17411584/metadata +# User-Agent: {Your application} +# Authorization: Bearer {OAuth access token} +# Host: api.overdrive.com +sub get_title_info { + my $self = shift; + my $title_id = shift; + $self->do_client_auth() if (!$self->{bearer_token}); + $self->get_library_info() if (!$self->{collection_token}); + my $collection_token = $self->{collection_token}; + my $req = { + method => 'GET', + uri => $self->{discovery_base_uri} . "/collections/$collection_token/products/$title_id/metadata" + }; + if (my $res = $self->handle_http_request($req, $self->{session_id})) { + if ($res->{content}->{title}) { + return { + title => $res->{content}->{title}, + author => $res->{content}->{creators}[0]{name} + }; + } else { + $logger->error("EbookAPI: OverDrive metadata lookup failed for $title_id"); + } + } else { + $logger->error("EbookAPI: no metadata response from OverDrive API"); + } + return; +} + +# GET http://api.overdrive.com/v1/collections/L1BAAEAAA2i/products/76C1B7D0-17F4-4C05-8397-C66C17411584/availability +# User-Agent: {Your application} +# Authorization: Bearer {OAuth access token} +# Host: api.overdrive.com +sub do_availability_lookup { + my $self = shift; + my $title_id = shift; + $self->do_client_auth() if (!$self->{bearer_token}); + $self->get_library_info() if (!$self->{collection_token}); + my $req = { + method => 'GET', + uri => $self->{discovery_base_uri} . "/collections/" . $self->{collection_token} . "/products/$title_id/availability" + }; + if (my $res = $self->handle_http_request($req, $self->{session_id})) { + return $res->{content}->{available}; + } else { + $logger->error("EbookAPI: could not retrieve OverDrive availability for title $title_id"); + return; + } +} + +# Holdings lookup has two parts: +# +# 1. Copy availability: as above, but grab more details. +# +# 2. Formats: +# GET https://api.overdrive.com/v1/collections/v1L1BYwAAAA2Q/products/76c1b7d0-17f4-4c05-8397-c66c17411584/metadata +# User-Agent: {Your application} +# Authorization: Bearer {OAuth access token} +# Host: api.overdrive.com +# +sub do_holdings_lookup { + my ($self, $title_id) = @_; + $self->do_client_auth() if (!$self->{bearer_token}); + $self->get_library_info() if (!$self->{collection_token}); + my $collection_token = $self->{collection_token}; + + # prepare data structure to be used as return value + my $holdings = { + copies_owned => 0, + copies_available => 0, + formats => [] + }; + + # request copy availability totals + my $avail_req = { + method => 'GET', + uri => $self->{discovery_base_uri} . "/collections/$collection_token/products/$title_id/availability" + }; + if (my $avail_res = $self->handle_http_request($avail_req, $self->{session_id})) { + $holdings->{copies_owned} = $avail_res->{content}->{copiesOwned}; + $holdings->{copies_available} = $avail_res->{content}->{copiesAvailable}; + } else { + $logger->error("EbookAPI: failed to retrieve OverDrive holdings counts for title $title_id"); + } + + # request available formats + my $format_req = { + method => 'GET', + uri => $self->{discovery_base_uri} . "/collections/$collection_token/products/$title_id/metadata" + }; + if (my $format_res = $self->handle_http_request($format_req, $self->{session_id})) { + if ($format_res->{content}->{formats}) { + foreach my $f (@{$format_res->{content}->{formats}}) { + push @{$holdings->{formats}}, $f->{name}; + } + } else { + $logger->info("EbookAPI: OverDrive holdings format request for title $title_id contained no format information"); + } + } else { + $logger->error("EbookAPI: failed to retrieve OverDrive holdings formats for title $title_id"); + } + + return $holdings; +} + +# List of patron checkouts: +# GET http://patron.api.overdrive.com/v1/patrons/me/checkouts +# User-Agent: {Your application} +# Authorization: Bearer {OAuth patron access token} +# Host: patron.api.overdrive.com +# +# Response looks like this: +# { +# "totalItems": 4, +# "totalCheckouts": 2, +# "checkouts": [ +# { +# "reserveId": "A03EAC2C-C088-46C6-B9E9-59D6C11A3596", +# "expires": "2015-08-11T18:53:00Z", +# ... +# } +# ], +# ... +# } +# +# To get title metadata (e.g. title/author), do get_title_info(reserveId). +sub get_patron_checkouts { + my $self = shift; + my $patron_token = shift; + if (my $res = $self->do_get_patron_xacts('checkouts', $patron_token)) { + my $checkouts = []; + foreach my $checkout (@{$res->{content}->{checkouts}}) { + my $title_id = $checkout->{reserveId}; + my $title_info = $self->get_title_info($title_id); + # TODO get download URL - need to "lock in" a format first, see OD Checkouts API docs + push @$checkouts, { + title_id => $title_id, + due_date => $checkout->{expires}, + title => $title_info->{title}, + author => $title_info->{author} + } + }; + $self->{checkouts} = $checkouts; + return $self->{checkouts}; + } else { + $logger->error("EbookAPI: unable to retrieve OverDrive checkouts for patron " . $self->{patron_barcode}); + return; + } +} + +sub get_patron_holds { + my $self = shift; + my $patron_token = shift; + if (my $res = $self->do_get_patron_xacts('holds', $patron_token)) { + my $holds = []; + foreach my $hold (@{$res->{content}->{holds}}) { + my $title_id = $hold->{reserveId}; + my $title_info = $self->get_title_info($title_id); + my $this_hold = { + title_id => $title_id, + queue_position => $hold->{holdListPosition}, + queue_size => $hold->{numberOfHolds}, + # TODO: special handling for ready-to-checkout holds + is_ready => ( $hold->{actions}->{checkout} ) ? 1 : 0, + create_date => $hold->{holdPlacedDate}, + expire_date => ( $hold->{holdExpires} ) ? $hold->{holdExpires} : '-', + title => $title_info->{title}, + author => $title_info->{author} + }; + # TODO: hold suspensions + push @$holds, $this_hold; + } + $self->{holds} = $holds; + return $self->{holds}; + } else { + $logger->error("EbookAPI: unable to retrieve OverDrive holds for patron " . $self->{patron_barcode}); + return; + } +} + +# generic function for retrieving patron transactions +sub do_get_patron_xacts { + my $self = shift; + my $xact_type = shift; + my $patron_token = shift; + if (!$patron_token) { + if ($self->{patron_barcode}) { + $self->do_client_auth() if (!$self->{bearer_token}); + $self->do_patron_auth(); + } else { + $logger->error("EbookAPI: Cannot retrieve OverDrive $xact_type with no patron information"); + } + } + my $req = { + method => 'GET', + uri => $self->{circulation_base_uri} . "/patrons/me/$xact_type" + }; + return $self->handle_http_request($req, $self->{session_id}); +} + diff --git a/Open-ILS/src/perlmods/t/23-OpenILS-Application-EbookAPI.t b/Open-ILS/src/perlmods/t/23-OpenILS-Application-EbookAPI.t index 338f043f4c..44a1d42298 100644 --- a/Open-ILS/src/perlmods/t/23-OpenILS-Application-EbookAPI.t +++ b/Open-ILS/src/perlmods/t/23-OpenILS-Application-EbookAPI.t @@ -1,9 +1,10 @@ #!perl -T -use Test::More tests => 2; +use Test::More tests => 3; BEGIN { use_ok( 'OpenILS::Application::EbookAPI' ); use_ok( 'OpenILS::Application::EbookAPI::Test' ); + use_ok( 'OpenILS::Application::EbookAPI::OverDrive' ); } diff --git a/Open-ILS/src/sql/Pg/950.data.seed-values.sql b/Open-ILS/src/sql/Pg/950.data.seed-values.sql index d294365374..08f8877a2b 100644 --- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql +++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql @@ -16666,3 +16666,137 @@ INSERT INTO config.global_flag (name, label, value, enabled) VALUES ( TRUE ); +INSERT INTO config.settings_group (name, label) + VALUES ('ebook_api', 'Ebook API Integration'); + +INSERT INTO config.org_unit_setting_type + (name, label, description, grp, datatype) +VALUES ( + 'ebook_api.overdrive.discovery_base_uri', + oils_i18n_gettext( + 'ebook_api.overdrive.discovery_base_uri', + 'OverDrive Discovery API Base URI', + 'coust', + 'label' + ), + oils_i18n_gettext( + 'ebook_api.overdrive.discovery_base_uri', + 'Base URI for OverDrive Discovery API (defaults to http://api.overdrive.com/v1)', + 'coust', + 'description' + ), + 'ebook_api', + 'string' +),( + 'ebook_api.overdrive.circulation_base_uri', + oils_i18n_gettext( + 'ebook_api.overdrive.circulation_base_uri', + 'OverDrive Circulation API Base URI', + 'coust', + 'label' + ), + oils_i18n_gettext( + 'ebook_api.overdrive.circulation_base_uri', + 'Base URI for OverDrive Circulation API (defaults to http://patron.api.overdrive.com/v1)', + 'coust', + 'description' + ), + 'ebook_api', + 'string' +),( + 'ebook_api.overdrive.account_id', + oils_i18n_gettext( + 'ebook_api.overdrive.account_id', + 'OverDrive Account ID', + 'coust', + 'label' + ), + oils_i18n_gettext( + 'ebook_api.overdrive.account_id', + 'Account ID (a.k.a. Library ID) for this library, as assigned by OverDrive', + 'coust', + 'description' + ), + 'ebook_api', + 'string' +),( + 'ebook_api.overdrive.websiteid', + oils_i18n_gettext( + 'ebook_api.overdrive.websiteid', + 'OverDrive Website ID', + 'coust', + 'label' + ), + oils_i18n_gettext( + 'ebook_api.overdrive.websiteid', + 'Website ID for this library, as assigned by OverDrive', + 'coust', + 'description' + ), + 'ebook_api', + 'string' +),( + 'ebook_api.overdrive.authorizationname', + oils_i18n_gettext( + 'ebook_api.overdrive.authorizationname', + 'OverDrive Authorization Name', + 'coust', + 'label' + ), + oils_i18n_gettext( + 'ebook_api.overdrive.authorizationname', + 'Authorization name for this library, as assigned by OverDrive', + 'coust', + 'description' + ), + 'ebook_api', + 'string' +),( + 'ebook_api.overdrive.basic_token', + oils_i18n_gettext( + 'ebook_api.overdrive.basic_token', + 'OverDrive Basic Token', + 'coust', + 'label' + ), + oils_i18n_gettext( + 'ebook_api.overdrive.basic_token', + 'Basic token for client authentication with OverDrive API (supplied by OverDrive)', + 'coust', + 'description' + ), + 'ebook_api', + 'string' +),( + 'ebook_api.overdrive.granted_auth_redirect_uri', + oils_i18n_gettext( + 'ebook_api.overdrive.granted_auth_redirect_uri', + 'OverDrive Granted Authorization Redirect URI', + 'coust', + 'label' + ), + oils_i18n_gettext( + 'ebook_api.overdrive.granted_auth_redirect_uri', + 'URI provided to OverDrive for use with granted authorization', + 'coust', + 'description' + ), + 'ebook_api', + 'string' +),( + 'ebook_api.overdrive.password_required', + oils_i18n_gettext( + 'ebook_api.overdrive.password_required', + 'OverDrive Password Required', + 'coust', + 'label' + ), + oils_i18n_gettext( + 'ebook_api.overdrive.password_required', + 'Does this library require a password when authenticating patrons with the OverDrive API?', + 'coust', + 'description' + ), + 'ebook_api', + 'bool' +); diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.org-setting.ebook-api-overdrive.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.org-setting.ebook-api-overdrive.sql new file mode 100644 index 0000000000..7e10262c46 --- /dev/null +++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.org-setting.ebook-api-overdrive.sql @@ -0,0 +1,141 @@ +BEGIN; + +SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version); + +INSERT INTO config.settings_group (name, label) + VALUES ('ebook_api', 'Ebook API Integration'); + +INSERT INTO config.org_unit_setting_type + (name, label, description, grp, datatype) +VALUES ( + 'ebook_api.overdrive.discovery_base_uri', + oils_i18n_gettext( + 'ebook_api.overdrive.discovery_base_uri', + 'OverDrive Discovery API Base URI', + 'coust', + 'label' + ), + oils_i18n_gettext( + 'ebook_api.overdrive.discovery_base_uri', + 'Base URI for OverDrive Discovery API (defaults to http://api.overdrive.com/v1)', + 'coust', + 'description' + ), + 'ebook_api', + 'string' +),( + 'ebook_api.overdrive.circulation_base_uri', + oils_i18n_gettext( + 'ebook_api.overdrive.circulation_base_uri', + 'OverDrive Circulation API Base URI', + 'coust', + 'label' + ), + oils_i18n_gettext( + 'ebook_api.overdrive.circulation_base_uri', + 'Base URI for OverDrive Circulation API (defaults to http://patron.api.overdrive.com/v1)', + 'coust', + 'description' + ), + 'ebook_api', + 'string' +),( + 'ebook_api.overdrive.account_id', + oils_i18n_gettext( + 'ebook_api.overdrive.account_id', + 'OverDrive Account ID', + 'coust', + 'label' + ), + oils_i18n_gettext( + 'ebook_api.overdrive.account_id', + 'Account ID (a.k.a. Library ID) for this library, as assigned by OverDrive', + 'coust', + 'description' + ), + 'ebook_api', + 'string' +),( + 'ebook_api.overdrive.websiteid', + oils_i18n_gettext( + 'ebook_api.overdrive.websiteid', + 'OverDrive Website ID', + 'coust', + 'label' + ), + oils_i18n_gettext( + 'ebook_api.overdrive.websiteid', + 'Website ID for this library, as assigned by OverDrive', + 'coust', + 'description' + ), + 'ebook_api', + 'string' +),( + 'ebook_api.overdrive.authorizationname', + oils_i18n_gettext( + 'ebook_api.overdrive.authorizationname', + 'OverDrive Authorization Name', + 'coust', + 'label' + ), + oils_i18n_gettext( + 'ebook_api.overdrive.authorizationname', + 'Authorization name for this library, as assigned by OverDrive', + 'coust', + 'description' + ), + 'ebook_api', + 'string' +),( + 'ebook_api.overdrive.basic_token', + oils_i18n_gettext( + 'ebook_api.overdrive.basic_token', + 'OverDrive Basic Token', + 'coust', + 'label' + ), + oils_i18n_gettext( + 'ebook_api.overdrive.basic_token', + 'Basic token for client authentication with OverDrive API (supplied by OverDrive)', + 'coust', + 'description' + ), + 'ebook_api', + 'string' +),( + 'ebook_api.overdrive.granted_auth_redirect_uri', + oils_i18n_gettext( + 'ebook_api.overdrive.granted_auth_redirect_uri', + 'OverDrive Granted Authorization Redirect URI', + 'coust', + 'label' + ), + oils_i18n_gettext( + 'ebook_api.overdrive.granted_auth_redirect_uri', + 'URI provided to OverDrive for use with granted authorization', + 'coust', + 'description' + ), + 'ebook_api', + 'string' +),( + 'ebook_api.overdrive.password_required', + oils_i18n_gettext( + 'ebook_api.overdrive.password_required', + 'OverDrive Password Required', + 'coust', + 'label' + ), + oils_i18n_gettext( + 'ebook_api.overdrive.password_required', + 'Does this library require a password when authenticating patrons with the OverDrive API?', + 'coust', + 'description' + ), + 'ebook_api', + 'bool' +); + +COMMIT; + -- 2.43.2