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

Remove ithenticate setting and improve exception handling (3.4.x) #44

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions PlagiarismIthenticateException.inc.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

/**
* @file PlagiarismIthenticateException.inc.php
*
* Copyright (c) 2003-2021 Simon Fraser University
* Copyright (c) 2003-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file LICENSE.
*
* @brief Plagiarism plugin iThenticate exception
*/


/**
* Define an exception class for iThenticate via this plugin
* This Exception will include the failed iThenticate connection, when possible.
*/
class PlagiarismIthenticateException extends Exception
{
private ?\bsobbe\ithenticate\Ithenticate $connection;

/*
* Constructor
* @param $message string
* @param $code int
* @param $previous Exception
* @param $connection Ithenticate
*/
public function __construct($message, $code = 0, ?Throwable $previous = null, ?\bsobbe\ithenticate\Ithenticate $connection = null) {
$this->connection = $connection;
parent::__construct($message, $code, $previous);
}

/*
* Constructor
* @return Ithenticate|null
*/
public function getConnection() {
return $this->connection;
}
}

89 changes: 63 additions & 26 deletions PlagiarismPlugin.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,37 +42,52 @@ public function getDescription() {

/**
* @copydoc LazyLoadPlugin::getCanEnable()
* If credentials are stored in config.inc.php, these force the plugin to enabled.
*/
function getCanEnable($contextId = null) {
return !Config::getVar('ithenticate', 'ithenticate');
list($user, $pass) = $this->getForcedCredentials($contextId);
// if config.inc.php supplies both user and password, the journal cannot enable/disable
return !($user && $pass);
}

/**
* @copydoc LazyLoadPlugin::getCanDisable()
* If credentials are stored in config.inc.php, these force the plugin to enabled.
*/
function getCanDisable($contextId = null) {
return !Config::getVar('ithenticate', 'ithenticate');
return $this->getCanEnable($contextId);
}

/**
* @copydoc LazyLoadPlugin::getEnabled()
* If credentials are stored in config.inc.php, these force the plugin to enabled.
*/
function getEnabled($contextId = null) {
return parent::getEnabled($contextId) || Config::getVar('ithenticate', 'ithenticate');
return parent::getEnabled($contextId) || !$this->getCanEnable($contextId);
}

/**
* Fetch credentials from config.inc.php, if available
* @param $contextId int Optional Context Id, autodetect from Request if not supplied, but existing site-wide settings will override any context
* @return array username and password, or null(s)
**/
function getForcedCredentials() {
$request = Application::get()->getRequest();
$context = $request->getContext();
$contextPath = $context->getPath();
$username = Config::getVar('ithenticate', 'username[' . $contextPath . ']',
Config::getVar('ithenticate', 'username'));
$password = Config::getVar('ithenticate', 'password[' . $contextPath . ']',
Config::getVar('ithenticate', 'password'));
function getForcedCredentials($contextId) {
$username = Config::getVar('ithenticate', 'username');
$password = Config::getVar('ithenticate', 'password');
if (!$username || !$password) {
if (!$contextId) {
$request = Application::get()->getRequest();
$context = $request->getContext();
} else {
$contextDao = Application::getContextDAO();
$context = $contextDao->getById($contextId);
}
if ($context) {
$contextPath = $context->getPath();
$username = Config::getVar('ithenticate', 'username[' . $contextPath . ']');
$password = Config::getVar('ithenticate', 'password[' . $contextPath . ']');
}
}
return [$username, $password];
}

Expand All @@ -95,6 +110,36 @@ public function sendErrorMessage($submissionid, $message) {
}
error_log('iThenticate submission '.$submissionid.' failed: '.$message);
}

/**
* Connects to iThenticate and validates interop prerequisites
* @param $username string iThenticate username
* @param $password string iThenticate password
* @param $groupname string An iThenticate folder group which will be created if not already existing
* @return Ithenticate iThenticate connection object
* @throws PlagiarismIthenticateException
*/
public function ithenticateConnect($username, $password, $groupname) {
require_once(dirname(__FILE__) . '/vendor/autoload.php');
import('plugins.generic.plagiarism.PlagiarismIthenticateException');

$ithenticate = null;
try {
$ithenticate = new \bsobbe\ithenticate\Ithenticate($username, $password);
} catch (Exception $e) {
throw new PlagiarismIthenticateException($e->getMessage(), 0, $e, null);
}
// Make sure there's a group list for this context, creating if necessary.
$groupList = $ithenticate->fetchGroupList();
if (!($groupId = array_search($groupname, $groupList))) {
// No folder group found for the context; create one.
$groupId = $ithenticate->createGroup($groupname);
if (!$groupId) {
throw new PlagiarismIthenticateException('Could not create folder group for context ' . $contextName . ' on iThenticate.', 0, null, $ithenticate);
}
}
return $ithenticate;
}

/**
* Send submission files to iThenticate.
Expand All @@ -109,34 +154,25 @@ public function callback($hookName, $args) {
$submission = $submissionDao->getById($request->getUserVar('submissionId'));
$publication = $submission->getCurrentPublication();

require_once(dirname(__FILE__) . '/vendor/autoload.php');

// try to get credentials for current context otherwise use default config
$contextId = $context->getId();
list($username, $password) = $this->getForcedCredentials();
list($username, $password) = $this->getForcedCredentials($context->getId());
if (empty($username) || empty($password)) {
$username = $this->getSetting($contextId, 'ithenticateUser');
$password = $this->getSetting($contextId, 'ithenticatePass');
}

$contextName = $context->getLocalizedName($context->getPrimaryLocale());

$ithenticate = null;
try {
$ithenticate = new \bsobbe\ithenticate\Ithenticate($username, $password);
$ithenticate = $this->ithenticateConnect($username, $password, $contextName);
$groupList = $ithenticate->fetchGroupList();
$groupId = array_search($contextName, $groupList);
} catch (Exception $e) {
$this->sendErrorMessage($submission->getId(), $e->getMessage());
return false;
}
// Make sure there's a group list for this context, creating if necessary.
$groupList = $ithenticate->fetchGroupList();
$contextName = $context->getLocalizedName($context->getPrimaryLocale());
if (!($groupId = array_search($contextName, $groupList))) {
// No folder group found for the context; create one.
$groupId = $ithenticate->createGroup($contextName);
if (!$groupId) {
$this->sendErrorMessage($submission->getId(), 'Could not create folder group for context ' . $contextName . ' on iThenticate.');
return false;
}
}

// Create a folder for this submission.
if (!($folderId = $ithenticate->createFolder(
Expand Down Expand Up @@ -255,3 +291,4 @@ public function submitDocument($essay_title, $author_firstname, $author_lastname
return true;
}
}

44 changes: 40 additions & 4 deletions PlagiarismSettingsForm.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ function __construct($plugin, $contextId) {

parent::__construct($plugin->getTemplateResource('settingsForm.tpl'));

$this->addCheck(new FormValidator($this, 'ithenticateUser', 'required', 'plugins.generic.plagiarism.manager.settings.usernameRequired'));
$this->addCheck(new FormValidator($this, 'ithenticatePass', 'required', 'plugins.generic.plagiarism.manager.settings.passwordRequired'));
$this->addCheck(new FormValidator($this, 'ithenticateUser', FORM_VALIDATOR_REQUIRED_VALUE, 'plugins.generic.plagiarism.manager.settings.usernameRequired'));
$this->addCheck(new FormValidator($this, 'ithenticatePass', FORM_VALIDATOR_REQUIRED_VALUE, 'plugins.generic.plagiarism.manager.settings.passwordRequired'));
$this->addCheck(new FormValidatorCustom($this, 'ithenticatePass', FORM_VALIDATOR_REQUIRED_VALUE, 'plugins.generic.plagiarism.manager.settings.loginFailed', array(&$this, '_checkConnection'), array(&$this), true));

$this->addCheck(new FormValidatorPost($this));
$this->addCheck(new FormValidatorCSRF($this));
Expand All @@ -32,7 +33,7 @@ function __construct($plugin, $contextId) {
* Initialize form data.
*/
function initData() {
list($username, $password) = $this->_plugin->getForcedCredentials();
list($username, $password) = $this->_plugin->getForcedCredentials($this->_contextId);
$this->_data = array(
'ithenticateUser' => $this->_plugin->getSetting($this->_contextId, 'ithenticateUser'),
'ithenticatePass' => $this->_plugin->getSetting($this->_contextId, 'ithenticatePass'),
Expand Down Expand Up @@ -61,7 +62,42 @@ function fetch($request, $template = null, $display = false) {
*/
function execute(...$functionArgs) {
$this->_plugin->updateSetting($this->_contextId, 'ithenticateUser', trim($this->getData('ithenticateUser'), "\"\';"), 'string');
$this->_plugin->updateSetting($this->_contextId, 'ithenticatePass', trim($this->getData('ithenticatepass'), "\"\';"), 'string');
$this->_plugin->updateSetting($this->_contextId, 'ithenticatePass', trim($this->getData('ithenticatePass'), "\"\';"), 'string');
parent::execute(...$functionArgs);
}

/**
* Check the username and password for the service
* @param $formPassword string the value of the field being checked
* @param $form object a reference to this form
* @return boolean Is there a problem with the form?
*/
function _checkConnection($formPassword, $form) {
$username = $form->getData('ithenticateUser');
// bypass testing if login is not present
if (empty($username) || empty($formPassword)) {
return false;
}

$contextDao = Application::getContextDAO();
$context = $contextDao->getById($this->_contextId);
// if credentials are forced, don't bother testing them. The user can't do anything about a failure on this form.
list($username, $password) = $this->_plugin->getForcedCredentials($this->_contextId);
if (!empty($username) && !empty($password)) {
return false;
}
$contextName = $context->getLocalizedName($context->getPrimaryLocale());
$username = $username = $form->getData('ithenticateUser');
$password = $formPassword;

$ithenticate = null;
try {
$ithenticate = $this->_plugin->ithenticateConnect($username, $password, $contextName);
} catch (Exception $e) {
error_log($e->getMessage());
return true;
}
return false;
}

}
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,11 @@ The config.inc.php settings format is:

[ithenticate]

; Enable iThenticate to submit manuscripts after submit step 4
;ithenticate = On

; Credentials can be set by context : specify journal path
; The username to access the API (usually an email address)
;username[MyJournal_path] = "[email protected]"
;username[journal_path] = "[email protected]"
; The password to access the API
;password[MyJournal_path] = "password"
;password[journal_path] = "password"

; default credentials
; The username to access the API (usually an email address)
Expand All @@ -52,3 +49,6 @@ The config.inc.php settings format is:
;password = "password"
```

Here, the `journal_path` follows the same convention as the `base_url[journal_path]` settings in config.inc.php.

There was previously a setting `ithenticate` which would indicate whether the plugin was enabled, but this has been removed. If both the username and password are present in config.inc.php, the plugin will be assumed to be enabled.
3 changes: 3 additions & 0 deletions locale/en_US/locale.po
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ msgstr "iThenticate Usename is required"
msgid "plugins.generic.plagiarism.manager.settings.passwordRequired"
msgstr "iThenticate Password is required"

msgid "plugins.generic.plagiarism.manager.settings.loginFailed"
msgstr "iThenticate login failed."

msgid "plugins.generic.plagiarism.manager.settings.areForced"
msgstr "iThenticate settings were found in config.inc.php and the settings here will not be used."

Expand Down