addRoleAssignment( [Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN], ['fetchGrid', 'fetchRow', 'viewPlugin'] ); $this->addRoleAssignment( [Role::ROLE_ID_SITE_ADMIN], ['installPlugin', 'upgradePlugin'] ); } // // Implement template methods from PKPHandler. // /** * @copydoc GridHandler::initialize() * * @param null|mixed $args */ public function initialize($request, $args = null) { parent::initialize($request, $args); // Basic grid configuration. $this->setTitle('manager.plugins.pluginGallery'); // // Grid columns. // $pluginGalleryGridCellProvider = new PluginGalleryGridCellProvider(); // Plugin name. $this->addColumn( new GridColumn( 'name', 'common.name', null, null, $pluginGalleryGridCellProvider ) ); // Description. $this->addColumn( new GridColumn( 'summary', 'common.description', null, null, $pluginGalleryGridCellProvider, ['width' => 50, 'alignment' => GridColumn::COLUMN_ALIGNMENT_LEFT] ) ); // Status. $this->addColumn( new GridColumn( 'status', 'common.status', null, null, $pluginGalleryGridCellProvider, ['width' => 20] ) ); } /** * @see PKPHandler::authorize() */ public function authorize($request, &$args, $roleAssignments) { $rolePolicy = new PolicySet(PolicySet::COMBINING_PERMIT_OVERRIDES); foreach ($roleAssignments as $role => $operations) { $rolePolicy->addPolicy(new RoleBasedHandlerOperationPolicy($request, $role, $operations)); } $this->addPolicy($rolePolicy); return parent::authorize($request, $args, $roleAssignments); } // // Implement methods from GridHandler. // /** * @see GridHandler::loadData() * * @param PKPRequest $request Request object * @param array $filter Filter parameters * * @return array Grid data. */ protected function loadData($request, $filter) { // Get all plugins. $pluginGalleryDao = DAORegistry::getDAO('PluginGalleryDAO'); /** @var PluginGalleryDAO $pluginGalleryDao */ return $pluginGalleryDao->getNewestCompatible( Application::get(), $request->getUserVar('category'), $request->getUserVar('pluginText') ); } /** * @see GridHandler::getFilterForm() */ protected function getFilterForm() { return 'controllers/grid/plugins/pluginGalleryGridFilter.tpl'; } /** * @see GridHandler::getFilterSelectionData() */ public function getFilterSelectionData($request) { $category = $request->getUserVar('category'); $pluginName = $request->getUserVar('pluginText'); if (is_null($category)) { $category = self::PLUGIN_GALLERY_ALL_CATEGORY_SEARCH_VALUE; } return ['category' => $category, 'pluginText' => $pluginName]; } /** * @copydoc GridHandler::renderFilter() */ protected function renderFilter($request, $filterData = []) { $categoriesSymbolic = $categories = PluginRegistry::getCategories(); $categories = [self::PLUGIN_GALLERY_ALL_CATEGORY_SEARCH_VALUE => __('grid.plugin.allCategories')]; foreach ($categoriesSymbolic as $category) { $categories[$category] = __("plugins.categories.{$category}"); } $filterData['categories'] = $categories; return parent::renderFilter($request, $filterData); } // // Public operations // /** * View a plugin's details */ public function viewPlugin(array $args, PKPRequest $request): JSONMessage { $plugin = $this->_getSpecifiedPlugin($request); // Display plugin information $templateMgr = TemplateManager::getManager($request); $templateMgr->assign('plugin', $plugin); // Get currently installed version, if any. $installActionKey = $installConfirmKey = $installOp = null; switch ($plugin->getCurrentStatus()) { case PLUGIN_GALLERY_STATE_NEWER: $statusKey = 'manager.plugins.installedVersionNewer'; $statusClass = 'newer'; break; case PLUGIN_GALLERY_STATE_UPGRADABLE: $statusKey = 'manager.plugins.installedVersionOlder'; $statusClass = 'older'; $installActionKey = 'grid.action.upgrade'; $installOp = 'upgradePlugin'; $installConfirmKey = 'manager.plugins.upgradeConfirm'; break; case PLUGIN_GALLERY_STATE_CURRENT: $statusKey = 'manager.plugins.installedVersionNewest'; $statusClass = 'newest'; break; case PLUGIN_GALLERY_STATE_AVAILABLE: $statusKey = 'manager.plugins.noInstalledVersion'; $statusClass = 'notinstalled'; $installActionKey = 'grid.action.install'; $installOp = 'installPlugin'; $installConfirmKey = 'manager.plugins.installConfirm'; break; case PLUGIN_GALLERY_STATE_INCOMPATIBLE: $statusKey = 'manager.plugins.noCompatibleVersion'; $statusClass = 'incompatible'; break; default: return throw new Exception('Unexpected gallery state'); } $templateMgr->assign([ 'statusKey' => $statusKey, 'statusClass' => $statusClass ]); $router = $request->getRouter(); if (Validation::isSiteAdmin() && $installOp) { $templateMgr->assign('installAction', new LinkAction( 'installPlugin', new RemoteActionConfirmationModal( $request->getSession(), __($installConfirmKey), __($installActionKey), $router->url($request, null, null, $installOp, null, ['rowId' => $request->getUserVar('rowId')]), 'modal_information' ), __($installActionKey), null )); } return new JSONMessage(true, $templateMgr->fetch('controllers/grid/plugins/viewPlugin.tpl')); } /** * Upgrade a plugin */ public function upgradePlugin(array $args, PKPRequest $request): JSONMessage { return $this->installPlugin($args, $request, true); } /** * Install or upgrade a plugin */ public function installPlugin(array $args, PKPRequest $request, bool $isUpgrade = false): JSONMessage { $redirectUrl = $request->getDispatcher()->url($request, PKPApplication::ROUTE_PAGE, null, 'management', 'settings', ['website'], ['r' => uniqid()], 'plugins'); if (!$request->checkCSRF()) { return $request->redirectUrlJson($redirectUrl); } $plugin = $this->_getSpecifiedPlugin($request); $notificationMgr = new NotificationManager(); $user = $request->getUser(); $pluginHelper = new PluginHelper(); // Create a temporary file to stream the download $pluginFile = new SplFileObject($pluginFilePath = tempnam(sys_get_temp_dir(), 'plugin'), 'w'); $pluginFile->flock(LOCK_EX); $pluginFilePath = $pluginFile->getPathname(); try { // Download the plugin package. $body = Application::get() ->getHttpClient() ->request('GET', $plugin->getReleasePackage()) ->getBody(); while ($data = $body->read(80 << 10)) { if ($pluginFile->fwrite($data) === false) { throw new Exception('Failed to download the plugin'); } } // Release the file $pluginFile = null; // Verify the plugin checksum. if (($md5 = md5_file($pluginFilePath)) !== $plugin->getReleaseMD5()) { throw new Exception("Integrity validation failed, expected MD5 {$plugin->getReleaseMD5()} received {$md5}"); } // Install/upgrade the plugin $fileName = basename(parse_url($plugin->getReleasePackage(), PHP_URL_PATH)); $pluginVersion = $isUpgrade ? $pluginHelper->upgradePlugin($plugin->getCategory(), $plugin->getProduct(), $pluginFilePath, $fileName) : $pluginHelper->installPlugin($pluginFilePath, $fileName); // Success notification $version = $pluginVersion->getVersionString(false); $notificationMgr->createTrivialNotification( $user->getId(), PKPNotification::NOTIFICATION_TYPE_SUCCESS, [ 'contents' => $isUpgrade ? __('manager.plugins.upgradeSuccessful', ['versionString' => $version]) : __('manager.plugins.installSuccessful', ['versionNumber' => $version]) ] ); } catch (Exception $e) { // Failure notification $notificationMgr->createTrivialNotification( $user->getId(), PKPNotification::NOTIFICATION_TYPE_ERROR, ['contents' => $e->getMessage()] ); } finally { // Release file $pluginFile = null; unlink($pluginFilePath); } return $request->redirectUrlJson($redirectUrl); } /** * Get the specified plugin. */ public function _getSpecifiedPlugin(PKPRequest $request): GalleryPlugin { // Get all plugins. $pluginGalleryDao = DAORegistry::getDAO('PluginGalleryDAO'); /** @var PluginGalleryDAO $pluginGalleryDao */ $plugins = $pluginGalleryDao->getNewestCompatible(Application::get()); // Get specified plugin. Indexes into $plugins are 0-based // but row IDs are 1-based; compensate. $rowId = (int) $request->getUserVar('rowId') - 1; if (!isset($plugins[$rowId])) { throw new Exception('Invalid row ID!'); } return $plugins[$rowId]; } }