Manage plugins from the user interface and from the command line
This commit is contained in:
162
app/Core/Plugin/Installer.php
Normal file
162
app/Core/Plugin/Installer.php
Normal file
@@ -0,0 +1,162 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Core\Plugin;
|
||||
|
||||
use RecursiveDirectoryIterator;
|
||||
use RecursiveIteratorIterator;
|
||||
use ZipArchive;
|
||||
|
||||
/**
|
||||
* Class Installer
|
||||
*
|
||||
* @package Kanboard\Core\Plugin
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class Installer extends \Kanboard\Core\Base
|
||||
{
|
||||
/**
|
||||
* Return true if Kanboard is configured to install plugins
|
||||
*
|
||||
* @static
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public static function isConfigured()
|
||||
{
|
||||
return PLUGIN_INSTALLER && is_writable(PLUGINS_DIR) && extension_loaded('zip');
|
||||
}
|
||||
|
||||
/**
|
||||
* Install a plugin
|
||||
*
|
||||
* @access public
|
||||
* @param string $archiveUrl
|
||||
* @throws PluginInstallerException
|
||||
*/
|
||||
public function install($archiveUrl)
|
||||
{
|
||||
$zip = $this->downloadPluginArchive($archiveUrl);
|
||||
|
||||
if (! $zip->extractTo(PLUGINS_DIR)) {
|
||||
$this->cleanupArchive($zip);
|
||||
throw new PluginInstallerException(t('Unable to extract plugin archive.'));
|
||||
}
|
||||
|
||||
$this->cleanupArchive($zip);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall a plugin
|
||||
*
|
||||
* @access public
|
||||
* @param string $pluginId
|
||||
* @throws PluginInstallerException
|
||||
*/
|
||||
public function uninstall($pluginId)
|
||||
{
|
||||
$pluginFolder = PLUGINS_DIR.DIRECTORY_SEPARATOR.basename($pluginId);
|
||||
|
||||
if (! file_exists($pluginFolder)) {
|
||||
throw new PluginInstallerException(t('Plugin not found.'));
|
||||
}
|
||||
|
||||
if (! is_writable($pluginFolder)) {
|
||||
throw new PluginInstallerException(e('You don\'t have the permission to remove this plugin.'));
|
||||
}
|
||||
|
||||
$this->removeAllDirectories($pluginFolder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a plugin
|
||||
*
|
||||
* @access public
|
||||
* @param string $archiveUrl
|
||||
* @throws PluginInstallerException
|
||||
*/
|
||||
public function update($archiveUrl)
|
||||
{
|
||||
$zip = $this->downloadPluginArchive($archiveUrl);
|
||||
|
||||
$firstEntry = $zip->statIndex(0);
|
||||
$this->uninstall($firstEntry['name']);
|
||||
|
||||
if (! $zip->extractTo(PLUGINS_DIR)) {
|
||||
$this->cleanupArchive($zip);
|
||||
throw new PluginInstallerException(t('Unable to extract plugin archive.'));
|
||||
}
|
||||
|
||||
$this->cleanupArchive($zip);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download archive from URL
|
||||
*
|
||||
* @access protected
|
||||
* @param string $archiveUrl
|
||||
* @return ZipArchive
|
||||
* @throws PluginInstallerException
|
||||
*/
|
||||
protected function downloadPluginArchive($archiveUrl)
|
||||
{
|
||||
$zip = new ZipArchive();
|
||||
$archiveData = $this->httpClient->get($archiveUrl);
|
||||
$archiveFile = tempnam(sys_get_temp_dir(), 'kb_plugin');
|
||||
|
||||
if (empty($archiveData)) {
|
||||
unlink($archiveFile);
|
||||
throw new PluginInstallerException(t('Unable to download plugin archive.'));
|
||||
}
|
||||
|
||||
if (file_put_contents($archiveFile, $archiveData) === false) {
|
||||
unlink($archiveFile);
|
||||
throw new PluginInstallerException(t('Unable to write temporary file for plugin.'));
|
||||
}
|
||||
|
||||
if ($zip->open($archiveFile) !== true) {
|
||||
unlink($archiveFile);
|
||||
throw new PluginInstallerException(t('Unable to open plugin archive.'));
|
||||
}
|
||||
|
||||
if ($zip->numFiles === 0) {
|
||||
unlink($archiveFile);
|
||||
throw new PluginInstallerException(t('There is no file in the plugin archive.'));
|
||||
}
|
||||
|
||||
return $zip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove archive file
|
||||
*
|
||||
* @access protected
|
||||
* @param ZipArchive $zip
|
||||
*/
|
||||
protected function cleanupArchive(ZipArchive $zip)
|
||||
{
|
||||
unlink($zip->filename);
|
||||
$zip->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove recursively a directory
|
||||
*
|
||||
* @access protected
|
||||
* @param string $directory
|
||||
*/
|
||||
protected function removeAllDirectories($directory)
|
||||
{
|
||||
$it = new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS);
|
||||
$files = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST);
|
||||
|
||||
foreach ($files as $file) {
|
||||
if ($file->isDir()) {
|
||||
rmdir($file->getRealPath());
|
||||
} else {
|
||||
unlink($file->getRealPath());
|
||||
}
|
||||
}
|
||||
|
||||
rmdir($directory);
|
||||
}
|
||||
}
|
||||
@@ -18,16 +18,16 @@ class Loader extends \Kanboard\Core\Base
|
||||
/**
|
||||
* Plugin instances
|
||||
*
|
||||
* @access public
|
||||
* @access protected
|
||||
* @var array
|
||||
*/
|
||||
public $plugins = array();
|
||||
protected $plugins = array();
|
||||
|
||||
/**
|
||||
* Get list of loaded plugins
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
* @return Base[]
|
||||
*/
|
||||
public function getPlugins()
|
||||
{
|
||||
@@ -52,7 +52,7 @@ class Loader extends \Kanboard\Core\Base
|
||||
if ($fileInfo->isDir() && substr($fileInfo->getFilename(), 0, 1) !== '.') {
|
||||
$pluginName = $fileInfo->getFilename();
|
||||
$this->loadSchema($pluginName);
|
||||
$this->initializePlugin($this->loadPlugin($pluginName));
|
||||
$this->initializePlugin($pluginName, $this->loadPlugin($pluginName));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -95,9 +95,10 @@ class Loader extends \Kanboard\Core\Base
|
||||
* Initialize plugin
|
||||
*
|
||||
* @access public
|
||||
* @param Base $plugin
|
||||
* @param string $pluginName
|
||||
* @param Base $plugin
|
||||
*/
|
||||
public function initializePlugin(Base $plugin)
|
||||
public function initializePlugin($pluginName, Base $plugin)
|
||||
{
|
||||
if (method_exists($plugin, 'onStartup')) {
|
||||
$this->dispatcher->addListener('app.bootstrap', array($plugin, 'onStartup'));
|
||||
@@ -107,6 +108,6 @@ class Loader extends \Kanboard\Core\Base
|
||||
Tool::buildDICHelpers($this->container, $plugin->getHelpers());
|
||||
|
||||
$plugin->initialize();
|
||||
$this->plugins[] = $plugin;
|
||||
$this->plugins[$pluginName] = $plugin;
|
||||
}
|
||||
}
|
||||
|
||||
15
app/Core/Plugin/PluginInstallerException.php
Normal file
15
app/Core/Plugin/PluginInstallerException.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Core\Plugin;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Class PluginInstallerException
|
||||
*
|
||||
* @package Kanboard\Core\Plugin
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class PluginInstallerException extends Exception
|
||||
{
|
||||
}
|
||||
Reference in New Issue
Block a user