From b42af10905652a124aa6d88098e9f7d117a09718 Mon Sep 17 00:00:00 2001 From: Diogo Cordeiro Date: Sat, 17 Aug 2019 05:52:02 +0100 Subject: [PATCH] [MODULES] Allow to delete third party plugins --- actions/plugindelete.php | 113 +++++++++++++++++++++++++++++++++++++++ lib/plugindeleteform.php | 101 ++++++++++++++++++++++++++++++++++ lib/pluginlist.php | 3 ++ lib/router.php | 3 ++ 4 files changed, 220 insertions(+) create mode 100644 actions/plugindelete.php create mode 100644 lib/plugindeleteform.php diff --git a/actions/plugindelete.php b/actions/plugindelete.php new file mode 100644 index 0000000000..04d74198dc --- /dev/null +++ b/actions/plugindelete.php @@ -0,0 +1,113 @@ +. + +defined('STATUSNET') || die(); + +require_once INSTALLDIR . '/lib/deletetree.php'; + +/** + * Form for deleting a plugin + * + * @category Action + * @package GNUsocial + * @author Diogo Cordeiro + * @copyright 2019 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ +class PlugindeleteAction extends Action +{ + var $user; + var $plugin; + + /** + * Check pre-requisites and instantiate attributes + * + * @param array $args array of arguments (URL, GET, POST) + * + * @return bool success flag + * @throws ClientException + */ + function prepare(array $args = []) + { + parent::prepare($args); + + // @fixme these are pretty common, should a parent class factor these out? + + // Only allow POST requests + + if ($_SERVER['REQUEST_METHOD'] != 'POST') { + // TRANS: Client error displayed when trying to use another method than POST. + // TRANS: Do not translate POST. + $this->clientError(_m('This action only accepts POST requests.')); + } + + // CSRF protection + + $token = $this->trimmed('token'); + + if (!$token || $token != common_session_token()) { + // TRANS: Client error displayed when the session token does not match or is not given. + $this->clientError(_m('There was a problem with your session token.'. + ' Try again, please.')); + } + + // Only for logged-in users + + $this->user = common_current_user(); + + if (empty($this->user)) { + // TRANS: Error message displayed when trying to perform an action that requires a logged in user. + $this->clientError(_m('Not logged in.')); + } + + if (!AdminPanelAction::canAdmin('plugins')) { + // TRANS: Client error displayed when trying to enable or disable a plugin without access rights. + $this->clientError(_m('You cannot administer plugins.')); + } + + $this->plugin = $this->arg('plugin'); + if (!array_key_exists($this->plugin, array_flip(PluginList::grabAllPluginNames()))) { + // TRANS: Client error displayed when trying to enable or disable a non-existing plugin. + $this->clientError(_m('No such plugin.')); + } + + return true; + } + + /** + * Handle request + * + * Does the subscription and returns results. + * + * @return void + * @throws ClientException + */ + function handle() + { + if (PluginList::isPluginLoaded($this->plugin)) { + $this->clientError(_m('You can\'t delete a plugin without first removing its loader from your config.php.')); + } + if (!is_writable(INSTALLDIR . '/local/plugins/'.$this->plugin)) { + $this->clientError(_m('We can only delete third party plugins.')); + } + deleteTree(INSTALLDIR . '/local/plugins/'.$this->plugin); + deleteTree(PUBLICDIR . '/local/plugins/'.$this->plugin); + + $url = common_local_url('pluginsadminpanel'); + common_redirect($url, 303); + } + +} diff --git a/lib/plugindeleteform.php b/lib/plugindeleteform.php new file mode 100644 index 0000000000..61f6406f43 --- /dev/null +++ b/lib/plugindeleteform.php @@ -0,0 +1,101 @@ +. + +defined('STATUSNET') || die(); + +/** + * Form for deleting a plugin + * + * @category Form + * @package GNUsocial + * @author Diogo Cordeiro + * @copyright 2019 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ +class PluginDeleteForm extends PluginEnableForm +{ + /** + * Plugin to delete + */ + public $plugin = null; + + /** + * Constructor + * + * @param HTMLOutputter $out output channel + * @param string $plugin plugin to delete + */ + public function __construct($out = null, $plugin = null) + { + parent::__construct($out); + + $this->plugin = $plugin; + } + + /** + * ID of the form + * + * @return string ID of the form + */ + public function id() + { + return 'plugin-delete-' . $this->plugin; + } + + /** + * class of the form + * + * @return string of the form class + */ + public function formClass() + { + return 'form_plugin_delete'; + } + + /** + * Action of the form + * + * @return string URL of the action + */ + public function action() + { + return common_local_url( + 'plugindelete', + ['plugin' => $this->plugin] + ); + } + + public function show() + { + if (!is_writable(INSTALLDIR . '/local/plugins/'.$this->plugin) || // We can only delete third party plugins + PluginList::isPluginLoaded($this->plugin)) { // We can't delete a plugin that has been loaded in config.php + return; + } + parent::show(); + } + + /** + * Action elements + * + * @return void + * @throws Exception + */ + public function formActions() + { + // TRANS: Plugin admin panel controls + $this->out->submit('submit', _m('plugin', 'Delete')); + } +} diff --git a/lib/pluginlist.php b/lib/pluginlist.php index c41d5d8f5e..db9f0fe4f8 100644 --- a/lib/pluginlist.php +++ b/lib/pluginlist.php @@ -236,6 +236,9 @@ class PluginListItem extends Widget $form = $this->getControlForm(); $form->show(); + $delete_form = new PluginDeleteForm($this->out, $this->plugin); + $delete_form->show(); + $this->out->elementEnd('td'); // Version and authors diff --git a/lib/router.php b/lib/router.php index 3164563883..a069ec2a86 100644 --- a/lib/router.php +++ b/lib/router.php @@ -811,6 +811,9 @@ class Router $m->connect('panel/plugins/disable/:plugin', ['action' => 'plugindisable'], ['plugin' => '[A-Za-z0-9_]+']); + $m->connect('panel/plugins/delete/:plugin', + ['action' => 'plugindelete'], + ['plugin' => '[A-Za-z0-9_]+']); $m->connect('panel/plugins/install', ['action' => 'plugininstall']);