From cca0be2b21ff350c4c305d7487ffa52bbb8b8334 Mon Sep 17 00:00:00 2001 From: Alec Smecher Date: Thu, 11 Oct 2012 11:42:21 -0700 Subject: [PATCH] *7961* Moved plugin grid to lib-pkp --- .../plugins/PluginCategoryGridRow.inc.php | 38 ++ .../plugins/PluginGridCellProvider.inc.php | 149 +++++++ .../grid/plugins/PluginGridHandler.inc.php | 383 ++++++++++++++++++ .../grid/plugins/PluginGridRow.inc.php | 168 ++++++++ .../plugins/form/UploadPluginForm.inc.php | 336 +++++++++++++++ 5 files changed, 1074 insertions(+) create mode 100644 controllers/grid/plugins/PluginCategoryGridRow.inc.php create mode 100644 controllers/grid/plugins/PluginGridCellProvider.inc.php create mode 100644 controllers/grid/plugins/PluginGridHandler.inc.php create mode 100644 controllers/grid/plugins/PluginGridRow.inc.php create mode 100644 controllers/grid/plugins/form/UploadPluginForm.inc.php diff --git a/controllers/grid/plugins/PluginCategoryGridRow.inc.php b/controllers/grid/plugins/PluginCategoryGridRow.inc.php new file mode 100644 index 00000000000..cd9b5f4c0f2 --- /dev/null +++ b/controllers/grid/plugins/PluginCategoryGridRow.inc.php @@ -0,0 +1,38 @@ +getData(); + return __("plugins.categories.$pluginCategory"); + } +} + +?> diff --git a/controllers/grid/plugins/PluginGridCellProvider.inc.php b/controllers/grid/plugins/PluginGridCellProvider.inc.php new file mode 100644 index 00000000000..2d48fe0e160 --- /dev/null +++ b/controllers/grid/plugins/PluginGridCellProvider.inc.php @@ -0,0 +1,149 @@ +getData(); + $columnId = $column->getId(); + assert(is_a($plugin, 'Plugin') && !empty($columnId)); + + switch ($columnId) { + case 'name': + return array('label' => $plugin->getDisplayName()); + break; + case 'category': + return array('label' => $plugin->getCategory()); + break; + case 'description': + return array('label' => $plugin->getDescription()); + break; + case 'enabled': + // Assume that every plugin is enabled... + $enabled = true; + // ... and that it doesn't have enable or disable management verbs. + $hasVerbs = false; + + // Check if plugin can be disabled. + if (is_callable(array($plugin, 'getEnabled'))) { + + // Plugin can be disabled, so check its current state. + if (!$plugin->getEnabled()) { + $enabled = false; + } + + // Check if plugin has management verbs to + // disable or enable. + $managementVerbs = $plugin->getManagementVerbs(); + if (!is_null($managementVerbs)) { + foreach($managementVerbs as $verb) { + list($verbName) = $verb; + if ($verbName === 'enable' || $verbName === 'disable') { + $hasVerbs = true; + break; + } + } + } + } else { + // Plugin cannot be disabled so it also doesn't + // have management verbs to those actions. + $hasVerbs = false; + } + + // Set the state of the select element that will + // be used to enable or disable the plugin. + $selectDisabled = true; + if ($hasVerbs) { + // Plugin have management verbs. + // Show an enabled select element. + $selectDisabled = false; + } + + return array('selected' => $enabled, + 'disabled' => $selectDisabled); + default: + break; + } + + return parent::getTemplateVarsFromRowColumn($row, $column); + } + + /** + * @see GridCellProvider::getCellActions() + */ + function getCellActions(&$request, &$row, &$column, $position = GRID_ACTION_POSITION_DEFAULT) { + if ($column->getId() == 'enabled') { + $plugin =& $row->getData(); /* @var $plugin Plugin */ + + $router =& $request->getRouter(); + $managementVerbs = $plugin->getManagementVerbs(); + + if (!is_null($managementVerbs)) { + foreach ($managementVerbs as $verb) { + list($verbName, $verbLocalizedName) = $verb; + + $actionArgs = array_merge(array( + 'plugin' => $plugin->getName(), + 'verb' => $verbName), + $row->getRequestArgs()); + + $actionRequest = null; + $defaultUrl = $router->url($request, null, null, 'plugin', null, $actionArgs); + + if ($verbName === 'enable') { + import('lib.pkp.classes.linkAction.request.AjaxAction'); + $actionRequest = new AjaxAction($defaultUrl); + } else if ($verbName === 'disable') { + import('lib.pkp.classes.linkAction.request.RemoteActionConfirmationModal'); + $actionRequest = new RemoteActionConfirmationModal(__('grid.plugin.disable'), + __('common.disable'), $defaultUrl); + } + + if ($actionRequest) { + $linkAction = new LinkAction( + $verbName, + $actionRequest, + $verbLocalizedName, + null + ); + + return array($linkAction); + } + } + } + // Plugin can't be disabled or don't have + // management verbs for that. + return array(); + } + return parent::getCellActions($request, $row, $column, $position); + } +} + +?> diff --git a/controllers/grid/plugins/PluginGridHandler.inc.php b/controllers/grid/plugins/PluginGridHandler.inc.php new file mode 100644 index 00000000000..89faf3964b6 --- /dev/null +++ b/controllers/grid/plugins/PluginGridHandler.inc.php @@ -0,0 +1,383 @@ +addRoleAssignment($roles, + array('fetchGrid, fetchCategory', 'fetchRow')); + + $this->addRoleAssignment(ROLE_ID_SITE_ADMIN, + array('installPlugin', 'upgradePlugin', 'deletePlugin')); + + parent::CategoryGridHandler(); + } + + + // + // Overridden template methods + // + /** + * @see GridHandler::authorize() + */ + function authorize($request, $args, $roleAssignments) { + $category = $request->getUserVar('category'); + $pluginName = $request->getUserVar('plugin'); + $verb = $request->getUserVar('verb'); + + if ($category && $pluginName) { + import('classes.security.authorization.OmpPluginAccessPolicy'); + if ($verb) { + $accessMode = ACCESS_MODE_MANAGE; + } else { + $accessMode = ACCESS_MODE_ADMIN; + } + + $this->addPolicy(new OmpPluginAccessPolicy($request, $args, $roleAssignments, $accessMode)); + } + + return parent::authorize($request, $args, $roleAssignments); + } + + /** + * @see GridHandler::initialize() + */ + function initialize(&$request) { + parent::initialize($request); + + // Load language components + AppLocale::requireComponents(LOCALE_COMPONENT_PKP_MANAGER, LOCALE_COMPONENT_PKP_COMMON); + AppLocale::requireComponents(LOCALE_COMPONENT_OMP_MANAGER); + + // Basic grid configuration + $this->setTitle('common.plugins'); + + // Set the no items row text + $this->setEmptyRowText('grid.noItems'); + + // Columns + import('controllers.grid.plugins.PluginGridCellProvider'); + $pluginCellProvider = new PluginGridCellProvider(); + $this->addColumn( + new GridColumn('name', + 'common.name', + null, + 'controllers/grid/gridCell.tpl', + $pluginCellProvider, + array('multiline' => true) + ) + ); + + $descriptionColumn = new GridColumn( + 'description', + 'common.description', + null, + 'controllers/grid/gridCell.tpl', + $pluginCellProvider + ); + $descriptionColumn->addFlag('html', true); + $this->addColumn($descriptionColumn); + + $this->addColumn( + new GridColumn('enabled', + 'common.enabled', + null, + 'controllers/grid/common/cell/selectStatusCell.tpl', + $pluginCellProvider + ) + ); + + $router =& $request->getRouter(); + + // Grid level actions. + $userRoles = $this->getAuthorizedContextObject(ASSOC_TYPE_USER_ROLES); + if (in_array(ROLE_ID_SITE_ADMIN, $userRoles)) { + import('lib.pkp.classes.linkAction.request.AjaxModal'); + + // Install plugin. + $this->addAction( + new LinkAction( + 'install', + new AjaxModal( + $router->url($request, null, null, 'installPlugin'), + __('manager.plugins.install'), 'modal_add_file'), + __('manager.plugins.install'), + 'add')); + } + } + + /** + * @see GridHandler::getFilterForm() + */ + function getFilterForm() { + return 'controllers/grid/plugins/pluginGridFilter.tpl'; + } + + /** + * @see GridHandler::getFilterSelectionData() + */ + function getFilterSelectionData(&$request) { + $category = $request->getUserVar('category'); + $pluginName = $request->getUserVar('pluginName'); + + if (is_null($category)) { + $category = 'all'; + } + + return array('category' => $category, 'pluginName' => $pluginName); + } + + /** + * @see GridHandler::renderFilter() + */ + function renderFilter($request) { + $categoriesSymbolic = $this->loadData($request, null); + $categories = array('all' => __('grid.plugin.allCategories')); + foreach ($categoriesSymbolic as $category) { + $categories[$category] = __("plugins.categories.$category"); + } + $filterData = array('categories' => $categories); + + return parent::renderFilter($request, $filterData); + } + + /** + * @see CategoryGridHandler::getCategoryRowInstance() + */ + function getCategoryRowInstance() { + import('controllers.grid.plugins.PluginCategoryGridRow'); + return new PluginCategoryGridRow(); + } + + /** + * @see CategoryGridHandler::getCategoryData() + */ + function getCategoryData($categoryDataElement, $filter) { + $plugins =& PluginRegistry::loadCategory($categoryDataElement); + + if (!is_null($filter) && isset($filter['pluginName']) && $filter['pluginName'] != "") { + // Find all plugins that have the filter name string in their display names. + $filteredPlugins = array(); + foreach ($plugins as $plugin) { /* @var $plugin Plugin */ + $pluginName = $plugin->getDisplayName(); + if (stristr($pluginName, $filter['pluginName']) !== false) { + $filteredPlugins[$plugin->getName()] = $plugin; + } + unset($plugin); + } + return $filteredPlugins; + } + + return $plugins; + } + + /** + * @see CategoryGridHandler::getCategoryRowIdParameterName() + */ + function getCategoryRowIdParameterName() { + return 'category'; + } + + /** + * @see CategoryGridHandler::getCategoryRowInstance() + * @param $contextLevel int One of the CONTEXT_ constants. + */ + function getRowInstance($contextLevel) { + $userRoles = $this->getAuthorizedContextObject(ASSOC_TYPE_USER_ROLES); + + import('controllers.grid.plugins.PluginGridRow'); + return new PluginGridRow($userRoles, $contextLevel); + } + + /** + * @see GridHandler::loadData() + */ + function loadData($request, $filter) { + $categories = PluginRegistry::getCategories(); + if (is_array($filter) && isset($filter['category']) && ($i = array_search($filter['category'], $categories)) !== false) { + return array($filter['category'] => $filter['category']); + } else { + return array_combine($categories, $categories); + } + } + + + // + // Public handler methods. + // + /** + * Perform plugin-specific management functions. + * @param $args array + * @param $request object + */ + function plugin($args, &$request) { + $verb = (string) $request->getUserVar('verb'); + + $this->setupTemplate(true); + + $plugin =& $this->getAuthorizedContextObject(ASSOC_TYPE_PLUGIN); /* @var $plugin Plugin */ + $message = null; + $pluginModalContent = null; + if (!is_a($plugin, 'Plugin') || !$plugin->manage($verb, $args, $message, $messageParams, $pluginModalContent)) { + if ($message) { + $notificationManager = new NotificationManager(); + $user =& $request->getUser(); + $notificationManager->createTrivialNotification($user->getId(), $message, $messageParams); + + return DAO::getDataChangedEvent($request->getUserVar('plugin'), $request->getUserVar($this->getCategoryRowIdParameterName())); + } + } + if ($pluginModalContent) { + $json = new JSONMessage(true, $pluginModalContent); + return $json->getString(); + } + } + + /** + * Show upload plugin form to install a new plugin. + * @param $args array + * @param $request PKPRequest + * @return string + */ + function installPlugin($args, &$request) { + return $this->_showUploadPluginForm('install'); + } + + /** + * Show upload plugin form to update an existing plugin. + * @param $args array + * @param $request PKPRequest + * @return string + */ + function upgradePlugin($args, &$request) { + return $this->_showUploadPluginForm('upgrade'); + } + + /** + * Upload a plugin file. + * @param $args array + * @param $request PKPRequest + */ + function uploadPlugin($args, &$request) { + $errorMsg = ''; + + import('classes.file.TemporaryFileManager'); + $temporaryFileManager = new TemporaryFileManager(); + $user =& $request->getUser(); + + // Return the temporary file id. + if ($temporaryFile = $temporaryFileManager->handleUpload('uploadedFile', $user->getId())) { + $json = new JSONMessage(true); + $json->setAdditionalAttributes(array( + 'temporaryFileId' => $temporaryFile->getId() + )); + } else { + $json = new JSONMessage(false, __('manager.plugins.uploadError')); + } + + return $json->getString(); + } + + /** + * Save upload plugin file form. + * @param $args array + * @param $request PKPRequest + * @return string + */ + function saveUploadPlugin($args, &$request) { + $function = $request->getUserVar('function'); + + import('controllers.grid.plugins.form.UploadPluginForm'); + $uploadPluginForm = new UploadPluginForm($function); + $uploadPluginForm->readInputData(); + + if($uploadPluginForm->validate()) { + if($uploadPluginForm->execute($request)) { + return DAO::getDataChangedEvent(); + } + } + + $json = new JSONMessage(false); + return $json->getString(); + } + + /** + * Delete plugin. + * @param $args array + * @param $request PKPRequest + */ + function deletePlugin($args, &$request) { + $this->setupTemplate(); + $plugin =& $this->getAuthorizedContextObject(ASSOC_TYPE_PLUGIN); + $category = $plugin->getCategory(); + $productName = basename($plugin->getPluginPath()); + + $versionDao =& DAORegistry::getDAO('VersionDAO'); /* @var $versionDao VersionDAO */ + $installedPlugin = $versionDao->getCurrentVersion('plugins.'.$category, $productName, true); + + $notificationMgr = new NotificationManager(); + $user =& $request->getUser(); + + if ($installedPlugin) { + $pluginDest = Core::getBaseDir() . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . $category . DIRECTORY_SEPARATOR . $productName; + $pluginLibDest = Core::getBaseDir() . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'pkp' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . $category . DIRECTORY_SEPARATOR . $productName; + + // make sure plugin type is valid and then delete the files + if (in_array($category, PluginRegistry::getCategories())) { + // Delete the plugin from the file system. + $fileManager = new FileManager(); + $fileManager->rmtree($pluginDest); + $fileManager->rmtree($pluginLibDest); + } + + if(is_dir($pluginDest) || is_dir($pluginLibDest)) { + $notificationMgr->createTrivialNotification($user->getId(), NOTIFICATION_TYPE_ERROR, array('contents' => __('manager.plugins.deleteError', array('pluginName' => $plugin->getDisplayName())))); + } else { + $versionDao->disableVersion('plugins.'.$category, $productName); + $notificationMgr->createTrivialNotification($user->getId(), NOTIFICATION_TYPE_SUCCESS, array('contents' => __('manager.plugins.deleteSuccess', array('pluginName' => $plugin->getDisplayName())))); + } + } else { + $notificationMgr->createTrivialNotification($user->getId(), NOTIFICATION_TYPE_ERROR, array('contents' => __('manager.plugins.doesNotExist', array('pluginName' => $plugin->getDisplayName())))); + } + + return DAO::getDataChangedEvent($plugin->getName()); + } + + /** + * Fetch upload plugin form. + * @param $function string + * @return string + */ + function _showUploadPluginForm($function) { + $this->setupTemplate(true); + + import('controllers.grid.plugins.form.UploadPluginForm'); + $uploadPluginForm = new UploadPluginForm($function); + $uploadPluginForm->initData(); + + $json = new JSONMessage(true, $uploadPluginForm->fetch($request)); + return $json->getString(); + } +} + +?> diff --git a/controllers/grid/plugins/PluginGridRow.inc.php b/controllers/grid/plugins/PluginGridRow.inc.php new file mode 100644 index 00000000000..8cc9fb81ef2 --- /dev/null +++ b/controllers/grid/plugins/PluginGridRow.inc.php @@ -0,0 +1,168 @@ +_userRoles = $userRoles; + $this->_contextLevel = $contextLevel; + + parent::GridRow(); + } + + + // + // Overridden methods from GridRow + // + /** + * @see GridRow::initialize() + */ + function initialize(&$request) { + parent::initialize($request); + + // Is this a new row or an existing row? + $plugin =& $this->getData(); /* @var $plugin Plugin */ + assert(is_a($plugin, 'Plugin')); + + $rowId = $this->getId(); + + // Only add row actions if this is an existing row + if (!is_null($rowId)) { + $router =& $request->getRouter(); /* @var $router PKPRouter */ + + $actionArgs = array_merge(array( + 'plugin' => $plugin->getName()), + $this->getRequestArgs()); + + if ($this->_canEdit($plugin)) { + + $managementVerbs = $plugin->getManagementVerbs(); + + // If plugin has not management verbs, we receive + // null. Check for it before foreach. + if (!is_null($managementVerbs)) { + foreach ($managementVerbs as $verb) { + list($verbName, $verbLocaleKey) = $verb; + + // Add the verb to action args array. + $actionArgs['verb'] = $verbName; + + $defaultUrl = $router->url($request, null, null, 'plugin', null, $actionArgs); + $linkAction = null; + $actionRequest = null; + $image = null; + + switch ($verbName) { + case 'enable': + case 'disable': + // Do nothing. User interact with those verbs via enabled grid column. + break; + default: + // Check if verb has a link action defined. + $verbLinkAction = $plugin->getManagementVerbLinkAction($request, $verb, $defaultUrl); + if (is_a($verbLinkAction, 'LinkAction')) { + $linkAction = $verbLinkAction; + } else { + // Define a default ajax modal request. + import('lib.pkp.classes.linkAction.request.AjaxModal'); + $actionRequest = new AjaxModal($defaultUrl, $verbLocaleKey); + } + break; + } + + // Build link action for those verbs who don't define one. + if (!$linkAction && $actionRequest) { + $linkAction = new LinkAction( + $verbName, + $actionRequest, + $verbLocaleKey, + $image + ); + } + + if ($linkAction) { + // Insert row link action. + $this->addAction($linkAction); + + unset($linkAction); + unset($actionRequest); + } + } + + // Remove verb from action args array. + unset($actionArgs['verb']); + } + } + + // Administrative functions. + if (in_array(ROLE_ID_SITE_ADMIN, $this->_userRoles)) { + import('lib.pkp.classes.linkAction.request.RemoteActionConfirmationModal'); + $this->addAction(new LinkAction( + 'delete', + new RemoteActionConfirmationModal( + __('manager.plugins.deleteConfirm'), + __('common.delete'), + $router->url($request, null, null, 'deletePlugin', null, $actionArgs), 'modal_delete'), + __('common.delete'), + 'delete')); + + $this->addAction(new LinkAction( + 'upgrade', + new AjaxModal( + $router->url($request, null, null, 'upgradePlugin', null, $actionArgs), + __('manager.plugins.upgrade'), 'modal_upgrade'), + __('grid.action.upgrade'), + 'upgrade')); + } + } + } + + + // + // Private helper methods + // + /** + * Return if user can edit a plugin settings or not. + * @param $plugin Plugin + * @return boolean + */ + function _canEdit(&$plugin) { + if ($plugin->isSitePlugin()) { + if (in_array(ROLE_ID_SITE_ADMIN, $this->_userRoles)) { + return true; + } + } elseif ($this->_contextLevel & CONTEXT_PRESS) { + if (in_array(ROLE_ID_PRESS_MANAGER, $this->_userRoles)) { + return true; + } + } + + return false; + } +} + +?> diff --git a/controllers/grid/plugins/form/UploadPluginForm.inc.php b/controllers/grid/plugins/form/UploadPluginForm.inc.php new file mode 100644 index 00000000000..4dcb37e4d23 --- /dev/null +++ b/controllers/grid/plugins/form/UploadPluginForm.inc.php @@ -0,0 +1,336 @@ +_function = $function; + + $this->addCheck(new FormValidator($this, 'temporaryFileId', 'required', 'Please select a file first')); + } + + // + // Implement template methods from Form. + // + /** + * @see Form::readInputData() + */ + function readInputData() { + $this->readUserVars(array('temporaryFileId')); + } + + /** + * @see Form::fetch() + */ + function fetch(&$request) { + $templateMgr =& TemplateManager::getManager(); + $templateMgr->assign('function', $this->_function); + + return parent::fetch($request); + } + + /** + * @see Form::execute() + */ + function execute(&$request) { + parent::execute($request); + + // Retrieve the temporary file. + $user =& $request->getUser(); + $temporaryFileId = $this->getData('temporaryFileId'); + $temporaryFileDao =& DAORegistry::getDAO('TemporaryFileDAO'); + $temporaryFile =& $temporaryFileDao->getTemporaryFile($temporaryFileId, $user->getId()); + + // tar archive basename (less potential version number) must equal plugin directory name + // and plugin files must be in a directory named after the plug-in. + $matches = array(); + String::regexp_match_get('/^[a-zA-Z0-9]+/', basename($temporaryFile->getOriginalFileName(), '.tar.gz'), $matches); + $pluginName = array_pop($matches); + + // Create random dirname to avoid symlink attacks. + $pluginDir = dirname($temporaryFile->getFilePath()) . DIRECTORY_SEPARATOR . $pluginName . substr(md5(mt_rand()), 0, 10); + mkdir($pluginDir); + + $errorMsg = null; + + // Test whether the tar binary is available for the export to work + $tarBinary = Config::getVar('cli', 'tar'); + if (!empty($tarBinary) && file_exists($tarBinary)) { + exec($tarBinary.' -xzf ' . escapeshellarg($temporaryFile->getFilePath()) . ' -C ' . escapeshellarg($pluginDir)); + } else { + $errorMsg = __('manager.plugins.tarCommandNotFound'); + } + + if (empty($errorMsg)) { + // We should now find a directory named after the + // plug-in within the extracted archive. + $pluginDir .= DIRECTORY_SEPARATOR . $pluginName; + if (is_dir($pluginDir)) { + $result = null; + if ($this->_function == 'install') { + $result = $this->_installPlugin($request, $pluginDir); + } else if ($this->_function == 'upgrade') { + $result = $this->_upgradePlugin($request, $pluginDir); + } + + if(!is_null($result) && $result !== true) { + $errorMsg = $result; + } + } else { + $errorMsg = __('manager.plugins.invalidPluginArchive'); + } + } + + if(!is_null($errorMsg) ) { + $notificationMgr = new NotificationManager(); + $notificationMgr->createTrivialNotification($user->getId(), NOTIFICATION_TYPE_ERROR, array('contents' => $errorMsg)); + return false; + } + + return true; + } + + + // + // Private helper methods. + // + /** + * Installs the uploaded plugin + * @param $request PKPRequest + * @param $path string path to plugin Directory + * @return boolean + */ + function _installPlugin($request, $path) { + $versionFile = $path . VERSION_FILE; + + $checkResult =& VersionCheck::getValidPluginVersionInfo($versionFile, true); + if (is_string($checkResult)) return __($checkResult); + if (is_a($checkResult, 'Version')) { + $pluginVersion = $checkResult; + } else { + assert(false); + } + + $versionDao =& DAORegistry::getDAO('VersionDAO'); /* @var $versionDao VersionDAO */ + $installedPlugin = $versionDao->getCurrentVersion($pluginVersion->getProductType(), $pluginVersion->getProduct(), true); + + if(!$installedPlugin) { + $pluginLibDest = Core::getBaseDir() . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'pkp' . DIRECTORY_SEPARATOR . strtr($pluginVersion->getProductType(), '.', DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $pluginVersion->getProduct(); + $pluginDest = Core::getBaseDir() . DIRECTORY_SEPARATOR . strtr($pluginVersion->getProductType(), '.', DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $pluginVersion->getProduct(); + + // Copy the plug-in from the temporary folder to the + // target folder. + // Start with the library part (if any). + $libPath = $path . DIRECTORY_SEPARATOR . 'lib'; + $fileManager = new FileManager(); + if (is_dir($libPath)) { + if(!$fileManager->copyDir($libPath, $pluginLibDest)) { + return __('manager.plugins.copyError'); + } + // Remove the library part of the temporary folder. + $fileManager->rmtree($libPath); + } + + // Continue with the application-specific part (mandatory). + if(!$fileManager->copyDir($path, $pluginDest)) { + return __('manager.plugins.copyError'); + } + + // Remove the temporary folder. + $fileManager->rmtree(dirname($path)); + + // Upgrade the database with the new plug-in. + $installFile = $pluginDest . INSTALL_FILE; + if(!is_file($installFile)) $installFile = Core::getBaseDir() . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'pkp' . DIRECTORY_SEPARATOR . 'xml' . DIRECTORY_SEPARATOR . 'defaultPluginInstall.xml'; + assert(is_file($installFile)); + $params = $this->_setConnectionParams(); + $installer = new Install($params, $installFile, true); + $installer->setCurrentVersion($pluginVersion); + if (!$installer->execute()) { + // Roll back the copy + if (is_dir($pluginLibDest)) $fileManager->rmtree($pluginLibDest); + if (is_dir($pluginDest)) $fileManager->rmtree($pluginDest); + return __('manager.plugins.installFailed', array('errorString' => $installer->getErrorString())); + } + + $notificationMgr = new NotificationManager(); + $user =& $request->getUser(); + $notificationMgr->createTrivialNotification( + $user->getId(), + NOTIFICATION_TYPE_SUCCESS, + array('contents' => + __('manager.plugins.installSuccessful', array('versionNumber' => $pluginVersion->getVersionString(false))))); + + $versionDao->insertVersion($pluginVersion, true); + return true; + } else { + if ($this->_checkIfNewer($pluginVersion->getProductType(), $pluginVersion->getProduct(), $pluginVersion)) { + return __('manager.plugins.pleaseUpgrade'); + } else { + return __('manager.plugins.installedVersionOlder'); + } + } + } + + /** + * Checks to see if local version of plugin is newer than installed version + * @param $productType string Product type of plugin + * @param $productName string Product name of plugin + * @param $newVersion Version Version object of plugin to check against database + * @return boolean + */ + function _checkIfNewer($productType, $productName, $newVersion) { + $versionDao =& DAORegistry::getDAO('VersionDAO'); + $installedPlugin = $versionDao->getCurrentVersion($productType, $productName, true); + + if (!$installedPlugin) return false; + if ($installedPlugin->compare($newVersion) > 0) return true; + else return false; + } + + /** + * Load database connection parameters into an array (needed for upgrade). + * @return array + */ + function _setConnectionParams() { + return array( + 'clientCharset' => Config::getVar('i18n', 'client_charset'), + 'connectionCharset' => Config::getVar('i18n', 'connection_charset'), + 'databaseCharset' => Config::getVar('i18n', 'database_charset'), + 'databaseDriver' => Config::getVar('database', 'driver'), + 'databaseHost' => Config::getVar('database', 'host'), + 'databaseUsername' => Config::getVar('database', 'username'), + 'databasePassword' => Config::getVar('database', 'password'), + 'databaseName' => Config::getVar('database', 'name') + ); + } + + /** + * Upgrade a plugin to a newer version from the user's filesystem + * @param $request PKPRequest + * @param $path string path to plugin Directory + * @param $templateMgr reference to template manager + * @param $category string + * @param $plugin string + * @return boolean + */ + function _upgradePlugin($request, $path, &$templateMgr) { + $category = $request->getUserVar('category'); + $plugin = $request->getUserVar('plugin'); + + $versionFile = $path . VERSION_FILE; + $templateMgr->assign('error', true); + + $pluginVersion =& VersionCheck::getValidPluginVersionInfo($versionFile, $templateMgr); + if (is_null($pluginVersion)) return false; + assert(is_a($pluginVersion, 'Version')); + + // Check whether the uploaded plug-in fits the original plug-in. + if ('plugins.'.$category != $pluginVersion->getProductType()) { + return __('manager.plugins.wrongCategory'); + } + + if ($plugin != $pluginVersion->getProduct()) { + return __('manager.plugins.wrongName'); + } + + $versionDao =& DAORegistry::getDAO('VersionDAO'); + $installedPlugin = $versionDao->getCurrentVersion($pluginVersion->getProductType(), $pluginVersion->getProduct(), true); + if(!$installedPlugin) { + return __('manager.plugins.pleaseInstall'); + } + + if ($this->_checkIfNewer($pluginVersion->getProductType(), $pluginVersion->getProduct(), $pluginVersion)) { + return __('manager.plugins.installedVersionNewer'); + } else { + $pluginDest = Core::getBaseDir() . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . $category . DIRECTORY_SEPARATOR . $plugin; + $pluginLibDest = Core::getBaseDir() . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'pkp' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . $category . DIRECTORY_SEPARATOR . $plugin; + + // Delete existing files. + $fileManager = new FileManager(); + if (is_dir($pluginDest)) $fileManager->rmtree($pluginDest); + if (is_dir($pluginLibDest)) $fileManager->rmtree($pluginLibDest); + + // Check whether deleting has worked. + if(is_dir($pluginDest) || is_dir($pluginLibDest)) { + return __('message', 'manager.plugins.deleteError'); + } + + // Copy the plug-in from the temporary folder to the + // target folder. + // Start with the library part (if any). + $libPath = $path . DIRECTORY_SEPARATOR . 'lib'; + if (is_dir($libPath)) { + if(!$fileManager->copyDir($libPath, $pluginLibDest)) { + return __('manager.plugins.copyError'); + } + // Remove the library part of the temporary folder. + $fileManager->rmtree($libPath); + } + + // Continue with the application-specific part (mandatory). + if(!$fileManager->copyDir($path, $pluginDest)) { + return __('manager.plugins.copyError'); + } + + // Remove the temporary folder. + $fileManager->rmtree(dirname($path)); + + $upgradeFile = $pluginDest . UPGRADE_FILE; + if($fileManager->fileExists($upgradeFile)) { + $params = $this->_setConnectionParams(); + $installer = new Upgrade($params, $upgradeFile, true); + + if (!$installer->execute()) { + return __('manager.plugins.upgradeFailed', array('errorString' => $installer->getErrorString())); + } + } + + $installedPlugin->setCurrent(0); + $pluginVersion->setCurrent(1); + $versionDao->insertVersion($pluginVersion, true); + + $notificationMgr = new NotificationManager(); + $notificationMgr->createTrivialNotification( + $user->getId(), NOTIFICATION_TYPE_SUCCESS, array('contents' => __('manager.plugins.upgradeSuccessful', array('versionString' => $pluginVersion->getVersionString(false))))); + + return true; + } + } +} + +?>