Implement uninstallAddon

This commit is contained in:
Art4 2025-05-14 14:54:14 +00:00
parent a39850871e
commit 33398298d5
2 changed files with 172 additions and 1 deletions

View file

@ -9,7 +9,9 @@ declare(strict_types=1);
namespace Friendica\Core\Addon; namespace Friendica\Core\Addon;
use Friendica\Core\Cache\Capability\ICanCache;
use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Database\Database;
use Friendica\Util\Profiler; use Friendica\Util\Profiler;
use Friendica\Util\Strings; use Friendica\Util\Strings;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
@ -23,8 +25,12 @@ final class AddonManagerHelper implements AddonHelper
{ {
private string $addonPath; private string $addonPath;
private Database $database;
private IManageConfigValues $config; private IManageConfigValues $config;
private ICanCache $cache;
private LoggerInterface $logger; private LoggerInterface $logger;
private Profiler $profiler; private Profiler $profiler;
@ -37,12 +43,16 @@ final class AddonManagerHelper implements AddonHelper
public function __construct( public function __construct(
string $addonPath, string $addonPath,
Database $database,
IManageConfigValues $config, IManageConfigValues $config,
ICanCache $cache,
LoggerInterface $logger, LoggerInterface $logger,
Profiler $profiler Profiler $profiler
) { ) {
$this->addonPath = $addonPath; $this->addonPath = $addonPath;
$this->database = $database;
$this->config = $config; $this->config = $config;
$this->cache = $cache;
$this->logger = $logger; $this->logger = $logger;
$this->profiler = $profiler; $this->profiler = $profiler;
@ -153,7 +163,31 @@ final class AddonManagerHelper implements AddonHelper
*/ */
public function uninstallAddon(string $addonId): void public function uninstallAddon(string $addonId): void
{ {
$this->proxy->uninstallAddon($addonId); $addonId = Strings::sanitizeFilePathItem($addonId);
$this->logger->debug("Addon {addon}: {action}", ['action' => 'uninstall', 'addon' => $addonId]);
$this->config->delete('addons', $addonId);
$addon_file_path = $this->getAddonPath() . '/' . $addonId . '/' . $addonId . '.php';
@include_once($addon_file_path);
if (function_exists($addonId . '_uninstall')) {
$func = $addonId . '_uninstall';
$func();
}
// Remove registered hooks for the addon
// Handles both relative and absolute file paths
$condition = ['`file` LIKE ?', "%/$addonId/$addonId.php"];
$result = $this->database->delete('hook', $condition);
if ($result) {
$this->cache->delete('routerDispatchData');
}
unset($this->addons[array_search($addonId, $this->addons)]);
} }
/** /**

View file

@ -12,7 +12,9 @@ namespace Friendica\Test\Unit\Core\Addon;
use Exception; use Exception;
use Friendica\Core\Addon\AddonInfo; use Friendica\Core\Addon\AddonInfo;
use Friendica\Core\Addon\AddonManagerHelper; use Friendica\Core\Addon\AddonManagerHelper;
use Friendica\Core\Cache\Capability\ICanCache;
use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Database\Database;
use Friendica\Util\Profiler; use Friendica\Util\Profiler;
use org\bovigo\vfs\vfsStream; use org\bovigo\vfs\vfsStream;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
@ -24,7 +26,9 @@ class AddonManagerHelperTest extends TestCase
{ {
$addonManagerHelper = new AddonManagerHelper( $addonManagerHelper = new AddonManagerHelper(
__DIR__ . '/../../../Util/addons', __DIR__ . '/../../../Util/addons',
$this->createStub(Database::class),
$this->createStub(IManageConfigValues::class), $this->createStub(IManageConfigValues::class),
$this->createStub(ICanCache::class),
$this->createStub(LoggerInterface::class), $this->createStub(LoggerInterface::class),
$this->createStub(Profiler::class) $this->createStub(Profiler::class)
); );
@ -48,7 +52,9 @@ class AddonManagerHelperTest extends TestCase
$addonManagerHelper = new AddonManagerHelper( $addonManagerHelper = new AddonManagerHelper(
__DIR__ . '/../../../Util/addons', __DIR__ . '/../../../Util/addons',
$this->createStub(Database::class),
$config, $config,
$this->createStub(ICanCache::class),
$this->createStub(LoggerInterface::class), $this->createStub(LoggerInterface::class),
$this->createStub(Profiler::class) $this->createStub(Profiler::class)
); );
@ -74,7 +80,9 @@ class AddonManagerHelperTest extends TestCase
$addonManagerHelper = new AddonManagerHelper( $addonManagerHelper = new AddonManagerHelper(
__DIR__ . '/../../../Util/addons', __DIR__ . '/../../../Util/addons',
$this->createStub(Database::class),
$config, $config,
$this->createStub(ICanCache::class),
$this->createStub(LoggerInterface::class), $this->createStub(LoggerInterface::class),
$this->createStub(Profiler::class) $this->createStub(Profiler::class)
); );
@ -98,7 +106,9 @@ class AddonManagerHelperTest extends TestCase
$addonManagerHelper = new AddonManagerHelper( $addonManagerHelper = new AddonManagerHelper(
__DIR__ . '/../../../Util/addons', __DIR__ . '/../../../Util/addons',
$this->createStub(Database::class),
$config, $config,
$this->createStub(ICanCache::class),
$this->createStub(LoggerInterface::class), $this->createStub(LoggerInterface::class),
$this->createStub(Profiler::class) $this->createStub(Profiler::class)
); );
@ -110,7 +120,9 @@ class AddonManagerHelperTest extends TestCase
{ {
$addonManagerHelper = new AddonManagerHelper( $addonManagerHelper = new AddonManagerHelper(
__DIR__ . '/../../../Util/addons', __DIR__ . '/../../../Util/addons',
$this->createStub(Database::class),
$this->createStub(IManageConfigValues::class), $this->createStub(IManageConfigValues::class),
$this->createStub(ICanCache::class),
$this->createStub(LoggerInterface::class), $this->createStub(LoggerInterface::class),
$this->createStub(Profiler::class) $this->createStub(Profiler::class)
); );
@ -128,7 +140,9 @@ class AddonManagerHelperTest extends TestCase
$addonManagerHelper = new AddonManagerHelper( $addonManagerHelper = new AddonManagerHelper(
$root->url(), $root->url(),
$this->createStub(Database::class),
$this->createStub(IManageConfigValues::class), $this->createStub(IManageConfigValues::class),
$this->createStub(ICanCache::class),
$this->createStub(LoggerInterface::class), $this->createStub(LoggerInterface::class),
$this->createStub(Profiler::class) $this->createStub(Profiler::class)
); );
@ -159,7 +173,9 @@ class AddonManagerHelperTest extends TestCase
$addonManagerHelper = new AddonManagerHelper( $addonManagerHelper = new AddonManagerHelper(
$root->url(), $root->url(),
$this->createStub(Database::class),
$this->createStub(IManageConfigValues::class), $this->createStub(IManageConfigValues::class),
$this->createStub(ICanCache::class),
$this->createStub(LoggerInterface::class), $this->createStub(LoggerInterface::class),
$this->createStub(Profiler::class) $this->createStub(Profiler::class)
); );
@ -189,7 +205,9 @@ class AddonManagerHelperTest extends TestCase
$addonManagerHelper = new AddonManagerHelper( $addonManagerHelper = new AddonManagerHelper(
$root->url(), $root->url(),
$this->createStub(Database::class),
$config, $config,
$this->createStub(ICanCache::class),
$this->createStub(LoggerInterface::class), $this->createStub(LoggerInterface::class),
$this->createStub(Profiler::class) $this->createStub(Profiler::class)
); );
@ -207,7 +225,9 @@ class AddonManagerHelperTest extends TestCase
$addonManagerHelper = new AddonManagerHelper( $addonManagerHelper = new AddonManagerHelper(
$root->url(), $root->url(),
$this->createStub(Database::class),
$this->createStub(IManageConfigValues::class), $this->createStub(IManageConfigValues::class),
$this->createStub(ICanCache::class),
$this->createStub(LoggerInterface::class), $this->createStub(LoggerInterface::class),
$this->createStub(Profiler::class) $this->createStub(Profiler::class)
); );
@ -218,4 +238,121 @@ class AddonManagerHelperTest extends TestCase
$this->assertSame(['helloaddon'], $addonManagerHelper->getEnabledAddons()); $this->assertSame(['helloaddon'], $addonManagerHelper->getEnabledAddons());
} }
public function testUninstallAddonIncludesAddonFile(): void
{
$root = vfsStream::setup(__FUNCTION__ . '_addons', 0777, [
'helloaddon' => [
'helloaddon.php' => '<?php throw new \Exception("Addon file loaded");',
]
]);
$addonManagerHelper = new AddonManagerHelper(
$root->url(),
$this->createStub(Database::class),
$this->createStub(IManageConfigValues::class),
$this->createStub(ICanCache::class),
$this->createStub(LoggerInterface::class),
$this->createStub(Profiler::class)
);
$this->expectException(Exception::class);
$this->expectExceptionMessage('Addon file loaded');
$addonManagerHelper->uninstallAddon('helloaddon');
}
public function testUninstallAddonCallsUninstallFunction(): void
{
// We need a unique name for the addon to avoid conflicts
// with other tests that may define the same install function.
$addonName = __FUNCTION__;
$root = vfsStream::setup(__FUNCTION__ . '_addons', 0777, [
$addonName => [
$addonName . '.php' => <<<PHP
<?php
function {$addonName}_uninstall()
{
throw new \Exception("Addon uninstalled");
}
PHP,
]
]);
$addonManagerHelper = new AddonManagerHelper(
$root->url(),
$this->createStub(Database::class),
$this->createStub(IManageConfigValues::class),
$this->createStub(ICanCache::class),
$this->createStub(LoggerInterface::class),
$this->createStub(Profiler::class)
);
$this->expectException(Exception::class);
$this->expectExceptionMessage('Addon uninstalled');
$addonManagerHelper->uninstallAddon($addonName);
}
public function testUninstallAddonRemovesHooksFromDatabase(): void
{
$root = vfsStream::setup(__FUNCTION__ . '_addons', 0777, [
'helloaddon' => [
'helloaddon.php' => '<?php',
]
]);
$database = $this->createMock(Database::class);
$database->expects($this->once())
->method('delete')
->with(
'hook',
['`file` LIKE ?', '%/helloaddon/helloaddon.php']
);
$addonManagerHelper = new AddonManagerHelper(
$root->url(),
$database,
$this->createStub(IManageConfigValues::class),
$this->createStub(ICanCache::class),
$this->createStub(LoggerInterface::class),
$this->createStub(Profiler::class)
);
$addonManagerHelper->uninstallAddon('helloaddon');
}
public function testUninstallAddonDisablesAddon(): void
{
$root = vfsStream::setup(__FUNCTION__ . '_addons', 0777, [
'helloaddon' => [
'helloaddon.php' => '<?php',
]
]);
$config = $this->createStub(IManageConfigValues::class);
$config->method('get')->willReturn([
'helloaddon' => [
'last_update' => 1234567890,
'admin' => false,
],
]);
$addonManagerHelper = new AddonManagerHelper(
$root->url(),
$this->createStub(Database::class),
$config,
$this->createStub(ICanCache::class),
$this->createStub(LoggerInterface::class),
$this->createStub(Profiler::class)
);
$addonManagerHelper->loadAddons();
$this->assertSame(['helloaddon'], $addonManagerHelper->getEnabledAddons());
$addonManagerHelper->uninstallAddon('helloaddon');
$this->assertSame([], $addonManagerHelper->getEnabledAddons());
}
} }