namespace Friendica\Core\Addon;
+use Friendica\Core\Cache\Capability\ICanCache;
use Friendica\Core\Config\Capability\IManageConfigValues;
+use Friendica\Database\Database;
use Friendica\Util\Profiler;
use Friendica\Util\Strings;
use Psr\Log\LoggerInterface;
{
private string $addonPath;
+ private Database $database;
+
private IManageConfigValues $config;
+ private ICanCache $cache;
+
private LoggerInterface $logger;
private Profiler $profiler;
public function __construct(
string $addonPath,
+ Database $database,
IManageConfigValues $config,
+ ICanCache $cache,
LoggerInterface $logger,
Profiler $profiler
) {
$this->addonPath = $addonPath;
+ $this->database = $database;
$this->config = $config;
+ $this->cache = $cache;
$this->logger = $logger;
$this->profiler = $profiler;
*/
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)]);
}
/**
use Exception;
use Friendica\Core\Addon\AddonInfo;
use Friendica\Core\Addon\AddonManagerHelper;
+use Friendica\Core\Cache\Capability\ICanCache;
use Friendica\Core\Config\Capability\IManageConfigValues;
+use Friendica\Database\Database;
use Friendica\Util\Profiler;
use org\bovigo\vfs\vfsStream;
use PHPUnit\Framework\TestCase;
{
$addonManagerHelper = new AddonManagerHelper(
__DIR__ . '/../../../Util/addons',
+ $this->createStub(Database::class),
$this->createStub(IManageConfigValues::class),
+ $this->createStub(ICanCache::class),
$this->createStub(LoggerInterface::class),
$this->createStub(Profiler::class)
);
$addonManagerHelper = new AddonManagerHelper(
__DIR__ . '/../../../Util/addons',
+ $this->createStub(Database::class),
$config,
+ $this->createStub(ICanCache::class),
$this->createStub(LoggerInterface::class),
$this->createStub(Profiler::class)
);
$addonManagerHelper = new AddonManagerHelper(
__DIR__ . '/../../../Util/addons',
+ $this->createStub(Database::class),
$config,
+ $this->createStub(ICanCache::class),
$this->createStub(LoggerInterface::class),
$this->createStub(Profiler::class)
);
$addonManagerHelper = new AddonManagerHelper(
__DIR__ . '/../../../Util/addons',
+ $this->createStub(Database::class),
$config,
+ $this->createStub(ICanCache::class),
$this->createStub(LoggerInterface::class),
$this->createStub(Profiler::class)
);
{
$addonManagerHelper = new AddonManagerHelper(
__DIR__ . '/../../../Util/addons',
+ $this->createStub(Database::class),
$this->createStub(IManageConfigValues::class),
+ $this->createStub(ICanCache::class),
$this->createStub(LoggerInterface::class),
$this->createStub(Profiler::class)
);
$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)
);
$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)
);
$addonManagerHelper = new AddonManagerHelper(
$root->url(),
+ $this->createStub(Database::class),
$config,
+ $this->createStub(ICanCache::class),
$this->createStub(LoggerInterface::class),
$this->createStub(Profiler::class)
);
$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->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());
+ }
}