Skip to content

Commit

Permalink
Add recommendation module for LibGuides Profiles (vufind-org#2977)
Browse files Browse the repository at this point in the history
  • Loading branch information
maccabeelevine authored and Brent Palmer committed Aug 5, 2023
1 parent ae63aad commit 105363b
Show file tree
Hide file tree
Showing 13 changed files with 886 additions and 0 deletions.
27 changes: 27 additions & 0 deletions config/vufind/LibGuidesAPI.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
; This file is used for the LibGuides *API*, which uses an
; oauth connection mechanism. This API is currently used
; by the LibGuidesProfile recommendation module.

; LibGuides API documentation:
; https://ask.springshare.com/libguides/faq/873

; This file is NOT used by the LibGuides (research guides)
; or LibGuidesAZ (database list) data sources, which
; do not actually use the LibGuides API
; -- they retrieve data through a LibGuides Search Box widget.
; https://ask.springshare.com/libguides/faq/867
; See LibGuides.ini and LibGuidesAZ.ini for that configuration.

[General]
; Client Id & Secret provided by LibGuides API configuration
; See https://ask.springshare.com/libguides/faq/873#api-auth
;client_id = 123
;client_secret = ABCD

; Base URL of the LibGuides API
api_base_url = https://lgapi-us.libapps.com/1.2

; Calls to GET (...)/accounts endpoint
[GetAccounts]
; Duration (seconds) to cache response data. Default is 600.
;cache_lifetime = 600
2 changes: 2 additions & 0 deletions config/vufind/contentsecuritypolicy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ worker-src[] = "blob:"
style-src[] = "'self'"
style-src[] = "'unsafe-inline'"
img-src[] = "'self'"
; If you are using LibGuidesProfile recommendation module, uncomment the line below
;img-src[] = libapps.s3.amazonaws.com
; If you are using MapSelection recommendation module, uncomment a line below
; for the basemap you are using:
;img-src[] = "https://maps.wikimedia.org"
Expand Down
5 changes: 5 additions & 0 deletions config/vufind/searches.ini
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,11 @@ WorkKeys = year
; FacetCloud:[ini section]:[ini name]
; Same functionality as ExpandFacets, but with a more compact interface to
; allow the display of more values.
; LibGuidesProfile
; Display a single LibGuides Profile for a LibGuides user (likely a librarian)
; who owns a subject guide whose title most closely matches the search terms.
; Uses configuration in LibGuidesAPI.ini and requires configuration in
; contentsecuritypolicy.ini.
; LibGuidesResults:[GET parameter]:[result limit]
; Display LibGuides research guides search results matching the terms found in
; the specified GET parameter (default = "lookfor"), limited to a specified
Expand Down
1 change: 1 addition & 0 deletions languages/en.ini
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,7 @@ Last Name = "Last Name"
Last Search Result = "Last Search Result"
less = "less"
less_ellipsis = "less…"
libguides_profile_suggestion_heading = "Talk to a Subject Librarian"
libguides_recommendations = "Research Guide Results"
libguides_recommendations_more = "More Research Guide Results"
libguidesaz_recommendations = "Database Results"
Expand Down
1 change: 1 addition & 0 deletions module/VuFind/config/module.config.php
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@
'VuFind\Config\PluginManager' => 'VuFind\Config\PluginManagerFactory',
'VuFind\Config\SearchSpecsReader' => 'VuFind\Config\YamlReaderFactory',
'VuFind\Config\YamlReader' => 'VuFind\Config\YamlReaderFactory',
'VuFind\Connection\LibGuides' => 'VuFind\Connection\LibGuidesFactory',
'VuFind\Connection\Relais' => 'VuFind\Connection\RelaisFactory',
'VuFind\Connection\WorldCatUtils' => 'VuFind\Connection\WorldCatUtilsFactory',
'VuFind\Content\PageLocator' => 'VuFind\Content\PageLocatorFactory',
Expand Down
190 changes: 190 additions & 0 deletions module/VuFind/src/VuFind/Connection/LibGuides.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
<?php

/**
* LibGuides API connection class.
*
* PHP version 8
*
* Copyright (C) Villanova University 2023.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* 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
*
* @category VuFind
* @package Connection
* @author Demian Katz <demian.katz@villanova.edu>
* @author Brent Palmer <brent-palmer@icpl.org>
* @author Maccabee Levine <msl321@lehigh.edu>
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
* @link https://vufind.org
*/

namespace VuFind\Connection;

use Exception;
use Laminas\Log\LoggerAwareInterface;

/**
* LibGuides API connection class.
*
* Note: This is for the LibGuides API used by the LibGuidesProfile recommendation service,
* this is *not* for the LibGuides search widget "API" used by the LibGuides and LibGuidesAZ
* data sources.
*
* Closely adapted from VuFind\DigitalContent\OverdriveConnector.
*
* @category VuFind
* @package Connection
* @author Demian Katz <demian.katz@villanova.edu>
* @author Brent Palmer <brent-palmer@icpl.org>
* @author Maccabee Levine <msl321@lehigh.edu>
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
* @link https://vufind.org
*/
class LibGuides implements
OauthServiceInterface,
\VuFindHttp\HttpServiceAwareInterface,
LoggerAwareInterface
{
use OauthServiceTrait;
use \VuFindHttp\HttpServiceAwareTrait;
use \VuFind\Log\LoggerAwareTrait {
logError as error;
}

/**
* HTTP Client
*
* @var \Laminas\Http\HttpClient
*/
protected $client;

/**
* Base URL of the LibGuides API
*
* @var string
*/
protected $baseUrl;

/**
* Client ID for a client_credentials grant
*
* @var string
*/
protected $clientId;

/**
* Client Secret for a client_credentials grant
*
* @var string
*/
protected $clientSecret;

/**
* User agent to send in header
*
* @var string
*/
protected $userAgent = "VuFind";

/**
* Constructor
*
* @param Config $config LibGuides API configuration object
* @param \Laminas\Http\Client $client HTTP client
*
* @link https://ask.springshare.com/libguides/faq/873#api-auth
*/
public function __construct(
$config,
$client
) {
$this->client = $client;
$this->baseUrl = $config->General->api_base_url;
$this->clientId = $config->General->client_id;
$this->clientSecret = $config->General->client_secret;
}

/**
* Load all LibGuides accounts.
*
* @return object|null A JSON object of all LibGuides accounts, or null
* if an error occurs
*/
public function getAccounts()
{
$tokenData = $this->authenticateWithClientCredentials(
$this->baseUrl . "/oauth/token",
$this->clientId,
$this->clientSecret
);
if (!$tokenData) {
return null;
}

$headers = [];
if (
isset($tokenData->token_type)
&& isset($tokenData->access_token)
) {
$headers[] = "Authorization: {$tokenData->token_type} "
. $tokenData->access_token;
}
$headers[] = "User-Agent: " . $this->userAgent;

$this->client->setHeaders($headers);
$this->client->setMethod("GET");
$this->client->setUri(
$this->baseUrl . "/accounts?expand=profile,subjects"
);
try {
$response = $this->client->send();
} catch (Exception $ex) {
$this->error(
"Exception during request: " .
$ex->getMessage()
);
return null;
}

if ($response->isServerError()) {
$this->error(
"LibGuides API HTTP Error: " .
$response->getStatusCode()
);
$this->debug("Request: " . $this->client->getRequest());
$this->debug("Response: " . $this->client->getResponse());
return null;
}
$body = $response->getBody();
$returnVal = json_decode($body);
$this->debug(
"Return from LibGuides API Call: " . print_r($returnVal, true)
);
if ($returnVal != null) {
if (isset($returnVal->errorCode)) {
// In some cases, this should be returned perhaps...
$this->error("LibGuides Error: " . $returnVal->errorCode);
}
return $returnVal;
} else {
$this->error(
"LibGuides API Error: Nothing returned from API call."
);
$this->debug(
"Body return from LibGuides API Call: " . print_r($body, true)
);
}
return null;
}
}
87 changes: 87 additions & 0 deletions module/VuFind/src/VuFind/Connection/LibGuidesFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?php

/**
* Libuides API connection factory.
*
* PHP version 8
*
* Copyright (C) Villanova University 2023.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* 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
*
* @category VuFind
* @package Connection
* @author Demian Katz <demian.katz@villanova.edu>
* @author Maccabee Levine <msl321@lehigh.edu>
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
* @link https://vufind.org/wiki/development Wiki
*/

namespace VuFind\Connection;

use Laminas\ServiceManager\Exception\ServiceNotCreatedException;
use Laminas\ServiceManager\Exception\ServiceNotFoundException;
use Laminas\ServiceManager\Factory\FactoryInterface;
use Psr\Container\ContainerExceptionInterface as ContainerException;
use Psr\Container\ContainerInterface;

/**
* LibGuides API connection factory.
*
* @category VuFind
* @package Connection
* @author Demian Katz <demian.katz@villanova.edu>
* @author Maccabee Levine <msl321@lehigh.edu>
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
* @link https://vufind.org/wiki/development Wiki
*/
class LibGuidesFactory implements FactoryInterface
{
/**
* Create an object
*
* @param ContainerInterface $container Service manager
* @param string $requestedName Service being created
* @param null|array $options Extra options (optional)
*
* @return object
*
* @throws ServiceNotFoundException if unable to resolve the service.
* @throws ServiceNotCreatedException if an exception is raised when
* creating a service.
* @throws ContainerException&\Throwable if any other error occurs
*/
public function __invoke(
ContainerInterface $container,
$requestedName,
array $options = null
) {
if (!empty($options)) {
throw new \Exception('Unexpected options sent to factory.');
}
$config = $container->get(\VuFind\Config\PluginManager::class)
->get('LibGuidesAPI');
if (!isset($config->General->client_id)) {
throw new \Exception('client_id key missing from configuration.');
}
if (!isset($config->General->client_secret)) {
throw new \Exception('client_secret key missing from configuration.');
}
$client = $container->get(\VuFindHttp\HttpService::class)->createClient();
return new $requestedName(
$config,
$client
);
}
}

0 comments on commit 105363b

Please sign in to comment.