first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-06-08 17:09:23 -04:00
commit df3a033196
17887 changed files with 8637778 additions and 0 deletions
@@ -0,0 +1,34 @@
<?php
/**
* @file controllers/grid/plugins/PluginCategoryGridRow.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class PluginCategoryGridRow
*
* @ingroup controllers_grid_plugins
*
* @brief Plugin category grid row definition.
*/
namespace PKP\controllers\grid\plugins;
use PKP\controllers\grid\GridCategoryRow;
class PluginCategoryGridRow extends GridCategoryRow
{
//
// Overridden methods from GridCategoryRow
//
/**
* @copydoc GridCategoryRow::getCategoryLabel()
*/
public function getCategoryLabel()
{
$pluginCategory = $this->getData();
return __("plugins.categories.{$pluginCategory}");
}
}
@@ -0,0 +1,103 @@
<?php
/**
* @file controllers/grid/plugins/PluginGalleryGridCellProvider.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2003-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class PluginGalleryGridCellProvider
*
* @ingroup controllers_grid_plugins
*
* @brief Provide information about plugins to the plugin gallery grid handler
*/
namespace PKP\controllers\grid\plugins;
use PKP\controllers\grid\GridCellProvider;
use PKP\controllers\grid\GridColumn;
use PKP\controllers\grid\GridHandler;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
use PKP\plugins\GalleryPlugin;
class PluginGalleryGridCellProvider extends GridCellProvider
{
/**
* Extracts variables for a given column from a data element
* so that they may be assigned to template before rendering.
*
* @param \PKP\controllers\grid\GridRow $row
* @param GridColumn $column
*
* @return ?array
*/
public function getTemplateVarsFromRowColumn($row, $column)
{
$element = $row->getData();
$columnId = $column->getId();
assert(($element instanceof GalleryPlugin) && !empty($columnId));
switch ($columnId) {
case 'name':
// The name is returned as an action.
return ['label' => ''];
case 'summary':
$label = $element->getLocalizedSummary();
return ['label' => $label];
case 'status':
switch ($element->getCurrentStatus()) {
case PLUGIN_GALLERY_STATE_NEWER:
$statusKey = 'manager.plugins.installedVersionNewer.short';
break;
case PLUGIN_GALLERY_STATE_UPGRADABLE:
$statusKey = 'manager.plugins.installedVersionOlder.short';
break;
case PLUGIN_GALLERY_STATE_CURRENT:
$statusKey = 'manager.plugins.installedVersionNewest.short';
break;
case PLUGIN_GALLERY_STATE_AVAILABLE:
$statusKey = null;
break;
case PLUGIN_GALLERY_STATE_INCOMPATIBLE:
$statusKey = 'manager.plugins.noCompatibleVersion.short';
break;
default:
assert(false);
return;
}
return ['label' => __($statusKey)];
default:
break;
}
}
/**
* Get cell actions associated with this row/column combination
*
* @param \PKP\controllers\grid\GridRow $row
* @param GridColumn $column
*
* @return array an array of LinkAction instances
*/
public function getCellActions($request, $row, $column, $position = GridHandler::GRID_ACTION_POSITION_DEFAULT)
{
$element = $row->getData();
switch ($column->getId()) {
case 'name':
$router = $request->getRouter();
return [new LinkAction(
'moreInformation',
new AjaxModal(
$router->url($request, null, null, 'viewPlugin', null, ['rowId' => $row->getId() + 1]),
htmlspecialchars($element->getLocalizedName()),
'modal_information',
true
),
htmlspecialchars($element->getLocalizedName()),
'details'
)];
}
return parent::getCellActions($request, $row, $column, $position);
}
}
@@ -0,0 +1,362 @@
<?php
/**
* @file controllers/grid/plugins/PluginGalleryGridHandler.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class PluginGalleryGridHandler
*
* @ingroup controllers_grid_settings_pluginGallery
*
* @brief Handle review form grid requests.
*/
namespace PKP\controllers\grid\plugins;
use APP\core\Application;
use APP\notification\NotificationManager;
use APP\template\TemplateManager;
use Exception;
use PKP\controllers\grid\GridColumn;
use PKP\controllers\grid\GridHandler;
use PKP\core\JSONMessage;
use PKP\core\PKPApplication;
use PKP\core\PKPRequest;
use PKP\db\DAORegistry;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\RemoteActionConfirmationModal;
use PKP\notification\PKPNotification;
use PKP\plugins\GalleryPlugin;
use PKP\plugins\PluginGalleryDAO;
use PKP\plugins\PluginHelper;
use PKP\plugins\PluginRegistry;
use PKP\security\authorization\PolicySet;
use PKP\security\authorization\RoleBasedHandlerOperationPolicy;
use PKP\security\Role;
use PKP\security\Validation;
use SplFileObject;
/**
* Global value for 'all' category string value
*/
class PluginGalleryGridHandler extends GridHandler
{
public const PLUGIN_GALLERY_ALL_CATEGORY_SEARCH_VALUE = 'all';
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->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];
}
}
@@ -0,0 +1,107 @@
<?php
/**
* @file controllers/grid/plugins/PluginGridCellProvider.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2003-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class PluginGridCellProvider
*
* @ingroup controllers_grid_plugins
*
* @brief Cell provider for columns in a plugin grid.
*/
namespace PKP\controllers\grid\plugins;
use PKP\controllers\grid\GridCellProvider;
use PKP\controllers\grid\GridColumn;
use PKP\controllers\grid\GridHandler;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxAction;
use PKP\linkAction\request\RemoteActionConfirmationModal;
use PKP\plugins\Plugin;
class PluginGridCellProvider extends GridCellProvider
{
/**
* Extracts variables for a given column from a data element
* so that they may be assigned to template before rendering.
*
* @param \PKP\controllers\grid\GridRow $row
* @param GridColumn $column
*
* @return array
*/
public function getTemplateVarsFromRowColumn($row, $column)
{
$plugin = & $row->getData();
$columnId = $column->getId();
assert(is_a($plugin, 'Plugin') && !empty($columnId));
switch ($columnId) {
case 'name':
return ['label' => $plugin->getDisplayName()];
case 'category':
return ['label' => $plugin->getCategory()];
case 'description':
return ['label' => $plugin->getDescription()];
case 'enabled':
$isEnabled = $plugin->getEnabled();
return [
'selected' => $isEnabled,
'disabled' => $isEnabled ? !$plugin->getCanDisable() : !$plugin->getCanEnable(),
];
default:
break;
}
return parent::getTemplateVarsFromRowColumn($row, $column);
}
/**
* @copydoc GridCellProvider::getCellActions()
*/
public function getCellActions($request, $row, $column, $position = GridHandler::GRID_ACTION_POSITION_DEFAULT)
{
switch ($column->getId()) {
case 'enabled':
$plugin = $row->getData(); /** @var Plugin $plugin */
$requestArgs = array_merge(
['plugin' => $plugin->getName()],
$row->getRequestArgs()
);
switch (true) {
case $plugin->getEnabled() && $plugin->getCanDisable():
// Create an action to disable the plugin
return [new LinkAction(
'disable',
new RemoteActionConfirmationModal(
$request->getSession(),
__('grid.plugin.disable'),
__('common.disable'),
$request->url(null, null, 'disable', null, $requestArgs)
),
__('manager.plugins.disable'),
null
)];
case !$plugin->getEnabled() && $plugin->getCanEnable():
// Create an action to enable the plugin
return [new LinkAction(
'enable',
new AjaxAction(
$request->url(null, null, 'enable', null, array_merge(
['csrfToken' => $request->getSession()->getCSRFToken()],
$requestArgs
))
),
__('manager.plugins.enable'),
null
)];
}
}
return parent::getCellActions($request, $row, $column, $position);
}
}
@@ -0,0 +1,130 @@
<?php
/**
* @file controllers/grid/plugins/PluginGridRow.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class PluginGridRow
*
* @ingroup controllers_grid_plugins
*
* @brief Plugin grid row definition
*/
namespace PKP\controllers\grid\plugins;
use PKP\controllers\grid\GridRow;
use PKP\core\PKPRouter;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
use PKP\linkAction\request\RemoteActionConfirmationModal;
use PKP\plugins\Plugin;
use PKP\security\Role;
class PluginGridRow extends GridRow
{
/** @var array */
public $_userRoles;
/**
* Constructor
*
* @param array $userRoles
*/
public function __construct($userRoles)
{
parent::__construct();
$this->_userRoles = $userRoles;
}
//
// Overridden methods from GridRow
//
/**
* @copydoc GridRow::initialize()
*
* @param null|mixed $template
*/
public function initialize($request, $template = null)
{
parent::initialize($request, $template);
// 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 PKPRouter $router */
$actionArgs = array_merge(
['plugin' => $plugin->getName()],
$this->getRequestArgs()
);
if ($this->_canEdit($plugin)) {
foreach ($plugin->getActions($request, $actionArgs) as $action) {
$this->addAction($action);
}
}
// Administrative functions.
if (in_array(Role::ROLE_ID_SITE_ADMIN, $this->_userRoles)) {
$this->addAction(new LinkAction(
'delete',
new RemoteActionConfirmationModal(
$request->getSession(),
__('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'
));
}
}
}
//
// Protected helper methods
//
/**
* Return if user can edit a plugin settings or not.
*
* @param Plugin $plugin
*
* @return bool
*/
protected function _canEdit($plugin)
{
if ($plugin->isSitePlugin()) {
if (in_array(Role::ROLE_ID_SITE_ADMIN, $this->_userRoles)) {
return true;
}
} else {
if (in_array(Role::ROLE_ID_MANAGER, $this->_userRoles)) {
return true;
}
}
return false;
}
}
@@ -0,0 +1,128 @@
<?php
/**
* @file controllers/grid/plugins/form/UploadPluginForm.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2003-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class UploadPluginForm
*
* @ingroup controllers_grid_plugins_form
*
* @brief Form to upload a plugin file.
*/
namespace PKP\controllers\grid\plugins\form;
use APP\core\Application;
use APP\notification\NotificationManager;
use APP\template\TemplateManager;
use Exception;
use PKP\db\DAORegistry;
use PKP\file\TemporaryFileDAO;
use PKP\file\TemporaryFileManager;
use PKP\form\Form;
use PKP\notification\PKPNotification;
use PKP\plugins\PluginHelper;
use PKP\plugins\PluginRegistry;
class UploadPluginForm extends Form
{
/**
* Constructor.
*
* @param string $pluginAction PLUGIN_ACTION_...
*/
public function __construct(private $pluginAction)
{
parent::__construct('controllers/grid/plugins/form/uploadPluginForm.tpl');
$this->addCheck(new \PKP\form\validation\FormValidator($this, 'temporaryFileId', 'required', 'manager.plugins.uploadFailed'));
}
//
// Implement template methods from Form.
//
/**
* @copydoc Form::readInputData()
*/
public function readInputData()
{
$this->readUserVars(['temporaryFileId']);
}
/**
* @copydoc Form::fetch()
*
* @param null|mixed $template
*/
public function fetch($request, $template = null, $display = false)
{
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign([
'function' => $this->pluginAction,
'category' => $request->getUserVar('category'),
'plugin' => $request->getUserVar('plugin'),
]);
return parent::fetch($request, $template, $display);
}
/**
* @copydoc Form::execute()
*/
public function execute(...$functionArgs)
{
parent::execute(...$functionArgs);
$request = Application::get()->getRequest();
$user = $request->getUser();
$pluginHelper = new PluginHelper();
$notificationMgr = new NotificationManager();
// Retrieve the temporary file.
$temporaryFileManager = new TemporaryFileManager();
$temporaryFileDao = DAORegistry::getDAO('TemporaryFileDAO'); /** @var TemporaryFileDAO $temporaryFileDao */
$temporaryFile = $temporaryFileDao->getTemporaryFile($this->getData('temporaryFileId'), $user->getId());
try {
if (!$temporaryFile) {
throw new Exception('The uploaded plugin file was not found');
}
switch ($this->pluginAction) {
case PluginHelper::PLUGIN_ACTION_UPLOAD:
$pluginVersion = $pluginHelper->installPlugin($temporaryFile->getFilePath(), $temporaryFile->getOriginalFileName());
$notificationMgr->createTrivialNotification(
$user->getId(),
PKPNotification::NOTIFICATION_TYPE_SUCCESS,
['contents' => __('manager.plugins.installSuccessful', ['versionNumber' => $pluginVersion->getVersionString(false)])]
);
break;
case PluginHelper::PLUGIN_ACTION_UPGRADE:
$plugin = PluginRegistry::getPlugin($request->getUserVar('category'), $request->getUserVar('plugin'));
$pluginVersion = $pluginHelper->upgradePlugin(
$request->getUserVar('category'),
basename($plugin->getPluginPath()),
$temporaryFile->getFilePath(),
$temporaryFile->getOriginalFileName()
);
$notificationMgr->createTrivialNotification(
$user->getId(),
PKPNotification::NOTIFICATION_TYPE_SUCCESS,
['contents' => __('manager.plugins.upgradeSuccessful', ['versionString' => $pluginVersion->getVersionString(false)])]
);
break;
default:
throw new Exception(__('common.unknownError'));
}
} catch (Exception $e) {
$notificationMgr->createTrivialNotification($user->getId(), PKPNotification::NOTIFICATION_TYPE_ERROR, ['contents' => $e->getMessage()]);
} finally {
if ($temporaryFile) {
$temporaryFileManager->deleteById($temporaryFile->getId(), $user->getId());
}
}
return true;
}
}