Merge pull request #14770 from Art4/new-addonproxy

New AddonHelper
This commit is contained in:
Hypolite Petovan 2025-02-10 07:53:24 -05:00 committed by GitHub
commit 17207dbb67
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 909 additions and 330 deletions

View file

@ -11,7 +11,6 @@ use Friendica\Content\Nav;
use Friendica\Content\Pager; use Friendica\Content\Pager;
use Friendica\Content\Text\BBCode; use Friendica\Content\Text\BBCode;
use Friendica\Core\ACL; use Friendica\Core\ACL;
use Friendica\Core\Addon;
use Friendica\Core\Hook; use Friendica\Core\Hook;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\Core\System; use Friendica\Core\System;
@ -1067,6 +1066,7 @@ function photos_content()
$cmnt_tpl = Renderer::getMarkupTemplate('comment_item.tpl'); $cmnt_tpl = Renderer::getMarkupTemplate('comment_item.tpl');
$tpl = Renderer::getMarkupTemplate('photo_item.tpl'); $tpl = Renderer::getMarkupTemplate('photo_item.tpl');
$return_path = DI::args()->getCommand(); $return_path = DI::args()->getCommand();
$addonHelper = DI::addonHelper();
if (!DBA::isResult($items)) { if (!DBA::isResult($items)) {
if (($can_post || Security::canWriteToUserWall($owner_uid))) { if (($can_post || Security::canWriteToUserWall($owner_uid))) {
@ -1075,7 +1075,7 @@ function photos_content()
* This should be better if done by a hook * This should be better if done by a hook
*/ */
$qcomment = null; $qcomment = null;
if (Addon::isEnabled('qcomment')) { if ($addonHelper->isAddonEnabled('qcomment')) {
$words = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'qcomment', 'words'); $words = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'qcomment', 'words');
$qcomment = $words ? explode("\n", $words) : []; $qcomment = $words ? explode("\n", $words) : [];
} }
@ -1131,7 +1131,7 @@ function photos_content()
* This should be better if done by a hook * This should be better if done by a hook
*/ */
$qcomment = null; $qcomment = null;
if (Addon::isEnabled('qcomment')) { if ($addonHelper->isAddonEnabled('qcomment')) {
$words = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'qcomment', 'words'); $words = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'qcomment', 'words');
$qcomment = $words ? explode("\n", $words) : []; $qcomment = $words ? explode("\n", $words) : [];
} }
@ -1211,7 +1211,7 @@ function photos_content()
* This should be better if done by a hook * This should be better if done by a hook
*/ */
$qcomment = null; $qcomment = null;
if (Addon::isEnabled('qcomment')) { if ($addonHelper->isAddonEnabled('qcomment')) {
$words = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'qcomment', 'words'); $words = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'qcomment', 'words');
$qcomment = $words ? explode("\n", $words) : []; $qcomment = $words ? explode("\n", $words) : [];
} }

View file

@ -17,6 +17,7 @@ use Friendica\App\Router;
use Friendica\Capabilities\ICanCreateResponses; use Friendica\Capabilities\ICanCreateResponses;
use Friendica\Capabilities\ICanHandleRequests; use Friendica\Capabilities\ICanHandleRequests;
use Friendica\Content\Nav; use Friendica\Content\Nav;
use Friendica\Core\Addon\AddonHelper;
use Friendica\Core\Addon\Capability\ICanLoadAddons; use Friendica\Core\Addon\Capability\ICanLoadAddons;
use Friendica\Core\Config\Factory\Config; use Friendica\Core\Config\Factory\Config;
use Friendica\Core\Container; use Friendica\Core\Container;
@ -171,6 +172,8 @@ class App
$this->session = $this->container->create(IHandleUserSessions::class); $this->session = $this->container->create(IHandleUserSessions::class);
$this->appHelper = $this->container->create(AppHelper::class); $this->appHelper = $this->container->create(AppHelper::class);
$addonHelper = $this->container->create(AddonHelper::class);
$this->load( $this->load(
$request->getServerParams(), $request->getServerParams(),
$this->container->create(DbaDefinition::class), $this->container->create(DbaDefinition::class),
@ -180,6 +183,7 @@ class App
$this->profiler, $this->profiler,
$this->container->create(EventDispatcherInterface::class), $this->container->create(EventDispatcherInterface::class),
$this->appHelper, $this->appHelper,
$addonHelper,
); );
$this->registerTemplateEngine(); $this->registerTemplateEngine();
@ -189,6 +193,7 @@ class App
$this->container->create(IManagePersonalConfigValues::class), $this->container->create(IManagePersonalConfigValues::class),
$this->container->create(Page::class), $this->container->create(Page::class),
$this->container->create(Nav::class), $this->container->create(Nav::class),
$addonHelper,
$this->container->create(ModuleHTTPException::class), $this->container->create(ModuleHTTPException::class),
$start_time, $start_time,
$request $request
@ -221,6 +226,7 @@ class App
$this->container->create(Profiler::class), $this->container->create(Profiler::class),
$this->container->create(EventDispatcherInterface::class), $this->container->create(EventDispatcherInterface::class),
$this->container->create(AppHelper::class), $this->container->create(AppHelper::class),
$this->container->create(AddonHelper::class),
); );
$this->registerTemplateEngine(); $this->registerTemplateEngine();
@ -252,6 +258,7 @@ class App
$this->container->create(Profiler::class), $this->container->create(Profiler::class),
$this->container->create(EventDispatcherInterface::class), $this->container->create(EventDispatcherInterface::class),
$this->container->create(AppHelper::class), $this->container->create(AppHelper::class),
$this->container->create(AddonHelper::class),
); );
/** @var BasePath */ /** @var BasePath */
@ -341,7 +348,8 @@ class App
IManageConfigValues $config, IManageConfigValues $config,
Profiler $profiler, Profiler $profiler,
EventDispatcherInterface $eventDispatcher, EventDispatcherInterface $eventDispatcher,
AppHelper $appHelper AppHelper $appHelper,
AddonHelper $addonHelper
): void { ): void {
if ($config->get('system', 'ini_max_execution_time') !== false) { if ($config->get('system', 'ini_max_execution_time') !== false) {
set_time_limit((int) $config->get('system', 'ini_max_execution_time')); set_time_limit((int) $config->get('system', 'ini_max_execution_time'));
@ -363,7 +371,7 @@ class App
if ($mode->has(Mode::DBAVAILABLE)) { if ($mode->has(Mode::DBAVAILABLE)) {
Core\Hook::loadHooks(); Core\Hook::loadHooks();
$loader = (new Config())->createConfigFileManager($appHelper->getBasePath(), $serverParams); $loader = (new Config())->createConfigFileManager($appHelper->getBasePath(), $addonHelper->getAddonPath(), $serverParams);
$eventDispatcher->dispatch(new ConfigLoadedEvent(ConfigLoadedEvent::CONFIG_LOADED, $loader)); $eventDispatcher->dispatch(new ConfigLoadedEvent(ConfigLoadedEvent::CONFIG_LOADED, $loader));
@ -415,6 +423,7 @@ class App
IManagePersonalConfigValues $pconfig, IManagePersonalConfigValues $pconfig,
Page $page, Page $page,
Nav $nav, Nav $nav,
AddonHelper $addonHelper,
ModuleHTTPException $httpException, ModuleHTTPException $httpException,
float $start_time, float $start_time,
ServerRequestInterface $request ServerRequestInterface $request
@ -503,12 +512,12 @@ class App
// but we need "view" module for stylesheet // but we need "view" module for stylesheet
if ($this->mode->isInstall() && $moduleName !== 'install') { if ($this->mode->isInstall() && $moduleName !== 'install') {
$this->baseURL->redirect('install'); $this->baseURL->redirect('install');
} else {
Core\Update::check($this->appHelper->getBasePath(), false);
Core\Addon::loadAddons();
Core\Hook::loadHooks();
} }
Core\Update::check($this->appHelper->getBasePath(), false);
$addonHelper->loadAddons();
Core\Hook::loadHooks();
// Compatibility with Hubzilla // Compatibility with Hubzilla
if ($moduleName == 'rpost') { if ($moduleName == 'rpost') {
$this->baseURL->redirect('compose'); $this->baseURL->redirect('compose');

View file

@ -7,13 +7,11 @@
namespace Friendica\App; namespace Friendica\App;
use Dice\Dice;
use FastRoute\DataGenerator\GroupCountBased; use FastRoute\DataGenerator\GroupCountBased;
use FastRoute\Dispatcher; use FastRoute\Dispatcher;
use FastRoute\RouteCollector; use FastRoute\RouteCollector;
use FastRoute\RouteParser\Std; use FastRoute\RouteParser\Std;
use Friendica\Capabilities\ICanHandleRequests; use Friendica\Core\Addon\AddonHelper;
use Friendica\Core\Addon;
use Friendica\Core\Cache\Enum\Duration; use Friendica\Core\Cache\Enum\Duration;
use Friendica\Core\Cache\Capability\ICanCache; use Friendica\Core\Cache\Capability\ICanCache;
use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Config\Capability\IManageConfigValues;
@ -86,6 +84,8 @@ class Router
/** @var LoggerInterface */ /** @var LoggerInterface */
private $logger; private $logger;
private AddonHelper $addonHelper;
/** @var bool */ /** @var bool */
private $isLocalUser; private $isLocalUser;
@ -110,17 +110,18 @@ class Router
* @param IHandleUserSessions $userSession * @param IHandleUserSessions $userSession
* @param RouteCollector|null $routeCollector * @param RouteCollector|null $routeCollector
*/ */
public function __construct(array $server, string $baseRoutesFilepath, L10n $l10n, ICanCache $cache, ICanLock $lock, IManageConfigValues $config, Arguments $args, LoggerInterface $logger, IHandleUserSessions $userSession, RouteCollector $routeCollector = null) public function __construct(array $server, string $baseRoutesFilepath, L10n $l10n, ICanCache $cache, ICanLock $lock, IManageConfigValues $config, Arguments $args, LoggerInterface $logger, AddonHelper $addonHelper, IHandleUserSessions $userSession, RouteCollector $routeCollector = null)
{ {
$this->baseRoutesFilepath = $baseRoutesFilepath; $this->baseRoutesFilepath = $baseRoutesFilepath;
$this->l10n = $l10n; $this->l10n = $l10n;
$this->cache = $cache; $this->cache = $cache;
$this->lock = $lock; $this->lock = $lock;
$this->args = $args; $this->args = $args;
$this->config = $config; $this->config = $config;
$this->server = $server; $this->server = $server;
$this->logger = $logger; $this->logger = $logger;
$this->isLocalUser = !empty($userSession->getLocalUserId()); $this->addonHelper = $addonHelper;
$this->isLocalUser = !empty($userSession->getLocalUserId());
$this->routeCollector = $routeCollector ?? new RouteCollector(new Std(), new GroupCountBased()); $this->routeCollector = $routeCollector ?? new RouteCollector(new Std(), new GroupCountBased());
@ -275,14 +276,14 @@ class Router
try { try {
// Check if the HTTP method is OPTIONS and return the special Options Module with the possible HTTP methods // Check if the HTTP method is OPTIONS and return the special Options Module with the possible HTTP methods
if ($this->args->getMethod() === static::OPTIONS) { if ($this->args->getMethod() === static::OPTIONS) {
$this->moduleClass = Options::class; $this->moduleClass = Options::class;
$this->parameters[] = ['AllowedMethods' => $dispatcher->getOptions($cmd)]; $this->parameters[] = ['AllowedMethods' => $dispatcher->getOptions($cmd)];
} else { } else {
$routeInfo = $dispatcher->dispatch($this->args->getMethod(), $cmd); $routeInfo = $dispatcher->dispatch($this->args->getMethod(), $cmd);
if ($routeInfo[0] === Dispatcher::FOUND) { if ($routeInfo[0] === Dispatcher::FOUND) {
$this->moduleClass = $routeInfo[1]; $this->moduleClass = $routeInfo[1];
$this->parameters[] = $routeInfo[2]; $this->parameters[] = $routeInfo[2];
} else if ($routeInfo[0] === Dispatcher::METHOD_NOT_ALLOWED) { } elseif ($routeInfo[0] === Dispatcher::METHOD_NOT_ALLOWED) {
throw new HTTPException\MethodNotAllowedException($this->l10n->t('Method not allowed for this module. Allowed method(s): %s', implode(', ', $routeInfo[1]))); throw new HTTPException\MethodNotAllowedException($this->l10n->t('Method not allowed for this module. Allowed method(s): %s', implode(', ', $routeInfo[1])));
} else { } else {
throw new HTTPException\NotFoundException($this->l10n->t('Page not found.')); throw new HTTPException\NotFoundException($this->l10n->t('Page not found.'));
@ -293,7 +294,7 @@ class Router
} catch (NotFoundException $e) { } catch (NotFoundException $e) {
$moduleName = $this->args->getModuleName(); $moduleName = $this->args->getModuleName();
// Then we try addon-provided modules that we wrap in the LegacyModule class // Then we try addon-provided modules that we wrap in the LegacyModule class
if (Addon::isEnabled($moduleName) && file_exists("addon/{$moduleName}/{$moduleName}.php")) { if ($this->addonHelper->isAddonEnabled($moduleName) && file_exists("addon/{$moduleName}/{$moduleName}.php")) {
//Check if module is an app and if public access to apps is allowed or not //Check if module is an app and if public access to apps is allowed or not
$privateapps = $this->config->get('config', 'private_addons', false); $privateapps = $this->config->get('config', 'private_addons', false);
if (!$this->isLocalUser && Hook::isAddonApp($moduleName) && $privateapps) { if (!$this->isLocalUser && Hook::isAddonApp($moduleName) && $privateapps) {

View file

@ -10,7 +10,7 @@ namespace Friendica\Console;
use Console_Table; use Console_Table;
use Friendica\App\Mode; use Friendica\App\Mode;
use Friendica\Core\L10n; use Friendica\Core\L10n;
use Friendica\Core\Addon as AddonCore; use Friendica\Core\Addon\AddonHelper;
use Friendica\Database\Database; use Friendica\Database\Database;
use Friendica\Util\Strings; use Friendica\Util\Strings;
use RuntimeException; use RuntimeException;
@ -34,6 +34,7 @@ class Addon extends \Asika\SimpleConsole\Console
* @var Database * @var Database
*/ */
private $dba; private $dba;
private AddonHelper $addonHelper;
protected function getHelp() protected function getHelp()
{ {
@ -56,15 +57,16 @@ HELP;
return $help; return $help;
} }
public function __construct(Mode $appMode, L10n $l10n, Database $dba, array $argv = null) public function __construct(Mode $appMode, L10n $l10n, Database $dba, AddonHelper $addonHelper, array $argv = null)
{ {
parent::__construct($argv); parent::__construct($argv);
$this->appMode = $appMode; $this->appMode = $appMode;
$this->l10n = $l10n; $this->l10n = $l10n;
$this->dba = $dba; $this->dba = $dba;
$this->addonHelper = $addonHelper;
AddonCore::loadAddons(); $this->addonHelper->loadAddons();
} }
protected function doExecute(): int protected function doExecute(): int
@ -122,23 +124,22 @@ HELP;
return false; return false;
} }
foreach (AddonCore::getAvailableList() as $addon) { foreach ($this->addonHelper->getAvailableAddons() as $addonId) {
$addon_name = $addon[0]; $enabled = $this->addonHelper->isAddonEnabled($addonId);
$enabled = AddonCore::isEnabled($addon_name);
if ($subCmd === 'all') { if ($subCmd === 'all') {
$table->addRow([$addon_name, $enabled ? 'enabled' : 'disabled']); $table->addRow([$addonId, $enabled ? 'enabled' : 'disabled']);
continue; continue;
} }
if ($subCmd === 'enabled' && $enabled === true) { if ($subCmd === 'enabled' && $enabled === true) {
$table->addRow([$addon_name]); $table->addRow([$addonId]);
continue; continue;
} }
if ($subCmd === 'disabled' && $enabled === false) { if ($subCmd === 'disabled' && $enabled === false) {
$table->addRow([$addon_name]); $table->addRow([$addonId]);
continue; continue;
} }
} }
@ -163,11 +164,11 @@ HELP;
throw new RuntimeException($this->l10n->t('Addon not found')); throw new RuntimeException($this->l10n->t('Addon not found'));
} }
if (AddonCore::isEnabled($addon)) { if ($this->addonHelper->isAddonEnabled($addon)) {
throw new RuntimeException($this->l10n->t('Addon already enabled')); throw new RuntimeException($this->l10n->t('Addon already enabled'));
} }
AddonCore::install($addon); $this->addonHelper->installAddon($addon);
return 0; return 0;
} }
@ -187,11 +188,11 @@ HELP;
throw new RuntimeException($this->l10n->t('Addon not found')); throw new RuntimeException($this->l10n->t('Addon not found'));
} }
if (!AddonCore::isEnabled($addon)) { if (!$this->addonHelper->isAddonEnabled($addon)) {
throw new RuntimeException($this->l10n->t('Addon already disabled')); throw new RuntimeException($this->l10n->t('Addon already disabled'));
} }
AddonCore::uninstall($addon); $this->addonHelper->uninstallAddon($addon);
return 0; return 0;
} }

View file

@ -11,7 +11,7 @@ namespace Friendica\Console;
use Asika\SimpleConsole\Console; use Asika\SimpleConsole\Console;
use Friendica\App\Mode; use Friendica\App\Mode;
use Friendica\Core\Addon; use Friendica\Core\Addon\AddonHelper;
use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\Hook; use Friendica\Core\Hook;
use Friendica\Core\KeyValueStorage\Capability\IManageKeyValuePairs; use Friendica\Core\KeyValueStorage\Capability\IManageKeyValuePairs;
@ -29,6 +29,7 @@ final class JetstreamDaemon extends Console
private IManageKeyValuePairs $keyValue; private IManageKeyValuePairs $keyValue;
private SysDaemon $daemon; private SysDaemon $daemon;
private Jetstream $jetstream; private Jetstream $jetstream;
private AddonHelper $addonHelper;
/** /**
* @param Mode $mode * @param Mode $mode
@ -38,15 +39,16 @@ final class JetstreamDaemon extends Console
* @param Jetstream $jetstream * @param Jetstream $jetstream
* @param array|null $argv * @param array|null $argv
*/ */
public function __construct(Mode $mode, IManageConfigValues $config, IManageKeyValuePairs $keyValue, SysDaemon $daemon, Jetstream $jetstream, array $argv = null) public function __construct(Mode $mode, IManageConfigValues $config, IManageKeyValuePairs $keyValue, SysDaemon $daemon, Jetstream $jetstream, AddonHelper $addonHelper, array $argv = null)
{ {
parent::__construct($argv); parent::__construct($argv);
$this->mode = $mode; $this->mode = $mode;
$this->config = $config; $this->config = $config;
$this->keyValue = $keyValue; $this->keyValue = $keyValue;
$this->jetstream = $jetstream; $this->jetstream = $jetstream;
$this->daemon = $daemon; $this->daemon = $daemon;
$this->addonHelper = $addonHelper;
} }
protected function getHelp(): string protected function getHelp(): string
@ -95,10 +97,10 @@ HELP;
); );
} }
Addon::loadAddons(); $this->addonHelper->loadAddons();
Hook::loadHooks(); Hook::loadHooks();
if (!Addon::isEnabled('bluesky')) { if (!$this->addonHelper->isAddonEnabled('bluesky')) {
throw new RuntimeException("Bluesky has to be enabled.\n"); throw new RuntimeException("Bluesky has to be enabled.\n");
} }

View file

@ -207,7 +207,7 @@ class Conversation
if ($total === 0) { if ($total === 0) {
throw new InternalServerErrorException(sprintf('There has to be at least one Liker for verb "%s"', $verb)); throw new InternalServerErrorException(sprintf('There has to be at least one Liker for verb "%s"', $verb));
} else if ($total === 1) { } elseif ($total === 1) {
$likerString = $likers[0]; $likerString = $likers[0];
} else { } else {
if ($total < $this->config->get('system', 'max_likers')) { if ($total < $this->config->get('system', 'max_likers')) {
@ -976,8 +976,8 @@ class Conversation
} }
foreach ($items as $key => $row) { foreach ($items as $key => $row) {
$items[$key]['emojis'] = $emojis[$key] ?? []; $items[$key]['emojis'] = $emojis[$key] ?? [];
$items[$key]['counts'] = $counts[$key] ?? 0; $items[$key]['counts'] = $counts[$key] ?? 0;
$items[$key]['quoteshares'] = $quoteshares[$key] ?? []; $items[$key]['quoteshares'] = $quoteshares[$key] ?? [];
$always_display = in_array($mode, [self::MODE_CONTACTS, self::MODE_CONTACT_POSTS]); $always_display = in_array($mode, [self::MODE_CONTACTS, self::MODE_CONTACT_POSTS]);
@ -1431,7 +1431,7 @@ class Conversation
public function getContextLessThreadList(array $items, string $mode, bool $preview, bool $pagedrop, string $formSecurityToken): array public function getContextLessThreadList(array $items, string $mode, bool $preview, bool $pagedrop, string $formSecurityToken): array
{ {
$threads = []; $threads = [];
$uriids = []; $uriids = [];
foreach ($items as $item) { foreach ($items as $item) {
if (in_array($item['uri-id'], $uriids)) { if (in_array($item['uri-id'], $uriids)) {
@ -1456,7 +1456,7 @@ class Conversation
$tags = Tag::populateFromItem($item); $tags = Tag::populateFromItem($item);
$author = [ $author = [
'uid' => 0, 'uid' => 0,
'id' => $item['author-id'], 'id' => $item['author-id'],
'network' => $item['author-network'], 'network' => $item['author-network'],
@ -1501,7 +1501,7 @@ class Conversation
$body_html = ItemModel::prepareBody($item, true, $preview); $body_html = ItemModel::prepareBody($item, true, $preview);
[$categories, $folders] = $this->item->determineCategoriesTerms($item, $this->session->getLocalUserId()); list($categories, $folders) = $this->item->determineCategoriesTerms($item, $this->session->getLocalUserId());
if (!empty($item['featured'])) { if (!empty($item['featured'])) {
$pinned = $this->l10n->t('Pinned item'); $pinned = $this->l10n->t('Pinned item');

View file

@ -7,7 +7,6 @@
namespace Friendica\Content; namespace Friendica\Content;
use Friendica\Core\Addon;
use Friendica\Core\Cache\Enum\Duration; use Friendica\Core\Cache\Enum\Duration;
use Friendica\Core\Protocol; use Friendica\Core\Protocol;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
@ -33,13 +32,13 @@ class Widget
*/ */
public static function follow(string $value = ''): string public static function follow(string $value = ''): string
{ {
return Renderer::replaceMacros(Renderer::getMarkupTemplate('widget/follow.tpl'), array( return Renderer::replaceMacros(Renderer::getMarkupTemplate('widget/follow.tpl'), [
'$connect' => DI::l10n()->t('Add New Contact'), '$connect' => DI::l10n()->t('Add New Contact'),
'$desc' => DI::l10n()->t('Enter address or web location'), '$desc' => DI::l10n()->t('Enter address or web location'),
'$hint' => DI::l10n()->t('Example: bob@example.com, http://example.com/barbara'), '$hint' => DI::l10n()->t('Example: bob@example.com, http://example.com/barbara'),
'$value' => $value, '$value' => $value,
'$follow' => DI::l10n()->t('Connect') '$follow' => DI::l10n()->t('Connect')
)); ]);
} }
/** /**
@ -60,21 +59,21 @@ class Widget
} }
} }
$nv = []; $nv = [];
$nv['findpeople'] = DI::l10n()->t('Find People'); $nv['findpeople'] = DI::l10n()->t('Find People');
$nv['desc'] = DI::l10n()->t('Enter name or interest'); $nv['desc'] = DI::l10n()->t('Enter name or interest');
$nv['label'] = DI::l10n()->t('Connect/Follow'); $nv['label'] = DI::l10n()->t('Connect/Follow');
$nv['hint'] = DI::l10n()->t('Examples: Robert Morgenstein, Fishing'); $nv['hint'] = DI::l10n()->t('Examples: Robert Morgenstein, Fishing');
$nv['findthem'] = DI::l10n()->t('Find'); $nv['findthem'] = DI::l10n()->t('Find');
$nv['suggest'] = DI::l10n()->t('Friend Suggestions'); $nv['suggest'] = DI::l10n()->t('Friend Suggestions');
$nv['similar'] = DI::l10n()->t('Similar Interests'); $nv['similar'] = DI::l10n()->t('Similar Interests');
$nv['random'] = DI::l10n()->t('Random Profile'); $nv['random'] = DI::l10n()->t('Random Profile');
$nv['inv'] = DI::l10n()->t('Invite Friends'); $nv['inv'] = DI::l10n()->t('Invite Friends');
$nv['directory'] = DI::l10n()->t('Global Directory'); $nv['directory'] = DI::l10n()->t('Global Directory');
$nv['global_dir'] = OpenWebAuth::getZrlUrl($global_dir, true); $nv['global_dir'] = OpenWebAuth::getZrlUrl($global_dir, true);
$nv['local_directory'] = DI::l10n()->t('Local Directory'); $nv['local_directory'] = DI::l10n()->t('Local Directory');
$aside = []; $aside = [];
$aside['$nv'] = $nv; $aside['$nv'] = $nv;
return Renderer::replaceMacros(Renderer::getMarkupTemplate('widget/peoplefind.tpl'), $aside); return Renderer::replaceMacros(Renderer::getMarkupTemplate('widget/peoplefind.tpl'), $aside);
@ -87,19 +86,21 @@ class Widget
*/ */
public static function unavailableNetworks(): array public static function unavailableNetworks(): array
{ {
$addonHelper = DI::addonHelper();
// Always hide content from these networks // Always hide content from these networks
$networks = [Protocol::PHANTOM, Protocol::FACEBOOK, Protocol::APPNET, Protocol::TWITTER, Protocol::ZOT, Protocol::OSTATUS, Protocol::STATUSNET]; $networks = [Protocol::PHANTOM, Protocol::FACEBOOK, Protocol::APPNET, Protocol::TWITTER, Protocol::ZOT, Protocol::OSTATUS, Protocol::STATUSNET];
Addon::loadAddons(); $addonHelper->loadAddons();
if (!Addon::isEnabled('discourse')) { if (!$addonHelper->isAddonEnabled('discourse')) {
$networks[] = Protocol::DISCOURSE; $networks[] = Protocol::DISCOURSE;
} }
if (!Addon::isEnabled('pumpio')) { if (!$addonHelper->isAddonEnabled('pumpio')) {
$networks[] = Protocol::PUMPIO; $networks[] = Protocol::PUMPIO;
} }
if (!Addon::isEnabled('tumblr')) { if (!$addonHelper->isAddonEnabled('tumblr')) {
$networks[] = Protocol::TUMBLR; $networks[] = Protocol::TUMBLR;
} }
@ -107,7 +108,7 @@ class Widget
$networks[] = Protocol::DIASPORA; $networks[] = Protocol::DIASPORA;
} }
if (!Addon::isEnabled('pnut')) { if (!$addonHelper->isAddonEnabled('pnut')) {
$networks[] = Protocol::PNUT; $networks[] = Protocol::PNUT;
} }
return $networks; return $networks;
@ -120,18 +121,20 @@ class Widget
*/ */
public static function availableNetworks(): array public static function availableNetworks(): array
{ {
$networks = [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::FEED]; $addonHelper = DI::addonHelper();
Addon::loadAddons();
if (Addon::isEnabled('discourse')) { $networks = [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::FEED];
$addonHelper->loadAddons();
if ($addonHelper->isAddonEnabled('discourse')) {
$networks[] = Protocol::DISCOURSE; $networks[] = Protocol::DISCOURSE;
} }
if (Addon::isEnabled('pumpio')) { if ($addonHelper->isAddonEnabled('pumpio')) {
$networks[] = Protocol::PUMPIO; $networks[] = Protocol::PUMPIO;
} }
if (Addon::isEnabled('tumblr')) { if ($addonHelper->isAddonEnabled('tumblr')) {
$networks[] = Protocol::TUMBLR; $networks[] = Protocol::TUMBLR;
} }
@ -143,7 +146,7 @@ class Widget
$networks[] = Protocol::MAIL; $networks[] = Protocol::MAIL;
} }
if (Addon::isEnabled('pnut')) { if ($addonHelper->isAddonEnabled('pnut')) {
$networks[] = Protocol::PNUT; $networks[] = Protocol::PNUT;
} }
return $networks; return $networks;
@ -174,7 +177,7 @@ class Widget
private static function filter(string $type, string $title, string $desc, string $all, string $baseUrl, array $options, string $selected = null): string private static function filter(string $type, string $title, string $desc, string $all, string $baseUrl, array $options, string $selected = null): string
{ {
$queryString = parse_url($baseUrl, PHP_URL_QUERY); $queryString = parse_url($baseUrl, PHP_URL_QUERY);
$queryArray = []; $queryArray = [];
if ($queryString) { if ($queryString) {
parse_str($queryString, $queryArray); parse_str($queryString, $queryArray);
@ -282,8 +285,8 @@ class Widget
return ''; return '';
} }
$networks = self::unavailableNetworks(); $networks = self::unavailableNetworks();
$query = "`uid` = ? AND NOT `deleted` AND `network` != '' AND NOT `network` IN (" . substr(str_repeat("?, ", count($networks)), 0, -2) . ")"; $query = "`uid` = ? AND NOT `deleted` AND `network` != '' AND NOT `network` IN (" . substr(str_repeat("?, ", count($networks)), 0, -2) . ")";
$condition = array_merge([$query], array_merge([DI::userSession()->getLocalUserId()], $networks)); $condition = array_merge([$query], array_merge([DI::userSession()->getLocalUserId()], $networks));
$r = DBA::select('contact', ['network'], $condition, ['group_by' => ['network'], 'order' => ['network']]); $r = DBA::select('contact', ['network'], $condition, ['group_by' => ['network'], 'order' => ['network']]);
@ -473,7 +476,7 @@ class Widget
$ret = []; $ret = [];
$cachekey = 'Widget::postedByYear' . $uid . '-' . (int)$wall; $cachekey = 'Widget::postedByYear' . $uid . '-' . (int)$wall;
$dthen = DI::cache()->get($cachekey); $dthen = DI::cache()->get($cachekey);
if (empty($dthen)) { if (empty($dthen)) {
$dthen = Item::firstPostDate($uid, $wall); $dthen = Item::firstPostDate($uid, $wall);
DI::cache()->set($cachekey, $dthen, Duration::HOUR); DI::cache()->set($cachekey, $dthen, Duration::HOUR);
@ -486,30 +489,30 @@ class Widget
if ($dthen) { if ($dthen) {
// Set the start and end date to the beginning of the month // Set the start and end date to the beginning of the month
$cutoffday = $dthen; $cutoffday = $dthen;
$thisday = substr($dnow, 4); $thisday = substr($dnow, 4);
$nextday = date('Y-m-d', strtotime($dnow . ' + 1 day')); $nextday = date('Y-m-d', strtotime($dnow . ' + 1 day'));
$nextday = substr($nextday, 4); $nextday = substr($nextday, 4);
$dnow = substr($dnow, 0, 8) . '01'; $dnow = substr($dnow, 0, 8) . '01';
$dthen = substr($dthen, 0, 8) . '01'; $dthen = substr($dthen, 0, 8) . '01';
/* /*
* Starting with the current month, get the first and last days of every * Starting with the current month, get the first and last days of every
* month down to and including the month of the first post * month down to and including the month of the first post
*/ */
while (substr($dnow, 0, 7) >= substr($dthen, 0, 7)) { while (substr($dnow, 0, 7) >= substr($dthen, 0, 7)) {
$dyear = intval(substr($dnow, 0, 4)); $dyear = intval(substr($dnow, 0, 4));
$dstart = substr($dnow, 0, 8) . '01'; $dstart = substr($dnow, 0, 8) . '01';
$dend = substr($dnow, 0, 8) . Temporal::getDaysInMonth(intval($dnow), intval(substr($dnow, 5))); $dend = substr($dnow, 0, 8) . Temporal::getDaysInMonth(intval($dnow), intval(substr($dnow, 5)));
$start_month = DateTimeFormat::utc($dstart, 'Y-m-d'); $start_month = DateTimeFormat::utc($dstart, 'Y-m-d');
$end_month = DateTimeFormat::utc($dend, 'Y-m-d'); $end_month = DateTimeFormat::utc($dend, 'Y-m-d');
$str = DI::l10n()->getDay(DateTimeFormat::utc($dnow, 'F')); $str = DI::l10n()->getDay(DateTimeFormat::utc($dnow, 'F'));
if (empty($ret[$dyear])) { if (empty($ret[$dyear])) {
$ret[$dyear] = []; $ret[$dyear] = [];
} }
$ret[$dyear][] = [$str, $end_month, $start_month]; $ret[$dyear][] = [$str, $end_month, $start_month];
$dnow = DateTimeFormat::utc($dnow . ' -1 month', 'Y-m-d'); $dnow = DateTimeFormat::utc($dnow . ' -1 month', 'Y-m-d');
} }
} }
@ -518,21 +521,21 @@ class Widget
} }
$cutoff_year = intval(DateTimeFormat::localNow('Y')) - $visible_years; $cutoff_year = intval(DateTimeFormat::localNow('Y')) - $visible_years;
$cutoff = array_key_exists($cutoff_year, $ret); $cutoff = array_key_exists($cutoff_year, $ret);
$o = Renderer::replaceMacros(Renderer::getMarkupTemplate('widget/posted_date.tpl'), [ $o = Renderer::replaceMacros(Renderer::getMarkupTemplate('widget/posted_date.tpl'), [
'$title' => DI::l10n()->t('Archives'), '$title' => DI::l10n()->t('Archives'),
'$size' => $visible_years, '$size' => $visible_years,
'$cutoff_year' => $cutoff_year, '$cutoff_year' => $cutoff_year,
'$cutoff' => $cutoff, '$cutoff' => $cutoff,
'$url' => $url, '$url' => $url,
'$dates' => $ret, '$dates' => $ret,
'$showless' => DI::l10n()->t('show less'), '$showless' => DI::l10n()->t('show less'),
'$showmore' => DI::l10n()->t('show more'), '$showmore' => DI::l10n()->t('show more'),
'$onthisdate' => DI::l10n()->t('On this date'), '$onthisdate' => DI::l10n()->t('On this date'),
'$thisday' => $thisday, '$thisday' => $thisday,
'$nextday' => $nextday, '$nextday' => $nextday,
'$cutoffday' => $cutoffday '$cutoffday' => $cutoffday
]); ]);
return $o; return $o;

View file

@ -18,6 +18,9 @@ class Addon
{ {
/** /**
* The addon sub-directory * The addon sub-directory
*
* @deprecated 2025.02 Use `Friendica\Core\Addon\AddonHelper::getAddonPath()` instead
*
* @var string * @var string
*/ */
const DIRECTORY = 'addon'; const DIRECTORY = 'addon';
@ -34,6 +37,8 @@ class Addon
* This list is made from scanning the addon/ folder. * This list is made from scanning the addon/ folder.
* Unsupported addons are excluded unless they already are enabled or system.show_unsupported_addon is set. * Unsupported addons are excluded unless they already are enabled or system.show_unsupported_addon is set.
* *
* @deprecated 2025.02 Use `Friendica\Core\Addon\AddonHelper::getAvailableAddons()` instead
*
* @return array * @return array
* @throws \Exception * @throws \Exception
*/ */
@ -64,6 +69,8 @@ class Addon
* Returns a list of addons that can be configured at the node level. * Returns a list of addons that can be configured at the node level.
* The list is formatted for display in the admin panel aside. * The list is formatted for display in the admin panel aside.
* *
* @deprecated 2025.02 Use `Friendica\Core\Addon\AddonHelper::getEnabledAddonsWithAdminSettings()` instead
*
* @return array * @return array
* @throws \Exception * @throws \Exception
*/ */
@ -88,7 +95,6 @@ class Addon
return $addons_admin; return $addons_admin;
} }
/** /**
* Synchronize addons: * Synchronize addons:
* *
@ -100,6 +106,7 @@ class Addon
* Then go through the config list and if we have a addon that isn't installed, * Then go through the config list and if we have a addon that isn't installed,
* call the install procedure and add it to the database. * call the install procedure and add it to the database.
* *
* @deprecated 2025.02 Use `Friendica\Core\Addon\AddonHelper::loadAddons()` instead
*/ */
public static function loadAddons() public static function loadAddons()
{ {
@ -109,6 +116,8 @@ class Addon
/** /**
* uninstalls an addon. * uninstalls an addon.
* *
* @deprecated 2025.02 Use `Friendica\Core\Addon\AddonHelper::uninstallAddon()` instead
*
* @param string $addon name of the addon * @param string $addon name of the addon
* @return void * @return void
* @throws \Exception * @throws \Exception
@ -135,6 +144,8 @@ class Addon
/** /**
* installs an addon. * installs an addon.
* *
* @deprecated 2025.02 Use `Friendica\Core\Addon\AddonHelper::installAddon()` instead
*
* @param string $addon name of the addon * @param string $addon name of the addon
* @return bool * @return bool
* @throws \Exception * @throws \Exception
@ -173,6 +184,8 @@ class Addon
/** /**
* reload all updated addons * reload all updated addons
* *
* @deprecated 2025.02 Use `Friendica\Core\Addon\AddonHelper::reloadAddons()` instead
*
* @return void * @return void
* @throws \Exception * @throws \Exception
* *
@ -209,6 +222,9 @@ class Addon
* * Maintainer: Jess <email> * * Maintainer: Jess <email>
* * * *
* *\endcode * *\endcode
*
* @deprecated 2025.02 Use `Friendica\Core\Addon\AddonHelper::getAddonInfo()` instead
*
* @param string $addon the name of the addon * @param string $addon the name of the addon
* @return array with the addon information * @return array with the addon information
* @throws \Exception * @throws \Exception
@ -275,6 +291,8 @@ class Addon
/** /**
* Checks if the provided addon is enabled * Checks if the provided addon is enabled
* *
* @deprecated 2025.02 Use `Friendica\Core\Addon\AddonHelper::isAddonEnabled()` instead
*
* @param string $addon * @param string $addon
* @return boolean * @return boolean
*/ */
@ -286,6 +304,8 @@ class Addon
/** /**
* Returns a list of the enabled addon names * Returns a list of the enabled addon names
* *
* @deprecated 2025.02 Use `Friendica\Core\Addon\AddonHelper::getEnabledAddons()` instead
*
* @return array * @return array
*/ */
public static function getEnabledList(): array public static function getEnabledList(): array
@ -296,6 +316,8 @@ class Addon
/** /**
* Returns the list of non-hidden enabled addon names * Returns the list of non-hidden enabled addon names
* *
* @deprecated 2025.02 Use `Friendica\Core\Addon\AddonHelper::getVisibleEnabledAddons()` instead
*
* @return array * @return array
* @throws \Exception * @throws \Exception
*/ */

View file

@ -0,0 +1,92 @@
<?php
// Copyright (C) 2010-2024, the Friendica project
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
//
// SPDX-License-Identifier: AGPL-3.0-or-later
declare(strict_types=1);
namespace Friendica\Core\Addon;
/**
* Some functions to handle addons
*/
interface AddonHelper
{
/**
* Returns the absolute path to the addon folder
*
* e.g. `/var/www/html/addon`
*/
public function getAddonPath(): string;
/**
* Returns the list of available addons.
*
* This list is made from scanning the addon/ folder.
* Unsupported addons are excluded unless they already are enabled or system.show_unsupported_addon is set.
*
* @return string[]
*/
public function getAvailableAddons(): array;
/**
* Installs an addon.
*
* @param string $addonId name of the addon
*
* @return bool true on success or false on failure
*/
public function installAddon(string $addonId): bool;
/**
* Uninstalls an addon.
*
* @param string $addonId name of the addon
*/
public function uninstallAddon(string $addonId): void;
/**
* Load addons.
*
* @internal
*/
public function loadAddons(): void;
/**
* Reload (uninstall and install) all updated addons.
*/
public function reloadAddons(): void;
/**
* Get the comment block of an addon as value object.
*/
public function getAddonInfo(string $addonId): AddonInfo;
/**
* Checks if the provided addon is enabled
*/
public function isAddonEnabled(string $addonId): bool;
/**
* Returns a list with the IDs of the enabled addons
*
* @return string[]
*/
public function getEnabledAddons(): array;
/**
* Returns a list with the IDs of the non-hidden enabled addons
*
* @return string[]
*/
public function getVisibleEnabledAddons(): array;
/**
* Returns a list with the IDs of the enabled addons that provides admin settings.
*
* @return string[]
*/
public function getEnabledAddonsWithAdminSettings(): array;
}

View file

@ -0,0 +1,140 @@
<?php
// Copyright (C) 2010-2024, the Friendica project
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
//
// SPDX-License-Identifier: AGPL-3.0-or-later
declare(strict_types=1);
namespace Friendica\Core\Addon;
/**
* Information about an addon
*/
final class AddonInfo
{
/**
* @internal Never create this object by yourself, use `Friendica\Core\Addon\AddonHelper::getAddonInfo()` instead.
*
* @see Friendica\Core\Addon\AddonHelper::getAddonInfo()
*/
public static function fromArray(array $info): self
{
$id = array_key_exists('id', $info) ? (string) $info['id'] : '';
$name = array_key_exists('name', $info) ? (string) $info['name'] : '';
$description = array_key_exists('description', $info) ? (string) $info['description'] : '';
$authors = array_key_exists('authors', $info) ? self::parseContributors($info['authors']) : [];
$maintainers = array_key_exists('maintainers', $info) ? self::parseContributors($info['maintainers']) : [];
$version = array_key_exists('version', $info) ? (string) $info['version'] : '';
$status = array_key_exists('status', $info) ? (string) $info['status'] : '';
return new self(
$id,
$name,
$description,
$authors,
$maintainers,
$version,
$status
);
}
private static function parseContributors($entries): array
{
if (!is_array($entries)) {
return [];
}
$contributors = [];
foreach ($entries as $entry) {
if (!is_array($entry)) {
continue;
}
if (!array_key_exists('name', $entry)) {
continue;
}
$contributor = [
'name' => (string) $entry['name'],
];
if (array_key_exists('link', $entry)) {
$contributor['link'] = (string) $entry['link'];
}
$contributors[] = $contributor;
}
return $contributors;
}
private string $id = '';
private string $name = '';
private string $description = '';
private array $authors = [];
private array $maintainers = [];
private string $version = '';
private string $status = '';
private function __construct(
string $id,
string $name,
string $description,
array $authors,
array $maintainers,
string $version,
string $status
) {
$this->id = $id;
$this->name = $name;
$this->description = $description;
$this->authors = $authors;
$this->maintainers = $maintainers;
$this->version = $version;
$this->status = $status;
}
public function getId(): string
{
return $this->id;
}
public function getName(): string
{
return $this->name;
}
public function getDescription(): string
{
return $this->description;
}
public function getAuthors(): array
{
return $this->authors;
}
public function getMaintainers(): array
{
return $this->maintainers;
}
public function getVersion(): string
{
return $this->version;
}
public function getStatus(): string
{
return $this->status;
}
}

View file

@ -0,0 +1,154 @@
<?php
// Copyright (C) 2010-2024, the Friendica project
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
//
// SPDX-License-Identifier: AGPL-3.0-or-later
declare(strict_types=1);
namespace Friendica\Core\Addon;
use Friendica\Core\Addon;
/**
* Proxy to the Addon class
*
* @internal
*/
final class AddonProxy implements AddonHelper
{
private string $addonPath;
public function __construct(string $addonPath)
{
$this->addonPath = $addonPath;
}
/**
* Returns the absolute path to the addon folder
*
* e.g. `/var/www/html/addon`
*/
public function getAddonPath(): string
{
return $this->addonPath;
}
/**
* Returns the list of available addons.
*
* This list is made from scanning the addon/ folder.
* Unsupported addons are excluded unless they already are enabled or system.show_unsupported_addon is set.
*
* @return string[]
*/
public function getAvailableAddons(): array
{
return array_map(
function (array $item) {
return $item[0];
},
Addon::getAvailableList()
);
}
/**
* Installs an addon.
*
* @param string $addonId name of the addon
*
* @return bool true on success or false on failure
*/
public function installAddon(string $addonId): bool
{
return Addon::install($addonId);
}
/**
* Uninstalls an addon.
*
* @param string $addonId name of the addon
*/
public function uninstallAddon(string $addonId): void
{
Addon::uninstall($addonId);
}
/**
* Load addons.
*
* @internal
*/
public function loadAddons(): void
{
Addon::loadAddons();
}
/**
* Reload (uninstall and install) all updated addons.
*/
public function reloadAddons(): void
{
Addon::reload();
}
/**
* Get the comment block of an addon as value object.
*/
public function getAddonInfo(string $addonId): AddonInfo
{
$data = Addon::getInfo($addonId);
// add addon ID
$data['id'] = $addonId;
// rename author to authors
$data['authors'] = $data['author'];
unset($data['author']);
// rename maintainer to maintainers
$data['maintainers'] = $data['maintainer'];
unset($data['maintainer']);
return AddonInfo::fromArray($data);
}
/**
* Checks if the provided addon is enabled
*/
public function isAddonEnabled(string $addonId): bool
{
return Addon::isEnabled($addonId);
}
/**
* Returns a list with the IDs of the enabled addons
*
* @return string[]
*/
public function getEnabledAddons(): array
{
return Addon::getEnabledList();
}
/**
* Returns a list with the IDs of the non-hidden enabled addons
*
* @return string[]
*/
public function getVisibleEnabledAddons(): array
{
return Addon::getVisibleList();
}
/**
* Returns a list with the IDs of the enabled addons that provides admin settings.
*
* @return string[]
*/
public function getEnabledAddonsWithAdminSettings(): array
{
return array_keys(Addon::getAdminList());
}
}

View file

@ -42,7 +42,7 @@ class Config
* *
* @return Util\ConfigFileManager * @return Util\ConfigFileManager
*/ */
public function createConfigFileManager(string $basePath, array $server = []): Util\ConfigFileManager public function createConfigFileManager(string $basePath, string $addonPath, array $server = []): Util\ConfigFileManager
{ {
if (!empty($server[self::CONFIG_DIR_ENV]) && is_dir($server[self::CONFIG_DIR_ENV])) { if (!empty($server[self::CONFIG_DIR_ENV]) && is_dir($server[self::CONFIG_DIR_ENV])) {
$configDir = $server[self::CONFIG_DIR_ENV]; $configDir = $server[self::CONFIG_DIR_ENV];
@ -51,7 +51,7 @@ class Config
} }
$staticDir = $basePath . DIRECTORY_SEPARATOR . self::STATIC_DIR; $staticDir = $basePath . DIRECTORY_SEPARATOR . self::STATIC_DIR;
return new Util\ConfigFileManager($basePath, $configDir, $staticDir, $server); return new Util\ConfigFileManager($basePath, $addonPath, $configDir, $staticDir, $server);
} }
/** /**

View file

@ -7,7 +7,6 @@
namespace Friendica\Core\Config\Util; namespace Friendica\Core\Config\Util;
use Friendica\Core\Addon;
use Friendica\Core\Config\Exception\ConfigFileException; use Friendica\Core\Config\Exception\ConfigFileException;
use Friendica\Core\Config\ValueObject\Cache; use Friendica\Core\Config\ValueObject\Cache;
@ -46,6 +45,7 @@ class ConfigFileManager
* @var string * @var string
*/ */
private $baseDir; private $baseDir;
private string $addonDir;
/** /**
* @var string * @var string
*/ */
@ -65,9 +65,10 @@ class ConfigFileManager
* @param string $configDir * @param string $configDir
* @param string $staticDir * @param string $staticDir
*/ */
public function __construct(string $baseDir, string $configDir, string $staticDir, array $server = []) public function __construct(string $baseDir, string $addonDir, string $configDir, string $staticDir, array $server = [])
{ {
$this->baseDir = $baseDir; $this->baseDir = $baseDir;
$this->addonDir = $addonDir;
$this->configDir = $configDir; $this->configDir = $configDir;
$this->staticDir = $staticDir; $this->staticDir = $staticDir;
$this->server = $server; $this->server = $server;
@ -122,7 +123,7 @@ class ConfigFileManager
if (file_exists($configName)) { if (file_exists($configName)) {
return $this->loadConfigFile($configName); return $this->loadConfigFile($configName);
} else if (file_exists($iniName)) { } elseif (file_exists($iniName)) {
return $this->loadINIConfigFile($iniName); return $this->loadINIConfigFile($iniName);
} else { } else {
return []; return [];
@ -160,17 +161,16 @@ class ConfigFileManager
*/ */
public function loadAddonConfig(string $name): array public function loadAddonConfig(string $name): array
{ {
$filepath = $this->baseDir . DIRECTORY_SEPARATOR . // /var/www/html/ $filepath = $this->addonDir . DIRECTORY_SEPARATOR . // /var/www/html/addon/
Addon::DIRECTORY . DIRECTORY_SEPARATOR . // addon/ $name . DIRECTORY_SEPARATOR . // openstreetmap/
$name . DIRECTORY_SEPARATOR . // openstreetmap/ 'config' . DIRECTORY_SEPARATOR . // config/
'config' . DIRECTORY_SEPARATOR . // config/ $name . ".config.php"; // openstreetmap.config.php
$name . ".config.php"; // openstreetmap.config.php
if (file_exists($filepath)) { if (!file_exists($filepath)) {
return $this->loadConfigFile($filepath);
} else {
return []; return [];
} }
return $this->loadConfigFile($filepath);
} }
/** /**

View file

@ -8,7 +8,6 @@
namespace Friendica\Core\Storage\Repository; namespace Friendica\Core\Storage\Repository;
use Exception; use Exception;
use Friendica\Core\Addon;
use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\Hook; use Friendica\Core\Hook;
use Friendica\Core\L10n; use Friendica\Core\L10n;
@ -20,6 +19,7 @@ use Friendica\Core\Storage\Capability\ICanConfigureStorage;
use Friendica\Core\Storage\Capability\ICanWriteToStorage; use Friendica\Core\Storage\Capability\ICanWriteToStorage;
use Friendica\Database\Database; use Friendica\Database\Database;
use Friendica\Core\Storage\Type; use Friendica\Core\Storage\Type;
use Friendica\DI;
use Friendica\Network\HTTPException\InternalServerErrorException; use Friendica\Network\HTTPException\InternalServerErrorException;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
@ -84,7 +84,7 @@ class StorageManager
/// @fixme Loading the addons & hooks here is really bad practice, but solves https://github.com/friendica/friendica/issues/11178 /// @fixme Loading the addons & hooks here is really bad practice, but solves https://github.com/friendica/friendica/issues/11178
/// clean solution = Making Addon & Hook dynamic and load them inside the constructor, so there's no custom load logic necessary anymore /// clean solution = Making Addon & Hook dynamic and load them inside the constructor, so there's no custom load logic necessary anymore
if ($includeAddon) { if ($includeAddon) {
Addon::loadAddons(); DI::addonHelper()->loadAddons();
Hook::loadHooks(); Hook::loadHooks();
} }
@ -138,7 +138,7 @@ class StorageManager
// Try the filesystem backend // Try the filesystem backend
case Type\Filesystem::getName(): case Type\Filesystem::getName():
return new Type\FilesystemConfig($this->config, $this->l10n); return new Type\FilesystemConfig($this->config, $this->l10n);
// try the database backend // try the database backend
case Type\Database::getName(): case Type\Database::getName():
return false; return false;
default: default:
@ -185,11 +185,11 @@ class StorageManager
$storageConfig = new Type\FilesystemConfig($this->config, $this->l10n); $storageConfig = new Type\FilesystemConfig($this->config, $this->l10n);
$this->backendInstances[$name] = new Type\Filesystem($storageConfig->getStoragePath()); $this->backendInstances[$name] = new Type\Filesystem($storageConfig->getStoragePath());
break; break;
// try the database backend // try the database backend
case Type\Database::getName(): case Type\Database::getName():
$this->backendInstances[$name] = new Type\Database($this->dba); $this->backendInstances[$name] = new Type\Database($this->dba);
break; break;
// at least, try if there's an addon for the backend // at least, try if there's an addon for the backend
case Type\SystemResource::getName(): case Type\SystemResource::getName():
$this->backendInstances[$name] = new Type\SystemResource(); $this->backendInstances[$name] = new Type\SystemResource();
break; break;
@ -228,11 +228,13 @@ class StorageManager
*/ */
public function isValidBackend(string $name = null, array $validBackends = null): bool public function isValidBackend(string $name = null, array $validBackends = null): bool
{ {
$validBackends = $validBackends ?? array_merge($this->validBackends, $validBackends = $validBackends ?? array_merge(
[ $this->validBackends,
Type\SystemResource::getName(), [
Type\ExternalResource::getName(), Type\SystemResource::getName(),
]); Type\ExternalResource::getName(),
]
);
return in_array($name, $validBackends); return in_array($name, $validBackends);
} }

View file

@ -8,6 +8,7 @@
namespace Friendica; namespace Friendica;
use Dice\Dice; use Dice\Dice;
use Friendica\Core\Addon\AddonHelper;
use Friendica\Core\Logger\Capability\ICheckLoggerSettings; use Friendica\Core\Logger\Capability\ICheckLoggerSettings;
use Friendica\Core\Logger\LoggerManager; use Friendica\Core\Logger\LoggerManager;
use Friendica\Core\Logger\Util\LoggerSettingsCheck; use Friendica\Core\Logger\Util\LoggerSettingsCheck;
@ -280,6 +281,11 @@ abstract class DI
return self::$dice->create(Core\Storage\Repository\StorageManager::class); return self::$dice->create(Core\Storage\Repository\StorageManager::class);
} }
public static function addonHelper(): AddonHelper
{
return self::$dice->create(AddonHelper::class);
}
/** /**
* @return \Friendica\Core\System * @return \Friendica\Core\System
*/ */

View file

@ -8,7 +8,6 @@
namespace Friendica\Module\Admin\Addons; namespace Friendica\Module\Admin\Addons;
use Friendica\Content\Text\Markdown; use Friendica\Content\Text\Markdown;
use Friendica\Core\Addon;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\DI; use Friendica\DI;
use Friendica\Module\BaseAdmin; use Friendica\Module\BaseAdmin;
@ -42,12 +41,12 @@ class Details extends BaseAdmin
{ {
parent::content(); parent::content();
$addons_admin = Addon::getAdminList(); $addonHelper = DI::addonHelper();
$addon = Strings::sanitizeFilePathItem($this->parameters['addon']); $addon = Strings::sanitizeFilePathItem($this->parameters['addon']);
if (!is_file("addon/$addon/$addon.php")) { if (!is_file("addon/$addon/$addon.php")) {
DI::sysmsg()->addNotice(DI::l10n()->t('Addon not found.')); DI::sysmsg()->addNotice(DI::l10n()->t('Addon not found.'));
Addon::uninstall($addon); $addonHelper->uninstallAddon($addon);
DI::baseUrl()->redirect('admin/addons'); DI::baseUrl()->redirect('admin/addons');
} }
@ -55,11 +54,11 @@ class Details extends BaseAdmin
self::checkFormSecurityTokenRedirectOnError('/admin/addons', 'admin_addons_details', 't'); self::checkFormSecurityTokenRedirectOnError('/admin/addons', 'admin_addons_details', 't');
// Toggle addon status // Toggle addon status
if (Addon::isEnabled($addon)) { if ($addonHelper->isAddonEnabled($addon)) {
Addon::uninstall($addon); $addonHelper->uninstallAddon($addon);
DI::sysmsg()->addInfo(DI::l10n()->t('Addon %s disabled.', $addon)); DI::sysmsg()->addInfo(DI::l10n()->t('Addon %s disabled.', $addon));
} else { } else {
Addon::install($addon); $addonHelper->installAddon($addon);
DI::sysmsg()->addInfo(DI::l10n()->t('Addon %s enabled.', $addon)); DI::sysmsg()->addInfo(DI::l10n()->t('Addon %s enabled.', $addon));
} }
@ -67,7 +66,7 @@ class Details extends BaseAdmin
} }
// display addon details // display addon details
if (Addon::isEnabled($addon)) { if ($addonHelper->isAddonEnabled($addon)) {
$status = 'on'; $status = 'on';
$action = DI::l10n()->t('Disable'); $action = DI::l10n()->t('Disable');
} else { } else {
@ -82,32 +81,42 @@ class Details extends BaseAdmin
$readme = '<pre>' . file_get_contents("addon/$addon/README") . '</pre>'; $readme = '<pre>' . file_get_contents("addon/$addon/README") . '</pre>';
} }
$addons_admin = $addonHelper->getEnabledAddonsWithAdminSettings();
$admin_form = ''; $admin_form = '';
if (array_key_exists($addon, $addons_admin)) { if (in_array($addon, $addons_admin)) {
require_once "addon/$addon/$addon.php"; require_once "addon/$addon/$addon.php";
$func = $addon . '_addon_admin'; $func = $addon . '_addon_admin';
$func($admin_form); $func($admin_form);
} }
$addonInfo = $addonHelper->getAddonInfo($addon);
$t = Renderer::getMarkupTemplate('admin/addons/details.tpl'); $t = Renderer::getMarkupTemplate('admin/addons/details.tpl');
return Renderer::replaceMacros($t, [ return Renderer::replaceMacros($t, [
'$title' => DI::l10n()->t('Administration'), '$title' => DI::l10n()->t('Administration'),
'$page' => DI::l10n()->t('Addons'), '$page' => DI::l10n()->t('Addons'),
'$toggle' => DI::l10n()->t('Toggle'), '$toggle' => DI::l10n()->t('Toggle'),
'$settings' => DI::l10n()->t('Settings'), '$settings' => DI::l10n()->t('Settings'),
'$addon' => $addon, '$addon' => $addon,
'$status' => $status, '$status' => $status,
'$action' => $action, '$action' => $action,
'$info' => Addon::getInfo($addon), '$info' => [
'$str_author' => DI::l10n()->t('Author: '), 'name' => $addonInfo->getName(),
'version' => $addonInfo->getVersion(),
'description' => $addonInfo->getDescription(),
'author' => $addonInfo->getAuthors(),
'maintainer' => $addonInfo->getMaintainers(),
],
'$str_author' => DI::l10n()->t('Author: '),
'$str_maintainer' => DI::l10n()->t('Maintainer: '), '$str_maintainer' => DI::l10n()->t('Maintainer: '),
'$admin_form' => $admin_form, '$admin_form' => $admin_form,
'$function' => 'addons', '$function' => 'addons',
'$screenshot' => '', '$screenshot' => '',
'$readme' => $readme, '$readme' => $readme,
'$form_security_token' => self::getFormSecurityToken('admin_addons_details'), '$form_security_token' => self::getFormSecurityToken('admin_addons_details'),
]); ]);

View file

@ -7,7 +7,6 @@
namespace Friendica\Module\Admin\Addons; namespace Friendica\Module\Admin\Addons;
use Friendica\Core\Addon;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\DI; use Friendica\DI;
use Friendica\Module\BaseAdmin; use Friendica\Module\BaseAdmin;
@ -24,22 +23,25 @@ class Index extends BaseAdmin
{ {
parent::content(); parent::content();
$addonHelper = DI::addonHelper();
// reload active themes // reload active themes
if (!empty($_GET['action'])) { if (!empty($_GET['action'])) {
self::checkFormSecurityTokenRedirectOnError('/admin/addons', 'admin_addons', 't'); self::checkFormSecurityTokenRedirectOnError('/admin/addons', 'admin_addons', 't');
switch ($_GET['action']) { switch ($_GET['action']) {
case 'reload': case 'reload':
Addon::reload(); $addonHelper->reloadAddons();
DI::sysmsg()->addInfo(DI::l10n()->t('Addons reloaded')); DI::sysmsg()->addInfo(DI::l10n()->t('Addons reloaded'));
break; break;
case 'toggle' : case 'toggle':
$addon = $_GET['addon'] ?? ''; $addon = $_GET['addon'] ?? '';
if (Addon::isEnabled($addon)) {
Addon::uninstall($addon); if ($addonHelper->isAddonEnabled($addon)) {
$addonHelper->uninstallAddon($addon);
DI::sysmsg()->addInfo(DI::l10n()->t('Addon %s disabled.', $addon)); DI::sysmsg()->addInfo(DI::l10n()->t('Addon %s disabled.', $addon));
} elseif (Addon::install($addon)) { } elseif ($addonHelper->installAddon($addon)) {
DI::sysmsg()->addInfo(DI::l10n()->t('Addon %s enabled.', $addon)); DI::sysmsg()->addInfo(DI::l10n()->t('Addon %s enabled.', $addon));
} else { } else {
DI::sysmsg()->addNotice(DI::l10n()->t('Addon %s failed to install.', $addon)); DI::sysmsg()->addNotice(DI::l10n()->t('Addon %s failed to install.', $addon));
@ -52,18 +54,34 @@ class Index extends BaseAdmin
DI::baseUrl()->redirect('admin/addons'); DI::baseUrl()->redirect('admin/addons');
} }
$addons = Addon::getAvailableList(); $addons = [];
foreach ($addonHelper->getAvailableAddons() as $addonId) {
$addonInfo = $addonHelper->getAddonInfo($addonId);
$info = [
'name' => $addonInfo->getName(),
'description' => $addonInfo->getDescription(),
'version' => $addonInfo->getVersion(),
];
$addons[] = [
$addonId,
($addonHelper->isAddonEnabled($addonId) ? 'on' : 'off'),
$info,
];
}
$t = Renderer::getMarkupTemplate('admin/addons/index.tpl'); $t = Renderer::getMarkupTemplate('admin/addons/index.tpl');
return Renderer::replaceMacros($t, [ return Renderer::replaceMacros($t, [
'$title' => DI::l10n()->t('Administration'), '$title' => DI::l10n()->t('Administration'),
'$page' => DI::l10n()->t('Addons'), '$page' => DI::l10n()->t('Addons'),
'$submit' => DI::l10n()->t('Save Settings'), '$submit' => DI::l10n()->t('Save Settings'),
'$reload' => DI::l10n()->t('Reload active addons'), '$reload' => DI::l10n()->t('Reload active addons'),
'$function' => 'addons', '$function' => 'addons',
'$addons' => $addons, '$addons' => $addons,
'$pcount' => count($addons), '$pcount' => count($addons),
'$noplugshint' => DI::l10n()->t('There are currently no addons available on your node. You can find the official addon repository at %1$s.', 'https://git.friendi.ca/friendica/friendica-addons'), '$noplugshint' => DI::l10n()->t('There are currently no addons available on your node. You can find the official addon repository at %1$s.', 'https://git.friendi.ca/friendica/friendica-addons'),
'$form_security_token' => self::getFormSecurityToken('admin_addons'), '$form_security_token' => self::getFormSecurityToken('admin_addons'),
]); ]);
} }

View file

@ -8,7 +8,6 @@
namespace Friendica\Module\Admin; namespace Friendica\Module\Admin;
use Friendica\App; use Friendica\App;
use Friendica\Core\Addon;
use Friendica\Core\Config\ValueObject\Cache; use Friendica\Core\Config\ValueObject\Cache;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\Core\Update; use Friendica\Core\Update;
@ -27,13 +26,14 @@ class Summary extends BaseAdmin
{ {
parent::content(); parent::content();
$basePath = DI::appHelper()->getBasePath(); $basePath = DI::appHelper()->getBasePath();
$addonPath = DI::addonHelper()->getAddonPath();
// are there MyISAM tables in the DB? If so, trigger a warning message // are there MyISAM tables in the DB? If so, trigger a warning message
$warningtext = []; $warningtext = [];
$templateEngine = Renderer::getTemplateEngine(); $templateEngine = Renderer::getTemplateEngine();
$errors = []; $errors = [];
$templateEngine->testInstall($errors); $templateEngine->testInstall($errors);
foreach ($errors as $error) { foreach ($errors as $error) {
$warningtext[] = DI::l10n()->t('Template engine (%s) error: %s', $templateEngine::$name, $error); $warningtext[] = DI::l10n()->t('Template engine (%s) error: %s', $templateEngine::$name, $error);
@ -51,7 +51,7 @@ class Summary extends BaseAdmin
// Avoid the database error 1615 "Prepared statement needs to be re-prepared", see https://github.com/friendica/friendica/issues/8550 // Avoid the database error 1615 "Prepared statement needs to be re-prepared", see https://github.com/friendica/friendica/issues/8550
if (!DI::config()->get('database', 'pdo_emulate_prepares')) { if (!DI::config()->get('database', 'pdo_emulate_prepares')) {
$table_definition_cache = DBA::getVariable('table_definition_cache'); $table_definition_cache = DBA::getVariable('table_definition_cache');
$table_open_cache = DBA::getVariable('table_open_cache'); $table_open_cache = DBA::getVariable('table_open_cache');
if (!empty($table_definition_cache) && !empty($table_open_cache)) { if (!empty($table_definition_cache) && !empty($table_open_cache)) {
$suggested_definition_cache = min(400 + round((int) $table_open_cache / 2, 1), 2000); $suggested_definition_cache = min(400 + round((int) $table_open_cache / 2, 1), 2000);
if ($suggested_definition_cache > $table_definition_cache) { if ($suggested_definition_cache > $table_definition_cache) {
@ -100,9 +100,13 @@ class Summary extends BaseAdmin
// Check server vitality // Check server vitality
if (!self::checkSelfHostMeta()) { if (!self::checkSelfHostMeta()) {
$well_known = DI::baseUrl() . Probe::HOST_META; $well_known = DI::baseUrl() . Probe::HOST_META;
$warningtext[] = DI::l10n()->t('<a href="%s">%s</a> is not reachable on your system. This is a severe configuration issue that prevents server to server communication. See <a href="%s">the installation page</a> for help.', $warningtext[] = DI::l10n()->t(
$well_known, $well_known, DI::baseUrl() . '/help/Install'); '<a href="%s">%s</a> is not reachable on your system. This is a severe configuration issue that prevents server to server communication. See <a href="%s">the installation page</a> for help.',
$well_known,
$well_known,
DI::baseUrl() . '/help/Install'
);
} }
// Check logfile permission // Check logfile permission
@ -114,8 +118,8 @@ class Summary extends BaseAdmin
} }
// check legacy basepath settings // check legacy basepath settings
$configLoader = (new Config())->createConfigFileManager($basePath, $_SERVER); $configLoader = (new Config())->createConfigFileManager($basePath, $addonPath, $_SERVER);
$configCache = new Cache(); $configCache = new Cache();
$configLoader->setupCache($configCache); $configLoader->setupCache($configCache);
$confBasepath = $configCache->get('system', 'basepath'); $confBasepath = $configCache->get('system', 'basepath');
$currBasepath = DI::config()->get('system', 'basepath'); $currBasepath = DI::config()->get('system', 'basepath');
@ -125,25 +129,31 @@ class Summary extends BaseAdmin
'from' => $currBasepath, 'from' => $currBasepath,
'to' => $confBasepath, 'to' => $confBasepath,
]); ]);
$warningtext[] = DI::l10n()->t('Friendica\'s system.basepath was updated from \'%s\' to \'%s\'. Please remove the system.basepath from your db to avoid differences.', $warningtext[] = DI::l10n()->t(
'Friendica\'s system.basepath was updated from \'%s\' to \'%s\'. Please remove the system.basepath from your db to avoid differences.',
$currBasepath, $currBasepath,
$confBasepath); $confBasepath
);
} elseif (!is_dir($currBasepath)) { } elseif (!is_dir($currBasepath)) {
DI::logger()->alert('Friendica\'s system.basepath is wrong.', [ DI::logger()->alert('Friendica\'s system.basepath is wrong.', [
'from' => $currBasepath, 'from' => $currBasepath,
'to' => $confBasepath, 'to' => $confBasepath,
]); ]);
$warningtext[] = DI::l10n()->t('Friendica\'s current system.basepath \'%s\' is wrong and the config file \'%s\' isn\'t used.', $warningtext[] = DI::l10n()->t(
'Friendica\'s current system.basepath \'%s\' is wrong and the config file \'%s\' isn\'t used.',
$currBasepath, $currBasepath,
$confBasepath); $confBasepath
);
} else { } else {
DI::logger()->alert('Friendica\'s system.basepath is wrong.', [ DI::logger()->alert('Friendica\'s system.basepath is wrong.', [
'from' => $currBasepath, 'from' => $currBasepath,
'to' => $confBasepath, 'to' => $confBasepath,
]); ]);
$warningtext[] = DI::l10n()->t('Friendica\'s current system.basepath \'%s\' is not equal to the config file \'%s\'. Please fix your configuration.', $warningtext[] = DI::l10n()->t(
'Friendica\'s current system.basepath \'%s\' is not equal to the config file \'%s\'. Please fix your configuration.',
$currBasepath, $currBasepath,
$confBasepath); $confBasepath
);
} }
} }
@ -177,7 +187,7 @@ class Summary extends BaseAdmin
'$platform' => App::PLATFORM, '$platform' => App::PLATFORM,
'$codename' => App::CODENAME, '$codename' => App::CODENAME,
'$build' => DI::config()->get('system', 'build'), '$build' => DI::config()->get('system', 'build'),
'$addons' => [DI::l10n()->t('Active addons'), Addon::getEnabledList()], '$addons' => [DI::l10n()->t('Active addons'), DI::addonHelper()->getEnabledAddons()],
'$serversettings' => $server_settings, '$serversettings' => $server_settings,
'$warningtext' => $warningtext, '$warningtext' => $warningtext,
]); ]);

View file

@ -8,7 +8,6 @@
namespace Friendica\Module; namespace Friendica\Module;
use Friendica\BaseModule; use Friendica\BaseModule;
use Friendica\Core\Addon;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\DI; use Friendica\DI;
use Friendica\Network\HTTPException; use Friendica\Network\HTTPException;
@ -69,43 +68,53 @@ abstract class BaseAdmin extends BaseModule
// not part of $aside to make the template more adjustable // not part of $aside to make the template more adjustable
$aside_sub = [ $aside_sub = [
'information' => [DI::l10n()->t('Information'), [ 'information' => [DI::l10n()->t('Information'), [
'overview' => ['admin' , DI::l10n()->t('Overview') , 'overview'], 'overview' => ['admin' , DI::l10n()->t('Overview') , 'overview'],
'federation' => ['admin/federation' , DI::l10n()->t('Federation Statistics') , 'federation'] 'federation' => ['admin/federation' , DI::l10n()->t('Federation Statistics') , 'federation']
]], ]],
'configuration' => [DI::l10n()->t('Configuration'), [ 'configuration' => [DI::l10n()->t('Configuration'), [
'site' => ['admin/site' , DI::l10n()->t('Site') , 'site'], 'site' => ['admin/site' , DI::l10n()->t('Site') , 'site'],
'storage' => ['admin/storage' , DI::l10n()->t('Storage') , 'storage'], 'storage' => ['admin/storage' , DI::l10n()->t('Storage') , 'storage'],
'addons' => ['admin/addons' , DI::l10n()->t('Addons') , 'addons'], 'addons' => ['admin/addons' , DI::l10n()->t('Addons') , 'addons'],
'themes' => ['admin/themes' , DI::l10n()->t('Themes') , 'themes'], 'themes' => ['admin/themes' , DI::l10n()->t('Themes') , 'themes'],
'features' => ['admin/features' , DI::l10n()->t('Additional features') , 'features'], 'features' => ['admin/features' , DI::l10n()->t('Additional features') , 'features'],
'tos' => ['admin/tos' , DI::l10n()->t('Terms of Service') , 'tos'], 'tos' => ['admin/tos' , DI::l10n()->t('Terms of Service') , 'tos'],
]], ]],
'database' => [DI::l10n()->t('Database'), [ 'database' => [DI::l10n()->t('Database'), [
'dbsync' => ['admin/dbsync' , DI::l10n()->t('DB updates') , 'dbsync'], 'dbsync' => ['admin/dbsync' , DI::l10n()->t('DB updates') , 'dbsync'],
'deferred' => ['admin/queue/deferred', DI::l10n()->t('Inspect Deferred Workers'), 'deferred'], 'deferred' => ['admin/queue/deferred', DI::l10n()->t('Inspect Deferred Workers'), 'deferred'],
'workerqueue' => ['admin/queue' , DI::l10n()->t('Inspect worker Queue') , 'workerqueue'], 'workerqueue' => ['admin/queue' , DI::l10n()->t('Inspect worker Queue') , 'workerqueue'],
]], ]],
'logs' => [DI::l10n()->t('Logs'), [ 'logs' => [DI::l10n()->t('Logs'), [
'logsconfig' => ['admin/logs/', DI::l10n()->t('Logs') , 'logs'], 'logsconfig' => ['admin/logs/', DI::l10n()->t('Logs') , 'logs'],
'logsview' => ['admin/logs/view' , DI::l10n()->t('View Logs') , 'viewlogs'], 'logsview' => ['admin/logs/view' , DI::l10n()->t('View Logs') , 'viewlogs'],
]], ]],
'diagnostics' => [DI::l10n()->t('Diagnostics'), [ 'diagnostics' => [DI::l10n()->t('Diagnostics'), [
'phpinfo' => ['admin/phpinfo?t=' . self::getFormSecurityToken('phpinfo'), DI::l10n()->t('PHP Info') , 'phpinfo'], 'phpinfo' => ['admin/phpinfo?t=' . self::getFormSecurityToken('phpinfo'), DI::l10n()->t('PHP Info') , 'phpinfo'],
'probe' => ['probe' , DI::l10n()->t('probe address') , 'probe'], 'probe' => ['probe' , DI::l10n()->t('probe address') , 'probe'],
'webfinger' => ['webfinger' , DI::l10n()->t('check webfinger') , 'webfinger'], 'webfinger' => ['webfinger' , DI::l10n()->t('check webfinger') , 'webfinger'],
'babel' => ['babel' , DI::l10n()->t('Babel') , 'babel'], 'babel' => ['babel' , DI::l10n()->t('Babel') , 'babel'],
'debug/ap' => ['debug/ap' , DI::l10n()->t('ActivityPub Conversion') , 'debug/ap'], 'debug/ap' => ['debug/ap' , DI::l10n()->t('ActivityPub Conversion') , 'debug/ap'],
]], ]],
]; ];
$addons_admin = [];
foreach (DI::addonHelper()->getEnabledAddonsWithAdminSettings() as $addonId) {
$addons_admin[$addonId] = [
'url' => 'admin/addons/' . $addonId,
'name' => $addonId,
'class' => 'addon',
];
}
$t = Renderer::getMarkupTemplate('admin/aside.tpl'); $t = Renderer::getMarkupTemplate('admin/aside.tpl');
DI::page()['aside'] .= Renderer::replaceMacros($t, [ DI::page()['aside'] .= Renderer::replaceMacros($t, [
'$admin' => ['addons_admin' => Addon::getAdminList()], '$admin' => ['addons_admin' => $addons_admin],
'$subpages' => $aside_sub, '$subpages' => $aside_sub,
'$admtxt' => DI::l10n()->t('Admin'), '$admtxt' => DI::l10n()->t('Admin'),
'$plugadmtxt' => DI::l10n()->t('Addon Features'), '$plugadmtxt' => DI::l10n()->t('Addon Features'),
'$h_pending' => DI::l10n()->t('User registrations waiting for confirmation'), '$h_pending' => DI::l10n()->t('User registrations waiting for confirmation'),
'$admurl' => 'admin/' '$admurl' => 'admin/'
]); ]);
return ''; return '';

View file

@ -56,7 +56,7 @@ class SaveTag extends BaseModule
$tpl = Renderer::getMarkupTemplate("filer_dialog.tpl"); $tpl = Renderer::getMarkupTemplate("filer_dialog.tpl");
echo Renderer::replaceMacros($tpl, [ echo Renderer::replaceMacros($tpl, [
'$field' => ['term', $this->t("Folder:"), '', '', $filetags, $this->t('- select -')], '$field' => ['term', $this->t("Folder:"), '', '', $filetags, $this->t('- select -')],
'$submit' => $this->t('Save'), '$submit' => $this->t('Save'),
]); ]);

View file

@ -11,7 +11,7 @@ use Friendica\App;
use Friendica\App\Arguments; use Friendica\App\Arguments;
use Friendica\App\BaseURL; use Friendica\App\BaseURL;
use Friendica\BaseModule; use Friendica\BaseModule;
use Friendica\Core\Addon; use Friendica\Core\Addon\AddonHelper;
use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\Hook; use Friendica\Core\Hook;
use Friendica\Core\KeyValueStorage\Capability\IManageKeyValuePairs; use Friendica\Core\KeyValueStorage\Capability\IManageKeyValuePairs;
@ -31,6 +31,7 @@ use Psr\Log\LoggerInterface;
*/ */
class Friendica extends BaseModule class Friendica extends BaseModule
{ {
private AddonHelper $addonHelper;
/** @var IManageConfigValues */ /** @var IManageConfigValues */
private $config; private $config;
/** @var IManageKeyValuePairs */ /** @var IManageKeyValuePairs */
@ -38,18 +39,19 @@ class Friendica extends BaseModule
/** @var IHandleUserSessions */ /** @var IHandleUserSessions */
private $session; private $session;
public function __construct(IHandleUserSessions $session, IManageKeyValuePairs $keyValue, IManageConfigValues $config, L10n $l10n, BaseURL $baseUrl, Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) public function __construct(AddonHelper $addonHelper, IHandleUserSessions $session, IManageKeyValuePairs $keyValue, IManageConfigValues $config, L10n $l10n, BaseURL $baseUrl, Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = [])
{ {
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
$this->config = $config; $this->config = $config;
$this->keyValue = $keyValue; $this->keyValue = $keyValue;
$this->session = $session; $this->session = $session;
$this->addonHelper = $addonHelper;
} }
protected function content(array $request = []): string protected function content(array $request = []): string
{ {
$visibleAddonList = Addon::getVisibleList(); $visibleAddonList = $this->addonHelper->getVisibleEnabledAddons();
if (!empty($visibleAddonList)) { if (!empty($visibleAddonList)) {
$sorted = $visibleAddonList; $sorted = $visibleAddonList;
@ -83,8 +85,8 @@ class Friendica extends BaseModule
if (!empty($blockList) && ($this->config->get('blocklist', 'public') || $this->session->isAuthenticated())) { if (!empty($blockList) && ($this->config->get('blocklist', 'public') || $this->session->isAuthenticated())) {
$blocked = [ $blocked = [
'title' => $this->t('On this server the following remote servers are blocked.'), 'title' => $this->t('On this server the following remote servers are blocked.'),
'header' => [ 'header' => [
$this->t('Blocked domain'), $this->t('Blocked domain'),
$this->t('Reason for the block'), $this->t('Reason for the block'),
], ],
@ -102,11 +104,13 @@ class Friendica extends BaseModule
$tpl = Renderer::getMarkupTemplate('friendica.tpl'); $tpl = Renderer::getMarkupTemplate('friendica.tpl');
return Renderer::replaceMacros($tpl, [ return Renderer::replaceMacros($tpl, [
'about' => $this->t('This is Friendica, version %s that is running at the web location %s. The database version is %s, the post update version is %s.', 'about' => $this->t(
'This is Friendica, version %s that is running at the web location %s. The database version is %s, the post update version is %s.',
'<strong>' . App::VERSION . '</strong>', '<strong>' . App::VERSION . '</strong>',
$this->baseUrl, $this->baseUrl,
'<strong>' . $this->config->get('system', 'build') . '/' . DB_UPDATE_VERSION . '</strong>', '<strong>' . $this->config->get('system', 'build') . '/' . DB_UPDATE_VERSION . '</strong>',
'<strong>' . $this->keyValue->get('post_update_version') . '/' . PostUpdate::VERSION . '</strong>'), '<strong>' . $this->keyValue->get('post_update_version') . '/' . PostUpdate::VERSION . '</strong>'
),
'friendica' => $this->t('Please visit <a href="https://friendi.ca">Friendi.ca</a> to learn more about the Friendica project.'), 'friendica' => $this->t('Please visit <a href="https://friendi.ca">Friendi.ca</a> to learn more about the Friendica project.'),
'bugs' => $this->t('Bug reports and issues: please visit') . ' ' . '<a href="https://github.com/friendica/friendica/issues?state=open">' . $this->t('the bugtracker at github') . '</a>', 'bugs' => $this->t('Bug reports and issues: please visit') . ' ' . '<a href="https://github.com/friendica/friendica/issues?state=open">' . $this->t('the bugtracker at github') . '</a>',
'info' => $this->t('Suggestions, praise, etc. - please email "info" at "friendi - dot - ca'), 'info' => $this->t('Suggestions, praise, etc. - please email "info" at "friendi - dot - ca'),
@ -148,7 +152,7 @@ class Friendica extends BaseModule
$register_policy = $register_policies[$register_policy_int]; $register_policy = $register_policies[$register_policy_int];
} }
$admin = []; $admin = [];
$administrator = User::getFirstAdmin(['username', 'nickname']); $administrator = User::getFirstAdmin(['username', 'nickname']);
if (!empty($administrator)) { if (!empty($administrator)) {
$admin = [ $admin = [
@ -157,11 +161,11 @@ class Friendica extends BaseModule
]; ];
} }
$visible_addons = Addon::getVisibleList(); $visible_addons = $this->addonHelper->getVisibleEnabledAddons();
$this->config->reload(); $this->config->reload();
$locked_features = []; $locked_features = [];
$featureLocks = $this->config->get('config', 'feature_lock'); $featureLocks = $this->config->get('config', 'feature_lock');
if (isset($featureLocks)) { if (isset($featureLocks)) {
foreach ($featureLocks as $feature => $lock) { foreach ($featureLocks as $feature => $lock) {
if ($feature === 'config_loaded') { if ($feature === 'config_loaded') {

View file

@ -8,7 +8,6 @@
namespace Friendica\Protocol; namespace Friendica\Protocol;
use Friendica\App; use Friendica\App;
use Friendica\Core\Addon;
use Friendica\DI; use Friendica\DI;
use Friendica\Module; use Friendica\Module;
use Friendica\Module\Register; use Friendica\Module\Register;
@ -43,6 +42,11 @@ class ZOT
*/ */
public static function getSiteInfo(): array public static function getSiteInfo(): array
{ {
$baseUrl = (string) DI::baseUrl();
$keyValue = DI::keyValue();
$addonHelper = DI::addonHelper();
$config = DI::config();
$policies = [ $policies = [
Module\Register::OPEN => 'open', Module\Register::OPEN => 'open',
Module\Register::APPROVE => 'approve', Module\Register::APPROVE => 'approve',
@ -50,14 +54,14 @@ class ZOT
]; ];
return [ return [
'url' => (string)DI::baseUrl(), 'url' => $baseUrl,
'openWebAuth' => (string)DI::baseUrl() . '/owa', 'openWebAuth' => $baseUrl . '/owa',
'authRedirect' => (string)DI::baseUrl() . '/magic', 'authRedirect' => $baseUrl . '/magic',
'register_policy' => $policies[Register::getPolicy()], 'register_policy' => $policies[Register::getPolicy()],
'accounts' => DI::keyValue()->get('nodeinfo_total_users'), 'accounts' => $keyValue->get('nodeinfo_total_users'),
'plugins' => Addon::getVisibleList(), 'plugins' => $addonHelper->getVisibleEnabledAddons(),
'sitename' => DI::config()->get('config', 'sitename'), 'sitename' => $config->get('config', 'sitename'),
'about' => DI::config()->get('config', 'info'), 'about' => $config->get('config', 'info'),
'project' => App::PLATFORM, 'project' => App::PLATFORM,
'version' => App::VERSION, 'version' => App::VERSION,
]; ];

View file

@ -7,7 +7,6 @@
namespace Friendica\Worker; namespace Friendica\Worker;
use Friendica\Core\Addon;
use Friendica\Core\Hook; use Friendica\Core\Hook;
use Friendica\Core\Worker; use Friendica\Core\Worker;
use Friendica\Database\DBA; use Friendica\Database\DBA;
@ -145,7 +144,7 @@ class Cron
// Update "blocked" status of servers // Update "blocked" status of servers
Worker::add(Worker::PRIORITY_LOW, 'UpdateBlockedServers'); Worker::add(Worker::PRIORITY_LOW, 'UpdateBlockedServers');
Addon::reload(); DI::addonHelper()->reloadAddons();
DI::keyValue()->set('last_cron_daily', time()); DI::keyValue()->set('last_cron_daily', time());
} }

View file

@ -42,6 +42,12 @@ return (function(string $basepath, array $getVars, array $serverVars, array $coo
[Dice::INSTANCE => Dice::SELF], [Dice::INSTANCE => Dice::SELF],
], ],
], ],
\Friendica\Core\Addon\AddonHelper::class => [
'instanceOf' => \Friendica\Core\Addon\AddonProxy::class,
'constructParams' => [
$basepath . '/addon',
],
],
\Friendica\Util\BasePath::class => [ \Friendica\Util\BasePath::class => [
'constructParams' => [ 'constructParams' => [
$basepath, $basepath,
@ -81,6 +87,7 @@ return (function(string $basepath, array $getVars, array $serverVars, array $coo
'call' => [ 'call' => [
['createConfigFileManager', [ ['createConfigFileManager', [
$basepath, $basepath,
$basepath . '/addon',
$serverVars, $serverVars,
], Dice::CHAIN_CALL], ], Dice::CHAIN_CALL],
], ],

View file

@ -8,7 +8,7 @@
namespace Friendica\Test; namespace Friendica\Test;
use Friendica\Capabilities\ICanCreateResponses; use Friendica\Capabilities\ICanCreateResponses;
use Friendica\Core\Addon; use Friendica\Core\Addon\AddonHelper;
use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\Hook; use Friendica\Core\Hook;
use Friendica\DI; use Friendica\DI;
@ -124,7 +124,7 @@ abstract class ApiTestCase extends FixtureTestCase
file_put_contents( file_put_contents(
$tmpFile, $tmpFile,
base64_decode( base64_decode(
// Empty 1x1 px PNG image // Empty 1x1 px PNG image
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==' 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg=='
) )
); );
@ -201,7 +201,7 @@ abstract class ApiTestCase extends FixtureTestCase
'plugin_admin' => function_exists($addon . '_addon_admin'), 'plugin_admin' => function_exists($addon . '_addon_admin'),
]); ]);
Addon::loadAddons(); $this->dice->create(AddonHelper::class)->loadAddons();
Hook::loadHooks(); Hook::loadHooks();
} }
} }

View file

@ -44,7 +44,7 @@ trait FixtureTestTrait
->addRules(include __DIR__ . '/../static/dependencies.config.php') ->addRules(include __DIR__ . '/../static/dependencies.config.php')
->addRule(ConfigFileManager::class, [ ->addRule(ConfigFileManager::class, [
'instanceOf' => Config::class, 'instanceOf' => Config::class,
'call' => [['createConfigFileManager', [$this->root->url(), $server,], Dice::CHAIN_CALL]]]) 'call' => [['createConfigFileManager', [$this->root->url(), $this->root->url() . '/addon', $server,], Dice::CHAIN_CALL]]])
->addRule(Database::class, ['instanceOf' => StaticDatabase::class, 'shared' => true]) ->addRule(Database::class, ['instanceOf' => StaticDatabase::class, 'shared' => true])
->addRule(IHandleSessions::class, ['instanceOf' => Memory::class, 'shared' => true, 'call' => null]) ->addRule(IHandleSessions::class, ['instanceOf' => Memory::class, 'shared' => true, 'call' => null])
->addRule(Arguments::class, [ ->addRule(Arguments::class, [

View file

@ -0,0 +1,55 @@
<?php
// Copyright (C) 2010-2024, the Friendica project
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
//
// SPDX-License-Identifier: AGPL-3.0-or-later
declare(strict_types=1);
namespace Friendica\Test\Unit\Core\Addon;
use Friendica\Core\Addon\AddonInfo;
use PHPUnit\Framework\TestCase;
class AddonInfoTest extends TestCase
{
public function testFromArrayCreatesObject(): void
{
$data = [
'id' => '',
'name' => '',
'description' => '',
'authors' => [],
'maintainers' => [],
'version' => '',
'status' => '',
];
$this->assertInstanceOf(AddonInfo::class, AddonInfo::fromArray($data));
}
public function testGetterReturningCorrectValues(): void
{
$data = [
'id' => 'test',
'name' => 'Test-Addon',
'description' => 'This is an addon for tests',
'authors' => [['name' => 'Sam']],
'maintainers' => [['name' => 'Sam', 'link' => 'https://example.com']],
'version' => '0.1',
'status' => 'In Development',
];
$info = AddonInfo::fromArray($data);
$this->assertSame($data['id'], $info->getId());
$this->assertSame($data['name'], $info->getName());
$this->assertSame($data['description'], $info->getDescription());
$this->assertSame($data['description'], $info->getDescription());
$this->assertSame($data['authors'], $info->getAuthors());
$this->assertSame($data['maintainers'], $info->getMaintainers());
$this->assertSame($data['version'], $info->getVersion());
$this->assertSame($data['status'], $info->getStatus());
}
}

View file

@ -15,8 +15,6 @@ use Friendica\Database\Definition\DbaDefinition;
use Friendica\Database\Definition\ViewDefinition; use Friendica\Database\Definition\ViewDefinition;
use Friendica\Test\DatabaseTestTrait; use Friendica\Test\DatabaseTestTrait;
use Friendica\Test\Util\Database\StaticDatabase; use Friendica\Test\Util\Database\StaticDatabase;
use Friendica\Util\Profiler;
use Psr\Log\NullLogger;
trait CreateDatabaseTrait trait CreateDatabaseTrait
{ {
@ -32,8 +30,13 @@ trait CreateDatabaseTrait
return $this->dba; return $this->dba;
} }
$configFileManager = new ConfigFileManager($this->root->url(), $this->root->url() . '/config/', $this->root->url() . '/static/'); $configFileManager = new ConfigFileManager(
$config = new ReadOnlyFileConfig(new Cache([ $this->root->url(),
$this->root->url() . '/addon',
$this->root->url() . '/config',
$this->root->url() . '/static'
);
$config = new ReadOnlyFileConfig(new Cache([
'database' => [ 'database' => [
'disable_pdo' => true 'disable_pdo' => true
], ],

View file

@ -34,6 +34,7 @@ class ConfigFileManagerTest extends MockedTestCase
$configFileLoader = new ConfigFileManager( $configFileLoader = new ConfigFileManager(
$this->root->url(), $this->root->url(),
$this->root->url() . DIRECTORY_SEPARATOR . 'addon',
$this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR, $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR,
$this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR
); );
@ -61,10 +62,11 @@ class ConfigFileManagerTest extends MockedTestCase
$configFileLoader = new ConfigFileManager( $configFileLoader = new ConfigFileManager(
$this->root->url(), $this->root->url(),
$this->root->url() . DIRECTORY_SEPARATOR . 'addon',
$this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR, $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR,
$this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR
); );
$configCache = new Cache(); $configCache = new Cache();
$configFileLoader->setupCache($configCache); $configFileLoader->setupCache($configCache);
} }
@ -90,10 +92,11 @@ class ConfigFileManagerTest extends MockedTestCase
$configFileLoader = new ConfigFileManager( $configFileLoader = new ConfigFileManager(
$this->root->url(), $this->root->url(),
$this->root->url() . DIRECTORY_SEPARATOR . 'addon',
$this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR, $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR,
$this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR
); );
$configCache = new Cache(); $configCache = new Cache();
$configFileLoader->setupCache($configCache); $configFileLoader->setupCache($configCache);
@ -127,10 +130,11 @@ class ConfigFileManagerTest extends MockedTestCase
$configFileLoader = new ConfigFileManager( $configFileLoader = new ConfigFileManager(
$this->root->url(), $this->root->url(),
$this->root->url() . DIRECTORY_SEPARATOR . 'addon',
$this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR, $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR,
$this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR
); );
$configCache = new Cache(); $configCache = new Cache();
$configFileLoader->setupCache($configCache); $configFileLoader->setupCache($configCache);
@ -163,10 +167,11 @@ class ConfigFileManagerTest extends MockedTestCase
$configFileLoader = new ConfigFileManager( $configFileLoader = new ConfigFileManager(
$this->root->url(), $this->root->url(),
$this->root->url() . DIRECTORY_SEPARATOR . 'addon',
$this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR, $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR,
$this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR
); );
$configCache = new Cache(); $configCache = new Cache();
$configFileLoader->setupCache($configCache); $configFileLoader->setupCache($configCache);
@ -217,6 +222,7 @@ class ConfigFileManagerTest extends MockedTestCase
$configFileLoader = new ConfigFileManager( $configFileLoader = new ConfigFileManager(
$this->root->url(), $this->root->url(),
$this->root->url() . DIRECTORY_SEPARATOR . 'addon',
$this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR, $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR,
$this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR
); );
@ -254,10 +260,11 @@ class ConfigFileManagerTest extends MockedTestCase
$configFileLoader = new ConfigFileManager( $configFileLoader = new ConfigFileManager(
$this->root->url(), $this->root->url(),
$this->root->url() . DIRECTORY_SEPARATOR . 'addon',
$this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR, $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR,
$this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR
); );
$configCache = new Cache(); $configCache = new Cache();
$configFileLoader->setupCache($configCache); $configFileLoader->setupCache($configCache);
@ -288,10 +295,11 @@ class ConfigFileManagerTest extends MockedTestCase
$configFileLoader = new ConfigFileManager( $configFileLoader = new ConfigFileManager(
$this->root->url(), $this->root->url(),
$this->root->url() . DIRECTORY_SEPARATOR . 'addon',
$this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR, $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR,
$this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR
); );
$configCache = new Cache(); $configCache = new Cache();
$configFileLoader->setupCache($configCache); $configFileLoader->setupCache($configCache);
@ -322,6 +330,7 @@ class ConfigFileManagerTest extends MockedTestCase
$configFileLoader = new ConfigFileManager( $configFileLoader = new ConfigFileManager(
$this->root->url(), $this->root->url(),
$this->root->url() . DIRECTORY_SEPARATOR . 'addon',
$this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR, $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR,
$this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR
); );
@ -341,8 +350,12 @@ class ConfigFileManagerTest extends MockedTestCase
{ {
$this->delConfigFile('local.config.php'); $this->delConfigFile('local.config.php');
$configFileManager = (new Config())->createConfigFileManager($this->root->url(), ['FRIENDICA_CONFIG_DIR' => '/a/wrong/dir/']); $configFileManager = (new Config())->createConfigFileManager(
$configCache = new Cache(); $this->root->url(),
$this->root->url() . '/addon',
['FRIENDICA_CONFIG_DIR' => '/a/wrong/dir/'],
);
$configCache = new Cache();
$configFileManager->setupCache($configCache); $configFileManager->setupCache($configCache);
@ -367,11 +380,12 @@ class ConfigFileManagerTest extends MockedTestCase
->at($this->root->getChild('config2')) ->at($this->root->getChild('config2'))
->setContent(file_get_contents($fileDir . 'B.config.php')); ->setContent(file_get_contents($fileDir . 'B.config.php'));
$configFileManager = (new Config())->createConfigFileManager($this->root->url(), $configFileManager = (new Config())->createConfigFileManager(
[ $this->root->url(),
'FRIENDICA_CONFIG_DIR' => $this->root->getChild('config2')->url(), $this->root->url() . '/addon',
]); ['FRIENDICA_CONFIG_DIR' => $this->root->getChild('config2')->url()],
$configCache = new Cache(); );
$configCache = new Cache();
$configFileManager->setupCache($configCache); $configFileManager->setupCache($configCache);
@ -389,11 +403,12 @@ class ConfigFileManagerTest extends MockedTestCase
->at($this->root->getChild('config')) ->at($this->root->getChild('config'))
->setContent(''); ->setContent('');
$configFileManager = (new Config())->createConfigFileManager($this->root->url()); $configFileManager = (new Config())->createConfigFileManager(
$configCache = new Cache(); $this->root->url(),
$this->root->url() . '/addon',
);
$configCache = new Cache();
$configFileManager->setupCache($configCache); $configFileManager->setupCache($configCache);
self::assertEquals(1,1);
} }
} }

View file

@ -16,7 +16,6 @@ use Friendica\Core\Config\ValueObject\Cache;
use Friendica\Test\DatabaseTestCase; use Friendica\Test\DatabaseTestCase;
use Friendica\Test\Util\CreateDatabaseTrait; use Friendica\Test\Util\CreateDatabaseTrait;
use Friendica\Test\Util\VFSTrait; use Friendica\Test\Util\VFSTrait;
use org\bovigo\vfs\vfsStream;
class ConfigTest extends DatabaseTestCase class ConfigTest extends DatabaseTestCase
{ {
@ -55,8 +54,13 @@ class ConfigTest extends DatabaseTestCase
parent::setUp(); parent::setUp();
$this->configCache = new Cache(); $this->configCache = new Cache();
$this->configFileManager = new ConfigFileManager($this->root->url(), $this->root->url() . '/config/', $this->root->url() . '/static/'); $this->configFileManager = new ConfigFileManager(
$this->root->url(),
$this->root->url() . '/addon',
$this->root->url() . '/config',
$this->root->url() . '/static'
);
} }
/** /**
@ -94,7 +98,7 @@ class ConfigTest extends DatabaseTestCase
'key1' => 'value1a', 'key1' => 'value1a',
'key4' => 'value4', 'key4' => 'value4',
], ],
'other' => [ 'other' => [
'key5' => 'value5', 'key5' => 'value5',
'key6' => 'value6', 'key6' => 'value6',
], ],
@ -108,18 +112,18 @@ class ConfigTest extends DatabaseTestCase
'config', 'config',
'other' 'other'
], ],
'load' => [ 'load' => [
'system', 'system',
], ],
], ],
'other' => [ 'other' => [
'data' => $data, 'data' => $data,
'possibleCats' => [ 'possibleCats' => [
'system', 'system',
'config', 'config',
'other' 'other'
], ],
'load' => [ 'load' => [
'other', 'other',
], ],
], ],
@ -130,18 +134,18 @@ class ConfigTest extends DatabaseTestCase
'config', 'config',
'other' 'other'
], ],
'load' => [ 'load' => [
'config', 'config',
], ],
], ],
'all' => [ 'all' => [
'data' => $data, 'data' => $data,
'possibleCats' => [ 'possibleCats' => [
'system', 'system',
'config', 'config',
'other' 'other'
], ],
'load' => [ 'load' => [
'system', 'system',
'config', 'config',
'other' 'other'
@ -173,7 +177,7 @@ class ConfigTest extends DatabaseTestCase
*/ */
public function testSetUp(array $data) public function testSetUp(array $data)
{ {
$this->loadDirectFixture($this->configToDbArray($data) , $this->getDbInstance()); $this->loadDirectFixture($this->configToDbArray($data), $this->getDbInstance());
$this->testedConfig = $this->getInstance(); $this->testedConfig = $this->getInstance();
self::assertInstanceOf(Cache::class, $this->testedConfig->getCache()); self::assertInstanceOf(Cache::class, $this->testedConfig->getCache());
@ -209,13 +213,13 @@ class ConfigTest extends DatabaseTestCase
{ {
return [ return [
'config' => [ 'config' => [
'data1' => [ 'data1' => [
'config' => [ 'config' => [
'key1' => 'value1', 'key1' => 'value1',
'key2' => 'value2', 'key2' => 'value2',
], ],
], ],
'data2' => [ 'data2' => [
'config' => [ 'config' => [
'key1' => 'overwritten!', 'key1' => 'overwritten!',
'key3' => 'value3', 'key3' => 'value3',
@ -230,19 +234,19 @@ class ConfigTest extends DatabaseTestCase
], ],
], ],
], ],
'other' => [ 'other' => [
'data1' => [ 'data1' => [
'config' => [ 'config' => [
'key12' => 'data4', 'key12' => 'data4',
'key45' => 7, 'key45' => 7,
], ],
'other' => [ 'other' => [
'key1' => 'value1', 'key1' => 'value1',
'key2' => 'value2', 'key2' => 'value2',
], ],
], ],
'data2' => [ 'data2' => [
'other' => [ 'other' => [
'key1' => 'overwritten!', 'key1' => 'overwritten!',
'key3' => 'value3', 'key3' => 'value3',
], ],
@ -252,7 +256,7 @@ class ConfigTest extends DatabaseTestCase
] ]
], ],
'expect' => [ 'expect' => [
'other' => [ 'other' => [
// load should overwrite values everytime! // load should overwrite values everytime!
'key1' => 'overwritten!', 'key1' => 'overwritten!',
'key2' => 'value2', 'key2' => 'value2',
@ -399,26 +403,26 @@ class ConfigTest extends DatabaseTestCase
public function dataTestCat() public function dataTestCat()
{ {
return [ return [
'test_with_hashmap' => [ 'test_with_hashmap' => [
'data' => [ 'data' => [
'test_with_hashmap' => [ 'test_with_hashmap' => [
'notifyall' => [ 'notifyall' => [
'last_update' => 1671051565, 'last_update' => 1671051565,
'admin' => true, 'admin' => true,
], ],
'blockbot' => [ 'blockbot' => [
'last_update' => 1658952852, 'last_update' => 1658952852,
'admin' => true, 'admin' => true,
], ],
], ],
'config' => [ 'config' => [
'register_policy' => 2, 'register_policy' => 2,
'register_text' => '', 'register_text' => '',
'sitename' => 'Friendica Social Network23', 'sitename' => 'Friendica Social Network23',
'hostname' => 'friendica.local', 'hostname' => 'friendica.local',
'private_addons' => false, 'private_addons' => false,
], ],
'system' => [ 'system' => [
'dbclean_expire_conversation' => 90, 'dbclean_expire_conversation' => 90,
], ],
], ],
@ -428,14 +432,14 @@ class ConfigTest extends DatabaseTestCase
'last_update' => 1671051565, 'last_update' => 1671051565,
'admin' => true, 'admin' => true,
], ],
'blockbot' => [ 'blockbot' => [
'last_update' => 1658952852, 'last_update' => 1658952852,
'admin' => true, 'admin' => true,
], ],
], ],
], ],
'test_with_keys' => [ 'test_with_keys' => [
'data' => [ 'data' => [
'test_with_keys' => [ 'test_with_keys' => [
[ [
'last_update' => 1671051565, 'last_update' => 1671051565,
@ -446,14 +450,14 @@ class ConfigTest extends DatabaseTestCase
'admin' => true, 'admin' => true,
], ],
], ],
'config' => [ 'config' => [
'register_policy' => 2, 'register_policy' => 2,
'register_text' => '', 'register_text' => '',
'sitename' => 'Friendica Social Network23', 'sitename' => 'Friendica Social Network23',
'hostname' => 'friendica.local', 'hostname' => 'friendica.local',
'private_addons' => false, 'private_addons' => false,
], ],
'system' => [ 'system' => [
'dbclean_expire_conversation' => 90, 'dbclean_expire_conversation' => 90,
], ],
], ],
@ -470,7 +474,7 @@ class ConfigTest extends DatabaseTestCase
], ],
], ],
'test_with_inner_array' => [ 'test_with_inner_array' => [
'data' => [ 'data' => [
'test_with_inner_array' => [ 'test_with_inner_array' => [
'notifyall' => [ 'notifyall' => [
'last_update' => 1671051565, 'last_update' => 1671051565,
@ -479,19 +483,19 @@ class ConfigTest extends DatabaseTestCase
'no' => 1.5, 'no' => 1.5,
], ],
], ],
'blogbot' => [ 'blogbot' => [
'last_update' => 1658952852, 'last_update' => 1658952852,
'admin' => true, 'admin' => true,
], ],
], ],
'config' => [ 'config' => [
'register_policy' => 2, 'register_policy' => 2,
'register_text' => '', 'register_text' => '',
'sitename' => 'Friendica Social Network23', 'sitename' => 'Friendica Social Network23',
'hostname' => 'friendica.local', 'hostname' => 'friendica.local',
'private_addons' => false, 'private_addons' => false,
], ],
'system' => [ 'system' => [
'dbclean_expire_conversation' => 90, 'dbclean_expire_conversation' => 90,
], ],
], ],
@ -504,7 +508,7 @@ class ConfigTest extends DatabaseTestCase
'no' => 1.5, 'no' => 1.5,
], ],
], ],
'blogbot' => [ 'blogbot' => [
'last_update' => 1658952852, 'last_update' => 1658952852,
'admin' => true, 'admin' => true,
], ],
@ -519,7 +523,7 @@ class ConfigTest extends DatabaseTestCase
public function testGetCategory(array $data, string $category, array $assertion) public function testGetCategory(array $data, string $category, array $assertion)
{ {
$this->configCache = new Cache($data); $this->configCache = new Cache($data);
$config = new ReadOnlyFileConfig($this->configCache); $config = new ReadOnlyFileConfig($this->configCache);
self::assertEquals($assertion, $config->get($category)); self::assertEquals($assertion, $config->get($category));
} }
@ -528,15 +532,15 @@ class ConfigTest extends DatabaseTestCase
{ {
return [ return [
'default' => [ 'default' => [
'value' => ['test' => ['array']], 'value' => ['test' => ['array']],
'assertion' => ['test' => ['array']], 'assertion' => ['test' => ['array']],
], ],
'issue-12803' => [ 'issue-12803' => [
'value' => 's:48:"s:40:"s:32:"https://punkrock-underground.com";";";', 'value' => 's:48:"s:40:"s:32:"https://punkrock-underground.com";";";',
'assertion' => 'https://punkrock-underground.com', 'assertion' => 'https://punkrock-underground.com',
], ],
'double-serialized-array' => [ 'double-serialized-array' => [
'value' => 's:53:"a:1:{s:9:"testArray";a:1:{s:4:"with";s:7:"entries";}}";', 'value' => 's:53:"a:1:{s:9:"testArray";a:1:{s:4:"with";s:7:"entries";}}";',
'assertion' => ['testArray' => ['with' => 'entries']], 'assertion' => ['testArray' => ['with' => 'entries']],
], ],
]; ];
@ -558,33 +562,33 @@ class ConfigTest extends DatabaseTestCase
$data = [ $data = [
'config' => [ 'config' => [
'admin_email' => 'value1', 'admin_email' => 'value1',
'timezone' => 'value2', 'timezone' => 'value2',
'language' => 'value3', 'language' => 'value3',
'sitename' => 'value', 'sitename' => 'value',
], ],
'system' => [ 'system' => [
'url' => 'value1a', 'url' => 'value1a',
'debugging' => true, 'debugging' => true,
'logfile' => 'value4', 'logfile' => 'value4',
'loglevel' => 'notice', 'loglevel' => 'notice',
'proflier' => true, 'proflier' => true,
], ],
'proxy' => [ 'proxy' => [
'trusted_proxies' => 'value5', 'trusted_proxies' => 'value5',
], ],
]; ];
return [ return [
'empty' => [ 'empty' => [
'data' => $data, 'data' => $data,
'server' => [], 'server' => [],
'assertDisabled' => [], 'assertDisabled' => [],
], ],
'mixed' => [ 'mixed' => [
'data' => $data, 'data' => $data,
'server' => [ 'server' => [
'FRIENDICA_ADMIN_MAIL' => 'test@friendica.local', 'FRIENDICA_ADMIN_MAIL' => 'test@friendica.local',
'FRIENDICA_DEBUGGING' => true, 'FRIENDICA_DEBUGGING' => true,
], ],
'assertDisabled' => [ 'assertDisabled' => [
'config' => [ 'config' => [
@ -608,7 +612,13 @@ class ConfigTest extends DatabaseTestCase
$this->setConfigFile('static' . DIRECTORY_SEPARATOR . 'env.config.php', true); $this->setConfigFile('static' . DIRECTORY_SEPARATOR . 'env.config.php', true);
$this->loadDirectFixture($this->configToDbArray($data), $this->getDbInstance()); $this->loadDirectFixture($this->configToDbArray($data), $this->getDbInstance());
$configFileManager = new ConfigFileManager($this->root->url(), $this->root->url() . '/config/', $this->root->url() . '/static/', $server); $configFileManager = new ConfigFileManager(
$this->root->url(),
$this->root->url() . '/addon',
$this->root->url() . '/config',
$this->root->url() . '/static',
$server
);
$configFileManager->setupCache($this->configCache); $configFileManager->setupCache($this->configCache);
$config = new DatabaseConfig($this->getDbInstance(), $this->configCache); $config = new DatabaseConfig($this->getDbInstance(), $this->configCache);

View file

@ -9,16 +9,11 @@ namespace Friendica\Test\src\Core\Config;
use Friendica\Core\Config\Capability\ISetConfigValuesTransactionally; use Friendica\Core\Config\Capability\ISetConfigValuesTransactionally;
use Friendica\Core\Config\Model\DatabaseConfig; use Friendica\Core\Config\Model\DatabaseConfig;
use Friendica\Core\Config\Model\ReadOnlyFileConfig;
use Friendica\Core\Config\Model\ConfigTransaction; use Friendica\Core\Config\Model\ConfigTransaction;
use Friendica\Core\Config\Util\ConfigFileManager; use Friendica\Core\Config\Util\ConfigFileManager;
use Friendica\Core\Config\ValueObject\Cache; use Friendica\Core\Config\ValueObject\Cache;
use Friendica\Database\Database; use Friendica\Database\Database;
use Friendica\Test\DatabaseTestCase;
use Friendica\Test\FixtureTestCase; use Friendica\Test\FixtureTestCase;
use Friendica\Test\MockedTest;
use Friendica\Test\Util\Database\StaticDatabase;
use Friendica\Test\Util\VFSTrait;
use Mockery\Exception\InvalidCountException; use Mockery\Exception\InvalidCountException;
class ConfigTransactionTest extends FixtureTestCase class ConfigTransactionTest extends FixtureTestCase
@ -30,7 +25,12 @@ class ConfigTransactionTest extends FixtureTestCase
{ {
parent::setUp(); parent::setUp();
$this->configFileManager = new ConfigFileManager($this->root->url(), $this->root->url() . '/config/', $this->root->url() . '/static/'); $this->configFileManager = new ConfigFileManager(
$this->root->url(),
$this->root->url() . '/addon',
$this->root->url() . '/config',
$this->root->url() . '/static'
);
} }
public function dataTests(): array public function dataTests(): array
@ -96,7 +96,7 @@ class ConfigTransactionTest extends FixtureTestCase
{ {
$this->configFileManager = \Mockery::spy(ConfigFileManager::class); $this->configFileManager = \Mockery::spy(ConfigFileManager::class);
$config = new DatabaseConfig($this->dice->create(Database::class), new Cache()); $config = new DatabaseConfig($this->dice->create(Database::class), new Cache());
$configTransaction = new ConfigTransaction($config); $configTransaction = new ConfigTransaction($config);
// commit empty transaction // commit empty transaction

View file

@ -21,16 +21,12 @@ use Friendica\Core\Storage\Repository\StorageManager;
use Friendica\Core\Storage\Type\Filesystem; use Friendica\Core\Storage\Type\Filesystem;
use Friendica\Core\Storage\Type\SystemResource; use Friendica\Core\Storage\Type\SystemResource;
use Friendica\Database\Database; use Friendica\Database\Database;
use Friendica\Database\Definition\DbaDefinition;
use Friendica\Database\Definition\ViewDefinition;
use Friendica\DI; use Friendica\DI;
use Friendica\Core\Config\Factory\Config; use Friendica\Core\Config\Factory\Config;
use Friendica\Core\Storage\Type; use Friendica\Core\Storage\Type;
use Friendica\Test\DatabaseTestCase; use Friendica\Test\DatabaseTestCase;
use Friendica\Test\Util\CreateDatabaseTrait; use Friendica\Test\Util\CreateDatabaseTrait;
use Friendica\Test\Util\Database\StaticDatabase; use Friendica\Test\Util\Database\StaticDatabase;
use Friendica\Test\Util\VFSTrait;
use Friendica\Util\Profiler;
use org\bovigo\vfs\vfsStream; use org\bovigo\vfs\vfsStream;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger; use Psr\Log\NullLogger;
@ -60,12 +56,15 @@ class StorageManagerTest extends DatabaseTestCase
vfsStream::newDirectory(Type\FilesystemConfig::DEFAULT_BASE_FOLDER, 0777)->at($this->root); vfsStream::newDirectory(Type\FilesystemConfig::DEFAULT_BASE_FOLDER, 0777)->at($this->root);
$this->logger = new NullLogger(); $this->logger = new NullLogger();
$this->database = $this->getDbInstance(); $this->database = $this->getDbInstance();
$configFactory = new Config(); $configFactory = new Config();
$configFileManager = $configFactory->createConfigFileManager($this->root->url()); $configFileManager = $configFactory->createConfigFileManager(
$configCache = $configFactory->createCache($configFileManager); $this->root->url(),
$this->root->url() . '/addon',
);
$configCache = $configFactory->createCache($configFileManager);
$this->config = new \Friendica\Core\Config\Model\DatabaseConfig($this->database, $configCache); $this->config = new \Friendica\Core\Config\Model\DatabaseConfig($this->database, $configCache);
$this->config->set('storage', 'name', 'Database'); $this->config->set('storage', 'name', 'Database');
@ -96,21 +95,21 @@ class StorageManagerTest extends DatabaseTestCase
public function dataStorages() public function dataStorages()
{ {
return [ return [
'empty' => [ 'empty' => [
'name' => '', 'name' => '',
'valid' => false, 'valid' => false,
'interface' => ICanReadFromStorage::class, 'interface' => ICanReadFromStorage::class,
'assert' => null, 'assert' => null,
'assertName' => '', 'assertName' => '',
], ],
'database' => [ 'database' => [
'name' => Type\Database::NAME, 'name' => Type\Database::NAME,
'valid' => true, 'valid' => true,
'interface' => ICanWriteToStorage::class, 'interface' => ICanWriteToStorage::class,
'assert' => Type\Database::class, 'assert' => Type\Database::class,
'assertName' => Type\Database::NAME, 'assertName' => Type\Database::NAME,
], ],
'filesystem' => [ 'filesystem' => [
'name' => Filesystem::NAME, 'name' => Filesystem::NAME,
'valid' => true, 'valid' => true,
'interface' => ICanWriteToStorage::class, 'interface' => ICanWriteToStorage::class,
@ -124,7 +123,7 @@ class StorageManagerTest extends DatabaseTestCase
'assert' => SystemResource::class, 'assert' => SystemResource::class,
'assertName' => SystemResource::NAME, 'assertName' => SystemResource::NAME,
], ],
'invalid' => [ 'invalid' => [
'name' => 'invalid', 'name' => 'invalid',
'valid' => false, 'valid' => false,
'interface' => null, 'interface' => null,

View file

@ -32,7 +32,12 @@ class DatabaseTest extends FixtureTestCase
parent::setUp(); parent::setUp();
$this->configCache = new Cache(); $this->configCache = new Cache();
$this->configFileManager = new ConfigFileManager($this->root->url(), $this->root->url() . '/config/', $this->root->url() . '/static/'); $this->configFileManager = new ConfigFileManager(
$this->root->url(),
$this->root->url() . '/addon',
$this->root->url() . '/config',
$this->root->url() . '/static'
);
} }
/** /**
@ -87,7 +92,7 @@ class DatabaseTest extends FixtureTestCase
self::assertTrue($db->update('gserver', ['active-week-users' => 0, 'registered-users' => 0], ['nurl' => 'http://friendica.local'])); self::assertTrue($db->update('gserver', ['active-week-users' => 0, 'registered-users' => 0], ['nurl' => 'http://friendica.local']));
$fields = ["`registered-users` = `registered-users` + 1"]; $fields = ["`registered-users` = `registered-users` + 1"];
$fields[] = "`active-week-users` = `active-week-users` + 2"; $fields[] = "`active-week-users` = `active-week-users` + 2";
self::assertTrue($db->update('gserver', $fields, ['nurl' => 'http://friendica.local'])); self::assertTrue($db->update('gserver', $fields, ['nurl' => 'http://friendica.local']));