Merge pull request #12772 from nupplaphil/feat/config_hybrid
Revert node.config.php into Config table
This commit is contained in:
		
				commit
				
					
						b168ff3e17
					
				
			
		
					 41 changed files with 678 additions and 984 deletions
				
			
		
							
								
								
									
										14
									
								
								database.sql
									
										
									
									
									
								
							
							
						
						
									
										14
									
								
								database.sql
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
-- ------------------------------------------
 | 
			
		||||
-- Friendica 2023.03-dev (Giant Rhubarb)
 | 
			
		||||
-- DB_UPDATE_VERSION 1513
 | 
			
		||||
-- DB_UPDATE_VERSION 1514
 | 
			
		||||
-- ------------------------------------------
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -495,6 +495,18 @@ CREATE TABLE IF NOT EXISTS `cache` (
 | 
			
		|||
	 INDEX `k_expires` (`k`,`expires`)
 | 
			
		||||
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Stores temporary data';
 | 
			
		||||
 | 
			
		||||
--
 | 
			
		||||
-- TABLE config
 | 
			
		||||
--
 | 
			
		||||
CREATE TABLE IF NOT EXISTS `config` (
 | 
			
		||||
	`id` int unsigned NOT NULL auto_increment COMMENT '',
 | 
			
		||||
	`cat` varbinary(50) NOT NULL DEFAULT '' COMMENT 'The category of the entry',
 | 
			
		||||
	`k` varbinary(50) NOT NULL DEFAULT '' COMMENT 'The key of the entry',
 | 
			
		||||
	`v` mediumtext COMMENT '',
 | 
			
		||||
	 PRIMARY KEY(`id`),
 | 
			
		||||
	 UNIQUE INDEX `cat_k` (`cat`,`k`)
 | 
			
		||||
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='main configuration storage';
 | 
			
		||||
 | 
			
		||||
--
 | 
			
		||||
-- TABLE contact-relation
 | 
			
		||||
--
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,6 +18,7 @@ Database Tables
 | 
			
		|||
| [arrived-activity](help/database/db_arrived-activity) | Id of arrived activities |
 | 
			
		||||
| [attach](help/database/db_attach) | file attachments |
 | 
			
		||||
| [cache](help/database/db_cache) | Stores temporary data |
 | 
			
		||||
| [config](help/database/db_config) | main configuration storage |
 | 
			
		||||
| [contact](help/database/db_contact) | contact table |
 | 
			
		||||
| [contact-relation](help/database/db_contact-relation) | Contact relations |
 | 
			
		||||
| [conv](help/database/db_conv) | private messages |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										53
									
								
								mods/local.config.ci.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								mods/local.config.ci.php
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,53 @@
 | 
			
		|||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * @copyright Copyright (C) 2010-2023, the Friendica project
 | 
			
		||||
 *
 | 
			
		||||
 * @license GNU AGPL version 3 or any later version
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as
 | 
			
		||||
 * published by the Free Software Foundation, either version 3 of the
 | 
			
		||||
 * License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
return [
 | 
			
		||||
	'database' => [
 | 
			
		||||
		'hostname' => 'localhost',
 | 
			
		||||
		'username' => 'friendica',
 | 
			
		||||
		'password' => 'friendica',
 | 
			
		||||
		'database' => 'friendica',
 | 
			
		||||
		'charset' => 'utf8mb4',
 | 
			
		||||
	],
 | 
			
		||||
 | 
			
		||||
	// ****************************************************************
 | 
			
		||||
	// The configuration below will be overruled by the admin panel.
 | 
			
		||||
	// Changes made below will only have an effect if the database does
 | 
			
		||||
	// not contain any configuration for the friendica system.
 | 
			
		||||
	// ****************************************************************
 | 
			
		||||
 | 
			
		||||
	'config' => [
 | 
			
		||||
		'hostname' => 'friendica.local',
 | 
			
		||||
		'admin_email' => 'admin@friendica.local',
 | 
			
		||||
		'sitename' => 'Friendica Social Network',
 | 
			
		||||
		'register_policy' => \Friendica\Module\Register::OPEN,
 | 
			
		||||
		'register_text' => '',
 | 
			
		||||
	],
 | 
			
		||||
	'system' => [
 | 
			
		||||
		'default_timezone' => 'UTC',
 | 
			
		||||
		'language' => 'en',
 | 
			
		||||
		'ssl_policy' => \Friendica\App\BaseURL::SSL_POLICY_SELFSIGN,
 | 
			
		||||
		'url' => 'https://friendica.local',
 | 
			
		||||
		'urlpath' => '',
 | 
			
		||||
		// don't start unexpected worker.php processes during test!
 | 
			
		||||
		'worker_dont_fork' => true,
 | 
			
		||||
	],
 | 
			
		||||
];
 | 
			
		||||
| 
						 | 
				
			
			@ -31,7 +31,7 @@ use Friendica\Core\Config\ValueObject\Cache;
 | 
			
		|||
interface IManageConfigValues
 | 
			
		||||
{
 | 
			
		||||
	/**
 | 
			
		||||
	 * Reloads all configuration values (from filesystem and environment variables)
 | 
			
		||||
	 * Reloads all configuration values from the persistence layer
 | 
			
		||||
	 *
 | 
			
		||||
	 * All configuration values of the system are stored in the cache.
 | 
			
		||||
	 *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,139 +0,0 @@
 | 
			
		|||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * @copyright Copyright (C) 2010-2023, the Friendica project
 | 
			
		||||
 *
 | 
			
		||||
 * @license GNU AGPL version 3 or any later version
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as
 | 
			
		||||
 * published by the Free Software Foundation, either version 3 of the
 | 
			
		||||
 * License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace Friendica\Core\Config\Model;
 | 
			
		||||
 | 
			
		||||
use Friendica\Core\Config\Capability\IManageConfigValues;
 | 
			
		||||
use Friendica\Core\Config\Capability\ISetConfigValuesTransactionally;
 | 
			
		||||
use Friendica\Core\Config\Exception\ConfigFileException;
 | 
			
		||||
use Friendica\Core\Config\Exception\ConfigPersistenceException;
 | 
			
		||||
use Friendica\Core\Config\Util\ConfigFileManager;
 | 
			
		||||
use Friendica\Core\Config\ValueObject\Cache;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Configuration model, which manages the whole system configuration
 | 
			
		||||
 */
 | 
			
		||||
class Config implements IManageConfigValues
 | 
			
		||||
{
 | 
			
		||||
	/** @var Cache */
 | 
			
		||||
	protected $configCache;
 | 
			
		||||
 | 
			
		||||
	/** @var ConfigFileManager */
 | 
			
		||||
	protected $configFileManager;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param ConfigFileManager $configFileManager The configuration file manager to save back configs
 | 
			
		||||
	 * @param Cache             $configCache       The configuration cache (based on the config-files)
 | 
			
		||||
	 */
 | 
			
		||||
	public function __construct(ConfigFileManager $configFileManager, Cache $configCache)
 | 
			
		||||
	{
 | 
			
		||||
		$this->configFileManager = $configFileManager;
 | 
			
		||||
		$this->configCache       = $configCache;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Load all configuration values from a given cache and saves it back in the configuration node store
 | 
			
		||||
	 * @see	ConfigFileManager::CONFIG_DATA_FILE
 | 
			
		||||
	 *
 | 
			
		||||
	 * All configuration values of the system are stored in the cache.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param Cache $cache a new cache
 | 
			
		||||
	 *
 | 
			
		||||
	 * @return void
 | 
			
		||||
	 *
 | 
			
		||||
	 * @throws ConfigPersistenceException In case the persistence layer throws errors
 | 
			
		||||
	 */
 | 
			
		||||
	public function setCacheAndSave(Cache $cache)
 | 
			
		||||
	{
 | 
			
		||||
		$this->configCache = $cache;
 | 
			
		||||
		$this->save();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * {@inheritDoc}
 | 
			
		||||
	 */
 | 
			
		||||
	public function getCache(): Cache
 | 
			
		||||
	{
 | 
			
		||||
		return $this->configCache;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**	{@inheritDoc} */
 | 
			
		||||
	public function beginTransaction(): ISetConfigValuesTransactionally
 | 
			
		||||
	{
 | 
			
		||||
		return new ConfigTransaction($this);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Saves the current Configuration back into the data config.
 | 
			
		||||
	 * @see ConfigFileManager::CONFIG_DATA_FILE
 | 
			
		||||
	 */
 | 
			
		||||
	protected function save()
 | 
			
		||||
	{
 | 
			
		||||
		try {
 | 
			
		||||
			$this->configFileManager->saveData($this->configCache);
 | 
			
		||||
			// reload after the save to possible reload default values of lower source-priorities again
 | 
			
		||||
			$this->reload();
 | 
			
		||||
		} catch (ConfigFileException $e) {
 | 
			
		||||
			throw new ConfigPersistenceException('Cannot save config', $e);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** {@inheritDoc} */
 | 
			
		||||
	public function reload()
 | 
			
		||||
	{
 | 
			
		||||
		$configCache = new Cache();
 | 
			
		||||
 | 
			
		||||
		try {
 | 
			
		||||
			$this->configFileManager->setupCache($configCache);
 | 
			
		||||
		} catch (ConfigFileException $e) {
 | 
			
		||||
			throw new ConfigPersistenceException('Cannot reload config', $e);
 | 
			
		||||
		}
 | 
			
		||||
		$this->configCache = $configCache;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** {@inheritDoc} */
 | 
			
		||||
	public function get(string $cat, string $key = null, $default_value = null)
 | 
			
		||||
	{
 | 
			
		||||
		return $this->configCache->get($cat, $key) ?? $default_value;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** {@inheritDoc} */
 | 
			
		||||
	public function set(string $cat, string $key, $value): bool
 | 
			
		||||
	{
 | 
			
		||||
		if ($this->configCache->set($cat, $key, $value, Cache::SOURCE_DATA)) {
 | 
			
		||||
			$this->save();
 | 
			
		||||
			return true;
 | 
			
		||||
		} else {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** {@inheritDoc} */
 | 
			
		||||
	public function delete(string $cat, string $key): bool
 | 
			
		||||
	{
 | 
			
		||||
		if ($this->configCache->delete($cat, $key)) {
 | 
			
		||||
			$this->save();
 | 
			
		||||
			return true;
 | 
			
		||||
		} else {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -34,20 +34,23 @@ class ConfigTransaction implements ISetConfigValuesTransactionally
 | 
			
		|||
	/** @var IManageConfigValues */
 | 
			
		||||
	protected $config;
 | 
			
		||||
	/** @var Cache */
 | 
			
		||||
	protected $cache;
 | 
			
		||||
	protected $setCache;
 | 
			
		||||
	/** @var Cache */
 | 
			
		||||
	protected $delCache;
 | 
			
		||||
	/** @var bool field to check if something is to save */
 | 
			
		||||
	protected $changedConfig = false;
 | 
			
		||||
 | 
			
		||||
	public function __construct(IManageConfigValues $config)
 | 
			
		||||
	public function __construct(DatabaseConfig $config)
 | 
			
		||||
	{
 | 
			
		||||
		$this->config = $config;
 | 
			
		||||
		$this->cache  = clone $config->getCache();
 | 
			
		||||
		$this->config   = $config;
 | 
			
		||||
		$this->setCache = new Cache();
 | 
			
		||||
		$this->delCache = new Cache();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** {@inheritDoc} */
 | 
			
		||||
	public function set(string $cat, string $key, $value): ISetConfigValuesTransactionally
 | 
			
		||||
	{
 | 
			
		||||
		$this->cache->set($cat, $key, $value, Cache::SOURCE_DATA);
 | 
			
		||||
		$this->setCache->set($cat, $key, $value, Cache::SOURCE_DATA);
 | 
			
		||||
		$this->changedConfig = true;
 | 
			
		||||
 | 
			
		||||
		return $this;
 | 
			
		||||
| 
						 | 
				
			
			@ -57,7 +60,7 @@ class ConfigTransaction implements ISetConfigValuesTransactionally
 | 
			
		|||
	/** {@inheritDoc} */
 | 
			
		||||
	public function delete(string $cat, string $key): ISetConfigValuesTransactionally
 | 
			
		||||
	{
 | 
			
		||||
		$this->cache->delete($cat, $key);
 | 
			
		||||
		$this->delCache->set($cat, $key, true, Cache::SOURCE_DATA);
 | 
			
		||||
		$this->changedConfig = true;
 | 
			
		||||
 | 
			
		||||
		return $this;
 | 
			
		||||
| 
						 | 
				
			
			@ -72,8 +75,9 @@ class ConfigTransaction implements ISetConfigValuesTransactionally
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		try {
 | 
			
		||||
			$this->config->setCacheAndSave($this->cache);
 | 
			
		||||
			$this->cache = clone $this->config->getCache();
 | 
			
		||||
			$this->config->setAndSave($this->setCache, $this->delCache);
 | 
			
		||||
			$this->setCache = new Cache();
 | 
			
		||||
			$this->delCache = new Cache();
 | 
			
		||||
		} catch (\Exception $e) {
 | 
			
		||||
			throw new ConfigPersistenceException('Cannot save config', $e);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										110
									
								
								src/Core/Config/Model/DatabaseConfig.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								src/Core/Config/Model/DatabaseConfig.php
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,110 @@
 | 
			
		|||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * @copyright Copyright (C) 2010-2023, the Friendica project
 | 
			
		||||
 *
 | 
			
		||||
 * @license GNU AGPL version 3 or any later version
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as
 | 
			
		||||
 * published by the Free Software Foundation, either version 3 of the
 | 
			
		||||
 * License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace Friendica\Core\Config\Model;
 | 
			
		||||
 | 
			
		||||
use Friendica\Core\Config\Capability\IManageConfigValues;
 | 
			
		||||
use Friendica\Core\Config\Capability\ISetConfigValuesTransactionally;
 | 
			
		||||
use Friendica\Core\Config\Util\SerializeUtil;
 | 
			
		||||
use Friendica\Core\Config\ValueObject\Cache;
 | 
			
		||||
use Friendica\Database\Database;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Complete system configuration model, bound with the database
 | 
			
		||||
 */
 | 
			
		||||
class DatabaseConfig implements IManageConfigValues
 | 
			
		||||
{
 | 
			
		||||
	/** @var Database */
 | 
			
		||||
	protected $database;
 | 
			
		||||
	/** @var Cache */
 | 
			
		||||
	protected $cache;
 | 
			
		||||
 | 
			
		||||
	public function __construct(Database $database, Cache $cache)
 | 
			
		||||
	{
 | 
			
		||||
		$this->database = $database;
 | 
			
		||||
		$this->cache    = $cache;
 | 
			
		||||
 | 
			
		||||
		$this->reload();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** {@inheritDoc} */
 | 
			
		||||
	public function reload()
 | 
			
		||||
	{
 | 
			
		||||
		$config = $this->database->selectToArray('config');
 | 
			
		||||
 | 
			
		||||
		foreach ($config as $entry) {
 | 
			
		||||
			$this->cache->set($entry['cat'], $entry['k'], SerializeUtil::maybeUnserialize($entry['v']), Cache::SOURCE_DATA);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public function setAndSave(Cache $setCache, Cache $delCache): bool
 | 
			
		||||
	{
 | 
			
		||||
		$this->database->transaction();
 | 
			
		||||
 | 
			
		||||
		foreach ($setCache->getAll() as $category => $data) {
 | 
			
		||||
			foreach ($data as $key => $value) {
 | 
			
		||||
				$this->cache->set($category, $key, $value, Cache::SOURCE_DATA);
 | 
			
		||||
				$this->database->insert('config', ['cat' => $category, 'k' => $key, 'v' => serialize($value)], Database::INSERT_UPDATE);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		foreach ($delCache->getAll() as $category => $keys) {
 | 
			
		||||
			foreach ($keys as $key => $value) {
 | 
			
		||||
				$this->cache->delete($category, $key);
 | 
			
		||||
				$this->database->delete('config', ['cat' => $category, 'k' => $key]);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return $this->database->commit();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** {@inheritDoc} */
 | 
			
		||||
	public function get(string $cat, string $key = null, $default_value = null)
 | 
			
		||||
	{
 | 
			
		||||
		return $this->cache->get($cat, $key) ?? $default_value;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** {@inheritDoc} */
 | 
			
		||||
	public function set(string $cat, string $key, $value): bool
 | 
			
		||||
	{
 | 
			
		||||
		$this->cache->set($cat, $key, $value, Cache::SOURCE_DATA);
 | 
			
		||||
		return $this->database->insert('config', ['cat' => $cat, 'k' => $key, 'v' => serialize($value)], Database::INSERT_UPDATE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** {@inheritDoc} */
 | 
			
		||||
	public function beginTransaction(): ISetConfigValuesTransactionally
 | 
			
		||||
	{
 | 
			
		||||
		return new ConfigTransaction($this);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** {@inheritDoc} */
 | 
			
		||||
	public function delete(string $cat, string $key): bool
 | 
			
		||||
	{
 | 
			
		||||
		$this->cache->delete($cat, $key);
 | 
			
		||||
		return $this->database->delete('config', ['cat' => $cat, 'k' => $key]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** {@inheritDoc} */
 | 
			
		||||
	public function getCache(): Cache
 | 
			
		||||
	{
 | 
			
		||||
		return $this->cache;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										82
									
								
								src/Core/Config/Model/ReadOnlyFileConfig.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								src/Core/Config/Model/ReadOnlyFileConfig.php
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,82 @@
 | 
			
		|||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * @copyright Copyright (C) 2010-2023, the Friendica project
 | 
			
		||||
 *
 | 
			
		||||
 * @license GNU AGPL version 3 or any later version
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as
 | 
			
		||||
 * published by the Free Software Foundation, either version 3 of the
 | 
			
		||||
 * License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace Friendica\Core\Config\Model;
 | 
			
		||||
 | 
			
		||||
use Friendica\Core\Config\Capability\IManageConfigValues;
 | 
			
		||||
use Friendica\Core\Config\Capability\ISetConfigValuesTransactionally;
 | 
			
		||||
use Friendica\Core\Config\Exception\ConfigPersistenceException;
 | 
			
		||||
use Friendica\Core\Config\ValueObject\Cache;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Creates a basic, readonly model for the file-based configuration
 | 
			
		||||
 */
 | 
			
		||||
class ReadOnlyFileConfig implements IManageConfigValues
 | 
			
		||||
{
 | 
			
		||||
	/** @var Cache */
 | 
			
		||||
	protected $configCache;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param Cache $configCache The configuration cache (based on the config-files)
 | 
			
		||||
	 */
 | 
			
		||||
	public function __construct(Cache $configCache)
 | 
			
		||||
	{
 | 
			
		||||
		$this->configCache = $configCache;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * {@inheritDoc}
 | 
			
		||||
	 */
 | 
			
		||||
	public function getCache(): Cache
 | 
			
		||||
	{
 | 
			
		||||
		return $this->configCache;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**    {@inheritDoc} */
 | 
			
		||||
	public function beginTransaction(): ISetConfigValuesTransactionally
 | 
			
		||||
	{
 | 
			
		||||
		throw new ConfigPersistenceException('beginTransaction not allowed.');
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** {@inheritDoc} */
 | 
			
		||||
	public function reload()
 | 
			
		||||
	{
 | 
			
		||||
		throw new ConfigPersistenceException('reload not allowed.');
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** {@inheritDoc} */
 | 
			
		||||
	public function get(string $cat, string $key = null, $default_value = null)
 | 
			
		||||
	{
 | 
			
		||||
		return $this->configCache->get($cat, $key) ?? $default_value;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** {@inheritDoc} */
 | 
			
		||||
	public function set(string $cat, string $key, $value): bool
 | 
			
		||||
	{
 | 
			
		||||
		throw new ConfigPersistenceException('set not allowed.');
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** {@inheritDoc} */
 | 
			
		||||
	public function delete(string $cat, string $key): bool
 | 
			
		||||
	{
 | 
			
		||||
		throw new ConfigPersistenceException('Save not allowed');
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -111,9 +111,6 @@ class ConfigFileManager
 | 
			
		|||
		// Now load every other config you find inside the 'config/' directory
 | 
			
		||||
		$this->loadCoreConfig($configCache);
 | 
			
		||||
 | 
			
		||||
		// Now load the node.config.php file with the node specific config values (based on admin gui/console actions)
 | 
			
		||||
		$this->loadDataConfig($configCache);
 | 
			
		||||
 | 
			
		||||
		$configCache->load($this->loadEnvConfig(), Cache::SOURCE_ENV);
 | 
			
		||||
 | 
			
		||||
		// In case of install mode, add the found basepath (because there isn't a basepath set yet
 | 
			
		||||
| 
						 | 
				
			
			@ -166,167 +163,6 @@ class ConfigFileManager
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Tries to load the data config file with the overridden data
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param Cache $configCache The Config cache
 | 
			
		||||
	 *
 | 
			
		||||
	 * @throws ConfigFileException In case the config file isn't loadable
 | 
			
		||||
	 */
 | 
			
		||||
	private function loadDataConfig(Cache $configCache)
 | 
			
		||||
	{
 | 
			
		||||
		$filename = $this->configDir . '/' . self::CONFIG_DATA_FILE;
 | 
			
		||||
 | 
			
		||||
		if (file_exists($filename) && (filesize($filename) > 0)) {
 | 
			
		||||
 | 
			
		||||
			// The fallback empty return content
 | 
			
		||||
			$content = '<?php return [];';
 | 
			
		||||
 | 
			
		||||
			/**
 | 
			
		||||
			 * This code-block creates a readonly node.config.php content stream (fopen() with "r")
 | 
			
		||||
			 * The stream is locked shared (LOCK_SH), so not exclusively, but the OS knows that there's a lock
 | 
			
		||||
			 *
 | 
			
		||||
			 * Any exclusive locking (LOCK_EX) would need to wait until all LOCK_SHs are unlocked
 | 
			
		||||
			 */
 | 
			
		||||
			if (($configStream = @fopen($filename, 'r')) === false) {
 | 
			
		||||
				throw new ConfigFileException(sprintf('Cannot open file "%s" in mode r', $filename));
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			try {
 | 
			
		||||
				if (flock($configStream, LOCK_SH)) {
 | 
			
		||||
					clearstatcache(true, $filename);
 | 
			
		||||
 | 
			
		||||
					if (($filesize = filesize($filename)) === 0) {
 | 
			
		||||
						return;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					$content = fread($configStream, $filesize);
 | 
			
		||||
					if (!$content) {
 | 
			
		||||
						throw new ConfigFileException(sprintf('Couldn\'t read file %s', $filename));
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			} finally {
 | 
			
		||||
				// unlock and close the stream for every circumstances
 | 
			
		||||
				flock($configStream, LOCK_UN);
 | 
			
		||||
				fclose($configStream);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/**
 | 
			
		||||
			 * Evaluate the content string as PHP code
 | 
			
		||||
			 *
 | 
			
		||||
			 * @see https://www.php.net/manual/en/function.eval.php
 | 
			
		||||
			 *
 | 
			
		||||
			 * @note
 | 
			
		||||
			 * To leave the PHP mode, we have to use the appropriate PHP tags '?>' as prefix.
 | 
			
		||||
			 */
 | 
			
		||||
			$dataArray = eval('?>' . $content);
 | 
			
		||||
 | 
			
		||||
			if (is_array($dataArray)) {
 | 
			
		||||
				$configCache->load($dataArray, Cache::SOURCE_DATA);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Checks, if the node.config.php is writable
 | 
			
		||||
	 *
 | 
			
		||||
	 * @return bool
 | 
			
		||||
	 */
 | 
			
		||||
	public function dataIsWritable(): bool
 | 
			
		||||
	{
 | 
			
		||||
		$filename = $this->configDir . '/' . self::CONFIG_DATA_FILE;
 | 
			
		||||
 | 
			
		||||
		if (file_exists($filename)) {
 | 
			
		||||
			return is_writable($filename);
 | 
			
		||||
		} else {
 | 
			
		||||
			return is_writable($this->configDir);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Saves overridden config entries back into the data.config.php
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param Cache $configCache The config cache
 | 
			
		||||
	 *
 | 
			
		||||
	 * @throws ConfigFileException In case the config file isn't writeable or the data is invalid
 | 
			
		||||
	 */
 | 
			
		||||
	public function saveData(Cache $configCache)
 | 
			
		||||
	{
 | 
			
		||||
		$filename = $this->configDir . '/' . self::CONFIG_DATA_FILE;
 | 
			
		||||
 | 
			
		||||
		if (file_exists($filename)) {
 | 
			
		||||
			$fileExists = true;
 | 
			
		||||
		} else {
 | 
			
		||||
			$fileExists = false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Creates a read-write stream
 | 
			
		||||
		 *
 | 
			
		||||
		 * @see  https://www.php.net/manual/en/function.fopen.php
 | 
			
		||||
		 * @note Open the file for reading and writing. If the file does not exist, it is created.
 | 
			
		||||
		 * If it exists, it is neither truncated (as opposed to 'w'), nor the call to this function fails
 | 
			
		||||
		 * (as is the case with 'x'). The file pointer is positioned on the beginning of the file.
 | 
			
		||||
		 *
 | 
			
		||||
		 */
 | 
			
		||||
		if (($configStream = @fopen($filename, 'c+')) === false) {
 | 
			
		||||
			throw new ConfigFileException(sprintf('Cannot open file "%s" in mode c+', $filename));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		try {
 | 
			
		||||
			// We do want an exclusive lock, so we wait until every LOCK_SH (config reading) is unlocked
 | 
			
		||||
			if (flock($configStream, LOCK_EX)) {
 | 
			
		||||
 | 
			
		||||
				/**
 | 
			
		||||
				 * If the file exists, we read the whole file again to avoid a race condition with concurrent threads that could have modified the file between the first config read of this thread and now
 | 
			
		||||
				 * Since we're currently exclusive locked, no other process can now change the config again
 | 
			
		||||
				 */
 | 
			
		||||
				if ($fileExists) {
 | 
			
		||||
					// When reading the config file too fast, we get a wrong filesize, "clearstatcache" prevents that
 | 
			
		||||
					clearstatcache(true, $filename);
 | 
			
		||||
					$content = fread($configStream, filesize($filename));
 | 
			
		||||
					if (!$content) {
 | 
			
		||||
						throw new ConfigFileException(sprintf('Cannot read file %s', $filename));
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					// Event truncating the whole content wouldn't automatically rewind the stream,
 | 
			
		||||
					// so we need to do it manually
 | 
			
		||||
					rewind($configStream);
 | 
			
		||||
 | 
			
		||||
					$dataArray = eval('?>' . $content);
 | 
			
		||||
 | 
			
		||||
					// Merge the new content into the existing file based config cache and use it
 | 
			
		||||
					// as the new config cache
 | 
			
		||||
					if (is_array($dataArray)) {
 | 
			
		||||
						$fileConfigCache = new Cache();
 | 
			
		||||
						$fileConfigCache->load($dataArray, Cache::SOURCE_DATA);
 | 
			
		||||
						$configCache = $fileConfigCache->merge($configCache);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// Only SOURCE_DATA is wanted, the rest isn't part of the node.config.php file
 | 
			
		||||
				$data = $configCache->getDataBySource(Cache::SOURCE_DATA);
 | 
			
		||||
 | 
			
		||||
				$encodedData = ConfigFileTransformer::encode($data);
 | 
			
		||||
				if (!$encodedData) {
 | 
			
		||||
					throw new ConfigFileException('config source cannot get encoded');
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// Once again to avoid wrong, implicit "filesize" calls during the fwrite() or ftruncate() call
 | 
			
		||||
				clearstatcache(true, $filename);
 | 
			
		||||
				if (!ftruncate($configStream, 0) ||
 | 
			
		||||
					!fwrite($configStream, $encodedData) ||
 | 
			
		||||
					!fflush($configStream)) {
 | 
			
		||||
					throw new ConfigFileException(sprintf('Cannot modify locked file %s', $filename));
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		} finally {
 | 
			
		||||
			// unlock and close the stream for every circumstances
 | 
			
		||||
			flock($configStream, LOCK_UN);
 | 
			
		||||
			fclose($configStream);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Tries to load the specified addon-configuration and returns the config array.
 | 
			
		||||
	 *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,237 +0,0 @@
 | 
			
		|||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * @copyright Copyright (C) 2010-2023, the Friendica project
 | 
			
		||||
 *
 | 
			
		||||
 * @license GNU AGPL version 3 or any later version
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as
 | 
			
		||||
 * published by the Free Software Foundation, either version 3 of the
 | 
			
		||||
 * License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace Friendica\Core\Config\Util;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Util to transform back the config array into a string
 | 
			
		||||
 */
 | 
			
		||||
class ConfigFileTransformer
 | 
			
		||||
{
 | 
			
		||||
	/**
 | 
			
		||||
	 * This method takes an array of config values and applies some standard rules for formatting on it
 | 
			
		||||
	 *
 | 
			
		||||
	 * Beware that the applied rules follow some basic formatting principles for node.config.php
 | 
			
		||||
	 * and doesn't support any custom formatting rules.
 | 
			
		||||
	 *
 | 
			
		||||
	 * f.e. associative array and list formatting are very complex with newlines and indentations, thus there are
 | 
			
		||||
	 * three hardcoded types of formatting for them.
 | 
			
		||||
	 *
 | 
			
		||||
	 * a negative example, what's NOT working:
 | 
			
		||||
	 * key => [ value1, [inner_value1, inner_value2], value2]
 | 
			
		||||
	 * Since this isn't necessary for config values, there's no further logic handling such complex-list-in-list scenarios
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param array $data A full config array
 | 
			
		||||
	 *
 | 
			
		||||
	 * @return string The config stream, which can be saved
 | 
			
		||||
	 */
 | 
			
		||||
	public static function encode(array $data): string
 | 
			
		||||
	{
 | 
			
		||||
		// Add the typical header values
 | 
			
		||||
		$dataString = '<?php' . PHP_EOL . PHP_EOL;
 | 
			
		||||
		$dataString .= 'return ';
 | 
			
		||||
 | 
			
		||||
		$dataString .= static::extractArray($data);
 | 
			
		||||
 | 
			
		||||
		// the last array line, close it with a semicolon
 | 
			
		||||
		$dataString .= ";" . PHP_EOL;
 | 
			
		||||
 | 
			
		||||
		return $dataString;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Extracts an inner config array.
 | 
			
		||||
	 * Either as an associative array or as a list
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param array $config The config array which should get extracted
 | 
			
		||||
	 * @param int   $level  The current level of recursion (necessary for tab-indentation calculation)
 | 
			
		||||
	 * @param bool  $inList If true, the current array resides inside another list. Different rules may be applicable
 | 
			
		||||
	 *
 | 
			
		||||
	 * @return string The config string
 | 
			
		||||
	 */
 | 
			
		||||
	protected static function extractArray(array $config, int $level = 0, bool $inList = false): string
 | 
			
		||||
	{
 | 
			
		||||
		if (array_values($config) === $config) {
 | 
			
		||||
			return self::extractList($config, $level, $inList);
 | 
			
		||||
		} else {
 | 
			
		||||
			return self::extractAssociativeArray($config, $level, $inList);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Extracts a key-value array and save it into a string
 | 
			
		||||
	 * output:
 | 
			
		||||
	 * [
 | 
			
		||||
	 *    'key' => value,
 | 
			
		||||
	 *    'key' => value,
 | 
			
		||||
	 *    ...
 | 
			
		||||
	 * ]
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param array $config The associative/key-value array
 | 
			
		||||
	 * @param int   $level  The current level of recursion (necessary for tab-indentation calculation)
 | 
			
		||||
	 * @param bool  $inList If true, the current array resides inside another list. Different rules may be applicable
 | 
			
		||||
	 *
 | 
			
		||||
	 * @return string The config string
 | 
			
		||||
	 */
 | 
			
		||||
	protected static function extractAssociativeArray(array $config, int $level = 0, bool $inList = false): string
 | 
			
		||||
	{
 | 
			
		||||
		$string = '';
 | 
			
		||||
 | 
			
		||||
		// Because we're in a list, we have to add a line-break first
 | 
			
		||||
		if ($inList) {
 | 
			
		||||
			$string .= PHP_EOL . str_repeat("\t", $level);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Add a typical Line break for a taxative list of key-value pairs
 | 
			
		||||
		$string .= '[' . PHP_EOL;
 | 
			
		||||
 | 
			
		||||
		foreach ($config as $configKey => $configValue) {
 | 
			
		||||
			$string .= str_repeat("\t", $level + 1) .
 | 
			
		||||
					   "'$configKey' => " .
 | 
			
		||||
					   static::transformConfigValue($configValue, $level) .
 | 
			
		||||
					   ',' . PHP_EOL;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		$string .= str_repeat("\t", $level) . ']';
 | 
			
		||||
 | 
			
		||||
		return $string;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Extracts a list and save it into a string
 | 
			
		||||
	 * output1 - simple:
 | 
			
		||||
	 * [ value, value, value ]
 | 
			
		||||
	 *
 | 
			
		||||
	 * output2 - complex:
 | 
			
		||||
	 * [
 | 
			
		||||
	 *    [ value, value, value ],
 | 
			
		||||
	 *    value,
 | 
			
		||||
	 *    [
 | 
			
		||||
	 *       key => value,
 | 
			
		||||
	 *       key => value,
 | 
			
		||||
	 *    ],
 | 
			
		||||
	 * ]
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param array $config The list
 | 
			
		||||
	 * @param int   $level  The current level of recursion (necessary for tab-indentation calculation)
 | 
			
		||||
	 * @param bool  $inList If true, the current array resides inside another list. Different rules may be applicable
 | 
			
		||||
	 *
 | 
			
		||||
	 * @return string The config string
 | 
			
		||||
	 */
 | 
			
		||||
	protected static function extractList(array $config, int $level = 0, bool $inList = false): string
 | 
			
		||||
	{
 | 
			
		||||
		$string = '[';
 | 
			
		||||
 | 
			
		||||
		$countConfigValues = count($config);
 | 
			
		||||
		// multiline defines, if each entry uses a new line
 | 
			
		||||
		$multiline = false;
 | 
			
		||||
 | 
			
		||||
		// Search if any value is an array, because then other formatting rules are applicable
 | 
			
		||||
		foreach ($config as $item) {
 | 
			
		||||
			if (is_array($item)) {
 | 
			
		||||
				$multiline = true;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for ($i = 0; $i < $countConfigValues; $i++) {
 | 
			
		||||
			$isArray = is_array($config[$i]);
 | 
			
		||||
 | 
			
		||||
			/**
 | 
			
		||||
			 * In case this is an array in an array, directly extract this array again and continue
 | 
			
		||||
			 * Skip any other logic since this isn't applicable for an array in an array
 | 
			
		||||
			 */
 | 
			
		||||
			if ($isArray) {
 | 
			
		||||
				$string .= PHP_EOL . str_repeat("\t", $level + 1);
 | 
			
		||||
				$string .= static::extractArray($config[$i], $level + 1, $inList) . ',';
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if ($multiline) {
 | 
			
		||||
				$string .= PHP_EOL . str_repeat("\t", $level + 1);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			$string .= static::transformConfigValue($config[$i], $level, true);
 | 
			
		||||
 | 
			
		||||
			// add trailing commas or whitespaces for certain config entries
 | 
			
		||||
			if (($i < ($countConfigValues - 1))) {
 | 
			
		||||
				$string .= ',';
 | 
			
		||||
				if (!$multiline) {
 | 
			
		||||
					$string .= ' ';
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Add a new line for the last bracket as well
 | 
			
		||||
		if ($multiline) {
 | 
			
		||||
			$string .= PHP_EOL . str_repeat("\t", $level);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		$string .= ']';
 | 
			
		||||
 | 
			
		||||
		return $string;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Transforms one config value and returns the corresponding text-representation
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param mixed $value  Any value to transform
 | 
			
		||||
	 * @param int   $level  The current level of recursion (necessary for tab-indentation calculation)
 | 
			
		||||
	 * @param bool  $inList If true, the current array resides inside another list. Different rules may be applicable
 | 
			
		||||
	 *
 | 
			
		||||
	 * @return string
 | 
			
		||||
	 */
 | 
			
		||||
	protected static function transformConfigValue($value, int $level = 0, bool $inList = false): string
 | 
			
		||||
	{
 | 
			
		||||
		switch (gettype($value)) {
 | 
			
		||||
			case "boolean":
 | 
			
		||||
				return ($value ? 'true' : 'false');
 | 
			
		||||
			case "integer":
 | 
			
		||||
			case "double":
 | 
			
		||||
				return $value;
 | 
			
		||||
			case "string":
 | 
			
		||||
				return sprintf('\'%s\'', addcslashes($value, '\'\\'));
 | 
			
		||||
			case "array":
 | 
			
		||||
				return static::extractArray($value, ++$level, $inList);
 | 
			
		||||
			case "NULL":
 | 
			
		||||
				return "null";
 | 
			
		||||
			case "object":
 | 
			
		||||
				if (method_exists($value, '__toString')) {
 | 
			
		||||
					return sprintf('\'%s\'', $value);
 | 
			
		||||
				} elseif ($value instanceof \Serializable) {
 | 
			
		||||
					try {
 | 
			
		||||
						return $value->serialize();
 | 
			
		||||
					} catch (\Exception $e) {
 | 
			
		||||
						throw new \InvalidArgumentException(sprintf('Cannot serialize %s.', gettype($value)), $e);
 | 
			
		||||
					}
 | 
			
		||||
				} else {
 | 
			
		||||
					throw new \InvalidArgumentException(sprintf('%s is an object without stringify.', gettype($value)));
 | 
			
		||||
				}
 | 
			
		||||
			case "resource":
 | 
			
		||||
			case "resource (closed)":
 | 
			
		||||
				throw new \InvalidArgumentException(sprintf('%s in configs are not supported yet.', gettype($value)));
 | 
			
		||||
			case "unknown type":
 | 
			
		||||
				throw new \InvalidArgumentException(sprintf('%s is an unknown value', $value));
 | 
			
		||||
			default:
 | 
			
		||||
				throw new \InvalidArgumentException(sprintf('%s is currently unsupported', $value));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										114
									
								
								src/Core/Config/Util/SerializeUtil.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								src/Core/Config/Util/SerializeUtil.php
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,114 @@
 | 
			
		|||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * @copyright Copyright (C) 2010-2023, the Friendica project
 | 
			
		||||
 *
 | 
			
		||||
 * @license GNU AGPL version 3 or any later version
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as
 | 
			
		||||
 * published by the Free Software Foundation, either version 3 of the
 | 
			
		||||
 * License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace Friendica\Core\Config\Util;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Serialize utils
 | 
			
		||||
 *
 | 
			
		||||
 * Retrieved from https://github.com/WordPress/wordpress-develop/blob/6.1/src/wp-includes/functions.php
 | 
			
		||||
 */
 | 
			
		||||
class SerializeUtil
 | 
			
		||||
{
 | 
			
		||||
	public static function maybeUnserialize($value)
 | 
			
		||||
	{
 | 
			
		||||
		if (static::isSerialized($value)) {
 | 
			
		||||
			return @unserialize(trim($value));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return $value;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Checks value to find if it was serialized.
 | 
			
		||||
	 *
 | 
			
		||||
	 * If $data is not a string, then returned value will always be false.
 | 
			
		||||
	 * Serialized data is always a string.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param mixed $data   Value to check to see if was serialized.
 | 
			
		||||
	 * @param bool  $strict Optional. Whether to be strict about the end of the string. Default true.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @return bool False if not serialized and true if it was.
 | 
			
		||||
	 * @since 6.1.0 Added Enum support.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @since 2.0.5
 | 
			
		||||
	 */
 | 
			
		||||
	public static function isSerialized($data, bool $strict = true): bool
 | 
			
		||||
	{
 | 
			
		||||
		// If it isn't a string, it isn't serialized.
 | 
			
		||||
		if (!is_string($data)) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		$data = trim($data);
 | 
			
		||||
		if ('N;' === $data) {
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
		if (strlen($data) < 4) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		if (':' !== $data[1]) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		if ($strict) {
 | 
			
		||||
			$lastc = substr($data, -1);
 | 
			
		||||
			if (';' !== $lastc && '}' !== $lastc) {
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			$semicolon = strpos($data, ';');
 | 
			
		||||
			$brace     = strpos($data, '}');
 | 
			
		||||
			// Either ; or } must exist.
 | 
			
		||||
			if (false === $semicolon && false === $brace) {
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
			// But neither must be in the first X characters.
 | 
			
		||||
			if (false !== $semicolon && $semicolon < 3) {
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
			if (false !== $brace && $brace < 4) {
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		$token = $data[0];
 | 
			
		||||
		switch ($token) {
 | 
			
		||||
			case 's':
 | 
			
		||||
				if ($strict) {
 | 
			
		||||
					if ('"' !== substr($data, -2, 1)) {
 | 
			
		||||
						return false;
 | 
			
		||||
					}
 | 
			
		||||
				} elseif (false === strpos($data, '"')) {
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
			// Or else fall through.
 | 
			
		||||
			// no break
 | 
			
		||||
			case 'a':
 | 
			
		||||
			case 'O':
 | 
			
		||||
			case 'E':
 | 
			
		||||
				return (bool)preg_match("/^{$token}:[0-9]+:/s", $data);
 | 
			
		||||
			case 'b':
 | 
			
		||||
			case 'i':
 | 
			
		||||
			case 'd':
 | 
			
		||||
				$end = $strict ? '$' : '';
 | 
			
		||||
				return (bool)preg_match("/^{$token}:[0-9.E+-]+;$end/", $data);
 | 
			
		||||
		}
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -92,7 +92,7 @@ class StreamLogger extends AbstractLogger implements IAmAStrategy
 | 
			
		|||
		$this->fileSystem = $fileSystem;
 | 
			
		||||
 | 
			
		||||
		$stream = $this->logfile ?? $config->get('system', 'logfile');
 | 
			
		||||
		if ((file_exists($stream) && !is_writable($stream)) || is_writable(basename($stream))) {
 | 
			
		||||
		if ((@file_exists($stream) && !@is_writable($stream)) && !@is_writable(basename($stream))) {
 | 
			
		||||
			throw new LoggerArgumentException(sprintf('%s is not a valid logfile', $stream));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -129,15 +129,26 @@ class Update
 | 
			
		|||
			DI::lock()->release('dbupdate', true);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!DBStructure::existsTable('config')) {
 | 
			
		||||
			DBA::e(<<<EOF
 | 
			
		||||
CREATE TABLE IF NOT EXISTS `config` (
 | 
			
		||||
	`id` int unsigned NOT NULL auto_increment COMMENT '',
 | 
			
		||||
	`cat` varbinary(50) NOT NULL DEFAULT '' COMMENT 'The category of the entry',
 | 
			
		||||
	`k` varbinary(50) NOT NULL DEFAULT '' COMMENT 'The key of the entry',
 | 
			
		||||
	`v` mediumtext COMMENT '',
 | 
			
		||||
	 PRIMARY KEY(`id`),
 | 
			
		||||
	 UNIQUE INDEX `cat_k` (`cat`,`k`)
 | 
			
		||||
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='main configuration storage';
 | 
			
		||||
EOF
 | 
			
		||||
);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		$build = DI::config()->get('system', 'build');
 | 
			
		||||
 | 
			
		||||
		if (empty($build)) {
 | 
			
		||||
			// legacy option - check if there's something in the Config table
 | 
			
		||||
			if (DBStructure::existsTable('config')) {
 | 
			
		||||
				$dbConfig = DBA::selectFirst('config', ['v'], ['cat' => 'system', 'k' => 'build']);
 | 
			
		||||
				if (!empty($dbConfig)) {
 | 
			
		||||
					$build = $dbConfig['v'];
 | 
			
		||||
				}
 | 
			
		||||
			$dbConfig = DBA::selectFirst('config', ['v'], ['cat' => 'system', 'k' => 'build']);
 | 
			
		||||
			if (!empty($dbConfig)) {
 | 
			
		||||
				$build = $dbConfig['v'];
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (empty($build) || ($build > DB_UPDATE_VERSION)) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										27
									
								
								src/DI.php
									
										
									
									
									
								
							
							
						
						
									
										27
									
								
								src/DI.php
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -37,9 +37,34 @@ abstract class DI
 | 
			
		|||
	/** @var Dice */
 | 
			
		||||
	private static $dice;
 | 
			
		||||
 | 
			
		||||
	public static function init(Dice $dice)
 | 
			
		||||
	/**
 | 
			
		||||
	 * Initialize the singleton DI container with the Dice instance
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param Dice $dice             The Dice instance
 | 
			
		||||
	 * @param bool $disableDepByHand If true, the database dependencies aren't set, thus any occurrence of logging or
 | 
			
		||||
	 *                               profiling in database methods would lead to an error. This flag is for testing only.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @return void
 | 
			
		||||
	 */
 | 
			
		||||
	public static function init(Dice $dice, bool $disableDepByHand = false)
 | 
			
		||||
	{
 | 
			
		||||
		self::$dice = $dice;
 | 
			
		||||
 | 
			
		||||
		if (!$disableDepByHand) {
 | 
			
		||||
			self::setCompositeRootDependencyByHand();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * I HATE this method, but everything else needs refactoring at the database itself
 | 
			
		||||
	 * Set the database dependencies manually, because of current, circular dependencies between the database and the config table
 | 
			
		||||
	 *
 | 
			
		||||
	 * @todo Instead of this madness, split the database in a core driver-dependent (mysql, mariadb, postgresql, ..) part without any other dependency unlike credentials and in the full-featured, driver-independent database class with all dependencies
 | 
			
		||||
	 */
 | 
			
		||||
	public static function setCompositeRootDependencyByHand()
 | 
			
		||||
	{
 | 
			
		||||
		$database = static::dba();
 | 
			
		||||
		$database->setDependency(static::config(), static::profiler(), static::logger());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -74,7 +74,7 @@ class DBStructure
 | 
			
		|||
		$old_tables = ['fserver', 'gcign', 'gcontact', 'gcontact-relation', 'gfollower' ,'glink', 'item-delivery-data',
 | 
			
		||||
			'item-activity', 'item-content', 'item_id', 'participation', 'poll', 'poll_result', 'queue', 'retriever_rule',
 | 
			
		||||
			'deliverq', 'dsprphotoq', 'ffinder', 'sign', 'spam', 'term', 'user-item', 'thread', 'item', 'challenge',
 | 
			
		||||
			'auth_codes', 'tokens', 'clients', 'profile_check', 'host', 'conversation', 'fcontact', 'config', 'addon'];
 | 
			
		||||
			'auth_codes', 'tokens', 'clients', 'profile_check', 'host', 'conversation', 'fcontact', 'addon'];
 | 
			
		||||
 | 
			
		||||
		$tables = DBA::selectToArray('INFORMATION_SCHEMA.TABLES', ['TABLE_NAME'],
 | 
			
		||||
			['TABLE_SCHEMA' => DBA::databaseName(), 'TABLE_TYPE' => 'BASE TABLE']);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,6 +36,7 @@ use PDO;
 | 
			
		|||
use PDOException;
 | 
			
		||||
use PDOStatement;
 | 
			
		||||
use Psr\Log\LoggerInterface;
 | 
			
		||||
use Psr\Log\NullLogger;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This class is for the low level database stuff that does driver specific things.
 | 
			
		||||
| 
						 | 
				
			
			@ -54,15 +55,15 @@ class Database
 | 
			
		|||
	/**
 | 
			
		||||
	 * @var IManageConfigValues
 | 
			
		||||
	 */
 | 
			
		||||
	protected $config;
 | 
			
		||||
	protected $config = null;
 | 
			
		||||
	/**
 | 
			
		||||
	 * @var Profiler
 | 
			
		||||
	 */
 | 
			
		||||
	protected $profiler;
 | 
			
		||||
	protected $profiler = null;
 | 
			
		||||
	/**
 | 
			
		||||
	 * @var LoggerInterface
 | 
			
		||||
	 */
 | 
			
		||||
	protected $logger;
 | 
			
		||||
	protected $logger = null;
 | 
			
		||||
	protected $server_info = '';
 | 
			
		||||
	/** @var PDO|mysqli */
 | 
			
		||||
	protected $connection;
 | 
			
		||||
| 
						 | 
				
			
			@ -80,18 +81,36 @@ class Database
 | 
			
		|||
	/** @var ViewDefinition */
 | 
			
		||||
	protected $viewDefinition;
 | 
			
		||||
 | 
			
		||||
	public function __construct(IManageConfigValues $config, Profiler $profiler, DbaDefinition $dbaDefinition, ViewDefinition $viewDefinition, LoggerInterface $logger)
 | 
			
		||||
	public function __construct(IManageConfigValues $config, DbaDefinition $dbaDefinition, ViewDefinition $viewDefinition)
 | 
			
		||||
	{
 | 
			
		||||
		// We are storing these values for being able to perform a reconnect
 | 
			
		||||
		$this->config         = $config;
 | 
			
		||||
		$this->profiler       = $profiler;
 | 
			
		||||
		$this->dbaDefinition  = $dbaDefinition;
 | 
			
		||||
		$this->viewDefinition = $viewDefinition;
 | 
			
		||||
		$this->logger         = $logger;
 | 
			
		||||
 | 
			
		||||
		// Use dummy values - necessary for the first factory call of the logger itself
 | 
			
		||||
		$this->logger = new NullLogger();
 | 
			
		||||
		$this->profiler = new Profiler($config);
 | 
			
		||||
 | 
			
		||||
		$this->connect();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param IManageConfigValues $config
 | 
			
		||||
	 * @param Profiler            $profiler
 | 
			
		||||
	 * @param LoggerInterface     $logger
 | 
			
		||||
	 *
 | 
			
		||||
	 * @return void
 | 
			
		||||
	 *
 | 
			
		||||
	 * @todo Make this method obsolet - use a clean pattern instead ...
 | 
			
		||||
	 */
 | 
			
		||||
	public function setDependency(IManageConfigValues $config, Profiler $profiler, LoggerInterface $logger)
 | 
			
		||||
	{
 | 
			
		||||
		$this->logger   = $logger;
 | 
			
		||||
		$this->profiler = $profiler;
 | 
			
		||||
		$this->config   = $config;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Tries to connect to database
 | 
			
		||||
	 *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -114,10 +114,6 @@ class Summary extends BaseAdmin
 | 
			
		|||
			$warningtext[] = DI::l10n()->t('Friendica\'s configuration now is stored in config/local.config.php, please copy config/local-sample.config.php and move your config from <code>config/local.ini.php</code>. See <a href="%s">the Config help page</a> for help with the transition.', DI::baseUrl()->get() . '/help/Config');
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!DI::configFileManager()->dataIsWritable()) {
 | 
			
		||||
			$warningtext[] = DI::l10n()->t('Friendica\'s configuration store "%s" isn\'t writable. Until then database updates won\'t be applied automatically, admin settings and console configuration changes won\'t be saved.', ConfigFileManager::CONFIG_DATA_FILE);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Check server vitality
 | 
			
		||||
		if (!self::checkSelfHostMeta()) {
 | 
			
		||||
			$well_known = DI::baseUrl()->get() . Probe::HOST_META;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -76,7 +76,7 @@ class HttpClient implements ICanSendHttpRequests
 | 
			
		|||
		if(!filter_var($host, FILTER_VALIDATE_IP) && !@dns_get_record($host . '.', DNS_A + DNS_AAAA) && !gethostbyname($host)) {
 | 
			
		||||
			$this->logger->debug('URL cannot be resolved.', ['url' => $url, 'callstack' => System::callstack(20)]);
 | 
			
		||||
			$this->profiler->stopRecording();
 | 
			
		||||
			return CurlResult::createErrorCurl($url);
 | 
			
		||||
			return CurlResult::createErrorCurl($this->logger, $url);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (Network::isLocalLink($url)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -86,7 +86,7 @@ class HttpClient implements ICanSendHttpRequests
 | 
			
		|||
		if (strlen($url) > 1000) {
 | 
			
		||||
			$this->logger->debug('URL is longer than 1000 characters.', ['url' => $url, 'callstack' => System::callstack(20)]);
 | 
			
		||||
			$this->profiler->stopRecording();
 | 
			
		||||
			return CurlResult::createErrorCurl(substr($url, 0, 200));
 | 
			
		||||
			return CurlResult::createErrorCurl($this->logger, substr($url, 0, 200));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		$parts2     = [];
 | 
			
		||||
| 
						 | 
				
			
			@ -105,7 +105,7 @@ class HttpClient implements ICanSendHttpRequests
 | 
			
		|||
		if (Network::isUrlBlocked($url)) {
 | 
			
		||||
			$this->logger->info('Domain is blocked.', ['url' => $url]);
 | 
			
		||||
			$this->profiler->stopRecording();
 | 
			
		||||
			return CurlResult::createErrorCurl($url);
 | 
			
		||||
			return CurlResult::createErrorCurl($this->logger, $url);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		$conf = [];
 | 
			
		||||
| 
						 | 
				
			
			@ -176,11 +176,11 @@ class HttpClient implements ICanSendHttpRequests
 | 
			
		|||
				$exception->hasResponse()) {
 | 
			
		||||
				return new GuzzleResponse($exception->getResponse(), $url, $exception->getCode(), '');
 | 
			
		||||
			} else {
 | 
			
		||||
				return new CurlResult($url, '', ['http_code' => 500], $exception->getCode(), '');
 | 
			
		||||
				return new CurlResult($this->logger, $url, '', ['http_code' => 500], $exception->getCode(), '');
 | 
			
		||||
			}
 | 
			
		||||
		} catch (InvalidArgumentException | \InvalidArgumentException $argumentException) {
 | 
			
		||||
			$this->logger->info('Invalid Argument for HTTP call.', ['url' => $url, 'method' => $method, 'exception' => $argumentException]);
 | 
			
		||||
			return new CurlResult($url, '', ['http_code' => 500], $argumentException->getCode(), $argumentException->getMessage());
 | 
			
		||||
			return new CurlResult($this->logger, $url, '', ['http_code' => 500], $argumentException->getCode(), $argumentException->getMessage());
 | 
			
		||||
		} finally {
 | 
			
		||||
			unlink($conf['sink']);
 | 
			
		||||
			$this->logger->debug('Request stop.', ['url' => $url, 'method' => $method]);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,6 +25,7 @@ use Friendica\Core\Logger;
 | 
			
		|||
use Friendica\Network\HTTPClient\Capability\ICanHandleHttpResponses;
 | 
			
		||||
use Friendica\Network\HTTPException\UnprocessableEntityException;
 | 
			
		||||
use Friendica\Util\Network;
 | 
			
		||||
use Psr\Log\LoggerInterface;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A content class for Curl call results
 | 
			
		||||
| 
						 | 
				
			
			@ -96,6 +97,11 @@ class CurlResult implements ICanHandleHttpResponses
 | 
			
		|||
	 */
 | 
			
		||||
	private $error;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @var LoggerInterface
 | 
			
		||||
	 */
 | 
			
		||||
	protected $logger;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Creates an errored CURL response
 | 
			
		||||
	 *
 | 
			
		||||
| 
						 | 
				
			
			@ -104,9 +110,9 @@ class CurlResult implements ICanHandleHttpResponses
 | 
			
		|||
	 * @return ICanHandleHttpResponses a CURL with error response
 | 
			
		||||
	 * @throws UnprocessableEntityException
 | 
			
		||||
	 */
 | 
			
		||||
	public static function createErrorCurl(string $url = '')
 | 
			
		||||
	public static function createErrorCurl(LoggerInterface $logger, string $url = '')
 | 
			
		||||
	{
 | 
			
		||||
		return new CurlResult($url, '', ['http_code' => 0]);
 | 
			
		||||
		return new CurlResult($logger, $url, '', ['http_code' => 0]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -120,8 +126,10 @@ class CurlResult implements ICanHandleHttpResponses
 | 
			
		|||
	 *
 | 
			
		||||
	 * @throws UnprocessableEntityException when HTTP code of the CURL response is missing
 | 
			
		||||
	 */
 | 
			
		||||
	public function __construct(string $url, string $result, array $info, int $errorNumber = 0, string $error = '')
 | 
			
		||||
	public function __construct(LoggerInterface $logger, string $url, string $result, array $info, int $errorNumber = 0, string $error = '')
 | 
			
		||||
	{
 | 
			
		||||
		$this->logger = $logger;
 | 
			
		||||
 | 
			
		||||
		if (!array_key_exists('http_code', $info)) {
 | 
			
		||||
			throw new UnprocessableEntityException('CURL response doesn\'t contains a response HTTP code');
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -132,7 +140,7 @@ class CurlResult implements ICanHandleHttpResponses
 | 
			
		|||
		$this->errorNumber = $errorNumber;
 | 
			
		||||
		$this->error       = $error;
 | 
			
		||||
 | 
			
		||||
		Logger::debug('construct', ['url' => $url, 'returncode' => $this->returnCode, 'result' => $result]);
 | 
			
		||||
		$this->logger->debug('construct', ['url' => $url, 'returncode' => $this->returnCode, 'result' => $result]);
 | 
			
		||||
 | 
			
		||||
		$this->parseBodyHeader($result);
 | 
			
		||||
		$this->checkSuccess();
 | 
			
		||||
| 
						 | 
				
			
			@ -172,7 +180,7 @@ class CurlResult implements ICanHandleHttpResponses
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		if (!$this->isSuccess) {
 | 
			
		||||
			Logger::debug('debug', ['info' => $this->info]);
 | 
			
		||||
			$this->logger->debug('debug', ['info' => $this->info]);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!$this->isSuccess && $this->errorNumber == CURLE_OPERATION_TIMEDOUT) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,7 +55,7 @@
 | 
			
		|||
use Friendica\Database\DBA;
 | 
			
		||||
 | 
			
		||||
if (!defined('DB_UPDATE_VERSION')) {
 | 
			
		||||
	define('DB_UPDATE_VERSION', 1513);
 | 
			
		||||
	define('DB_UPDATE_VERSION', 1514);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
return [
 | 
			
		||||
| 
						 | 
				
			
			@ -554,6 +554,19 @@ return [
 | 
			
		|||
			"k_expires" => ["k", "expires"],
 | 
			
		||||
		]
 | 
			
		||||
	],
 | 
			
		||||
	"config" => [
 | 
			
		||||
		"comment" => "main configuration storage",
 | 
			
		||||
		"fields" => [
 | 
			
		||||
			"id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
 | 
			
		||||
			"cat" => ["type" => "varbinary(50)", "not null" => "1", "default" => "", "comment" => "The category of the entry"],
 | 
			
		||||
			"k" => ["type" => "varbinary(50)", "not null" => "1", "default" => "", "comment" => "The key of the entry"],
 | 
			
		||||
			"v" => ["type" => "mediumtext", "comment" => ""],
 | 
			
		||||
		],
 | 
			
		||||
		"indexes" => [
 | 
			
		||||
			"PRIMARY" => ["id"],
 | 
			
		||||
			"cat_k" => ["UNIQUE", "cat", "k"],
 | 
			
		||||
		]
 | 
			
		||||
	],
 | 
			
		||||
	"contact-relation" => [
 | 
			
		||||
		"comment" => "Contact relations",
 | 
			
		||||
		"fields" => [
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -108,7 +108,7 @@ return [
 | 
			
		|||
		],
 | 
			
		||||
	],
 | 
			
		||||
	Config\Capability\IManageConfigValues::class => [
 | 
			
		||||
		'instanceOf' => Config\Model\Config::class,
 | 
			
		||||
		'instanceOf' => Config\Model\DatabaseConfig::class,
 | 
			
		||||
		'constructParams' => [
 | 
			
		||||
			$_SERVER,
 | 
			
		||||
		],
 | 
			
		||||
| 
						 | 
				
			
			@ -137,7 +137,7 @@ return [
 | 
			
		|||
	],
 | 
			
		||||
	Database::class                         => [
 | 
			
		||||
		'constructParams' => [
 | 
			
		||||
			[Dice::INSTANCE => \Psr\Log\NullLogger::class],
 | 
			
		||||
			[Dice::INSTANCE => Config\Model\ReadOnlyFileConfig::class],
 | 
			
		||||
		],
 | 
			
		||||
	],
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -53,16 +53,14 @@ trait DatabaseTestTrait
 | 
			
		|||
	/**
 | 
			
		||||
	 * Loads a given DB fixture for this DB test
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param string   $fixture The path to the fixture
 | 
			
		||||
	 * @param string[][] $fixture The fixture array
 | 
			
		||||
	 * @param Database $dba     The DB connection
 | 
			
		||||
	 *
 | 
			
		||||
	 * @throws \Exception
 | 
			
		||||
	 */
 | 
			
		||||
	protected function loadFixture(string $fixture, Database $dba)
 | 
			
		||||
	protected function loadDirectFixture(array $fixture, Database $dba)
 | 
			
		||||
	{
 | 
			
		||||
		$data = include $fixture;
 | 
			
		||||
 | 
			
		||||
		foreach ($data as $tableName => $rows) {
 | 
			
		||||
		foreach ($fixture as $tableName => $rows) {
 | 
			
		||||
			if (is_numeric($tableName)) {
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -77,4 +75,19 @@ trait DatabaseTestTrait
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Loads a given DB fixture-file for this DB test
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param string   $fixture The path to the fixture
 | 
			
		||||
	 * @param Database $dba     The DB connection
 | 
			
		||||
	 *
 | 
			
		||||
	 * @throws \Exception
 | 
			
		||||
	 */
 | 
			
		||||
	protected function loadFixture(string $fixture, Database $dba)
 | 
			
		||||
	{
 | 
			
		||||
		$data = include $fixture;
 | 
			
		||||
 | 
			
		||||
		$this->loadDirectFixture($data, $dba);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,7 +21,7 @@
 | 
			
		|||
 | 
			
		||||
namespace Friendica\Test\Util;
 | 
			
		||||
 | 
			
		||||
use Friendica\Core\Config\Model\Config;
 | 
			
		||||
use Friendica\Core\Config\Model\ReadOnlyFileConfig;
 | 
			
		||||
use Friendica\Core\Config\Util\ConfigFileManager;
 | 
			
		||||
use Friendica\Core\Config\ValueObject\Cache;
 | 
			
		||||
use Friendica\Database\Database;
 | 
			
		||||
| 
						 | 
				
			
			@ -37,16 +37,23 @@ trait CreateDatabaseTrait
 | 
			
		|||
	use DatabaseTestTrait;
 | 
			
		||||
	use VFSTrait;
 | 
			
		||||
 | 
			
		||||
	/** @var Database|null */
 | 
			
		||||
	protected $dba = null;
 | 
			
		||||
 | 
			
		||||
	public function getDbInstance(): Database
 | 
			
		||||
	{
 | 
			
		||||
		if (isset($this->dba)) {
 | 
			
		||||
			return $this->dba;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		$configFileManager = new ConfigFileManager($this->root->url(), $this->root->url() . '/config/', $this->root->url() . '/static/');
 | 
			
		||||
		$config            = new Config($configFileManager, new Cache([
 | 
			
		||||
		$config            = new ReadOnlyFileConfig(new Cache([
 | 
			
		||||
			'database' => [
 | 
			
		||||
				'disable_pdo' => true
 | 
			
		||||
			],
 | 
			
		||||
		]));
 | 
			
		||||
 | 
			
		||||
		$database = new StaticDatabase($config, new Profiler($config), (new DbaDefinition($this->root->url()))->load(), (new ViewDefinition($this->root->url()))->load(), new NullLogger());
 | 
			
		||||
		$database = new StaticDatabase($config, (new DbaDefinition($this->root->url()))->load(), (new ViewDefinition($this->root->url()))->load());
 | 
			
		||||
		$database->setTestmode(true);
 | 
			
		||||
 | 
			
		||||
		return $database;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -49,45 +49,38 @@ trait VFSTrait
 | 
			
		|||
		// create a virtual directory and copy all needed files and folders to it
 | 
			
		||||
		$this->root = vfsStream::setup('friendica', 0777, $structure);
 | 
			
		||||
 | 
			
		||||
		$this->setConfigFile('dbstructure.config.php', true);
 | 
			
		||||
		$this->setConfigFile('dbview.config.php', true);
 | 
			
		||||
		$this->setConfigFile('defaults.config.php', true);
 | 
			
		||||
		$this->setConfigFile('settings.config.php', true);
 | 
			
		||||
		$this->setConfigFile('local.config.php');
 | 
			
		||||
		$this->setDataFile('node.config.php');
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	protected function setDataFile(string $filename)
 | 
			
		||||
	{
 | 
			
		||||
		$file = dirname(__DIR__) . DIRECTORY_SEPARATOR .
 | 
			
		||||
				'datasets' . DIRECTORY_SEPARATOR .
 | 
			
		||||
				'config' . DIRECTORY_SEPARATOR .
 | 
			
		||||
				$filename;
 | 
			
		||||
 | 
			
		||||
		if (file_exists($file)) {
 | 
			
		||||
			vfsStream::newFile($filename)
 | 
			
		||||
				->at($this->root->getChild('config'))
 | 
			
		||||
				->setContent(file_get_contents($file));
 | 
			
		||||
		}
 | 
			
		||||
		$this->setConfigFile('static' . DIRECTORY_SEPARATOR . 'dbstructure.config.php', true);
 | 
			
		||||
		$this->setConfigFile('static' . DIRECTORY_SEPARATOR . 'dbview.config.php', true);
 | 
			
		||||
		$this->setConfigFile('static' . DIRECTORY_SEPARATOR . 'defaults.config.php', true);
 | 
			
		||||
		$this->setConfigFile('static' . DIRECTORY_SEPARATOR . 'settings.config.php', true);
 | 
			
		||||
		$this->setConfigFile(
 | 
			
		||||
			'mods' . DIRECTORY_SEPARATOR . 'local.config.ci.php',
 | 
			
		||||
			false, 'local.config.php'
 | 
			
		||||
		);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Copying a config file from the file system to the Virtual File System
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param string $filename The filename of the config file
 | 
			
		||||
	 * @param bool   $static   True, if the folder `static` instead of `config` should be used
 | 
			
		||||
	 * @param string $sourceFilePath The filename of the config file
 | 
			
		||||
	 * @param bool   $static         True, if the folder `static` instead of `config` should be used
 | 
			
		||||
	 */
 | 
			
		||||
	protected function setConfigFile(string $filename, bool $static = false)
 | 
			
		||||
	protected function setConfigFile(string $sourceFilePath, bool $static = false, string $targetFileName = null)
 | 
			
		||||
	{
 | 
			
		||||
		$file = dirname(__DIR__) . DIRECTORY_SEPARATOR .
 | 
			
		||||
			'..' . DIRECTORY_SEPARATOR .
 | 
			
		||||
			($static ? 'static' : 'config') . DIRECTORY_SEPARATOR .
 | 
			
		||||
			$filename;
 | 
			
		||||
				$sourceFilePath;
 | 
			
		||||
 | 
			
		||||
		if (file_exists($file)) {
 | 
			
		||||
			vfsStream::newFile($filename)
 | 
			
		||||
			if (empty($targetFileName)) {
 | 
			
		||||
				$tmpArray = preg_split('/\\' . DIRECTORY_SEPARATOR . '/', $sourceFilePath);
 | 
			
		||||
				$targetFileName = array_pop($tmpArray);
 | 
			
		||||
			}
 | 
			
		||||
			vfsStream::newFile($targetFileName)
 | 
			
		||||
				->at($this->root->getChild(($static ? 'static' : 'config')))
 | 
			
		||||
				->setContent(file_get_contents($file));
 | 
			
		||||
		} else {
 | 
			
		||||
			throw new \Exception(sprintf('Unexpected missing config \'%s\'', $file));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,8 +20,6 @@
 | 
			
		|||
 * This file is loaded by PHPUnit before any test.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
use Dice\Dice;
 | 
			
		||||
use Friendica\DI;
 | 
			
		||||
use PHPUnit\Framework\TestCase;
 | 
			
		||||
 | 
			
		||||
if (!file_exists(__DIR__ . '/../vendor/autoload.php')) {
 | 
			
		||||
| 
						 | 
				
			
			@ -34,8 +32,3 @@ require __DIR__ . '/../vendor/autoload.php';
 | 
			
		|||
if (!class_exists(TestCase::class)) {
 | 
			
		||||
	class_alias(\PHPUnit\Framework\TestCase::class, TestCase::class);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$dice = new Dice();
 | 
			
		||||
$dice = $dice->addRules(include  __DIR__ . '/../static/dependencies.config.php');
 | 
			
		||||
 | 
			
		||||
DI::init($dice);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,8 +21,10 @@
 | 
			
		|||
 | 
			
		||||
namespace Friendica\Test\src\Console;
 | 
			
		||||
 | 
			
		||||
use Dice\Dice;
 | 
			
		||||
use Friendica\Console\ServerBlock;
 | 
			
		||||
use Friendica\Core\Config\Capability\IManageConfigValues;
 | 
			
		||||
use Friendica\DI;
 | 
			
		||||
use Friendica\Moderation\DomainPatternBlocklist;
 | 
			
		||||
use Mockery;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -78,6 +80,11 @@ CONS;
 | 
			
		|||
	 */
 | 
			
		||||
	public function testAddBlockedServer()
 | 
			
		||||
	{
 | 
			
		||||
		$dice = new Dice();
 | 
			
		||||
		$dice = $dice->addRules(include  __DIR__ . '/../../../static/dependencies.config.php');
 | 
			
		||||
 | 
			
		||||
		DI::init($dice, true);
 | 
			
		||||
 | 
			
		||||
		$this->blocklistMock
 | 
			
		||||
			->shouldReceive('addPattern')
 | 
			
		||||
			->with('testme.now', 'I like it!')
 | 
			
		||||
| 
						 | 
				
			
			@ -98,6 +105,11 @@ CONS;
 | 
			
		|||
	 */
 | 
			
		||||
	public function testUpdateBlockedServer()
 | 
			
		||||
	{
 | 
			
		||||
		$dice = new Dice();
 | 
			
		||||
		$dice = $dice->addRules(include  __DIR__ . '/../../../static/dependencies.config.php');
 | 
			
		||||
 | 
			
		||||
		DI::init($dice, true);
 | 
			
		||||
 | 
			
		||||
		$this->blocklistMock
 | 
			
		||||
			->shouldReceive('addPattern')
 | 
			
		||||
			->with('pod.ordoevangelistarum.com', 'Other reason')
 | 
			
		||||
| 
						 | 
				
			
			@ -118,6 +130,11 @@ CONS;
 | 
			
		|||
	 */
 | 
			
		||||
	public function testRemoveBlockedServer()
 | 
			
		||||
	{
 | 
			
		||||
		$dice = new Dice();
 | 
			
		||||
		$dice = $dice->addRules(include  __DIR__ . '/../../../static/dependencies.config.php');
 | 
			
		||||
 | 
			
		||||
		DI::init($dice, true);
 | 
			
		||||
 | 
			
		||||
		$this->blocklistMock
 | 
			
		||||
			->shouldReceive('removePattern')
 | 
			
		||||
			->with('pod.ordoevangelistarum.com')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,19 +22,14 @@
 | 
			
		|||
namespace Friendica\Test\src\Core\Cache;
 | 
			
		||||
 | 
			
		||||
use Friendica\Core\Cache;
 | 
			
		||||
use Friendica\Core\Config\Factory\Config;
 | 
			
		||||
use Friendica\Database\Definition\DbaDefinition;
 | 
			
		||||
use Friendica\Database\Definition\ViewDefinition;
 | 
			
		||||
use Friendica\Test\DatabaseTestTrait;
 | 
			
		||||
use Friendica\Test\Util\Database\StaticDatabase;
 | 
			
		||||
use Friendica\Test\Util\CreateDatabaseTrait;
 | 
			
		||||
use Friendica\Test\Util\VFSTrait;
 | 
			
		||||
use Friendica\Util\Profiler;
 | 
			
		||||
use Mockery;
 | 
			
		||||
use Psr\Log\NullLogger;
 | 
			
		||||
 | 
			
		||||
class DatabaseCacheTest extends CacheTest
 | 
			
		||||
{
 | 
			
		||||
	use DatabaseTestTrait;
 | 
			
		||||
	use CreateDatabaseTrait;
 | 
			
		||||
	use VFSTrait;
 | 
			
		||||
 | 
			
		||||
	protected function setUp(): void
 | 
			
		||||
| 
						 | 
				
			
			@ -48,23 +43,7 @@ class DatabaseCacheTest extends CacheTest
 | 
			
		|||
 | 
			
		||||
	protected function getInstance()
 | 
			
		||||
	{
 | 
			
		||||
		$profiler = Mockery::mock(Profiler::class);
 | 
			
		||||
		$profiler->shouldReceive('startRecording');
 | 
			
		||||
		$profiler->shouldReceive('stopRecording');
 | 
			
		||||
		$profiler->shouldReceive('saveTimestamp')->withAnyArgs()->andReturn(true);
 | 
			
		||||
 | 
			
		||||
		// load real config to avoid mocking every config-entry which is related to the Database class
 | 
			
		||||
		$configFactory     = new Config();
 | 
			
		||||
		$configFileManager = (new Config())->createConfigFileManager($this->root->url(), []);
 | 
			
		||||
		$configCache       = $configFactory->createCache($configFileManager);
 | 
			
		||||
		$config            = new \Friendica\Core\Config\Model\Config($configFileManager, $configCache);
 | 
			
		||||
 | 
			
		||||
		$dbaDefinition  = (new DbaDefinition($configCache->get('system', 'basepath')))->load();
 | 
			
		||||
		$viewDefinition = (new ViewDefinition($configCache->get('system', 'basepath')))->load();
 | 
			
		||||
 | 
			
		||||
		$dba = new StaticDatabase($config, $profiler, $dbaDefinition, $viewDefinition, new NullLogger());
 | 
			
		||||
 | 
			
		||||
		$this->cache = new Cache\Type\DatabaseCache('database', $dba);
 | 
			
		||||
		$this->cache = new Cache\Type\DatabaseCache('database', $this->getDbInstance());
 | 
			
		||||
		return $this->cache;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -392,91 +392,6 @@ class ConfigFileManagerTest extends MockedTest
 | 
			
		|||
		self::assertEquals('newValue', $configCache->get('system', 'newKey'));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public function testSaveData()
 | 
			
		||||
	{
 | 
			
		||||
		$this->delConfigFile('local.config.php');
 | 
			
		||||
 | 
			
		||||
		$fileDir = dirname(__DIR__) . DIRECTORY_SEPARATOR .
 | 
			
		||||
				   '..' . DIRECTORY_SEPARATOR .
 | 
			
		||||
				   '..' . DIRECTORY_SEPARATOR .
 | 
			
		||||
				   '..' . DIRECTORY_SEPARATOR .
 | 
			
		||||
				   'datasets' . DIRECTORY_SEPARATOR .
 | 
			
		||||
				   'config' . DIRECTORY_SEPARATOR;
 | 
			
		||||
 | 
			
		||||
		vfsStream::newFile('B.config.php')
 | 
			
		||||
				 ->at($this->root->getChild('config2'))
 | 
			
		||||
				 ->setContent(file_get_contents($fileDir . 'B.config.php'));
 | 
			
		||||
 | 
			
		||||
		$configFileManager = (new Config())->createConfigFileManager($this->root->url(),
 | 
			
		||||
			[
 | 
			
		||||
				'FRIENDICA_CONFIG_DIR' => $this->root->getChild('config2')->url(),
 | 
			
		||||
			]);
 | 
			
		||||
		$configCache       = new Cache();
 | 
			
		||||
 | 
			
		||||
		$configFileManager->setupCache($configCache);
 | 
			
		||||
 | 
			
		||||
		$specialChars = '!"§$%&/()(/&%$\'><?$a,;:[]}{}\\?¿¿ß';
 | 
			
		||||
 | 
			
		||||
		// overwrite some data and save it back to the config file
 | 
			
		||||
		$configCache->set('system', 'test', 'it', Cache::SOURCE_DATA);
 | 
			
		||||
		$configCache->set('config', 'test', 'it', Cache::SOURCE_DATA);
 | 
			
		||||
		$configCache->set('system', 'test_2', 2, Cache::SOURCE_DATA);
 | 
			
		||||
		$configCache->set('special_chars', 'special', $specialChars, Cache::SOURCE_DATA);
 | 
			
		||||
		$configFileManager->saveData($configCache);
 | 
			
		||||
 | 
			
		||||
		// Reload the configCache with the new values
 | 
			
		||||
		$configCache2 = new Cache();
 | 
			
		||||
		$configFileManager->setupCache($configCache2);
 | 
			
		||||
 | 
			
		||||
		self::assertEquals($configCache, $configCache2);
 | 
			
		||||
		self::assertEquals([
 | 
			
		||||
			'system'        => [
 | 
			
		||||
				'test'   => 'it',
 | 
			
		||||
				'test_2' => 2
 | 
			
		||||
			],
 | 
			
		||||
			'config'        => [
 | 
			
		||||
				'test' => 'it',
 | 
			
		||||
			],
 | 
			
		||||
			'special_chars' => [
 | 
			
		||||
				'special' => $specialChars,
 | 
			
		||||
			]], $configCache2->getDataBySource(Cache::SOURCE_DATA));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * If we delete something with the Cache::delete() functionality, be sure to probably reset it to the underlying key
 | 
			
		||||
	 */
 | 
			
		||||
	public function testDeleteKeyOverwrite()
 | 
			
		||||
	{
 | 
			
		||||
		$this->delConfigFile('node.config.php');
 | 
			
		||||
 | 
			
		||||
		$fileDir = dirname(__DIR__) . DIRECTORY_SEPARATOR .
 | 
			
		||||
				   '..' . DIRECTORY_SEPARATOR .
 | 
			
		||||
				   '..' . DIRECTORY_SEPARATOR .
 | 
			
		||||
				   '..' . DIRECTORY_SEPARATOR .
 | 
			
		||||
				   'datasets' . DIRECTORY_SEPARATOR .
 | 
			
		||||
				   'config' . DIRECTORY_SEPARATOR;
 | 
			
		||||
 | 
			
		||||
		vfsStream::newFile('B.config.php')
 | 
			
		||||
				 ->at($this->root->getChild('config'))
 | 
			
		||||
				 ->setContent(file_get_contents($fileDir . 'B.config.php'));
 | 
			
		||||
 | 
			
		||||
		$configFileManager = (new Config())->createConfigFileManager($this->root->url());
 | 
			
		||||
		$configCache       = new Cache();
 | 
			
		||||
 | 
			
		||||
		$configFileManager->setupCache($configCache);
 | 
			
		||||
 | 
			
		||||
		$configCache->delete('system', 'default_timezone');
 | 
			
		||||
 | 
			
		||||
		$configFileManager->saveData($configCache);
 | 
			
		||||
 | 
			
		||||
		// assert that system.default_timezone is now the restored 'UTC' from the defaults
 | 
			
		||||
		$configCache       = new Cache();
 | 
			
		||||
 | 
			
		||||
		$configFileManager->setupCache($configCache);
 | 
			
		||||
 | 
			
		||||
		self::assertEquals('UTC', $configCache->get('system', 'default_timezone'));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Test for empty node.config.php
 | 
			
		||||
	 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,18 +23,20 @@ namespace Friendica\Test\src\Core\Config;
 | 
			
		|||
 | 
			
		||||
use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts;
 | 
			
		||||
use Friendica\Core\Config\Capability\IManageConfigValues;
 | 
			
		||||
use Friendica\Core\Config\Model\Config;
 | 
			
		||||
use Friendica\Core\Config\Model\DatabaseConfig;
 | 
			
		||||
use Friendica\Core\Config\Model\ReadOnlyFileConfig;
 | 
			
		||||
use Friendica\Core\Config\Util\ConfigFileManager;
 | 
			
		||||
use Friendica\Core\Config\Util\ConfigFileTransformer;
 | 
			
		||||
use Friendica\Core\Config\ValueObject\Cache;
 | 
			
		||||
use Friendica\Test\MockedTest;
 | 
			
		||||
use Friendica\Test\DatabaseTest;
 | 
			
		||||
use Friendica\Test\Util\CreateDatabaseTrait;
 | 
			
		||||
use Friendica\Test\Util\VFSTrait;
 | 
			
		||||
use org\bovigo\vfs\vfsStream;
 | 
			
		||||
 | 
			
		||||
class ConfigTest extends MockedTest
 | 
			
		||||
class ConfigTest extends DatabaseTest
 | 
			
		||||
{
 | 
			
		||||
	use ArraySubsetAsserts;
 | 
			
		||||
	use VFSTrait;
 | 
			
		||||
	use CreateDatabaseTrait;
 | 
			
		||||
 | 
			
		||||
	/** @var Cache */
 | 
			
		||||
	protected $configCache;
 | 
			
		||||
| 
						 | 
				
			
			@ -77,7 +79,7 @@ class ConfigTest extends MockedTest
 | 
			
		|||
	public function getInstance()
 | 
			
		||||
	{
 | 
			
		||||
		$this->configFileManager->setupCache($this->configCache);
 | 
			
		||||
		return new Config($this->configFileManager, $this->configCache);
 | 
			
		||||
		return new DatabaseConfig($this->getDbInstance(), $this->configCache);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public function dataTests()
 | 
			
		||||
| 
						 | 
				
			
			@ -162,15 +164,30 @@ class ConfigTest extends MockedTest
 | 
			
		|||
		];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public function configToDbArray(array $config): array
 | 
			
		||||
	{
 | 
			
		||||
		$dbarray = [];
 | 
			
		||||
 | 
			
		||||
		foreach ($config as $category => $data) {
 | 
			
		||||
			foreach ($data as $key => $value) {
 | 
			
		||||
				$dbarray[] = [
 | 
			
		||||
					'cat' => $category,
 | 
			
		||||
					'k'   => $key,
 | 
			
		||||
					'v'   => $value,
 | 
			
		||||
				];
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return ['config' => $dbarray];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Test the configuration initialization
 | 
			
		||||
	 * @dataProvider dataConfigLoad
 | 
			
		||||
	 */
 | 
			
		||||
	public function testSetUp(array $data)
 | 
			
		||||
	{
 | 
			
		||||
		vfsStream::newFile(ConfigFileManager::CONFIG_DATA_FILE)
 | 
			
		||||
				 ->at($this->root->getChild('config'))
 | 
			
		||||
				 ->setContent(ConfigFileTransformer::encode($data));
 | 
			
		||||
		$this->loadDirectFixture($this->configToDbArray($data) , $this->getDbInstance());
 | 
			
		||||
 | 
			
		||||
		$this->testedConfig = $this->getInstance();
 | 
			
		||||
		self::assertInstanceOf(Cache::class, $this->testedConfig->getCache());
 | 
			
		||||
| 
						 | 
				
			
			@ -189,9 +206,7 @@ class ConfigTest extends MockedTest
 | 
			
		|||
	 */
 | 
			
		||||
	public function testReload(array $data, array $load)
 | 
			
		||||
	{
 | 
			
		||||
		vfsStream::newFile(ConfigFileManager::CONFIG_DATA_FILE)
 | 
			
		||||
				 ->at($this->root->getChild('config'))
 | 
			
		||||
				 ->setContent(ConfigFileTransformer::encode($data));
 | 
			
		||||
		$this->loadDirectFixture($this->configToDbArray($data), $this->getDbInstance());
 | 
			
		||||
 | 
			
		||||
		$this->testedConfig = $this->getInstance();
 | 
			
		||||
		self::assertInstanceOf(Cache::class, $this->testedConfig->getCache());
 | 
			
		||||
| 
						 | 
				
			
			@ -274,9 +289,7 @@ class ConfigTest extends MockedTest
 | 
			
		|||
	 */
 | 
			
		||||
	public function testCacheLoadDouble(array $data1, array $data2, array $expect = [])
 | 
			
		||||
	{
 | 
			
		||||
		vfsStream::newFile(ConfigFileManager::CONFIG_DATA_FILE)
 | 
			
		||||
				 ->at($this->root->getChild('config'))
 | 
			
		||||
				 ->setContent(ConfigFileTransformer::encode($data1));
 | 
			
		||||
		$this->loadDirectFixture($this->configToDbArray($data1), $this->getDbInstance());
 | 
			
		||||
 | 
			
		||||
		$this->testedConfig = $this->getInstance();
 | 
			
		||||
		self::assertInstanceOf(Cache::class, $this->testedConfig->getCache());
 | 
			
		||||
| 
						 | 
				
			
			@ -286,9 +299,7 @@ class ConfigTest extends MockedTest
 | 
			
		|||
			self::assertConfig($cat, $data);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		vfsStream::newFile(ConfigFileManager::CONFIG_DATA_FILE)
 | 
			
		||||
				 ->at($this->root->getChild('config'))
 | 
			
		||||
				 ->setContent(ConfigFileTransformer::encode($data2));
 | 
			
		||||
		$this->loadDirectFixture($this->configToDbArray($data2), $this->getDbInstance());
 | 
			
		||||
 | 
			
		||||
		$this->testedConfig->reload();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -302,7 +313,7 @@ class ConfigTest extends MockedTest
 | 
			
		|||
	 */
 | 
			
		||||
	public function testLoadWrong()
 | 
			
		||||
	{
 | 
			
		||||
		$this->testedConfig = new Config($this->configFileManager, new Cache());
 | 
			
		||||
		$this->testedConfig = new ReadOnlyFileConfig(new Cache());
 | 
			
		||||
		self::assertInstanceOf(Cache::class, $this->testedConfig->getCache());
 | 
			
		||||
 | 
			
		||||
		self::assertEmpty($this->testedConfig->getCache()->getAll());
 | 
			
		||||
| 
						 | 
				
			
			@ -354,7 +365,7 @@ class ConfigTest extends MockedTest
 | 
			
		|||
	{
 | 
			
		||||
		$this->configCache->load(['test' => ['it' => $data]], Cache::SOURCE_FILE);
 | 
			
		||||
 | 
			
		||||
		$this->testedConfig = new Config($this->configFileManager, $this->configCache);
 | 
			
		||||
		$this->testedConfig = new DatabaseConfig($this->getDbInstance(), $this->configCache);
 | 
			
		||||
		self::assertInstanceOf(Cache::class, $this->testedConfig->getCache());
 | 
			
		||||
 | 
			
		||||
		self::assertEquals($data, $this->testedConfig->get('test', 'it'));
 | 
			
		||||
| 
						 | 
				
			
			@ -386,19 +397,15 @@ class ConfigTest extends MockedTest
 | 
			
		|||
	 */
 | 
			
		||||
	public function testSetGetLowPrio()
 | 
			
		||||
	{
 | 
			
		||||
		vfsStream::newFile(ConfigFileManager::CONFIG_DATA_FILE)
 | 
			
		||||
				 ->at($this->root->getChild('config'))
 | 
			
		||||
				 ->setContent(ConfigFileTransformer::encode([
 | 
			
		||||
					 'config' => ['test' => 'it'],
 | 
			
		||||
				 ]));
 | 
			
		||||
		$this->loadDirectFixture(['config' => [['cat' => 'config', 'k' => 'test', 'v' => 'it']]], $this->getDbInstance());
 | 
			
		||||
 | 
			
		||||
		$this->testedConfig = $this->getInstance();
 | 
			
		||||
		self::assertInstanceOf(Cache::class, $this->testedConfig->getCache());
 | 
			
		||||
		self::assertEquals('it', $this->testedConfig->get('config', 'test'));
 | 
			
		||||
 | 
			
		||||
		$this->testedConfig->getCache()->set('config', 'test', 'prio', Cache::SOURCE_ENV);
 | 
			
		||||
		// now you have to get the env variable entry as output, even with a new set (which failed) and a get refresh
 | 
			
		||||
		self::assertFalse($this->testedConfig->set('config', 'test', '123'));
 | 
			
		||||
		// You can set a config value, but if there's a value with a higher priority (environment), this value will persist when retrieving
 | 
			
		||||
		self::assertTrue($this->testedConfig->set('config', 'test', '123'));
 | 
			
		||||
		self::assertEquals('prio', $this->testedConfig->get('config', 'test', '', true));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -526,26 +533,8 @@ class ConfigTest extends MockedTest
 | 
			
		|||
	public function testGetCategory(array $data, string $category, array $assertion)
 | 
			
		||||
	{
 | 
			
		||||
		$this->configCache = new Cache($data);
 | 
			
		||||
		$config = new Config($this->configFileManager, $this->configCache);
 | 
			
		||||
		$config = new ReadOnlyFileConfig($this->configCache);
 | 
			
		||||
 | 
			
		||||
		self::assertEquals($assertion, $config->get($category));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Tests, if an overwritten value of an existing key will reset to it's default after deletion
 | 
			
		||||
	 */
 | 
			
		||||
	public function testDeleteReturnsDefault()
 | 
			
		||||
	{
 | 
			
		||||
		vfsStream::newFile(ConfigFileManager::CONFIG_DATA_FILE)
 | 
			
		||||
				 ->at($this->root->getChild('config'))
 | 
			
		||||
				 ->setContent(ConfigFileTransformer::encode([
 | 
			
		||||
					 'config' => ['sitename' => 'overritten'],
 | 
			
		||||
				 ]));
 | 
			
		||||
 | 
			
		||||
		$config = $this->getInstance();
 | 
			
		||||
		self::assertEquals('overritten', $config->get('config', 'sitename'));
 | 
			
		||||
 | 
			
		||||
		$config->delete('config', 'sitename');
 | 
			
		||||
		self::assertEquals('Friendica Social Network', $config->get('config', 'sitename'));
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,18 +22,21 @@
 | 
			
		|||
namespace Friendica\Test\src\Core\Config;
 | 
			
		||||
 | 
			
		||||
use Friendica\Core\Config\Capability\ISetConfigValuesTransactionally;
 | 
			
		||||
use Friendica\Core\Config\Model\Config;
 | 
			
		||||
use Friendica\Core\Config\Model\DatabaseConfig;
 | 
			
		||||
use Friendica\Core\Config\Model\ReadOnlyFileConfig;
 | 
			
		||||
use Friendica\Core\Config\Model\ConfigTransaction;
 | 
			
		||||
use Friendica\Core\Config\Util\ConfigFileManager;
 | 
			
		||||
use Friendica\Core\Config\ValueObject\Cache;
 | 
			
		||||
use Friendica\Database\Database;
 | 
			
		||||
use Friendica\Test\DatabaseTest;
 | 
			
		||||
use Friendica\Test\FixtureTest;
 | 
			
		||||
use Friendica\Test\MockedTest;
 | 
			
		||||
use Friendica\Test\Util\Database\StaticDatabase;
 | 
			
		||||
use Friendica\Test\Util\VFSTrait;
 | 
			
		||||
use Mockery\Exception\InvalidCountException;
 | 
			
		||||
 | 
			
		||||
class ConfigTransactionTest extends MockedTest
 | 
			
		||||
class ConfigTransactionTest extends FixtureTest
 | 
			
		||||
{
 | 
			
		||||
	use VFSTrait;
 | 
			
		||||
 | 
			
		||||
	/** @var ConfigFileManager */
 | 
			
		||||
	protected $configFileManager;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -41,8 +44,6 @@ class ConfigTransactionTest extends MockedTest
 | 
			
		|||
	{
 | 
			
		||||
		parent::setUp();
 | 
			
		||||
 | 
			
		||||
		$this->setUpVfsDir();
 | 
			
		||||
 | 
			
		||||
		$this->configFileManager = new ConfigFileManager($this->root->url(), $this->root->url() . '/config/', $this->root->url() . '/static/');
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -57,7 +58,7 @@ class ConfigTransactionTest extends MockedTest
 | 
			
		|||
 | 
			
		||||
	public function testInstance()
 | 
			
		||||
	{
 | 
			
		||||
		$config            = new Config($this->configFileManager, new Cache());
 | 
			
		||||
		$config            = new DatabaseConfig($this->dice->create(Database::class), new Cache());
 | 
			
		||||
		$configTransaction = new ConfigTransaction($config);
 | 
			
		||||
 | 
			
		||||
		self::assertInstanceOf(ISetConfigValuesTransactionally::class, $configTransaction);
 | 
			
		||||
| 
						 | 
				
			
			@ -66,17 +67,13 @@ class ConfigTransactionTest extends MockedTest
 | 
			
		|||
 | 
			
		||||
	public function testConfigTransaction()
 | 
			
		||||
	{
 | 
			
		||||
		$config = new Config($this->configFileManager, new Cache());
 | 
			
		||||
		$config = new DatabaseConfig($this->dice->create(Database::class), new Cache());
 | 
			
		||||
		$config->set('config', 'key1', 'value1');
 | 
			
		||||
		$config->set('system', 'key2', 'value2');
 | 
			
		||||
		$config->set('system', 'keyDel', 'valueDel');
 | 
			
		||||
		$config->set('delete', 'keyDel', 'catDel');
 | 
			
		||||
 | 
			
		||||
		$configTransaction = new ConfigTransaction($config);
 | 
			
		||||
		// the config file knows it as well immediately
 | 
			
		||||
		$tempData = include $this->root->url() . '/config/' . ConfigFileManager::CONFIG_DATA_FILE;
 | 
			
		||||
		self::assertEquals('value1', $tempData['config']['key1'] ?? null);
 | 
			
		||||
		self::assertEquals('value2', $tempData['system']['key2'] ?? null);
 | 
			
		||||
 | 
			
		||||
		// new key-value
 | 
			
		||||
		$configTransaction->set('transaction', 'key3', 'value3');
 | 
			
		||||
| 
						 | 
				
			
			@ -93,11 +90,6 @@ class ConfigTransactionTest extends MockedTest
 | 
			
		|||
		self::assertEquals('valueDel', $config->get('system', 'keyDel'));
 | 
			
		||||
		self::assertEquals('catDel', $config->get('delete', 'keyDel'));
 | 
			
		||||
		// The config file still doesn't know it either
 | 
			
		||||
		$tempData = include $this->root->url() . '/config/' . ConfigFileManager::CONFIG_DATA_FILE;
 | 
			
		||||
		self::assertEquals('value1', $tempData['config']['key1'] ?? null);
 | 
			
		||||
		self::assertEquals('value2', $tempData['system']['key2'] ?? null);
 | 
			
		||||
		self::assertEquals('catDel', $tempData['delete']['keyDel'] ?? null);
 | 
			
		||||
		self::assertNull($tempData['transaction']['key3'] ?? null);
 | 
			
		||||
 | 
			
		||||
		// save it back!
 | 
			
		||||
		$configTransaction->commit();
 | 
			
		||||
| 
						 | 
				
			
			@ -107,12 +99,6 @@ class ConfigTransactionTest extends MockedTest
 | 
			
		|||
		self::assertEquals('value3', $config->get('transaction', 'key3'));
 | 
			
		||||
		self::assertNull($config->get('system', 'keyDel'));
 | 
			
		||||
		self::assertNull($config->get('delete', 'keyDel'));
 | 
			
		||||
		$tempData = include $this->root->url() . '/config/' . ConfigFileManager::CONFIG_DATA_FILE;
 | 
			
		||||
		self::assertEquals('changedValue1', $tempData['config']['key1'] ?? null);
 | 
			
		||||
		self::assertEquals('value2', $tempData['system']['key2'] ?? null);
 | 
			
		||||
		self::assertEquals('value3', $tempData['transaction']['key3'] ?? null);
 | 
			
		||||
		self::assertNull($tempData['system']['keyDel'] ?? null);
 | 
			
		||||
		self::assertNull($tempData['delete']['keyDel'] ?? null);
 | 
			
		||||
		// the whole category should be gone
 | 
			
		||||
		self::assertNull($tempData['delete'] ?? null);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -124,7 +110,7 @@ class ConfigTransactionTest extends MockedTest
 | 
			
		|||
	{
 | 
			
		||||
		$this->configFileManager = \Mockery::spy(ConfigFileManager::class);
 | 
			
		||||
 | 
			
		||||
		$config = new Config($this->configFileManager, new Cache());
 | 
			
		||||
		$config = new DatabaseConfig($this->dice->create(Database::class), new Cache());
 | 
			
		||||
		$configTransaction = new ConfigTransaction($config);
 | 
			
		||||
 | 
			
		||||
		// commit empty transaction
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,110 +0,0 @@
 | 
			
		|||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * @copyright Copyright (C) 2010-2023, the Friendica project
 | 
			
		||||
 *
 | 
			
		||||
 * @license GNU AGPL version 3 or any later version
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as
 | 
			
		||||
 * published by the Free Software Foundation, either version 3 of the
 | 
			
		||||
 * License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace Friendica\Test\src\Core\Config\Util;
 | 
			
		||||
 | 
			
		||||
use Friendica\Core\Config\Util\ConfigFileTransformer;
 | 
			
		||||
use Friendica\Test\MockedTest;
 | 
			
		||||
use Friendica\Test\Util\SerializableObjectDouble;
 | 
			
		||||
use ParagonIE\HiddenString\HiddenString;
 | 
			
		||||
use function PHPUnit\Framework\assertEquals;
 | 
			
		||||
 | 
			
		||||
class ConfigFileTransformerTest extends MockedTest
 | 
			
		||||
{
 | 
			
		||||
	public function dataTests()
 | 
			
		||||
	{
 | 
			
		||||
		return [
 | 
			
		||||
			'default' => [
 | 
			
		||||
				'configFile' => (dirname(__DIR__, 4) . '/datasets/config/A.node.config.php'),
 | 
			
		||||
			],
 | 
			
		||||
			'extended' => [
 | 
			
		||||
				'configFile' => (dirname(__DIR__, 4) . '/datasets/config/B.node.config.php'),
 | 
			
		||||
			],
 | 
			
		||||
			'friendica.local' => [
 | 
			
		||||
				'configFile' => (dirname(__DIR__, 4) . '/datasets/config/transformer/C.node.config.php'),
 | 
			
		||||
			],
 | 
			
		||||
			'friendica.local.2' => [
 | 
			
		||||
				'configFile' => (dirname(__DIR__, 4) . '/datasets/config/transformer/D.node.config.php'),
 | 
			
		||||
			],
 | 
			
		||||
			'object_invalid' => [
 | 
			
		||||
				'configFile' => (dirname(__DIR__, 4) . '/datasets/config/transformer/object.node.config.php'),
 | 
			
		||||
				'assertException' => true,
 | 
			
		||||
			],
 | 
			
		||||
			'resource' => [
 | 
			
		||||
				'configFile' => (dirname(__DIR__, 4) . '/datasets/config/transformer/ressource.node.config.php'),
 | 
			
		||||
				'assertException' => false,
 | 
			
		||||
				'assertion' => <<<EOF
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
return [
 | 
			
		||||
	'ressource' => [
 | 
			
		||||
		'ressources_not_allowed' => '',
 | 
			
		||||
	],
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
EOF,
 | 
			
		||||
			],
 | 
			
		||||
			'object_valid' => [
 | 
			
		||||
				'configFile' => (dirname(__DIR__, 4) . '/datasets/config/transformer/object_valid.node.config.php'),
 | 
			
		||||
				'assertException' => false,
 | 
			
		||||
				'assertion' => <<<EOF
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
return [
 | 
			
		||||
	'object' => [
 | 
			
		||||
		'toString' => 'test',
 | 
			
		||||
		'serializable' => 'serialized',
 | 
			
		||||
	],
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
EOF,
 | 
			
		||||
			],
 | 
			
		||||
			'test_types' => [
 | 
			
		||||
				'configFile' => (dirname(__DIR__, 4) . '/datasets/config/transformer/types.node.config.php'),
 | 
			
		||||
			],
 | 
			
		||||
			'small_types' => [
 | 
			
		||||
				'configFile' => (dirname(__DIR__, 4) . '/datasets/config/transformer/small_types.node.config.php'),
 | 
			
		||||
			]
 | 
			
		||||
		];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Tests if the given config will be decoded into an array and encoded into the same string again
 | 
			
		||||
	 *
 | 
			
		||||
	 * @dataProvider dataTests
 | 
			
		||||
	 */
 | 
			
		||||
	public function testConfigFile(string $configFile, bool $assertException = false, $assertion = null)
 | 
			
		||||
	{
 | 
			
		||||
		$dataArray = include $configFile;
 | 
			
		||||
 | 
			
		||||
		if ($assertException) {
 | 
			
		||||
			self::expectException(\InvalidArgumentException::class);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		$newConfig = ConfigFileTransformer::encode($dataArray);
 | 
			
		||||
 | 
			
		||||
		if (empty($assertion)) {
 | 
			
		||||
			self::assertEquals(file_get_contents($configFile), $newConfig);
 | 
			
		||||
		} else {
 | 
			
		||||
			self::assertEquals($assertion, $newConfig);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -63,7 +63,7 @@ class InstallerTest extends MockedTest
 | 
			
		|||
		           ->with(L10n::class)
 | 
			
		||||
		           ->andReturn($this->l10nMock);
 | 
			
		||||
 | 
			
		||||
		DI::init($this->dice);
 | 
			
		||||
		DI::init($this->dice, true);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static function tearDownAfterClass(): void
 | 
			
		||||
| 
						 | 
				
			
			@ -361,7 +361,7 @@ class InstallerTest extends MockedTest
 | 
			
		|||
		     ->with(ICanSendHttpRequests::class)
 | 
			
		||||
		     ->andReturn($networkMock);
 | 
			
		||||
 | 
			
		||||
		DI::init($this->dice);
 | 
			
		||||
		DI::init($this->dice, true);
 | 
			
		||||
 | 
			
		||||
		// Mocking that we can use CURL
 | 
			
		||||
		$this->setFunctions(['curl_init' => true]);
 | 
			
		||||
| 
						 | 
				
			
			@ -408,7 +408,7 @@ class InstallerTest extends MockedTest
 | 
			
		|||
		           ->with(ICanSendHttpRequests::class)
 | 
			
		||||
		           ->andReturn($networkMock);
 | 
			
		||||
 | 
			
		||||
		DI::init($this->dice);
 | 
			
		||||
		DI::init($this->dice, true);
 | 
			
		||||
 | 
			
		||||
		// Mocking that we can use CURL
 | 
			
		||||
		$this->setFunctions(['curl_init' => true]);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,11 +24,8 @@ namespace Friendica\Test\src\Core\Lock;
 | 
			
		|||
use Dice\Dice;
 | 
			
		||||
use Friendica\App;
 | 
			
		||||
use Friendica\Core\Config\Capability\IManageConfigValues;
 | 
			
		||||
use Friendica\Core\Config\Model\Config;
 | 
			
		||||
use Friendica\Core\Config\Type\JitConfig;
 | 
			
		||||
use Friendica\Core\Config\Util\ConfigFileManager;
 | 
			
		||||
use Friendica\Core\Config\Model\ReadOnlyFileConfig;
 | 
			
		||||
use Friendica\Core\Config\ValueObject\Cache;
 | 
			
		||||
use Friendica\Core\Lock\Type\SemaphoreLock;
 | 
			
		||||
use Friendica\Core\System;
 | 
			
		||||
use Friendica\DI;
 | 
			
		||||
use Mockery;
 | 
			
		||||
| 
						 | 
				
			
			@ -46,11 +43,11 @@ class SemaphoreLockTest extends LockTest
 | 
			
		|||
		$dice->shouldReceive('create')->with(App::class)->andReturn($app);
 | 
			
		||||
 | 
			
		||||
		$configCache = new Cache(['system' => ['temppath' => '/tmp']]);
 | 
			
		||||
		$configMock = new Config(Mockery::mock(ConfigFileManager::class), $configCache);
 | 
			
		||||
		$configMock = new ReadOnlyFileConfig($configCache);
 | 
			
		||||
		$dice->shouldReceive('create')->with(IManageConfigValues::class)->andReturn($configMock);
 | 
			
		||||
 | 
			
		||||
		// @todo Because "get_temppath()" is using static methods, we have to initialize the BaseObject
 | 
			
		||||
		DI::init($dice);
 | 
			
		||||
		DI::init($dice, true);
 | 
			
		||||
 | 
			
		||||
		parent::setUp();
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -75,19 +75,19 @@ class StorageManagerTest extends DatabaseTest
 | 
			
		|||
		vfsStream::newDirectory(Type\FilesystemConfig::DEFAULT_BASE_FOLDER, 0777)->at($this->root);
 | 
			
		||||
 | 
			
		||||
		$this->logger = new NullLogger();
 | 
			
		||||
		$this->database = $this->getDbInstance();
 | 
			
		||||
 | 
			
		||||
		$configFactory     = new Config();
 | 
			
		||||
		$configFileManager = $configFactory->createConfigFileManager($this->root->url());
 | 
			
		||||
		$configCache       = $configFactory->createCache($configFileManager);
 | 
			
		||||
 | 
			
		||||
		$this->config = new \Friendica\Core\Config\Model\Config($configFileManager, $configCache);
 | 
			
		||||
		$this->config = new \Friendica\Core\Config\Model\DatabaseConfig($this->database, $configCache);
 | 
			
		||||
		$this->config->set('storage', 'name', 'Database');
 | 
			
		||||
		$this->config->set('storage', 'filesystem_path', $this->root->getChild(Type\FilesystemConfig::DEFAULT_BASE_FOLDER)
 | 
			
		||||
																	->url());
 | 
			
		||||
 | 
			
		||||
		$this->l10n = \Mockery::mock(L10n::class);
 | 
			
		||||
 | 
			
		||||
		$this->database = $this->getDbInstance();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	protected function tearDown(): void
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,7 +36,7 @@ class SystemTest extends TestCase
 | 
			
		|||
		$dice = \Mockery::mock(Dice::class);
 | 
			
		||||
		$dice->shouldReceive('create')->with(BaseURL::class)->andReturn($baseUrl);
 | 
			
		||||
 | 
			
		||||
		DI::init($dice);
 | 
			
		||||
		DI::init($dice, true);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private function assertGuid($guid, $length, $prefix = '')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,7 +47,7 @@ class UserTest extends MockedTest
 | 
			
		|||
		/** @var Dice|MockInterface $diceMock */
 | 
			
		||||
		$diceMock = $diceMock->addRules(include __DIR__ . '/../../../static/dependencies.config.php');
 | 
			
		||||
		$diceMock->shouldReceive('create')->withArgs([Database::class])->andReturn($this->dbMock);
 | 
			
		||||
		DI::init($diceMock);
 | 
			
		||||
		DI::init($diceMock, true);
 | 
			
		||||
 | 
			
		||||
		$this->parent = [
 | 
			
		||||
			'uid'      => 1,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -41,12 +41,12 @@ class ConfigTest extends ApiTest
 | 
			
		|||
			->run($this->httpExceptionMock);
 | 
			
		||||
		$json = $this->toJson($response);
 | 
			
		||||
 | 
			
		||||
		self::assertEquals('localhost', $json->site->server);
 | 
			
		||||
		self::assertEquals('frio', $json->site->theme);
 | 
			
		||||
		self::assertEquals(DI::config()->get('config', 'hostname'), $json->site->server);
 | 
			
		||||
		self::assertEquals(DI::config()->get('system', 'theme'), $json->site->theme);
 | 
			
		||||
		self::assertEquals(DI::baseUrl() . '/images/friendica-64.png', $json->site->logo);
 | 
			
		||||
		self::assertTrue($json->site->fancy);
 | 
			
		||||
		self::assertEquals('en', $json->site->language);
 | 
			
		||||
		self::assertEquals('UTC', $json->site->timezone);
 | 
			
		||||
		self::assertEquals(DI::config()->get('system', 'language'), $json->site->language);
 | 
			
		||||
		self::assertEquals(DI::config()->get('system', 'default_timezone'), $json->site->timezone);
 | 
			
		||||
		self::assertEquals(200000, $json->site->textlimit);
 | 
			
		||||
		self::assertFalse($json->site->private);
 | 
			
		||||
		self::assertEquals('always', $json->site->ssl);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,32 +21,12 @@
 | 
			
		|||
 | 
			
		||||
namespace Friendica\Test\src\Network\HTTPClient\Response;
 | 
			
		||||
 | 
			
		||||
use Dice\Dice;
 | 
			
		||||
use Friendica\DI;
 | 
			
		||||
use Friendica\Network\HTTPClient\Response\CurlResult;
 | 
			
		||||
use Mockery\MockInterface;
 | 
			
		||||
use PHPUnit\Framework\TestCase;
 | 
			
		||||
use Psr\Log\LoggerInterface;
 | 
			
		||||
use Psr\Log\NullLogger;
 | 
			
		||||
 | 
			
		||||
class CurlResultTest extends TestCase
 | 
			
		||||
{
 | 
			
		||||
	protected function setUp(): void
 | 
			
		||||
	{
 | 
			
		||||
		parent::setUp();
 | 
			
		||||
 | 
			
		||||
		/** @var Dice|MockInterface $dice */
 | 
			
		||||
		$dice = \Mockery::mock(Dice::class)->makePartial();
 | 
			
		||||
		$dice = $dice->addRules(include __DIR__ . '/../../../../../static/dependencies.config.php');
 | 
			
		||||
 | 
			
		||||
		$logger = new NullLogger();
 | 
			
		||||
		$dice->shouldReceive('create')
 | 
			
		||||
		           ->with(LoggerInterface::class)
 | 
			
		||||
		           ->andReturn($logger);
 | 
			
		||||
 | 
			
		||||
		DI::init($dice);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @small
 | 
			
		||||
	 */
 | 
			
		||||
| 
						 | 
				
			
			@ -57,7 +37,7 @@ class CurlResultTest extends TestCase
 | 
			
		|||
		$body = file_get_contents(__DIR__ . '/../../../../datasets/curl/about.body');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		$curlResult = new \Friendica\Network\HTTPClient\Response\CurlResult('https://test.local', $header . $body, [
 | 
			
		||||
		$curlResult = new \Friendica\Network\HTTPClient\Response\CurlResult(new NullLogger(),'https://test.local', $header . $body, [
 | 
			
		||||
			'http_code' => 200,
 | 
			
		||||
			'content_type' => 'text/html; charset=utf-8',
 | 
			
		||||
			'url' => 'https://test.local'
 | 
			
		||||
| 
						 | 
				
			
			@ -85,7 +65,7 @@ class CurlResultTest extends TestCase
 | 
			
		|||
		$body = file_get_contents(__DIR__ . '/../../../../datasets/curl/about.body');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		$curlResult = new \Friendica\Network\HTTPClient\Response\CurlResult('https://test.local/test/it', $header . $body, [
 | 
			
		||||
		$curlResult = new \Friendica\Network\HTTPClient\Response\CurlResult(new NullLogger(),'https://test.local/test/it', $header . $body, [
 | 
			
		||||
			'http_code' => 301,
 | 
			
		||||
			'content_type' => 'text/html; charset=utf-8',
 | 
			
		||||
			'url' => 'https://test.local/test/it',
 | 
			
		||||
| 
						 | 
				
			
			@ -112,7 +92,7 @@ class CurlResultTest extends TestCase
 | 
			
		|||
		$body = file_get_contents(__DIR__ . '/../../../../datasets/curl/about.body');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		$curlResult = new \Friendica\Network\HTTPClient\Response\CurlResult('https://test.local/test/it', $header . $body, [
 | 
			
		||||
		$curlResult = new \Friendica\Network\HTTPClient\Response\CurlResult(new NullLogger(),'https://test.local/test/it', $header . $body, [
 | 
			
		||||
			'http_code' => 500,
 | 
			
		||||
			'content_type' => 'text/html; charset=utf-8',
 | 
			
		||||
			'url' => 'https://test.local/test/it',
 | 
			
		||||
| 
						 | 
				
			
			@ -141,7 +121,7 @@ class CurlResultTest extends TestCase
 | 
			
		|||
		$body = file_get_contents(__DIR__ . '/../../../../datasets/curl/about.body');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		$curlResult = new CurlResult('https://test.local/test/it?key=value', $header . $body, [
 | 
			
		||||
		$curlResult = new CurlResult(new NullLogger(),'https://test.local/test/it?key=value', $header . $body, [
 | 
			
		||||
			'http_code' => 301,
 | 
			
		||||
			'content_type' => 'text/html; charset=utf-8',
 | 
			
		||||
			'url' => 'https://test.local/test/it?key=value',
 | 
			
		||||
| 
						 | 
				
			
			@ -165,7 +145,7 @@ class CurlResultTest extends TestCase
 | 
			
		|||
		$header = file_get_contents(__DIR__ . '/../../../../datasets/curl/about.head');
 | 
			
		||||
		$body = file_get_contents(__DIR__ . '/../../../../datasets/curl/about.body');
 | 
			
		||||
 | 
			
		||||
		$curlResult = new \Friendica\Network\HTTPClient\Response\CurlResult('https://test.local', $header . $body, [
 | 
			
		||||
		$curlResult = new \Friendica\Network\HTTPClient\Response\CurlResult(new NullLogger(),'https://test.local', $header . $body, [
 | 
			
		||||
			'http_code' => 200,
 | 
			
		||||
			'content_type' => 'text/html; charset=utf-8',
 | 
			
		||||
			'url' => 'https://test.local'
 | 
			
		||||
| 
						 | 
				
			
			@ -182,7 +162,7 @@ class CurlResultTest extends TestCase
 | 
			
		|||
		$header = file_get_contents(__DIR__ . '/../../../../datasets/curl/about.head');
 | 
			
		||||
		$body = file_get_contents(__DIR__ . '/../../../../datasets/curl/about.body');
 | 
			
		||||
 | 
			
		||||
		$curlResult = new \Friendica\Network\HTTPClient\Response\CurlResult('https://test.local', $header . $body, [
 | 
			
		||||
		$curlResult = new \Friendica\Network\HTTPClient\Response\CurlResult(new NullLogger(), 'https://test.local', $header . $body, [
 | 
			
		||||
			'http_code' => 200,
 | 
			
		||||
			'content_type' => 'text/html; charset=utf-8',
 | 
			
		||||
			'url' => 'https://test.local'
 | 
			
		||||
| 
						 | 
				
			
			@ -202,7 +182,7 @@ class CurlResultTest extends TestCase
 | 
			
		|||
		$header = file_get_contents(__DIR__ . '/../../../../datasets/curl/about.head');
 | 
			
		||||
		$body = file_get_contents(__DIR__ . '/../../../../datasets/curl/about.body');
 | 
			
		||||
 | 
			
		||||
		$curlResult = new CurlResult('https://test.local', $header . $body, [
 | 
			
		||||
		$curlResult = new CurlResult(new NullLogger(),'https://test.local', $header . $body, [
 | 
			
		||||
			'http_code' => 200,
 | 
			
		||||
			'content_type' => 'text/html; charset=utf-8',
 | 
			
		||||
			'url' => 'https://test.local'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,15 +23,18 @@ namespace Friendica\Test\src\Util;
 | 
			
		|||
 | 
			
		||||
use Friendica\App\BaseURL;
 | 
			
		||||
use Friendica\Core\Config\Capability\IManageConfigValues;
 | 
			
		||||
use Friendica\Core\Config\Model\Config;
 | 
			
		||||
use Friendica\Core\Config\Model\DatabaseConfig;
 | 
			
		||||
use Friendica\Core\Config\Model\ReadOnlyFileConfig;
 | 
			
		||||
use Friendica\Core\Config\Util\ConfigFileManager;
 | 
			
		||||
use Friendica\Core\Config\ValueObject\Cache;
 | 
			
		||||
use Friendica\Test\MockedTest;
 | 
			
		||||
use Friendica\Test\DatabaseTest;
 | 
			
		||||
use Friendica\Test\Util\CreateDatabaseTrait;
 | 
			
		||||
use Friendica\Test\Util\VFSTrait;
 | 
			
		||||
 | 
			
		||||
class BaseURLTest extends MockedTest
 | 
			
		||||
class BaseURLTest extends DatabaseTest
 | 
			
		||||
{
 | 
			
		||||
	use VFSTrait;
 | 
			
		||||
	use CreateDatabaseTrait;
 | 
			
		||||
 | 
			
		||||
	protected function setUp(): void
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			@ -302,8 +305,7 @@ class BaseURLTest extends MockedTest
 | 
			
		|||
	 */
 | 
			
		||||
	public function testSave($input, $save, $url)
 | 
			
		||||
	{
 | 
			
		||||
		$configFileManager = new ConfigFileManager($this->root->url(), $this->root->url() . '/config/', $this->root->url() . '/static/');
 | 
			
		||||
		$config = new Config($configFileManager, new Cache([
 | 
			
		||||
		$config = new DatabaseConfig($this->getDbInstance(), new Cache([
 | 
			
		||||
			'config' => [
 | 
			
		||||
				'hostname' => $input['hostname'] ?? null,
 | 
			
		||||
			],
 | 
			
		||||
| 
						 | 
				
			
			@ -332,8 +334,7 @@ class BaseURLTest extends MockedTest
 | 
			
		|||
	 */
 | 
			
		||||
	public function testSaveByUrl($input, $save, $url)
 | 
			
		||||
	{
 | 
			
		||||
		$configFileManager = new ConfigFileManager($this->root->url(), $this->root->url() . '/config/', $this->root->url() . '/static/');
 | 
			
		||||
		$config = new Config($configFileManager, new Cache([
 | 
			
		||||
		$config = new DatabaseConfig($this->getDbInstance(), new Cache([
 | 
			
		||||
			'config' => [
 | 
			
		||||
				'hostname' => $input['hostname'] ?? null,
 | 
			
		||||
			],
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										34
									
								
								update.php
									
										
									
									
									
								
							
							
						
						
									
										34
									
								
								update.php
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1253,3 +1253,37 @@ function update_1513()
 | 
			
		|||
	DI::config()->delete('system', 'git_friendica_version');
 | 
			
		||||
	DI::config()->delete('twitter', 'application_name');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function update_1514()
 | 
			
		||||
{
 | 
			
		||||
	if (file_exists(dirname(__FILE__) . '/config/node.config.php')) {
 | 
			
		||||
 | 
			
		||||
		$transactionalConfig = DI::config()->beginTransaction();
 | 
			
		||||
		$oldConfig = include dirname(__FILE__) . '/config/node.config.php';
 | 
			
		||||
 | 
			
		||||
		if (is_array($oldConfig)) {
 | 
			
		||||
			$categories = array_keys($oldConfig);
 | 
			
		||||
 | 
			
		||||
			foreach ($categories as $category) {
 | 
			
		||||
				if (is_array($oldConfig[$category])) {
 | 
			
		||||
					$keys = array_keys($oldConfig[$category]);
 | 
			
		||||
 | 
			
		||||
					foreach ($keys as $key) {
 | 
			
		||||
						$transactionalConfig->set($category, $key, $oldConfig[$category][$key]);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		$transactionalConfig->commit();
 | 
			
		||||
 | 
			
		||||
		// Rename the node.config.php so it won't get used, but it isn't deleted.
 | 
			
		||||
		if (rename(dirname(__FILE__) . '/config/node.config.php', dirname(__FILE__) . '/config/node.config.php.bak')) {
 | 
			
		||||
			return Update::SUCCESS;
 | 
			
		||||
		} else {
 | 
			
		||||
			return Update::FAILED;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Update::SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,7 @@ msgid ""
 | 
			
		|||
msgstr ""
 | 
			
		||||
"Project-Id-Version: 2023.03-dev\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: \n"
 | 
			
		||||
"POT-Creation-Date: 2023-02-04 19:53-0500\n"
 | 
			
		||||
"POT-Creation-Date: 2023-02-12 12:37+0000\n"
 | 
			
		||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 | 
			
		||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 | 
			
		||||
"Language-Team: LANGUAGE <LL@li.org>\n"
 | 
			
		||||
| 
						 | 
				
			
			@ -3188,7 +3188,7 @@ msgstr ""
 | 
			
		|||
msgid "[no subject]"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: src/Model/Photo.php:1184 src/Module/Media/Photo/Upload.php:198
 | 
			
		||||
#: src/Model/Photo.php:1189 src/Module/Media/Photo/Upload.php:198
 | 
			
		||||
msgid "Wall Photos"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3296,7 +3296,7 @@ msgstr ""
 | 
			
		|||
msgid "Title/Description:"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: src/Model/Profile.php:1023 src/Module/Admin/Summary.php:221
 | 
			
		||||
#: src/Model/Profile.php:1023 src/Module/Admin/Summary.php:217
 | 
			
		||||
#: src/Module/Moderation/Summary.php:77
 | 
			
		||||
msgid "Summary"
 | 
			
		||||
msgstr ""
 | 
			
		||||
| 
						 | 
				
			
			@ -3623,7 +3623,7 @@ msgstr ""
 | 
			
		|||
#: src/Module/Admin/Federation.php:207 src/Module/Admin/Logs/Settings.php:79
 | 
			
		||||
#: src/Module/Admin/Logs/View.php:84 src/Module/Admin/Queue.php:72
 | 
			
		||||
#: src/Module/Admin/Site.php:435 src/Module/Admin/Storage.php:138
 | 
			
		||||
#: src/Module/Admin/Summary.php:220 src/Module/Admin/Themes/Details.php:90
 | 
			
		||||
#: src/Module/Admin/Summary.php:216 src/Module/Admin/Themes/Details.php:90
 | 
			
		||||
#: src/Module/Admin/Themes/Index.php:111 src/Module/Admin/Tos.php:77
 | 
			
		||||
#: src/Module/Moderation/Users/Create.php:61
 | 
			
		||||
#: src/Module/Moderation/Users/Pending.php:96
 | 
			
		||||
| 
						 | 
				
			
			@ -5091,15 +5091,7 @@ msgid ""
 | 
			
		|||
"with the transition."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: src/Module/Admin/Summary.php:118
 | 
			
		||||
#, php-format
 | 
			
		||||
msgid ""
 | 
			
		||||
"Friendica's configuration store \"%s\" isn't writable. Until then database "
 | 
			
		||||
"updates won't be applied automatically, admin settings and console "
 | 
			
		||||
"configuration changes won't be saved."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: src/Module/Admin/Summary.php:124
 | 
			
		||||
#: src/Module/Admin/Summary.php:120
 | 
			
		||||
#, php-format
 | 
			
		||||
msgid ""
 | 
			
		||||
"<a href=\"%s\">%s</a> is not reachable on your system. This is a severe "
 | 
			
		||||
| 
						 | 
				
			
			@ -5107,50 +5099,50 @@ msgid ""
 | 
			
		|||
"href=\"%s\">the installation page</a> for help."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: src/Module/Admin/Summary.php:142
 | 
			
		||||
#: src/Module/Admin/Summary.php:138
 | 
			
		||||
#, php-format
 | 
			
		||||
msgid "The logfile '%s' is not usable. No logging possible (error: '%s')"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: src/Module/Admin/Summary.php:156
 | 
			
		||||
#: src/Module/Admin/Summary.php:152
 | 
			
		||||
#, php-format
 | 
			
		||||
msgid "The debug logfile '%s' is not usable. No logging possible (error: '%s')"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: src/Module/Admin/Summary.php:172
 | 
			
		||||
#: src/Module/Admin/Summary.php:168
 | 
			
		||||
#, php-format
 | 
			
		||||
msgid ""
 | 
			
		||||
"Friendica's system.basepath was updated from '%s' to '%s'. Please remove the "
 | 
			
		||||
"system.basepath from your db to avoid differences."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: src/Module/Admin/Summary.php:180
 | 
			
		||||
#: src/Module/Admin/Summary.php:176
 | 
			
		||||
#, php-format
 | 
			
		||||
msgid ""
 | 
			
		||||
"Friendica's current system.basepath '%s' is wrong and the config file '%s' "
 | 
			
		||||
"isn't used."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: src/Module/Admin/Summary.php:188
 | 
			
		||||
#: src/Module/Admin/Summary.php:184
 | 
			
		||||
#, php-format
 | 
			
		||||
msgid ""
 | 
			
		||||
"Friendica's current system.basepath '%s' is not equal to the config file "
 | 
			
		||||
"'%s'. Please fix your configuration."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: src/Module/Admin/Summary.php:199
 | 
			
		||||
#: src/Module/Admin/Summary.php:195
 | 
			
		||||
msgid "Message queues"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: src/Module/Admin/Summary.php:205
 | 
			
		||||
#: src/Module/Admin/Summary.php:201
 | 
			
		||||
msgid "Server Settings"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: src/Module/Admin/Summary.php:223
 | 
			
		||||
#: src/Module/Admin/Summary.php:219
 | 
			
		||||
msgid "Version"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: src/Module/Admin/Summary.php:227
 | 
			
		||||
#: src/Module/Admin/Summary.php:223
 | 
			
		||||
msgid "Active addons"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue