Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add recommendation module for LibGuides Profiles #2977

Merged
merged 30 commits into from
Jul 7, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
ac48fbf
LibGuides Profile recommendation module
maccabeelevine Jul 3, 2023
413369c
Add email and escape output
maccabeelevine Jul 5, 2023
b39a416
Refactor oauth connection logic
maccabeelevine Jul 5, 2023
9730793
Add documention and clean code
maccabeelevine Jul 5, 2023
8e0af3c
Remove comment
maccabeelevine Jul 5, 2023
ff8e614
Fix log message
maccabeelevine Jul 5, 2023
9e0983f
Document in searches.ini
maccabeelevine Jul 5, 2023
c746cf2
Clarify API documentation link
maccabeelevine Jul 6, 2023
2e9766c
Note CSP requirement
maccabeelevine Jul 6, 2023
2b2baac
Add class property for user agent.
maccabeelevine Jul 6, 2023
6f5d0d6
Simplify if/else condition
maccabeelevine Jul 6, 2023
a9008c5
Document $tokenData class
maccabeelevine Jul 6, 2023
80f1ba3
Fix comments & spacing
maccabeelevine Jul 6, 2023
5b042c6
Remove unused method
maccabeelevine Jul 6, 2023
b865a03
Fix indent
maccabeelevine Jul 6, 2023
b30edc8
Translate heading and fix class names
maccabeelevine Jul 6, 2023
ec97543
Check for empty values
maccabeelevine Jul 6, 2023
8da260b
Handle empty last name.
maccabeelevine Jul 6, 2023
840e62e
Add missing heading
maccabeelevine Jul 6, 2023
7c1ee61
Remove unused $forceNewConnection
maccabeelevine Jul 6, 2023
cc38660
Return null if failure in getAccounts()
maccabeelevine Jul 6, 2023
e80a06e
Create LibGuides connector via factory
maccabeelevine Jul 6, 2023
7f9a5ab
Log only if $this->log exists
maccabeelevine Jul 6, 2023
758e088
Avoid collsions with safe logging
maccabeelevine Jul 6, 2023
71c2ab1
Cache /accounts response
maccabeelevine Jul 6, 2023
31ea155
Fix mention of LoggerAwareInterface
maccabeelevine Jul 6, 2023
78c653f
Remove useless algorithm
maccabeelevine Jul 6, 2023
15ddd33
Fix typo
maccabeelevine Jul 7, 2023
755d8bc
Rename methods for clarity
maccabeelevine Jul 7, 2023
6e261f9
Fix typo
maccabeelevine Jul 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 20 additions & 0 deletions config/vufind/LibGuidesAPI.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
; This file is used for the LibGuides *API*, which uses an
; oauth connection mechanism. This API is currently used
; by the LibGuidesProfile recommendation module.
; https://ask.springshare.com/libguides/faq/873
demiankatz marked this conversation as resolved.
Show resolved Hide resolved

; 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
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
demiankatz marked this conversation as resolved.
Show resolved Hide resolved
; 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
4 changes: 4 additions & 0 deletions config/vufind/searches.ini
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,10 @@ 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.
demiankatz marked this conversation as resolved.
Show resolved Hide resolved
; 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
192 changes: 192 additions & 0 deletions module/VuFind/src/VuFind/Connection/LibGuides.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
<?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;

/**
* Constructor
*
* @param \Laminas\Http\Client $client HTTP client
* @param string $baseUrl Base URL of the LibGuides API
* @param string $clientId Client Id provided by LibGuides API configuration
* @param string $clientSecret Client Secret provided by LibGuides API configuration
* @param bool $forceNewConnection Force a new connection (get a new token)
*
* @link https://ask.springshare.com/libguides/faq/873#api-auth
*/
public function __construct(
$client,
$baseUrl,
$clientId,
$clientSecret,
$forceNewConnection = false
demiankatz marked this conversation as resolved.
Show resolved Hide resolved
) {
$this->client = $client;
$this->baseUrl = $baseUrl;
$this->clientId = $clientId;
$this->clientSecret = $clientSecret;
}

/**
* Load all LibGuides accounts.
*
* @return array An array of all LibGuides accounts, or an empty array
* if an error occurs
demiankatz marked this conversation as resolved.
Show resolved Hide resolved
*/
public function getAccounts()
{
$tokenData = $this->authenticateWithClientCredentials(
$this->baseUrl . "/oauth/token",
$this->clientId,
$this->clientSecret
);
if (!$tokenData) {
return [];
}

$headers = [];
if (
isset($tokenData->token_type)
&& isset($tokenData->access_token)
) {
$headers[] = "Authorization: {$tokenData->token_type} "
. $tokenData->access_token;
}
$headers[] = "User-Agent: VuFind";
demiankatz marked this conversation as resolved.
Show resolved Hide resolved

$this->client->setHeaders($headers);
$this->client->setMethod("GET");
$this->client->setUri(
$this->baseUrl . "/accounts?expand=profile,subjects"
);
try {
// throw new Exception('testException');
demiankatz marked this conversation as resolved.
Show resolved Hide resolved
$response = $this->client->send();
} catch (Exception $ex) {
$this->error(
"Exception during request: " .
$ex->getMessage()
);
return [];
}

if ($response->isServerError()) {
$this->error(
"LibGuides API HTTP Error: " .
$response->getStatusCode()
);
$this->debug("Request: " . $this->client->getRequest());
$this->debug("Response: " . $this->client->getResponse());
return [];
}
$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...
demiankatz marked this conversation as resolved.
Show resolved Hide resolved
$this->error("LibGuides Error: " . $returnVal->errorCode);
return $returnVal;
} else {
return $returnVal;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're returning the result regardless of what happens, you don't really need this else clause -- you could slightly simplify the code here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup another odd one copied from Overdrive, but fixed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it's worth a small PR to apply these trivial fixes to Overdrive so we keep things in alignment. I can do it if you like; just let me know!

}
} else {
$this->error(
"LibGuides API Error: Nothing returned from API call."
);
$this->debug(
"Body return from LibGuides API Call: " . print_r($body, true)
);
}
return [];
}
}
62 changes: 62 additions & 0 deletions module/VuFind/src/VuFind/Connection/OauthServiceInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

/**
* Interface for classes using OauthServiceTrait.
*
* 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 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;

/**
* Interface for classes using OauthServiceTrait.
*
* @category VuFind
* @package Connection
* @author Maccabee Levine <msl321@lehigh.edu>
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
* @link https://vufind.org
*/
interface OauthServiceInterface
{
/**
* Authentiate via the OAuth Client Credentials grant type.
*
* @param string $oauthUrl URL of thee OAuth service
* @param string $clientId client_id for a client_credentials grant
* @param string $clientSecret client_secret for a client_credentials grant
* @param bool $forceNewConnection Force a new connection (get a new token)
*
* @return string token for the session or false
* if the token request failed
*
* @link https://www.oauth.com/oauth2-servers/access-tokens/client-credentials/
*/
public function authenticateWithClientCredentials(
$oauthUrl,
$clientId,
$clientSecret,
$forceNewConnection
);
}