diff --git a/PlagiarismIthenticateException.inc.php b/PlagiarismIthenticateException.inc.php new file mode 100644 index 0000000..425b343 --- /dev/null +++ b/PlagiarismIthenticateException.inc.php @@ -0,0 +1,42 @@ +connection = $connection; + parent::__construct($message, $code, $previous); + } + + /* + * Constructor + * @return Ithenticate|null + */ + public function getConnection() { + return $this->connection; + } +} + diff --git a/PlagiarismPlugin.inc.php b/PlagiarismPlugin.inc.php index a1616ba..af895fb 100644 --- a/PlagiarismPlugin.inc.php +++ b/PlagiarismPlugin.inc.php @@ -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]; } @@ -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. @@ -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( @@ -255,3 +291,4 @@ public function submitDocument($essay_title, $author_firstname, $author_lastname return true; } } + diff --git a/PlagiarismSettingsForm.inc.php b/PlagiarismSettingsForm.inc.php index d756913..d1711f6 100644 --- a/PlagiarismSettingsForm.inc.php +++ b/PlagiarismSettingsForm.inc.php @@ -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)); @@ -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'), @@ -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; + } + } diff --git a/README.md b/README.md index 10adbd7..0ce9004 100644 --- a/README.md +++ b/README.md @@ -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] = "user@email.com" +;username[journal_path] = "user@email.com" ; 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) @@ -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. diff --git a/locale/en_US/locale.po b/locale/en_US/locale.po index edf9d1f..9486d17 100644 --- a/locale/en_US/locale.po +++ b/locale/en_US/locale.po @@ -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."