favicon.*
-.htconfig.php
-.htpreconfig.php
+/.htconfig.php
+/.htpreconfig.php
\#*
*.log
*.out
Fixed the notification order [JeroenED]
Fixed the timezone of Friendica logs [nupplaphil]
Fixed tag completion painfully slow [AlfredSK]
+ Fixed a regression in notifications [MrPetovan]
+ Fixed an issue with smilies and code blocks [MrPetovan]
General Code cleaning and restructuring [nupplaphil]
Added frio color scheme sharing [JeroenED]
Added syslog and stream Logger [nupplaphil]
Added storage move cronjob [MrPetovan]
+ Added collapsible panel for connector permission fields [MrPetovan]
Closed Issues:
- 6303, 6478, 6319
+ 6303, 6478, 6319, 6921, 6903
Version 2019.03 (2019-03-22)
Friendica Core:
use Friendica\Database\DBA;
if (!defined('DB_UPDATE_VERSION')) {
- define('DB_UPDATE_VERSION', 1305);
+ define('DB_UPDATE_VERSION', 1308);
}
return [
"hook_file_function" => ["UNIQUE", "hook", "file", "function"],
]
],
+ "inbox-status" => [
+ "comment" => "Status of ActivityPub inboxes",
+ "fields" => [
+ "url" => ["type" => "varbinary(255)", "not null" => "1", "primary" => "1", "comment" => "URL of the inbox"],
+ "created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Creation date of this entry"],
+ "success" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Date of the last successful delivery"],
+ "failure" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Date of the last failed delivery"],
+ "previous" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Previous delivery date"],
+ "archive" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Is the inbox archived?"],
+ "shared" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Is it a shared inbox?"]
+ ],
+ "indexes" => [
+ "PRIMARY" => ["url"]
+ ]
+ ],
"intro" => [
"comment" => "",
"fields" => [
],
"indexes" => [
"PRIMARY" => ["tid"],
- "term_type" => ["term", "type"],
+ "term_type" => ["term(64)", "type"],
"oid_otype_type_term" => ["oid", "otype", "type", "term(32)"],
"uid_otype_type_term_global_created" => ["uid", "otype", "type", "term(32)", "global", "created"],
"uid_otype_type_url" => ["uid", "otype", "type", "url(64)"],
-- ------------------------------------------
--- Friendica 2019.03-dev (The Tazmans Flax-lily)
--- DB_UPDATE_VERSION 1300
+-- Friendica 2019.06-dev (Dalmatian Bellflower)
+-- DB_UPDATE_VERSION 1308
-- ------------------------------------------
UNIQUE INDEX `hook_file_function` (`hook`,`file`,`function`)
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='addon hook registry';
+--
+-- TABLE inbox-status
+--
+CREATE TABLE IF NOT EXISTS `inbox-status` (
+ `url` varbinary(255) NOT NULL COMMENT 'URL of the inbox',
+ `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Creation date of this entry',
+ `success` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Date of the last successful delivery',
+ `failure` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Date of the last failed delivery',
+ `previous` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Previous delivery date',
+ `archive` boolean NOT NULL DEFAULT '0' COMMENT 'Is the inbox archived?',
+ `shared` boolean NOT NULL DEFAULT '0' COMMENT 'Is it a shared inbox?',
+ PRIMARY KEY(`url`)
+) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Status of ActivityPub inboxes';
+
--
-- TABLE intro
--
`deny_gid` mediumtext COMMENT 'Access Control - list of denied groups',
`backend-class` tinytext COMMENT 'Storage backend class',
`backend-ref` text COMMENT 'Storage backend data reference',
- `updated` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'edited timestamp',
+ `updated` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '',
PRIMARY KEY(`id`),
INDEX `contactid` (`contact-id`),
INDEX `uid_contactid` (`uid`,`contact-id`),
`global` boolean NOT NULL DEFAULT '0' COMMENT '',
`uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id',
PRIMARY KEY(`tid`),
- INDEX `term_type` (`term`, `type`),
+ INDEX `term_type` (`term`(64),`type`),
INDEX `oid_otype_type_term` (`oid`,`otype`,`type`,`term`(32)),
INDEX `uid_otype_type_term_global_created` (`uid`,`otype`,`type`,`term`(32),`global`,`created`),
INDEX `uid_otype_type_url` (`uid`,`otype`,`type`,`url`(64)),
`retrial` tinyint NOT NULL DEFAULT 0 COMMENT 'Retrial counter',
`done` boolean NOT NULL DEFAULT '0' COMMENT 'Marked 1 when the task was done - will be deleted later',
PRIMARY KEY(`id`),
- INDEX `pid` (`pid`),
- INDEX `parameter` (`parameter`(64)),
- INDEX `priority_created_next_try` (`priority`,`created`,`next_try`),
- INDEX `done_priority_executed_next_try` (`done`,`priority`,`executed`,`next_try`),
- INDEX `done_executed_next_try` (`done`,`executed`,`next_try`),
+ INDEX `done_parameter` (`done`,`parameter`(64)),
+ INDEX `done_executed` (`done`,`executed`),
+ INDEX `done_priority_created` (`done`,`priority`,`created`),
INDEX `done_priority_next_try` (`done`,`priority`,`next_try`),
- INDEX `done_next_try` (`done`,`next_try`)
+ INDEX `done_pid_next_try` (`done`,`pid`,`next_try`),
+ INDEX `done_pid_priority_created` (`done`,`pid`,`priority`,`created`)
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Background tasks queue entries';
--
visitor => array with the contact record of the visitor
url => the query string
+### jot_networks
+Called when displaying the post permission screen.
+Hook data is a list of form fields that need to be displayed along the ACL.
+Form field array structure is:
+
+- **type**: `checkbox` or `select`.
+- **field**: Standard field data structure to be used by `field_checkbox.tpl` and `field_select.tpl`.
+
+For `checkbox`, **field** is:
+ - [0] (String): Form field name; Mandatory.
+ - [1]: (String): Form field label; Optional, default is none.
+ - [2]: (Boolean): Whether the checkbox should be checked by default; Optional, default is false.
+ - [3]: (String): Additional help text; Optional, default is none.
+ - [4]: (String): Additional HTML attributes; Optional, default is none.
+
+For `select`, **field** is:
+ - [0] (String): Form field name; Mandatory.
+ - [1] (String): Form field label; Optional, default is none.
+ - [2] (Boolean): Default value to be selected by default; Optional, default is none.
+ - [3] (String): Additional help text; Optional, default is none.
+ - [4] (Array): Associative array of options. Item key is option value, item value is option label; Mandatory.
+
+
+
## Complete list of hook callbacks
Here is a complete list of all hook callbacks with file locations (as of 24-Sep-2018). Please see the source for details of any hooks not documented above.
$showwarning = true;
$warningtext[] = L10n::t('The database update failed. Please run "php bin/console.php dbstructure update" from the command line and have a look at the errors that might appear.');
}
+ if (Config::get('system', 'update') == Update::FAILED) {
+ $showwarning = true;
+ $warningtext[] = L10n::t('The last update failed. Please run "php bin/console.php dbstructure update" from the command line and have a look at the errors that might appear. (Some of the errors are possibly inside the logfile.)');
+ }
$last_worker_call = Config::get('system', 'last_worker_execution', false);
if (!$last_worker_call) {
update_table($a, "gcontact", ['connect', 'addr'], $old_host, $new_host);
// update config
- Config::set('system', 'hostname', parse_url($new_url, PHP_URL_HOST));
+ $configFileSaver = new \Friendica\Util\Config\ConfigFileSaver($a->getBasePath());
+ $configFileSaver->addConfigValue('config', 'hostname', parse_url($new_url, PHP_URL_HOST));
+ $configFileSaver->saveToConfigFile();
Config::set('system', 'url', $new_url);
$a->setBaseURL($new_url);
// end relocate
$sitename = (!empty($_POST['sitename']) ? Strings::escapeTags(trim($_POST['sitename'])) : '');
- $hostname = (!empty($_POST['hostname']) ? Strings::escapeTags(trim($_POST['hostname'])) : '');
$sender_email = (!empty($_POST['sender_email']) ? Strings::escapeTags(trim($_POST['sender_email'])) : '');
$banner = (!empty($_POST['banner']) ? trim($_POST['banner']) : false);
$shortcut_icon = (!empty($_POST['shortcut_icon']) ? Strings::escapeTags(trim($_POST['shortcut_icon'])) : '');
$itemcache_duration = (!empty($_POST['itemcache_duration']) ? intval($_POST['itemcache_duration']) : 0);
$max_comments = (!empty($_POST['max_comments']) ? intval($_POST['max_comments']) : 0);
$temppath = (!empty($_POST['temppath']) ? Strings::escapeTags(trim($_POST['temppath'])) : '');
- $basepath = (!empty($_POST['basepath']) ? Strings::escapeTags(trim($_POST['basepath'])) : '');
$singleuser = (!empty($_POST['singleuser']) ? Strings::escapeTags(trim($_POST['singleuser'])) : '');
$proxy_disabled = !empty($_POST['proxy_disabled']);
$only_tag_search = !empty($_POST['only_tag_search']);
Config::set('system', 'poco_local_search' , $poco_local_search);
Config::set('system', 'nodeinfo' , $nodeinfo);
Config::set('config', 'sitename' , $sitename);
- Config::set('config', 'hostname' , $hostname);
Config::set('config', 'sender_email' , $sender_email);
Config::set('system', 'suppress_tags' , $suppress_tags);
Config::set('system', 'shortcut_icon' , $shortcut_icon);
Config::set('system', 'temppath', $temppath);
- if ($basepath != '') {
- $basepath = BasePath::getRealPath($basepath);
- }
-
- Config::set('system', 'basepath' , $basepath);
Config::set('system', 'proxy_disabled' , $proxy_disabled);
Config::set('system', 'only_tag_search' , $only_tag_search);
"develop" => L10n::t("check the development version")
];
- if (empty(Config::get('config', 'hostname'))) {
- Config::set('config', 'hostname', $a->getHostName());
- }
$diaspora_able = ($a->getURLPath() == "");
$optimize_max_tablesize = Config::get('system', 'optimize_max_tablesize', -1);
// name, label, value, help string, extra data...
'$sitename' => ['sitename', L10n::t("Site name"), Config::get('config', 'sitename'), ''],
- '$hostname' => ['hostname', L10n::t("Host name"), Config::get('config', 'hostname'), ""],
'$sender_email' => ['sender_email', L10n::t("Sender Email"), Config::get('config', 'sender_email'), L10n::t("The email address your server shall use to send notification emails from."), "", "", "email"],
'$banner' => ['banner', L10n::t("Banner/Logo"), $banner, ""],
'$shortcut_icon' => ['shortcut_icon', L10n::t("Shortcut icon"), Config::get('system', 'shortcut_icon'), L10n::t("Link to an icon that will be used for browsers.")],
'$itemcache_duration' => ['itemcache_duration', L10n::t("Cache duration in seconds"), Config::get('system', 'itemcache_duration'), L10n::t("How long should the cache files be hold? Default value is 86400 seconds \x28One day\x29. To disable the item cache, set the value to -1.")],
'$max_comments' => ['max_comments', L10n::t("Maximum numbers of comments per post"), Config::get('system', 'max_comments'), L10n::t("How much comments should be shown for each post? Default value is 100.")],
'$temppath' => ['temppath', L10n::t("Temp path"), Config::get('system', 'temppath'), L10n::t("If you have a restricted system where the webserver can't access the system temp path, enter another path here.")],
- '$basepath' => ['basepath', L10n::t("Base path to installation"), Config::get('system', 'basepath'), L10n::t("If the system cannot detect the correct path to your installation, enter the correct path here. This setting should only be set if you are using a restricted system and symbolic links to your webroot.")],
'$proxy_disabled' => ['proxy_disabled', L10n::t("Disable picture proxy"), Config::get('system', 'proxy_disabled'), L10n::t("The picture proxy increases performance and privacy. It shouldn't be used on systems with very low bandwidth.")],
'$only_tag_search' => ['only_tag_search', L10n::t("Only search in tags"), Config::get('system', 'only_tag_search'), L10n::t("On large systems the text search can slow down the system extremely.")],
use DOMDocument;
use DOMXPath;
use Exception;
-use Friendica\Core\Config\Cache\ConfigCacheLoader;
use Friendica\Core\Config\Cache\IConfigCache;
use Friendica\Core\Config\Configuration;
use Friendica\Database\DBA;
use Friendica\Model\Profile;
use Friendica\Network\HTTPException\InternalServerErrorException;
+use Friendica\Util\Config\ConfigFileLoader;
use Friendica\Util\HTTPSignature;
use Friendica\Util\Profiler;
use Psr\Log\LoggerInterface;
*/
private $mode;
- /**
- * @var string The App base path
- */
- private $basePath;
-
/**
* @var string The App URL path
*/
*/
public function getBasePath()
{
- return $this->basePath;
+ return $this->config->get('system', 'basepath');
}
/**
*/
public function registerStylesheet($path)
{
- $url = str_replace($this->basePath . DIRECTORY_SEPARATOR, '', $path);
+ $url = str_replace($this->getBasePath() . DIRECTORY_SEPARATOR, '', $path);
$this->stylesheets[] = trim($url, '/');
}
*/
public function registerFooterScript($path)
{
- $url = str_replace($this->basePath . DIRECTORY_SEPARATOR, '', $path);
+ $url = str_replace($this->getBasePath() . DIRECTORY_SEPARATOR, '', $path);
$this->footerScripts[] = trim($url, '/');
}
/**
* @brief App constructor.
*
- * @param string $basePath The basedir of the app
* @param Configuration $config The Configuration
* @param App\Mode $mode The mode of this Friendica app
* @param LoggerInterface $logger The current app logger
*
* @throws Exception if the Basepath is not usable
*/
- public function __construct($basePath, Configuration $config, App\Mode $mode, LoggerInterface $logger, Profiler $profiler, $isBackend = true)
+ public function __construct(Configuration $config, App\Mode $mode, LoggerInterface $logger, Profiler $profiler, $isBackend = true)
{
BaseObject::setApp($this);
$this->config = $config;
$this->profiler = $profiler;
$this->mode = $mode;
- $cfgBasePath = $this->config->get('system', 'basepath');
- $this->basePath = !empty($cfgBasePath) ? $cfgBasePath : $basePath;
-
- if (!Core\System::isDirectoryUsable($this->basePath, false)) {
- throw new Exception('Basepath \'' . $this->basePath . '\' isn\'t usable.');
- }
- $this->basePath = rtrim($this->basePath, DIRECTORY_SEPARATOR);
$this->checkBackend($isBackend);
$this->checkFriendicaApp();
set_include_path(
get_include_path() . PATH_SEPARATOR
- . $this->basePath . DIRECTORY_SEPARATOR . 'include' . PATH_SEPARATOR
- . $this->basePath . DIRECTORY_SEPARATOR . 'library' . PATH_SEPARATOR
- . $this->basePath);
+ . $this->getBasePath() . DIRECTORY_SEPARATOR . 'include' . PATH_SEPARATOR
+ . $this->getBasePath() . DIRECTORY_SEPARATOR . 'library' . PATH_SEPARATOR
+ . $this->getBasePath());
if (!empty($_SERVER['QUERY_STRING']) && strpos($_SERVER['QUERY_STRING'], 'pagename=') === 0) {
$this->query_string = substr($_SERVER['QUERY_STRING'], 9);
{
$this->determineURLPath();
- $this->getMode()->determine($this->basePath);
+ $this->getMode()->determine($this->getBasePath());
if ($this->getMode()->has(App\Mode::DBAVAILABLE)) {
- $loader = new ConfigCacheLoader($this->basePath, $this->getMode());
+ $loader = new ConfigFileLoader($this->getBasePath(), $this->getMode());
$this->config->getCache()->load($loader->loadCoreConfig('addon'), true);
$this->profiler->update(
$this->config->get('rendertime', 'callstack', false));
Core\Hook::loadHooks();
- $loader = new ConfigCacheLoader($this->basePath, $this->mode);
+ $loader = new ConfigFileLoader($this->getBasePath(), $this->mode);
Core\Hook::callAll('load_config', $loader);
}
{
$scheme = $this->scheme;
- if (Core\Config::get('system', 'ssl_policy') == SSL_POLICY_FULL) {
+ if ($this->config->get('system', 'ssl_policy') == SSL_POLICY_FULL) {
$scheme = 'https';
}
// Basically, we have $ssl = true on any links which can only be seen by a logged in user
// (and also the login link). Anything seen by an outsider will have it turned off.
- if (Core\Config::get('system', 'ssl_policy') == SSL_POLICY_SELFSIGN) {
+ if ($this->config->get('system', 'ssl_policy') == SSL_POLICY_SELFSIGN) {
if ($ssl) {
$scheme = 'https';
} else {
}
}
- if (Core\Config::get('config', 'hostname') != '') {
- $this->hostname = Core\Config::get('config', 'hostname');
+ if ($this->config->get('config', 'hostname') != '') {
+ $this->hostname = $this->config->get('config', 'hostname');
}
return $scheme . '://' . $this->hostname . (!empty($this->getURLPath()) ? '/' . $this->getURLPath() : '' );
$this->urlPath = trim($parsed['path'], '\\/');
}
- if (file_exists($this->basePath . '/.htpreconfig.php')) {
- include $this->basePath . '/.htpreconfig.php';
+ if (file_exists($this->getBasePath() . '/.htpreconfig.php')) {
+ include $this->getBasePath() . '/.htpreconfig.php';
}
- if (Core\Config::get('config', 'hostname') != '') {
- $this->hostname = Core\Config::get('config', 'hostname');
+ if ($this->config->get('config', 'hostname') != '') {
+ $this->hostname = $this->config->get('config', 'hostname');
}
if (!isset($this->hostname) || ($this->hostname == '')) {
public function getHostName()
{
- if (Core\Config::get('config', 'hostname') != '') {
- $this->hostname = Core\Config::get('config', 'hostname');
+ if ($this->config->get('config', 'hostname') != '') {
+ $this->hostname = $this->config->get('config', 'hostname');
}
return $this->hostname;
$this->registerStylesheet($stylesheet);
- $shortcut_icon = Core\Config::get('system', 'shortcut_icon');
+ $shortcut_icon = $this->config->get('system', 'shortcut_icon');
if ($shortcut_icon == '') {
$shortcut_icon = 'images/friendica-32.png';
}
- $touch_icon = Core\Config::get('system', 'touch_icon');
+ $touch_icon = $this->config->get('system', 'touch_icon');
if ($touch_icon == '') {
$touch_icon = 'images/friendica-128.png';
}
'$update_interval' => $interval,
'$shortcut_icon' => $shortcut_icon,
'$touch_icon' => $touch_icon,
- '$block_public' => intval(Core\Config::get('system', 'block_public')),
+ '$block_public' => intval($this->config->get('system', 'block_public')),
'$stylesheets' => $this->stylesheets,
]) . $this->page['htmlhead'];
}
'fetch',
'hcard',
'hostxrd',
+ 'manifest',
'nodeinfo',
'noscrape',
'p',
*
if ($this->is_backend()) {
$process = 'backend';
- $max_processes = Core\Config::get('system', 'max_processes_backend');
+ $max_processes = $this->config->get('system', 'max_processes_backend');
if (intval($max_processes) == 0) {
$max_processes = 5;
}
} else {
$process = 'frontend';
- $max_processes = Core\Config::get('system', 'max_processes_frontend');
+ $max_processes = $this->config->get('system', 'max_processes_frontend');
if (intval($max_processes) == 0) {
$max_processes = 20;
}
*/
public function isMinMemoryReached()
{
- $min_memory = Core\Config::get('system', 'min_memory', 0);
+ $min_memory = $this->config->get('system', 'min_memory', 0);
if ($min_memory == 0) {
return false;
}
{
if ($this->isBackend()) {
$process = 'backend';
- $maxsysload = intval(Core\Config::get('system', 'maxloadavg'));
+ $maxsysload = intval($this->config->get('system', 'maxloadavg'));
if ($maxsysload < 1) {
$maxsysload = 50;
}
} else {
$process = 'frontend';
- $maxsysload = intval(Core\Config::get('system', 'maxloadavg_frontend'));
+ $maxsysload = intval($this->config->get('system', 'maxloadavg_frontend'));
if ($maxsysload < 1) {
$maxsysload = 50;
}
}
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
- $resource = proc_open('cmd /c start /b ' . $cmdline, [], $foo, $this->basePath);
+ $resource = proc_open('cmd /c start /b ' . $cmdline, [], $foo, $this->getBasePath());
} else {
- $resource = proc_open($cmdline . ' &', [], $foo, $this->basePath);
+ $resource = proc_open($cmdline . ' &', [], $foo, $this->getBasePath());
}
if (!is_resource($resource)) {
Core\Logger::log('We got no resource for command ' . $cmdline, Core\Logger::DEBUG);
*/
public function getSenderEmailAddress()
{
- $sender_email = Core\Config::get('config', 'sender_email');
+ $sender_email = $this->config->get('config', 'sender_email');
if (empty($sender_email)) {
$hostname = $this->getHostName();
if (strpos($hostname, ':')) {
*/
private function computeCurrentTheme()
{
- $system_theme = Core\Config::get('system', 'theme');
+ $system_theme = $this->config->get('system', 'theme');
if (!$system_theme) {
throw new Exception(Core\L10n::t('No system theme config value set.'));
}
// Sane default
$this->currentTheme = $system_theme;
- $allowed_themes = explode(',', Core\Config::get('system', 'allowed_themes', $system_theme));
+ $allowed_themes = explode(',', $this->config->get('system', 'allowed_themes', $system_theme));
$page_theme = null;
// Find the theme that belongs to the user whose stuff we are looking at
// Specific mobile theme override
if (($this->is_mobile || $this->is_tablet) && Core\Session::get('show-mobile', true)) {
- $system_mobile_theme = Core\Config::get('system', 'mobile-theme');
+ $system_mobile_theme = $this->config->get('system', 'mobile-theme');
$user_mobile_theme = Core\Session::get('mobile-theme', $system_mobile_theme);
// --- means same mobile theme as desktop
*/
public function checkURL()
{
- $url = Core\Config::get('system', 'url');
+ $url = $this->config->get('system', 'url');
// if the url isn't set or the stored url is radically different
// than the currently visited url, store the current value accordingly.
// We will only change the url to an ip address if there is no existing setting
if (empty($url) || (!Util\Strings::compareLink($url, $this->getBaseURL())) && (!preg_match("/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/", $this->getHostName()))) {
- Core\Config::set('system', 'url', $this->getBaseURL());
+ $this->config->set('system', 'url', $this->getBaseURL());
}
}
if (!$this->getMode()->isInstall()) {
// Force SSL redirection
- if (Core\Config::get('system', 'force_ssl') && ($this->getScheme() == "http")
- && intval(Core\Config::get('system', 'ssl_policy')) == SSL_POLICY_FULL
+ if ($this->config->get('system', 'force_ssl') && ($this->getScheme() == "http")
+ && intval($this->config->get('system', 'ssl_policy')) == SSL_POLICY_FULL
&& strpos($this->getBaseURL(), 'https://') === 0
&& $_SERVER['REQUEST_METHOD'] == 'GET') {
header('HTTP/1.1 302 Moved Temporarily');
$this->module = 'maintenance';
} else {
$this->checkURL();
- Core\Update::check($this->basePath, false);
+ Core\Update::check($this->getBasePath(), false);
Core\Addon::loadAddons();
Core\Hook::loadHooks();
}
$this->module = "login";
}
- $privateapps = Core\Config::get('config', 'private_addons', false);
+ $privateapps = $this->config->get('config', 'private_addons', false);
if (Core\Addon::isEnabled($this->module) && file_exists("addon/{$this->module}/{$this->module}.php")) {
//Check if module is an app and if public access to apps is allowed or not
if ((!local_user()) && Core\Hook::isAddonApp($this->module) && $privateapps) {
header("X-Friendica-Version: " . FRIENDICA_VERSION);
header("Content-type: text/html; charset=utf-8");
- if (Core\Config::get('system', 'hsts') && (Core\Config::get('system', 'ssl_policy') == SSL_POLICY_FULL)) {
+ if ($this->config->get('system', 'hsts') && ($this->config->get('system', 'ssl_policy') == SSL_POLICY_FULL)) {
header("Strict-Transport-Security: max-age=31536000");
}
$stmtContacts = DBA::p(
"SELECT `contact`.`id`, `contact`.`name`, COUNT(*) AS `count` FROM `item`
INNER JOIN `contact` ON `item`.`contact-id` = `contact`.`id`
- WHERE `item`.`uid` = %d AND `item`.`visible` AND NOT `item`.`deleted` AND `item`.`unseen`
+ WHERE `item`.`uid` = ? AND `item`.`visible` AND NOT `item`.`deleted` AND `item`.`unseen`
AND `contact`.`network`= 'dfrn' AND (`contact`.`forum` OR `contact`.`prv`)
AND NOT `contact`.`blocked` AND NOT `contact`.`hidden`
AND NOT `contact`.`pending` AND NOT `contact`.`archive`
AND `contact`.`success_update` > `failure_update`
GROUP BY `contact`.`id` ",
- intval(local_user())
+ local_user()
);
return DBA::toArray($stmtContacts);
return $text;
}
- $text = preg_replace_callback('/<pre>(.*?)<\/pre>/ism' , 'self::encode', $text);
$text = preg_replace_callback('/<code>(.*?)<\/code>/ism', 'self::encode', $text);
if ($no_images) {
$text = preg_replace_callback('/<(3+)/', 'self::pregHeart', $text);
$text = self::strOrigReplace($smilies['texts'], $smilies['icons'], $text);
- $text = preg_replace_callback('/<pre>(.*?)<\/pre>/ism', 'self::decode', $text);
$text = preg_replace_callback('/<code>(.*?)<\/code>/ism', 'self::decode', $text);
return $text;
*/
private static function encode($m)
{
- return(str_replace($m[1], Strings::base64UrlEncode($m[1]), $m[0]));
+ return '<code>' . Strings::base64UrlEncode($m[1]) . '</code>';
}
/**
*/
private static function decode($m)
{
- return(str_replace($m[1], Strings::base64UrlDecode($m[1]), $m[0]));
+ return '<code>' . Strings::base64UrlDecode($m[1]) . '</code>';
}
$default_permissions = self::getDefaultUserPermissions($user);
}
- $jotnets = '';
+ $jotnets_fields = [];
if ($show_jotnets) {
- $imap_disabled = !function_exists('imap_open') || Config::get('system', 'imap_disabled');
-
$mail_enabled = false;
$pubmail_enabled = false;
- if (!$imap_disabled) {
+ if (function_exists('imap_open') && !Config::get('system', 'imap_disabled')) {
$mailacct = DBA::selectFirst('mailacct', ['pubmail'], ['`uid` = ? AND `server` != ""', local_user()]);
if (DBA::isResult($mailacct)) {
$mail_enabled = true;
if (empty($default_permissions['hidewall'])) {
if ($mail_enabled) {
- $selected = $pubmail_enabled ? ' checked="checked"' : '';
- $jotnets .= '<div class="profile-jot-net"><input type="checkbox" name="pubmail_enable"' . $selected . ' value="1" /> ' . L10n::t("Post to Email") . '</div>';
+ $jotnets_fields[] = [
+ 'type' => 'checkbox',
+ 'field' => [
+ 'pubmail_enable',
+ L10n::t('Post to Email'),
+ $pubmail_enabled
+ ]
+ ];
}
- Hook::callAll('jot_networks', $jotnets);
- } else {
- $jotnets .= L10n::t('Connectors disabled, since "%s" is enabled.',
- L10n::t('Hide your profile details from unknown viewers?'));
+ Hook::callAll('jot_networks', $jotnets_fields);
}
}
-
+
$tpl = Renderer::getMarkupTemplate('acl_selector.tpl');
$o = Renderer::replaceMacros($tpl, [
'$showall' => L10n::t('Visible to everybody'),
'$networks' => $show_jotnets,
'$emailcc' => L10n::t('CC: email addresses'),
'$emtitle' => L10n::t('Example: bob@example.com, mary@example.com'),
- '$jotnets' => $jotnets,
+ '$jotnets_enabled' => empty($default_permissions['hidewall']),
+ '$jotnets_summary' => L10n::t('Connectors'),
+ '$jotnets_fields' => $jotnets_fields,
+ '$jotnets_disabled_label' => L10n::t('Connectors disabled, since "%s" is enabled.', L10n::t('Hide your profile details from unknown viewers?')),
'$aclModalTitle' => L10n::t('Permissions'),
'$aclModalDismiss' => L10n::t('Close'),
'$features' => [
/**
* The Friendica config cache for the application
* Initial, all *.config.php files are loaded into this cache with the
- * ConfigCacheLoader ( @see ConfigCacheLoader )
+ * ConfigFileLoader ( @see ConfigFileLoader )
*/
class ConfigCache implements IConfigCache, IPConfigCache
{
+++ /dev/null
-<?php
-
-namespace Friendica\Core\Config\Cache;
-
-use Friendica\App;
-use Friendica\Core\Addon;
-
-/**
- * The ConfigCacheLoader loads config-files and stores them in a ConfigCache ( @see ConfigCache )
- *
- * It is capable of loading the following config files:
- * - *.config.php (current)
- * - *.ini.php (deprecated)
- * - *.htconfig.php (deprecated)
- */
-class ConfigCacheLoader
-{
- /**
- * The Sub directory of the config-files
- * @var string
- */
- const SUBDIRECTORY = 'config';
-
- private $baseDir;
- private $configDir;
-
- /**
- * @var App\Mode
- */
- private $appMode;
-
- public function __construct($baseDir, App\Mode $mode)
- {
- $this->appMode = $mode;
- $this->baseDir = $baseDir;
- $this->configDir = $baseDir . DIRECTORY_SEPARATOR . self::SUBDIRECTORY;
- }
-
- /**
- * Load the configuration files
- *
- * First loads the default value for all the configuration keys, then the legacy configuration files, then the
- * expected local.config.php
- *
- * @param IConfigCache The config cache to load to
- *
- * @throws \Exception
- */
- public function loadConfigFiles(IConfigCache $config)
- {
- $config->load($this->loadCoreConfig('defaults'));
- $config->load($this->loadCoreConfig('settings'));
-
- $config->load($this->loadLegacyConfig('htpreconfig'), true);
- $config->load($this->loadLegacyConfig('htconfig'), true);
-
- $config->load($this->loadCoreConfig('local'), true);
-
- // In case of install mode, add the found basepath (because there isn't a basepath set yet
- if ($this->appMode->isInstall()) {
- // Setting at least the basepath we know
- $config->set('system', 'basepath', $this->baseDir);
- }
- }
-
- /**
- * Tries to load the specified core-configuration and returns the config array.
- *
- * @param string $name The name of the configuration
- *
- * @return array The config array (empty if no config found)
- *
- * @throws \Exception if the configuration file isn't readable
- */
- public function loadCoreConfig($name)
- {
- if (file_exists($this->configDir . DIRECTORY_SEPARATOR . $name . '.config.php')) {
- return $this->loadConfigFile($this->configDir . DIRECTORY_SEPARATOR . $name . '.config.php');
- } elseif (file_exists($this->configDir . DIRECTORY_SEPARATOR . $name . '.ini.php')) {
- return $this->loadINIConfigFile($this->configDir . DIRECTORY_SEPARATOR . $name . '.ini.php');
- } else {
- return [];
- }
- }
-
- /**
- * Tries to load the specified addon-configuration and returns the config array.
- *
- * @param string $name The name of the configuration
- *
- * @return array The config array (empty if no config found)
- *
- * @throws \Exception if the configuration file isn't readable
- */
- public function loadAddonConfig($name)
- {
- $filepath = $this->baseDir . DIRECTORY_SEPARATOR . // /var/www/html/
- Addon::DIRECTORY . DIRECTORY_SEPARATOR . // addon/
- $name . DIRECTORY_SEPARATOR . // openstreetmap/
- self::SUBDIRECTORY . DIRECTORY_SEPARATOR . // config/
- $name . ".config.php"; // openstreetmap.config.php
-
- if (file_exists($filepath)) {
- return $this->loadConfigFile($filepath);
- } else {
- return [];
- }
- }
-
- /**
- * Tries to load the legacy config files (.htconfig.php, .htpreconfig.php) and returns the config array.
- *
- * @param string $name The name of the config file
- *
- * @return array The configuration array (empty if no config found)
- *
- * @deprecated since version 2018.09
- */
- private function loadLegacyConfig($name)
- {
- $filePath = $this->baseDir . DIRECTORY_SEPARATOR . '.' . $name . '.php';
-
- $config = [];
-
- if (file_exists($filePath)) {
- $a = new \stdClass();
- $a->config = [];
- include $filePath;
-
- $htConfigCategories = array_keys($a->config);
-
- // map the legacy configuration structure to the current structure
- foreach ($htConfigCategories as $htConfigCategory) {
- if (is_array($a->config[$htConfigCategory])) {
- $keys = array_keys($a->config[$htConfigCategory]);
-
- foreach ($keys as $key) {
- $config[$htConfigCategory][$key] = $a->config[$htConfigCategory][$key];
- }
- } else {
- $config['config'][$htConfigCategory] = $a->config[$htConfigCategory];
- }
- }
-
- unset($a);
-
- if (isset($db_host)) {
- $config['database']['hostname'] = $db_host;
- unset($db_host);
- }
- if (isset($db_user)) {
- $config['database']['username'] = $db_user;
- unset($db_user);
- }
- if (isset($db_pass)) {
- $config['database']['password'] = $db_pass;
- unset($db_pass);
- }
- if (isset($db_data)) {
- $config['database']['database'] = $db_data;
- unset($db_data);
- }
- if (isset($config['system']['db_charset'])) {
- $config['database']['charset'] = $config['system']['db_charset'];
- }
- if (isset($pidfile)) {
- $config['system']['pidfile'] = $pidfile;
- unset($pidfile);
- }
- if (isset($default_timezone)) {
- $config['system']['default_timezone'] = $default_timezone;
- unset($default_timezone);
- }
- if (isset($lang)) {
- $config['system']['language'] = $lang;
- unset($lang);
- }
- }
-
- return $config;
- }
-
- /**
- * Tries to load the specified legacy configuration file and returns the config array.
- *
- * @deprecated since version 2018.12
- * @param string $filepath
- *
- * @return array The configuration array
- * @throws \Exception
- */
- private function loadINIConfigFile($filepath)
- {
- $contents = include($filepath);
-
- $config = parse_ini_string($contents, true, INI_SCANNER_TYPED);
-
- if ($config === false) {
- throw new \Exception('Error parsing INI config file ' . $filepath);
- }
-
- return $config;
- }
-
- /**
- * Tries to load the specified configuration file and returns the config array.
- *
- * The config format is PHP array and the template for configuration files is the following:
- *
- * <?php return [
- * 'section' => [
- * 'key' => 'value',
- * ],
- * ];
- *
- * @param string $filepath The filepath of the
- * @return array The config array0
- *
- * @throws \Exception if the config cannot get loaded.
- */
- private function loadConfigFile($filepath)
- {
- $config = include($filepath);
-
- if (!is_array($config)) {
- throw new \Exception('Error loading config file ' . $filepath);
- }
-
- return $config;
- }
-}
*/
class Configuration
{
+ /**
+ * The blacklist of configuration settings, which should not get saved to the backend
+ * @var array
+ */
+ private $configSaveBlacklist = [
+ 'config' => [
+ 'hostname' => true,
+ ]
+ ];
+
/**
* @var Cache\IConfigCache
*/
$cached = $this->configCache->set($cat, $key, $value);
// If there is no connected adapter, we're finished
- if (!$this->configAdapter->isConnected()) {
+ if (!$this->configAdapter->isConnected() || !empty($this->configSaveBlacklist[$cat][$key])) {
return $cached;
}
use Friendica\Core\Config;
use Friendica\Core\Installer;
use Friendica\Core\Theme;
+use Friendica\Util\Config\ConfigFileLoader;
use RuntimeException;
class AutomaticInstallation extends Console
}
//reload the config cache
- $loader = new Config\Cache\ConfigCacheLoader($a->getBasePath(), $a->getMode());
- $loader->loadConfigFiles($configCache);
+ $loader = new ConfigFileLoader($a->getBasePath(), $a->getMode());
+ $loader->setupCache($configCache);
} else {
// Creating config file
*/
public function setSeen($note, $seen = true)
{
- return DBA::update('notify', ['seen' => $seen], ['link' => $note['link'], 'parent' => $note['parent'], 'otype' => $note['otype'], 'uid' => local_user()]);
+ return DBA::update('notify', ['seen' => $seen], [
+ '(`link` = ? OR (`parent` != 0 AND `parent` = ? AND `otype` = ?)) AND `uid` = ?',
+ $note['link'],
+ $note['parent'],
+ $note['otype'],
+ local_user()
+ ]);
}
/**
$sql_extra = "";
if (!$all) {
- $sql_extra = " AND `ignore` = 0 ";
+ $sql_extra = " AND NOT `ignore` ";
}
/// @todo Fetch contact details by "Contact::getDetailsByUrl" instead of queries to contact, fcontact and gcontact
LEFT JOIN `contact` ON `contact`.`id` = `intro`.`contact-id`
LEFT JOIN `gcontact` ON `gcontact`.`nurl` = `contact`.`nurl`
LEFT JOIN `fcontact` ON `intro`.`fid` = `fcontact`.`id`
- WHERE `intro`.`uid` = %d $sql_extra AND `intro`.`blocked` = 0
- LIMIT %d, %d",
- intval($_SESSION['uid']),
- intval($start),
- intval($limit)
+ WHERE `intro`.`uid` = ? $sql_extra AND `intro`.`blocked` = 0
+ LIMIT ?, ?",
+ $_SESSION['uid'],
+ $start,
+ $limit
);
if (DBA::isResult($stmtNotifies)) {
$notifs = $this->formatIntros(DBA::toArray($stmtNotifies));
namespace Friendica\Core;
+use Friendica\App;
+use Friendica\Core\Config\Cache\IConfigCache;
use Friendica\Database\DBA;
use Friendica\Database\DBStructure;
+use Friendica\Util\BasePath;
+use Friendica\Util\Config\ConfigFileLoader;
+use Friendica\Util\Config\ConfigFileSaver;
use Friendica\Util\Strings;
class Update
return;
}
+ // Don't check the status if the last update was failed
+ if (Config::get('system', 'update', Update::SUCCESS, true) == Update::FAILED) {
+ return;
+ }
+
$build = Config::get('system', 'build');
if (empty($build)) {
for ($x = $stored + 1; $x <= $current; $x++) {
$r = self::runUpdateFunction($x, 'pre_update');
if (!$r) {
- break;
+ Config::set('system', 'update', Update::FAILED);
+ Lock::release('dbupdate');
+ return $r;
}
}
);
}
Logger::error('Update ERROR.', ['from' => $stored, 'to' => $current, 'retval' => $retval]);
+ Config::set('system', 'update', Update::FAILED);
Lock::release('dbupdate');
return $retval;
} else {
for ($x = $stored + 1; $x <= $current; $x++) {
$r = self::runUpdateFunction($x, 'update');
if (!$r) {
- break;
+ Config::set('system', 'update', Update::FAILED);
+ Lock::release('dbupdate');
+ return $r;
}
}
self::updateSuccessfull($stored, $current);
}
+ Config::set('system', 'update', Update::SUCCESS);
Lock::release('dbupdate');
}
}
}
}
+ /**
+ * Checks the config settings and saves given config values into the config file
+ *
+ * @param string $basePath The basepath of Friendica
+ * @param App\Mode $mode The Application mode
+ *
+ * @return bool True, if something has been saved
+ */
+ public static function saveConfigToFile($basePath, App\Mode $mode)
+ {
+ $configFileLoader = new ConfigFileLoader($basePath, $mode);
+ $configCache = new Config\Cache\ConfigCache();
+ $configFileLoader->setupCache($configCache, true);
+ $configFileSaver = new ConfigFileSaver($basePath);
+
+ $updated = false;
+
+ if (self::updateConfigEntry($configCache, $configFileSaver,'config', 'hostname')) {
+ $updated = true;
+ };
+
+ if (self::updateConfigEntry($configCache, $configFileSaver,'system', 'basepath', BasePath::create(dirname(__DIR__) . '/../'))) {
+ $updated = true;
+ }
+
+ // In case there is nothing to do, skip the update
+ if (!$updated) {
+ return true;
+ }
+
+ if (!$configFileSaver->saveToConfigFile()) {
+ Logger::alert('Config entry update failed - maybe wrong permission?');
+ return false;
+ }
+
+ DBA::delete('config', ['cat' => 'config', 'k' => 'hostname']);
+ DBA::delete('config', ['cat' => 'system', 'k' => 'basepath']);
+
+ return true;
+ }
+
+ /**
+ * Adds a value to the ConfigFileSave in case it isn't already updated
+ *
+ * @param IConfigCache $configCache The cached config file
+ * @param ConfigFileSaver $configFileSaver The config file saver
+ * @param string $cat The config category
+ * @param string $key The config key
+ * @param string $default A default value, if none of the settings are valid
+ *
+ * @return boolean True, if a value was updated
+ *
+ * @throws \Exception if DBA or Logger doesn't work
+ */
+ private static function updateConfigEntry(IConfigCache $configCache, ConfigFileSaver $configFileSaver, $cat, $key, $default = '')
+ {
+ // check if the config file differs from the whole configuration (= The db contains other values)
+ $fileConfig = $configCache->get($cat, $key);
+
+ $savedConfig = DBA::selectFirst('config', ['v'], ['cat' => $cat, 'k' => $key]);
+
+ if (DBA::isResult($savedConfig)) {
+ $savedValue = $savedConfig['v'];
+ } else {
+ $savedValue = null;
+ }
+
+ // If the db contains a config value, check it
+ if (isset($savedValue) && $fileConfig !== $savedValue) {
+ Logger::info('Difference in config found', ['cat' => $cat, 'key' => $key, 'file' => $fileConfig, 'saved' => $savedValue]);
+ $configFileSaver->addConfigValue($cat, $key, $savedValue);
+ return true;
+
+ // If both config values are not set, use the default value
+ } elseif (!isset($fileConfig) && !isset($savedValue)) {
+ Logger::info('Using default for config', ['cat' => $cat, 'key' => $key, 'value' => $default]);
+ $configFileSaver->addConfigValue($cat, $key, $default);
+ return true;
+
+ // If either the file config value isn't empty or the db value is the same as the
+ // file config value, skip it
+ } else {
+ Logger::info('No Difference in config found', ['cat' => $cat, 'key' => $key, 'value' => $fileConfig, 'saved' => $savedValue]);
+ return false;
+ }
+ }
+
/**
* send the email and do what is needed to do on update fails
*
const STATE_REFETCH = 3; // Worker had refetched jobs in the execution loop.
const STATE_SHORT_LOOP = 4; // Worker is processing preassigned jobs, thus saving much time.
+ const FAST_COMMANDS = ['APDelivery', 'Delivery', 'CreateShadowEntry'];
+
+
private static $up_start;
private static $db_duration = 0;
private static $db_duration_count = 0;
return [];
}
- if ($priority <= PRIORITY_MEDIUM) {
- $limit = Config::get('system', 'worker_fetch_limit', 1);
- } else {
- $limit = 1;
- }
+ $limit = Config::get('system', 'worker_fetch_limit', 1);
$ids = [];
$stamp = (float)microtime(true);
$condition = ["`priority` = ? AND `pid` = 0 AND NOT `done` AND `next_try` < ?", $priority, DateTimeFormat::utcNow()];
- $tasks = DBA::select('workerqueue', ['id'], $condition, ['limit' => $limit, 'order' => ['created']]);
+ $tasks = DBA::select('workerqueue', ['id', 'parameter'], $condition, ['limit' => $limit, 'order' => ['created']]);
self::$db_duration += (microtime(true) - $stamp);
while ($task = DBA::fetch($tasks)) {
$ids[] = $task['id'];
+ // Only continue that loop while we are storing commands that can be processed quickly
+ $command = json_decode($task['parameter'])[0];
+ if (!in_array($command, self::FAST_COMMANDS)) {
+ break;
+ }
}
DBA::close($tasks);
- Logger::info('Found:', ['id' => $ids, 'priority' => $priority]);
+ Logger::info('Found:', ['priority' => $priority, 'id' => $ids]);
return $ids;
}
// If there is no result we check without priority limit
if (empty($ids)) {
+ $limit = Config::get('system', 'worker_fetch_limit', 1);
+
$stamp = (float)microtime(true);
$condition = ["`pid` = 0 AND NOT `done` AND `next_try` < ?", DateTimeFormat::utcNow()];
- $result = DBA::select('workerqueue', ['id'], $condition, ['limit' => 1, 'order' => ['priority', 'created']]);
+ $tasks = DBA::select('workerqueue', ['id', 'parameter'], $condition, ['limit' => $limit, 'order' => ['priority', 'created']]);
self::$db_duration += (microtime(true) - $stamp);
- while ($id = DBA::fetch($result)) {
- $ids[] = $id["id"];
+ while ($task = DBA::fetch($tasks)) {
+ $ids[] = $task['id'];
+ // Only continue that loop while we are storing commands that can be processed quickly
+ $command = json_decode($task['parameter'])[0];
+ if (!in_array($command, self::FAST_COMMANDS)) {
+ break;
+ }
}
- DBA::close($result);
+ DBA::close($tasks);
}
if (!empty($ids)) {
use Friendica\Core\Config;
use Friendica\Core\Config\Adapter;
use Friendica\Core\Config\Cache;
+use Friendica\Util\Config\ConfigFileLoader;
class ConfigFactory
{
/**
- * @param Cache\ConfigCacheLoader $loader The Config Cache loader (INI/config/.htconfig)
+ * @param ConfigFileLoader $loader The Config Cache loader (INI/config/.htconfig)
*
* @return Cache\ConfigCache
*/
- public static function createCache(Cache\ConfigCacheLoader $loader)
+ public static function createCache(ConfigFileLoader $loader)
{
$configCache = new Cache\ConfigCache();
- $loader->loadConfigFiles($configCache);
+ $loader->setupCache($configCache);
return $configCache;
}
namespace Friendica\Factory;
use Friendica\App;
-use Friendica\Core\Config\Cache;
use Friendica\Factory;
use Friendica\Util\BasePath;
+use Friendica\Util\Config;
class DependencyFactory
{
{
$basePath = BasePath::create($directory, $_SERVER);
$mode = new App\Mode($basePath);
- $configLoader = new Cache\ConfigCacheLoader($basePath, $mode);
+ $configLoader = new Config\ConfigFileLoader($basePath, $mode);
$configCache = Factory\ConfigFactory::createCache($configLoader);
$profiler = Factory\ProfilerFactory::create($configCache);
Factory\DBFactory::init($basePath, $configCache, $profiler, $_SERVER);
$logger = Factory\LoggerFactory::create($channel, $config, $profiler);
Factory\LoggerFactory::createDev($channel, $config, $profiler);
- return new App($basePath, $config, $mode, $logger, $profiler, $isBackend);
+ return new App($config, $mode, $logger, $profiler, $isBackend);
}
}
$apcontact['following'] = JsonLD::fetchElement($compacted, 'as:following', '@id');
$apcontact['followers'] = JsonLD::fetchElement($compacted, 'as:followers', '@id');
$apcontact['inbox'] = JsonLD::fetchElement($compacted, 'ldp:inbox', '@id');
+ self::unarchiveInbox($apcontact['inbox'], false);
+
$apcontact['outbox'] = JsonLD::fetchElement($compacted, 'as:outbox', '@id');
$apcontact['sharedinbox'] = '';
if (!empty($compacted['as:endpoints'])) {
$apcontact['sharedinbox'] = JsonLD::fetchElement($compacted['as:endpoints'], 'as:sharedInbox', '@id');
+ self::unarchiveInbox($apcontact['sharedinbox'], true);
}
$apcontact['nick'] = JsonLD::fetchElement($compacted, 'as:preferredUsername');
return $apcontact;
}
+
+ /**
+ * Unarchive inboxes
+ *
+ * @param string $url inbox url
+ */
+ private static function unarchiveInbox($url, $shared)
+ {
+ if (empty($url)) {
+ return;
+ }
+
+ $now = DateTimeFormat::utcNow();
+
+ $fields = ['archive' => false, 'success' => $now, 'shared' => $shared];
+
+ if (!DBA::exists('inbox-status', ['url' => $url])) {
+ $fields = array_merge($fields, ['url' => $url, 'created' => $now]);
+ DBA::insert('inbox-status', $fields);
+ } else {
+ DBA::update('inbox-status', $fields, ['url' => $url]);
+ }
+ }
}
return $receivers;
}
+ /**
+ * Check if an inbox is archived
+ *
+ * @param string $url Inbox url
+ *
+ * @return boolean "true" if inbox is archived
+ */
+ private static function archivedInbox($url)
+ {
+ return DBA::exists('inbox-status', ['url' => $url, 'archive' => true]);
+ }
+
/**
* Fetches a list of inboxes of followers of a given user
*
} else {
$target = $profile['sharedinbox'];
}
- $inboxes[$target] = $target;
+ if (!self::archivedInbox($target)) {
+ $inboxes[$target] = $target;
+ }
}
}
DBA::close($contacts);
} else {
$target = $profile['sharedinbox'];
}
- $inboxes[$target] = $target;
+ if (!self::archivedInbox($target)) {
+ $inboxes[$target] = $target;
+ }
}
}
}
--- /dev/null
+<?php
+
+namespace Friendica\Util\Config;
+
+use Friendica\App;
+use Friendica\Core\Addon;
+use Friendica\Core\Config\Cache\IConfigCache;
+
+/**
+ * The ConfigFileLoader loads config-files and stores them in a IConfigCache ( @see IConfigCache )
+ *
+ * It is capable of loading the following config files:
+ * - *.config.php (current)
+ * - *.ini.php (deprecated)
+ * - *.htconfig.php (deprecated)
+ */
+class ConfigFileLoader extends ConfigFileManager
+{
+ /**
+ * @var App\Mode
+ */
+ private $appMode;
+
+ public function __construct($baseDir, App\Mode $mode)
+ {
+ parent::__construct($baseDir);
+ $this->appMode = $mode;
+ }
+
+ /**
+ * Load the configuration files into an configuration cache
+ *
+ * First loads the default value for all the configuration keys, then the legacy configuration files, then the
+ * expected local.config.php
+ *
+ * @param IConfigCache $config The config cache to load to
+ * @param bool $raw Setup the raw config format
+ *
+ * @throws \Exception
+ */
+ public function setupCache(IConfigCache $config, $raw = false)
+ {
+ $config->load($this->loadCoreConfig('defaults'));
+ $config->load($this->loadCoreConfig('settings'));
+
+ $config->load($this->loadLegacyConfig('htpreconfig'), true);
+ $config->load($this->loadLegacyConfig('htconfig'), true);
+
+ $config->load($this->loadCoreConfig('local'), true);
+
+ // In case of install mode, add the found basepath (because there isn't a basepath set yet
+ if (!$raw && ($this->appMode->isInstall() || empty($config->get('system', 'basepath')))) {
+ // Setting at least the basepath we know
+ $config->set('system', 'basepath', $this->baseDir);
+ }
+ }
+
+ /**
+ * Tries to load the specified core-configuration and returns the config array.
+ *
+ * @param string $name The name of the configuration (default is empty, which means 'local')
+ *
+ * @return array The config array (empty if no config found)
+ *
+ * @throws \Exception if the configuration file isn't readable
+ */
+ public function loadCoreConfig($name = '')
+ {
+ if (!empty($this->getConfigFullName($name))) {
+ return $this->loadConfigFile($this->getConfigFullName($name));
+ } elseif (!empty($this->getIniFullName($name))) {
+ return $this->loadINIConfigFile($this->getIniFullName($name));
+ } else {
+ return [];
+ }
+ }
+
+ /**
+ * Tries to load the specified addon-configuration and returns the config array.
+ *
+ * @param string $name The name of the configuration
+ *
+ * @return array The config array (empty if no config found)
+ *
+ * @throws \Exception if the configuration file isn't readable
+ */
+ public function loadAddonConfig($name)
+ {
+ $filepath = $this->baseDir . DIRECTORY_SEPARATOR . // /var/www/html/
+ Addon::DIRECTORY . DIRECTORY_SEPARATOR . // addon/
+ $name . DIRECTORY_SEPARATOR . // openstreetmap/
+ self::SUBDIRECTORY . DIRECTORY_SEPARATOR . // config/
+ $name . ".config.php"; // openstreetmap.config.php
+
+ if (file_exists($filepath)) {
+ return $this->loadConfigFile($filepath);
+ } else {
+ return [];
+ }
+ }
+
+ /**
+ * Tries to load the legacy config files (.htconfig.php, .htpreconfig.php) and returns the config array.
+ *
+ * @param string $name The name of the config file (default is empty, which means .htconfig.php)
+ *
+ * @return array The configuration array (empty if no config found)
+ *
+ * @deprecated since version 2018.09
+ */
+ private function loadLegacyConfig($name = '')
+ {
+ $config = [];
+ if (!empty($this->getHtConfigFullName($name))) {
+ $a = new \stdClass();
+ $a->config = [];
+ include $this->getHtConfigFullName($name);
+
+ $htConfigCategories = array_keys($a->config);
+
+ // map the legacy configuration structure to the current structure
+ foreach ($htConfigCategories as $htConfigCategory) {
+ if (is_array($a->config[$htConfigCategory])) {
+ $keys = array_keys($a->config[$htConfigCategory]);
+
+ foreach ($keys as $key) {
+ $config[$htConfigCategory][$key] = $a->config[$htConfigCategory][$key];
+ }
+ } else {
+ $config['config'][$htConfigCategory] = $a->config[$htConfigCategory];
+ }
+ }
+
+ unset($a);
+
+ if (isset($db_host)) {
+ $config['database']['hostname'] = $db_host;
+ unset($db_host);
+ }
+ if (isset($db_user)) {
+ $config['database']['username'] = $db_user;
+ unset($db_user);
+ }
+ if (isset($db_pass)) {
+ $config['database']['password'] = $db_pass;
+ unset($db_pass);
+ }
+ if (isset($db_data)) {
+ $config['database']['database'] = $db_data;
+ unset($db_data);
+ }
+ if (isset($config['system']['db_charset'])) {
+ $config['database']['charset'] = $config['system']['db_charset'];
+ }
+ if (isset($pidfile)) {
+ $config['system']['pidfile'] = $pidfile;
+ unset($pidfile);
+ }
+ if (isset($default_timezone)) {
+ $config['system']['default_timezone'] = $default_timezone;
+ unset($default_timezone);
+ }
+ if (isset($lang)) {
+ $config['system']['language'] = $lang;
+ unset($lang);
+ }
+ }
+
+ return $config;
+ }
+
+ /**
+ * Tries to load the specified legacy configuration file and returns the config array.
+ *
+ * @deprecated since version 2018.12
+ * @param string $filepath
+ *
+ * @return array The configuration array
+ * @throws \Exception
+ */
+ private function loadINIConfigFile($filepath)
+ {
+ $contents = include($filepath);
+
+ $config = parse_ini_string($contents, true, INI_SCANNER_TYPED);
+
+ if ($config === false) {
+ throw new \Exception('Error parsing INI config file ' . $filepath);
+ }
+
+ return $config;
+ }
+
+ /**
+ * Tries to load the specified configuration file and returns the config array.
+ *
+ * The config format is PHP array and the template for configuration files is the following:
+ *
+ * <?php return [
+ * 'section' => [
+ * 'key' => 'value',
+ * ],
+ * ];
+ *
+ * @param string $filepath The filepath of the
+ * @return array The config array0
+ *
+ * @throws \Exception if the config cannot get loaded.
+ */
+ private function loadConfigFile($filepath)
+ {
+ $config = include($filepath);
+
+ if (!is_array($config)) {
+ throw new \Exception('Error loading config file ' . $filepath);
+ }
+
+ return $config;
+ }
+}
--- /dev/null
+<?php
+
+namespace Friendica\Util\Config;
+
+/**
+ * An abstract class in case of handling with config files
+ */
+abstract class ConfigFileManager
+{
+ /**
+ * The Sub directory of the config-files
+ * @var string
+ */
+ const SUBDIRECTORY = 'config';
+
+ /**
+ * The default name of the user defined config file
+ * @var string
+ */
+ const CONFIG_LOCAL = 'local';
+
+ /**
+ * The default name of the user defined ini file
+ * @var string
+ */
+ const CONFIG_INI = 'local';
+
+ /**
+ * The default name of the user defined legacy config file
+ * @var string
+ */
+ const CONFIG_HTCONFIG = 'htconfig';
+
+ protected $baseDir;
+ protected $configDir;
+
+ /**
+ * @param string $baseDir The base directory of Friendica
+ */
+ public function __construct($baseDir)
+ {
+ $this->baseDir = $baseDir;
+ $this->configDir = $baseDir . DIRECTORY_SEPARATOR . self::SUBDIRECTORY;
+ }
+
+ /**
+ * Gets the full name (including the path) for a *.config.php (default is local.config.php)
+ *
+ * @param string $name The config name (default is empty, which means local.config.php)
+ *
+ * @return string The full name or empty if not found
+ */
+ protected function getConfigFullName($name = '')
+ {
+ $name = !empty($name) ? $name : self::CONFIG_LOCAL;
+
+ $fullName = $this->configDir . DIRECTORY_SEPARATOR . $name . '.config.php';
+ return file_exists($fullName) ? $fullName : '';
+ }
+
+ /**
+ * Gets the full name (including the path) for a *.ini.php (default is local.ini.php)
+ *
+ * @param string $name The config name (default is empty, which means local.ini.php)
+ *
+ * @return string The full name or empty if not found
+ */
+ protected function getIniFullName($name = '')
+ {
+ $name = !empty($name) ? $name : self::CONFIG_INI;
+
+ $fullName = $this->configDir . DIRECTORY_SEPARATOR . $name . '.ini.php';
+ return file_exists($fullName) ? $fullName : '';
+ }
+
+ /**
+ * Gets the full name (including the path) for a .*.php (default is .htconfig.php)
+ *
+ * @param string $name The config name (default is empty, which means .htconfig.php)
+ *
+ * @return string The full name or empty if not found
+ */
+ protected function getHtConfigFullName($name = '')
+ {
+ $name = !empty($name) ? $name : self::CONFIG_HTCONFIG;
+
+ $fullName = $this->baseDir . DIRECTORY_SEPARATOR . '.' . $name . '.php';
+ return file_exists($fullName) ? $fullName : '';
+ }
+}
--- /dev/null
+<?php
+
+namespace Friendica\Util\Config;
+
+/**
+ * The ConfigFileSaver saves specific variables into the config-files
+ *
+ * It is capable of loading the following config files:
+ * - *.config.php (current)
+ * - *.ini.php (deprecated)
+ * - *.htconfig.php (deprecated)
+ */
+class ConfigFileSaver extends ConfigFileManager
+{
+ /**
+ * The standard indentation for config files
+ * @var string
+ */
+ const INDENT = "\t";
+
+ /**
+ * The settings array to save to
+ * @var array
+ */
+ private $settings = [];
+
+ /**
+ * Adds a given value to the config file
+ * Either it replaces the current value or it will get added
+ *
+ * @param string $cat The configuration category
+ * @param string $key The configuration key
+ * @param string $value The new value
+ */
+ public function addConfigValue($cat, $key, $value)
+ {
+ $settingsCount = count(array_keys($this->settings));
+
+ for ($i = 0; $i < $settingsCount; $i++) {
+ // if already set, overwrite the value
+ if ($this->settings[$i]['cat'] === $cat &&
+ $this->settings[$i]['key'] === $key) {
+ $this->settings[$i] = ['cat' => $cat, 'key' => $key, 'value' => $value];
+ return;
+ }
+ }
+
+ $this->settings[] = ['cat' => $cat, 'key' => $key, 'value' => $value];
+ }
+
+ /**
+ * Resetting all added configuration entries so far
+ */
+ public function reset()
+ {
+ $this->settings = [];
+ }
+
+ /**
+ * Save all added configuration entries to the given config files
+ * After updating the config entries, all configuration entries will be reseted
+ *
+ * @param string $name The name of the configuration file (default is empty, which means the default name each type)
+ *
+ * @return bool true, if at least one configuration file was successfully updated or nothing to do
+ */
+ public function saveToConfigFile($name = '')
+ {
+ // If no settings et, return true
+ if (count(array_keys($this->settings)) === 0) {
+ return true;
+ }
+
+ $saved = false;
+
+ // Check for the *.config.php file inside the /config/ path
+ list($reading, $writing) = $this->openFile($this->getConfigFullName($name));
+ if (isset($reading) && isset($writing)) {
+ $this->saveConfigFile($reading, $writing);
+ // Close the current file handler and rename them
+ if ($this->closeFile($this->getConfigFullName($name), $reading, $writing)) {
+ // just return true, if everything went fine
+ $saved = true;
+ }
+ }
+
+ // Check for the *.ini.php file inside the /config/ path
+ list($reading, $writing) = $this->openFile($this->getIniFullName($name));
+ if (isset($reading) && isset($writing)) {
+ $this->saveINIConfigFile($reading, $writing);
+ // Close the current file handler and rename them
+ if ($this->closeFile($this->getIniFullName($name), $reading, $writing)) {
+ // just return true, if everything went fine
+ $saved = true;
+ }
+ }
+
+ // Check for the *.php file (normally .htconfig.php) inside the / path
+ list($reading, $writing) = $this->openFile($this->getHtConfigFullName($name));
+ if (isset($reading) && isset($writing)) {
+ $this->saveToLegacyConfig($reading, $writing);
+ // Close the current file handler and rename them
+ if ($this->closeFile($this->getHtConfigFullName($name), $reading, $writing)) {
+ // just return true, if everything went fine
+ $saved = true;
+ }
+ }
+
+ $this->reset();
+
+ return $saved;
+ }
+
+ /**
+ * Opens a config file and returns two handler for reading and writing
+ *
+ * @param string $fullName The full name of the current config
+ *
+ * @return array An array containing the two reading and writing handler
+ */
+ private function openFile($fullName)
+ {
+ if (empty($fullName)) {
+ return [null, null];
+ }
+
+ try {
+ $reading = fopen($fullName, 'r');
+ } catch (\Exception $exception) {
+ return [null, null];
+ }
+
+ if (!$reading) {
+ return [null, null];
+ }
+
+ try {
+ $writing = fopen($fullName . '.tmp', 'w');
+ } catch (\Exception $exception) {
+ fclose($reading);
+ return [null, null];
+ }
+
+ if (!$writing) {
+ fclose($reading);
+ return [null, null];
+ }
+
+ return [$reading, $writing];
+ }
+
+ /**
+ * Close and rename the config file
+ *
+ * @param string $fullName The full name of the current config
+ * @param resource $reading The reading resource handler
+ * @param resource $writing The writing resource handler
+ *
+ * @return bool True, if the close was successful
+ */
+ private function closeFile($fullName, $reading, $writing)
+ {
+ fclose($reading);
+ fclose($writing);
+
+ try {
+ $renamed = rename($fullName, $fullName . '.old');
+ } catch (\Exception $exception) {
+ return false;
+ }
+
+ if (!$renamed) {
+ return false;
+ }
+
+ try {
+ $renamed = rename($fullName . '.tmp', $fullName);
+ } catch (\Exception $exception) {
+ // revert the move of the current config file to have at least the old config
+ rename($fullName . '.old', $fullName);
+ return false;
+ }
+
+ if (!$renamed) {
+ // revert the move of the current config file to have at least the old config
+ rename($fullName . '.old', $fullName);
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Saves all configuration values to a config file
+ *
+ * @param resource $reading The reading handler
+ * @param resource $writing The writing handler
+ */
+ private function saveConfigFile($reading, $writing)
+ {
+ $settingsCount = count(array_keys($this->settings));
+ $categoryFound = array_fill(0, $settingsCount, false);
+ $categoryBracketFound = array_fill(0, $settingsCount, false);;
+ $lineFound = array_fill(0, $settingsCount, false);;
+ $lineArrowFound = array_fill(0, $settingsCount, false);;
+
+ while (!feof($reading)) {
+
+ $line = fgets($reading);
+
+ // check for each added setting if we have to replace a config line
+ for ($i = 0; $i < $settingsCount; $i++) {
+
+ // find the first line like "'system' =>"
+ if (!$categoryFound[$i] && stristr($line, sprintf('\'%s\'', $this->settings[$i]['cat']))) {
+ $categoryFound[$i] = true;
+ }
+
+ // find the first line with a starting bracket ( "[" )
+ if ($categoryFound[$i] && !$categoryBracketFound[$i] && stristr($line, '[')) {
+ $categoryBracketFound[$i] = true;
+ }
+
+ // find the first line with the key like "'value'"
+ if ($categoryBracketFound[$i] && !$lineFound[$i] && stristr($line, sprintf('\'%s\'', $this->settings[$i]['key']))) {
+ $lineFound[$i] = true;
+ }
+
+ // find the first line with an arrow ("=>") after finding the key
+ if ($lineFound[$i] && !$lineArrowFound[$i] && stristr($line, '=>')) {
+ $lineArrowFound[$i] = true;
+ }
+
+ // find the current value and replace it
+ if ($lineArrowFound[$i] && preg_match_all('/\'(.*?)\'/', $line, $matches, PREG_SET_ORDER)) {
+ $lineVal = end($matches)[0];
+ $line = str_replace($lineVal, '\'' . $this->settings[$i]['value'] . '\'', $line);
+ $categoryFound[$i] = false;
+ $categoryBracketFound[$i] = false;
+ $lineFound[$i] = false;
+ $lineArrowFound[$i] = false;
+ // if a line contains a closing bracket for the category ( "]" ) and we didn't find the key/value pair,
+ // add it as a new line before the closing bracket
+ } elseif ($categoryBracketFound[$i] && !$lineArrowFound[$i] && stristr($line, ']')) {
+ $categoryFound[$i] = false;
+ $categoryBracketFound[$i] = false;
+ $lineFound[$i] = false;
+ $lineArrowFound[$i] = false;
+ $newLine = sprintf(self::INDENT . self::INDENT . '\'%s\' => \'%s\',' . PHP_EOL, $this->settings[$i]['key'], $this->settings[$i]['value']);
+ $line = $newLine . $line;
+ }
+ }
+
+ fputs($writing, $line);
+ }
+ }
+
+ /**
+ * Saves a value to a ini file
+ *
+ * @param resource $reading The reading handler
+ * @param resource $writing The writing handler
+ */
+ private function saveINIConfigFile($reading, $writing)
+ {
+ $settingsCount = count(array_keys($this->settings));
+ $categoryFound = array_fill(0, $settingsCount, false);
+
+ while (!feof($reading)) {
+
+ $line = fgets($reading);
+
+ // check for each added setting if we have to replace a config line
+ for ($i = 0; $i < $settingsCount; $i++) {
+
+ // find the category of the current setting
+ if (!$categoryFound[$i] && stristr($line, sprintf('[%s]', $this->settings[$i]['cat']))) {
+ $categoryFound[$i] = true;
+
+ // check the current value
+ } elseif ($categoryFound[$i] && preg_match_all('/^' . $this->settings[$i]['key'] . '\s*=\s*(.*?)$/', $line, $matches, PREG_SET_ORDER)) {
+ $line = $this->settings[$i]['key'] . ' = ' . $this->settings[$i]['value'] . PHP_EOL;
+ $categoryFound[$i] = false;
+
+ // If end of INI file, add the line before the INI end
+ } elseif ($categoryFound[$i] && (preg_match_all('/^\[.*?\]$/', $line) || preg_match_all('/^INI;.*$/', $line))) {
+ $categoryFound[$i] = false;
+ $newLine = $this->settings[$i]['key'] . ' = ' . $this->settings[$i]['value'] . PHP_EOL;
+ $line = $newLine . $line;
+ }
+ }
+
+ fputs($writing, $line);
+ }
+ }
+
+ /**
+ * Saves a value to a .php file (normally .htconfig.php)
+ *
+ * @param resource $reading The reading handler
+ * @param resource $writing The writing handler
+ */
+ private function saveToLegacyConfig($reading, $writing)
+ {
+ $settingsCount = count(array_keys($this->settings));
+ $found = array_fill(0, $settingsCount, false);
+ while (!feof($reading)) {
+
+ $line = fgets($reading);
+
+ // check for each added setting if we have to replace a config line
+ for ($i = 0; $i < $settingsCount; $i++) {
+
+ // check for a non plain config setting (use category too)
+ if ($this->settings[$i]['cat'] !== 'config' && preg_match_all('/^\$a\-\>config\[\'' . $this->settings[$i]['cat'] . '\'\]\[\'' . $this->settings[$i]['key'] . '\'\]\s*=\s\'*(.*?)\';$/', $line, $matches, PREG_SET_ORDER)) {
+ $line = '$a->config[\'' . $this->settings[$i]['cat'] . '\'][\'' . $this->settings[$i]['key'] . '\'] = \'' . $this->settings[$i]['value'] . '\';' . PHP_EOL;
+ $found[$i] = true;
+
+ // check for a plain config setting (don't use a category)
+ } elseif ($this->settings[$i]['cat'] === 'config' && preg_match_all('/^\$a\-\>config\[\'' . $this->settings[$i]['key'] . '\'\]\s*=\s\'*(.*?)\';$/', $line, $matches, PREG_SET_ORDER)) {
+ $line = '$a->config[\'' . $this->settings[$i]['key'] . '\'] = \'' . $this->settings[$i]['value'] . '\';' . PHP_EOL;
+ $found[$i] = true;
+ }
+ }
+
+ fputs($writing, $line);
+ }
+
+ for ($i = 0; $i < $settingsCount; $i++) {
+ if (!$found[$i]) {
+ if ($this->settings[$i]['cat'] !== 'config') {
+ $line = '$a->config[\'' . $this->settings[$i]['cat'] . '\'][\'' . $this->settings[$i]['key'] . '\'] = \'' . $this->settings[$i]['value'] . '\';' . PHP_EOL;
+ } else {
+ $line = '$a->config[\'' . $this->settings[$i]['key'] . '\'] = \'' . $this->settings[$i]['value'] . '\';' . PHP_EOL;
+ }
+
+ fputs($writing, $line);
+ }
+ }
+ }
+}
*/
namespace Friendica\Util;
+use Friendica\Database\DBA;
use Friendica\Core\Config;
use Friendica\Core\Logger;
use Friendica\Model\User;
Logger::log('Transmit to ' . $target . ' returned ' . $return_code, Logger::DEBUG);
- return ($return_code >= 200) && ($return_code <= 299);
+ $success = ($return_code >= 200) && ($return_code <= 299);
+
+ self::setInboxStatus($target, $success);
+
+ return $success;
+ }
+
+ /**
+ * @brief Set the delivery status for a given inbox
+ *
+ * @param string $url The URL of the inbox
+ * @param boolean $success Transmission status
+ */
+ static private function setInboxStatus($url, $success)
+ {
+ $now = DateTimeFormat::utcNow();
+
+ $status = DBA::selectFirst('inbox-status', [], ['url' => $url]);
+ if (!DBA::isResult($status)) {
+ DBA::insert('inbox-status', ['url' => $url, 'created' => $now]);
+ $status = DBA::selectFirst('inbox-status', [], ['url' => $url]);
+ }
+
+ if ($success) {
+ $fields = ['success' => $now];
+ } else {
+ $fields = ['failure' => $now];
+ }
+
+ if ($status['failure'] > DBA::NULL_DATETIME) {
+ $new_previous_stamp = strtotime($status['failure']);
+ $old_previous_stamp = strtotime($status['previous']);
+
+ // Only set "previous" with at least one day difference.
+ // We use this to assure to not accidentally archive too soon.
+ if (($new_previous_stamp - $old_previous_stamp) >= 86400) {
+ $fields['previous'] = $status['failure'];
+ }
+ }
+
+ if (!$success) {
+ if ($status['success'] <= DBA::NULL_DATETIME) {
+ $stamp1 = strtotime($status['created']);
+ } else {
+ $stamp1 = strtotime($status['success']);
+ }
+
+ $stamp2 = strtotime($now);
+ $previous_stamp = strtotime($status['previous']);
+
+ // Archive the inbox when there had been failures for five days.
+ // Additionally ensure that at least one previous attempt has to be in between.
+ if ((($stamp2 - $stamp1) >= 86400 * 5) && ($previous_stamp > $stamp1)) {
+ $fields['archive'] = true;
+ }
+ } else {
+ $fields['archive'] = false;
+ }
+
+ DBA::update('inbox-status', $fields, ['url' => $url]);
}
/**
namespace Friendica\Worker;
use Friendica\BaseObject;
+use Friendica\Core\Config;
use Friendica\Core\Update;
class DBUpdate extends BaseObject
{
public static function execute()
{
- Update::run(self::getApp()->getBasePath());
+ // Just in case the last update wasn't failed
+ if (Config::get('system', 'update', Update::SUCCESS, true) != Update::FAILED) {
+ Update::run(self::getApp()->getBasePath());
+ }
}
}
namespace Friendica\Test;
use Friendica\App;
-use Friendica\Core\Config\Cache;
use Friendica\Database\DBA;
use Friendica\Factory;
use Friendica\Util\BasePath;
+use Friendica\Util\Config\ConfigFileLoader;
use Friendica\Util\Profiler;
use PHPUnit\DbUnit\DataSet\YamlDataSet;
use PHPUnit\DbUnit\TestCaseTrait;
$basePath = BasePath::create(dirname(__DIR__));
$mode = new App\Mode($basePath);
- $configLoader = new Cache\ConfigCacheLoader($basePath, $mode);
+ $configLoader = new ConfigFileLoader($basePath, $mode);
$config = Factory\ConfigFactory::createCache($configLoader);
$profiler = \Mockery::mock(Profiler::class);
--- /dev/null
+<?php
+/**
+ * A test .htconfig file
+ */
+
+$db_host = 'testhost';
+$db_user = 'testuser';
+$db_pass = 'testpw';
+$db_data = 'testdb';
+
+$pidfile = '/var/run/friendica.pid';
+
+// Set the database connection charset to UTF8.
+// Changing this value will likely corrupt the special characters.
+// You have been warned.
+$a->config['system']['db_charset'] = "anotherCharset";
+
+// Choose a legal default timezone. If you are unsure, use "America/Los_Angeles".
+// It can be changed later and only applies to timestamps for anonymous viewers.
+$default_timezone = 'Europe/Berlin';
+$lang = 'fr';
+
+// What is your site name?
+$a->config['sitename'] = "Friendica My Network";
+
+// Your choices are REGISTER_OPEN, REGISTER_APPROVE, or REGISTER_CLOSED.
+// Be certain to create your own personal account before setting
+// REGISTER_CLOSED. 'register_text' (if set) will be displayed prominently on
+// the registration page. REGISTER_APPROVE requires you set 'admin_email'
+// to the email address of an already registered person who can authorise
+// and/or approve/deny the request.
+// In order to perform system administration via the admin panel, admin_email
+// must precisely match the email address of the person logged in.
+$a->config['register_policy'] = REGISTER_OPEN;
+$a->config['register_text'] = 'A register text';
+$a->config['admin_email'] = 'admin@test.it';
+$a->config['admin_nickname'] = 'Friendly admin';
+
+// Maximum size of an imported message, 0 is unlimited
+$a->config['max_import_size'] = 999;
+
+// maximum size of uploaded photos
+$a->config['system']['maximagesize'] = 666;
+
+// Location of PHP command line processor
+$a->config['php_path'] = '/another/php';
+
+// PuSH - aka pubsubhubbub URL. This makes delivery of public posts as fast as private posts
+$a->config['system']['huburl'] = '[internal]';
+
+// allowed themes (change this from admin panel after installation)
+$a->config['system']['allowed_themes'] = 'quattro,vier,duepuntozero';
+
+// default system theme
+$a->config['system']['theme'] = 'frio';
+
+// By default allow pseudonyms
+$a->config['system']['no_regfullname'] = true;
+
+//Deny public access to the local directory
+//$a->config['system']['block_local_dir'] = false;
+// Location of the global directory
+$a->config['system']['directory'] = 'http://another.url';
+++ /dev/null
-<?php
-/**
- * A test .htconfig file
- */
-
-$db_host = 'testhost';
-$db_user = 'testuser';
-$db_pass = 'testpw';
-$db_data = 'testdb';
-
-$pidfile = '/var/run/friendica.pid';
-
-// Set the database connection charset to UTF8.
-// Changing this value will likely corrupt the special characters.
-// You have been warned.
-$a->config['system']['db_charset'] = "anotherCharset";
-
-// Choose a legal default timezone. If you are unsure, use "America/Los_Angeles".
-// It can be changed later and only applies to timestamps for anonymous viewers.
-$default_timezone = 'Europe/Berlin';
-$lang = 'fr';
-
-// What is your site name?
-$a->config['sitename'] = "Friendica My Network";
-
-// Your choices are REGISTER_OPEN, REGISTER_APPROVE, or REGISTER_CLOSED.
-// Be certain to create your own personal account before setting
-// REGISTER_CLOSED. 'register_text' (if set) will be displayed prominently on
-// the registration page. REGISTER_APPROVE requires you set 'admin_email'
-// to the email address of an already registered person who can authorise
-// and/or approve/deny the request.
-// In order to perform system administration via the admin panel, admin_email
-// must precisely match the email address of the person logged in.
-$a->config['register_policy'] = REGISTER_OPEN;
-$a->config['register_text'] = 'A register text';
-$a->config['admin_email'] = 'admin@friendica.local';
-$a->config['admin_nickname'] = 'Friendly admin';
-
-// Maximum size of an imported message, 0 is unlimited
-$a->config['max_import_size'] = 999;
-
-// maximum size of uploaded photos
-$a->config['system']['maximagesize'] = 666;
-
-// Location of PHP command line processor
-$a->config['php_path'] = '/another/php';
-
-// PuSH - aka pubsubhubbub URL. This makes delivery of public posts as fast as private posts
-$a->config['system']['huburl'] = '[internal]';
-
-// allowed themes (change this from admin panel after installation)
-$a->config['system']['allowed_themes'] = 'quattro,vier,duepuntozero';
-
-// default system theme
-$a->config['system']['theme'] = 'duepuntozero';
-
-// By default allow pseudonyms
-$a->config['system']['no_regfullname'] = true;
-
-//Deny public access to the local directory
-//$a->config['system']['block_local_dir'] = false;
-// Location of the global directory
-$a->config['system']['directory'] = 'http://another.url';
'system' => [
'default_timezone' => 'UTC',
'language' => 'en',
+ 'theme' => 'frio',
],
];
password = testpw
database = testdb
+[system]
+theme = frio
+
[config]
admin_email = admin@test.it
INI;
use Friendica\App;
use Friendica\Core\Config;
-use Friendica\Core\Config\Cache;
use Friendica\Core\PConfig;
use Friendica\Core\Protocol;
use Friendica\Core\System;
use Friendica\Factory;
use Friendica\Network\HTTPException;
use Friendica\Util\BasePath;
+use Friendica\Util\Config\ConfigFileLoader;
use Monolog\Handler\TestHandler;
require_once __DIR__ . '/../../include/api.php';
{
$basePath = BasePath::create(dirname(__DIR__) . '/../');
$mode = new App\Mode($basePath);
- $configLoader = new Cache\ConfigCacheLoader($basePath, $mode);
+ $configLoader = new ConfigFileLoader($basePath, $mode);
$configCache = Factory\ConfigFactory::createCache($configLoader);
$profiler = Factory\ProfilerFactory::create($configCache);
Factory\DBFactory::init($basePath, $configCache, $profiler, $_SERVER);
$config = Factory\ConfigFactory::createConfig($configCache);
Factory\ConfigFactory::createPConfig($configCache);
$logger = Factory\LoggerFactory::create('test', $config, $profiler);
- $this->app = new App($basePath, $config, $mode, $logger, $profiler, false);
+ $this->app = new App($config, $mode, $logger, $profiler, false);
parent::setUp();
--- /dev/null
+<?php\r
+/**\r
+ * Created by PhpStorm.\r
+ * User: benlo\r
+ * Date: 25/03/19\r
+ * Time: 21:36\r
+ */\r
+\r
+namespace Friendica\Test\src\Content;\r
+\r
+use Friendica\Content\Smilies;\r
+use Friendica\Test\MockedTest;\r
+use Friendica\Test\Util\AppMockTrait;\r
+use Friendica\Test\Util\L10nMockTrait;\r
+use Friendica\Test\Util\VFSTrait;\r
+\r
+class SmiliesTest extends MockedTest\r
+{\r
+ use VFSTrait;\r
+ use AppMockTrait;\r
+ use L10nMockTrait;\r
+\r
+ protected function setUp()\r
+ {\r
+ parent::setUp();\r
+ $this->setUpVfsDir();\r
+ $this->mockApp($this->root);\r
+ $this->app->videowidth = 425;\r
+ $this->app->videoheight = 350;\r
+ $this->configMock->shouldReceive('get')\r
+ ->with('system', 'no_smilies')\r
+ ->andReturn(false);\r
+ $this->configMock->shouldReceive('get')\r
+ ->with(false, 'system', 'no_smilies')\r
+ ->andReturn(false);\r
+ }\r
+\r
+ public function dataLinks()\r
+ {\r
+ return [\r
+ /** @see https://github.com/friendica/friendica/pull/6933 */\r
+ 'bug-6933-1' => [\r
+ 'data' => '<code>/</code>',\r
+ 'smilies' => ['texts' => [], 'icons' => []],\r
+ 'expected' => '<code>/</code>',\r
+ ],\r
+ 'bug-6933-2' => [\r
+ 'data' => '<code>code</code>',\r
+ 'smilies' => ['texts' => [], 'icons' => []],\r
+ 'expected' => '<code>code</code>',\r
+ ],\r
+ ];\r
+ }\r
+\r
+ /**\r
+ * Test replace smilies in different texts\r
+ * @dataProvider dataLinks\r
+ *\r
+ * @param string $text Test string\r
+ * @param array $smilies List of smilies to replace\r
+ * @param string $expected Expected result\r
+ * @throws \Friendica\Network\HTTPException\InternalServerErrorException\r
+ */\r
+ public function testReplaceFromArray($text, $smilies, $expected)\r
+ {\r
+ $output = Smilies::replaceFromArray($text, $smilies);\r
+ $this->assertEquals($expected, $output);\r
+ }\r
+}\r
+++ /dev/null
-<?php
-
-namespace Friendica\Test\src\Core\Config\Cache;
-
-use Friendica\App;
-use Friendica\Core\Config\Cache\ConfigCache;
-use Friendica\Core\Config\Cache\ConfigCacheLoader;
-use Friendica\Test\MockedTest;
-use Friendica\Test\Util\VFSTrait;
-use Mockery\MockInterface;
-use org\bovigo\vfs\vfsStream;
-
-class ConfigCacheLoaderTest extends MockedTest
-{
- use VFSTrait;
-
- /**
- * @var App\Mode|MockInterface
- */
- private $mode;
-
- protected function setUp()
- {
- parent::setUp();
-
- $this->setUpVfsDir();
-
- $this->mode = \Mockery::mock(App\Mode::class);
- $this->mode->shouldReceive('isInstall')->andReturn(true);
- }
-
- /**
- * Test the loadConfigFiles() method with default values
- */
- public function testLoadConfigFiles()
- {
- $configCacheLoader = new ConfigCacheLoader($this->root->url(), $this->mode);
- $configCache = new ConfigCache();
-
- $configCacheLoader->loadConfigFiles($configCache);
-
- $this->assertEquals($this->root->url(), $configCache->get('system', 'basepath'));
- }
-
- /**
- * Test the loadConfigFiles() method with a wrong local.config.php
- * @expectedException \Exception
- * @expectedExceptionMessageRegExp /Error loading config file \w+/
- */
- public function testLoadConfigWrong()
- {
- $this->delConfigFile('local.config.php');
-
- vfsStream::newFile('local.config.php')
- ->at($this->root->getChild('config'))
- ->setContent('<?php return true;');
-
- $configCacheLoader = new ConfigCacheLoader($this->root->url(), $this->mode);
- $configCache = new ConfigCache();
-
- $configCacheLoader->loadConfigFiles($configCache);
- }
-
- /**
- * Test the loadConfigFiles() method with a local.config.php file
- */
- public function testLoadConfigFilesLocal()
- {
- $this->delConfigFile('local.config.php');
-
- $file = dirname(__DIR__) . DIRECTORY_SEPARATOR .
- '..' . DIRECTORY_SEPARATOR .
- '..' . DIRECTORY_SEPARATOR .
- '..' . DIRECTORY_SEPARATOR .
- 'datasets' . DIRECTORY_SEPARATOR .
- 'config' . DIRECTORY_SEPARATOR .
- 'local.config.php';
-
- vfsStream::newFile('local.config.php')
- ->at($this->root->getChild('config'))
- ->setContent(file_get_contents($file));
-
- $configCacheLoader = new ConfigCacheLoader($this->root->url(), $this->mode);
- $configCache = new ConfigCache();
-
- $configCacheLoader->loadConfigFiles($configCache);
-
- $this->assertEquals('testhost', $configCache->get('database', 'hostname'));
- $this->assertEquals('testuser', $configCache->get('database', 'username'));
- $this->assertEquals('testpw', $configCache->get('database', 'password'));
- $this->assertEquals('testdb', $configCache->get('database', 'database'));
-
- $this->assertEquals('admin@test.it', $configCache->get('config', 'admin_email'));
- $this->assertEquals('Friendica Social Network', $configCache->get('config', 'sitename'));
- }
-
- /**
- * Test the loadConfigFile() method with a local.ini.php file
- */
- public function testLoadConfigFilesINI()
- {
- $this->delConfigFile('local.config.php');
-
- $file = dirname(__DIR__) . DIRECTORY_SEPARATOR .
- '..' . DIRECTORY_SEPARATOR .
- '..' . DIRECTORY_SEPARATOR .
- '..' . DIRECTORY_SEPARATOR .
- 'datasets' . DIRECTORY_SEPARATOR .
- 'config' . DIRECTORY_SEPARATOR .
- 'local.ini.php';
-
- vfsStream::newFile('local.ini.php')
- ->at($this->root->getChild('config'))
- ->setContent(file_get_contents($file));
-
- $configCacheLoader = new ConfigCacheLoader($this->root->url(), $this->mode);
- $configCache = new ConfigCache();
-
- $configCacheLoader->loadConfigFiles($configCache);
-
- $this->assertEquals('testhost', $configCache->get('database', 'hostname'));
- $this->assertEquals('testuser', $configCache->get('database', 'username'));
- $this->assertEquals('testpw', $configCache->get('database', 'password'));
- $this->assertEquals('testdb', $configCache->get('database', 'database'));
-
- $this->assertEquals('admin@test.it', $configCache->get('config', 'admin_email'));
- }
-
- /**
- * Test the loadConfigFile() method with a .htconfig.php file
- */
- public function testLoadConfigFilesHtconfig()
- {
- $this->delConfigFile('local.config.php');
-
- $file = dirname(__DIR__) . DIRECTORY_SEPARATOR .
- '..' . DIRECTORY_SEPARATOR .
- '..' . DIRECTORY_SEPARATOR .
- '..' . DIRECTORY_SEPARATOR .
- 'datasets' . DIRECTORY_SEPARATOR .
- 'config' . DIRECTORY_SEPARATOR .
- '.htconfig.test.php';
-
- vfsStream::newFile('.htconfig.php')
- ->at($this->root)
- ->setContent(file_get_contents($file));
-
- $configCacheLoader = new ConfigCacheLoader($this->root->url(), $this->mode);
- $configCache = new ConfigCache();
-
- $configCacheLoader->loadConfigFiles($configCache);
-
- $this->assertEquals('testhost', $configCache->get('database', 'hostname'));
- $this->assertEquals('testuser', $configCache->get('database', 'username'));
- $this->assertEquals('testpw', $configCache->get('database', 'password'));
- $this->assertEquals('testdb', $configCache->get('database', 'database'));
- $this->assertEquals('anotherCharset', $configCache->get('database', 'charset'));
-
- $this->assertEquals('/var/run/friendica.pid', $configCache->get('system', 'pidfile'));
- $this->assertEquals('Europe/Berlin', $configCache->get('system', 'default_timezone'));
- $this->assertEquals('fr', $configCache->get('system', 'language'));
-
- $this->assertEquals('admin@friendica.local', $configCache->get('config', 'admin_email'));
- $this->assertEquals('Friendly admin', $configCache->get('config', 'admin_nickname'));
-
- $this->assertEquals('/another/php', $configCache->get('config', 'php_path'));
- $this->assertEquals('999', $configCache->get('config', 'max_import_size'));
- $this->assertEquals('666', $configCache->get('system', 'maximagesize'));
-
- $this->assertEquals('quattro,vier,duepuntozero', $configCache->get('system', 'allowed_themes'));
- $this->assertEquals('1', $configCache->get('system', 'no_regfullname'));
- }
-
- public function testLoadAddonConfig()
- {
- $structure = [
- 'addon' => [
- 'test' => [
- 'config' => [],
- ],
- ],
- ];
-
- vfsStream::create($structure, $this->root);
-
- $file = dirname(__DIR__) . DIRECTORY_SEPARATOR .
- '..' . DIRECTORY_SEPARATOR .
- '..' . DIRECTORY_SEPARATOR .
- '..' . DIRECTORY_SEPARATOR .
- 'datasets' . DIRECTORY_SEPARATOR .
- 'config' . DIRECTORY_SEPARATOR .
- 'local.config.php';
-
- vfsStream::newFile('test.config.php')
- ->at($this->root->getChild('addon')->getChild('test')->getChild('config'))
- ->setContent(file_get_contents($file));
-
- $configCacheLoader = new ConfigCacheLoader($this->root->url(), $this->mode);
-
- $conf = $configCacheLoader->loadAddonConfig('test');
-
- $this->assertEquals('testhost', $conf['database']['hostname']);
- $this->assertEquals('testuser', $conf['database']['username']);
- $this->assertEquals('testpw', $conf['database']['password']);
- $this->assertEquals('testdb', $conf['database']['database']);
-
- $this->assertEquals('admin@test.it', $conf['config']['admin_email']);
- }
-}
use Friendica\App;
use Friendica\Core\Config;
-use Friendica\Core\Config\Cache;
use Friendica\Database\DBA;
use Friendica\Factory;
use Friendica\Test\DatabaseTest;
use Friendica\Util\BasePath;
+use Friendica\Util\Config\ConfigFileLoader;
class DBATest extends DatabaseTest
{
{
$basePath = BasePath::create(dirname(__DIR__) . '/../../');
$mode = new App\Mode($basePath);
- $configLoader = new Cache\ConfigCacheLoader($basePath, $mode);
+ $configLoader = new ConfigFileLoader($basePath, $mode);
$configCache = Factory\ConfigFactory::createCache($configLoader);
$profiler = Factory\ProfilerFactory::create($configCache);
Factory\DBFactory::init($basePath, $configCache, $profiler, $_SERVER);
$config = Factory\ConfigFactory::createConfig($configCache);
Factory\ConfigFactory::createPConfig($configCache);
$logger = Factory\LoggerFactory::create('test', $config, $profiler);
- $this->app = new App($basePath, $config, $mode, $logger, $profiler, false);
+ $this->app = new App($config, $mode, $logger, $profiler, false);
parent::setUp();
namespace Friendica\Test\src\Database;
use Friendica\App;
-use Friendica\Core\Config\Cache;
use Friendica\Database\DBStructure;
use Friendica\Factory;
use Friendica\Test\DatabaseTest;
use Friendica\Util\BasePath;
+use Friendica\Util\Config\ConfigFileLoader;
class DBStructureTest extends DatabaseTest
{
{
$basePath = BasePath::create(dirname(__DIR__) . '/../../');
$mode = new App\Mode($basePath);
- $configLoader = new Cache\ConfigCacheLoader($basePath, $mode);
+ $configLoader = new ConfigFileLoader($basePath, $mode);
$configCache = Factory\ConfigFactory::createCache($configLoader);
$profiler = Factory\ProfilerFactory::create($configCache);
Factory\DBFactory::init($basePath, $configCache, $profiler, $_SERVER);
$config = Factory\ConfigFactory::createConfig($configCache);
Factory\ConfigFactory::createPConfig($configCache);
$logger = Factory\LoggerFactory::create('test', $config, $profiler);
- $this->app = new App($basePath, $config, $mode, $logger, $profiler, false);
+ $this->app = new App($config, $mode, $logger, $profiler, false);
parent::setUp();
}
--- /dev/null
+<?php
+
+namespace Friendica\Test\src\Util\Config;
+
+use Friendica\App;
+use Friendica\Core\Config\Cache\ConfigCache;
+use Friendica\Test\MockedTest;
+use Friendica\Test\Util\VFSTrait;
+use Friendica\Util\Config\ConfigFileLoader;
+use Mockery\MockInterface;
+use org\bovigo\vfs\vfsStream;
+
+class ConfigFileLoaderTest extends MockedTest
+{
+ use VFSTrait;
+
+ /**
+ * @var App\Mode|MockInterface
+ */
+ private $mode;
+
+ protected function setUp()
+ {
+ parent::setUp();
+
+ $this->setUpVfsDir();
+
+ $this->mode = \Mockery::mock(App\Mode::class);
+ $this->mode->shouldReceive('isInstall')->andReturn(true);
+ }
+
+ /**
+ * Test the loadConfigFiles() method with default values
+ */
+ public function testLoadConfigFiles()
+ {
+ $configFileLoader = new ConfigFileLoader($this->root->url(), $this->mode);
+ $configCache = new ConfigCache();
+
+ $configFileLoader->setupCache($configCache);
+
+ $this->assertEquals($this->root->url(), $configCache->get('system', 'basepath'));
+ }
+
+ /**
+ * Test the loadConfigFiles() method with a wrong local.config.php
+ * @expectedException \Exception
+ * @expectedExceptionMessageRegExp /Error loading config file \w+/
+ */
+ public function testLoadConfigWrong()
+ {
+ $this->delConfigFile('local.config.php');
+
+ vfsStream::newFile('local.config.php')
+ ->at($this->root->getChild('config'))
+ ->setContent('<?php return true;');
+
+ $configFileLoader = new ConfigFileLoader($this->root->url(), $this->mode);
+ $configCache = new ConfigCache();
+
+ $configFileLoader->setupCache($configCache);
+ }
+
+ /**
+ * Test the loadConfigFiles() method with a local.config.php file
+ */
+ public function testLoadConfigFilesLocal()
+ {
+ $this->delConfigFile('local.config.php');
+
+ $file = dirname(__DIR__) . DIRECTORY_SEPARATOR .
+ '..' . DIRECTORY_SEPARATOR .
+ '..' . DIRECTORY_SEPARATOR .
+ 'datasets' . DIRECTORY_SEPARATOR .
+ 'config' . DIRECTORY_SEPARATOR .
+ 'local.config.php';
+
+ vfsStream::newFile('local.config.php')
+ ->at($this->root->getChild('config'))
+ ->setContent(file_get_contents($file));
+
+ $configFileLoader = new ConfigFileLoader($this->root->url(), $this->mode);
+ $configCache = new ConfigCache();
+
+ $configFileLoader->setupCache($configCache);
+
+ $this->assertEquals('testhost', $configCache->get('database', 'hostname'));
+ $this->assertEquals('testuser', $configCache->get('database', 'username'));
+ $this->assertEquals('testpw', $configCache->get('database', 'password'));
+ $this->assertEquals('testdb', $configCache->get('database', 'database'));
+
+ $this->assertEquals('admin@test.it', $configCache->get('config', 'admin_email'));
+ $this->assertEquals('Friendica Social Network', $configCache->get('config', 'sitename'));
+ }
+
+ /**
+ * Test the loadConfigFile() method with a local.ini.php file
+ */
+ public function testLoadConfigFilesINI()
+ {
+ $this->delConfigFile('local.config.php');
+
+ $file = dirname(__DIR__) . DIRECTORY_SEPARATOR .
+ '..' . DIRECTORY_SEPARATOR .
+ '..' . DIRECTORY_SEPARATOR .
+ 'datasets' . DIRECTORY_SEPARATOR .
+ 'config' . DIRECTORY_SEPARATOR .
+ 'local.ini.php';
+
+ vfsStream::newFile('local.ini.php')
+ ->at($this->root->getChild('config'))
+ ->setContent(file_get_contents($file));
+
+ $configFileLoader = new ConfigFileLoader($this->root->url(), $this->mode);
+ $configCache = new ConfigCache();
+
+ $configFileLoader->setupCache($configCache);
+
+ $this->assertEquals('testhost', $configCache->get('database', 'hostname'));
+ $this->assertEquals('testuser', $configCache->get('database', 'username'));
+ $this->assertEquals('testpw', $configCache->get('database', 'password'));
+ $this->assertEquals('testdb', $configCache->get('database', 'database'));
+
+ $this->assertEquals('admin@test.it', $configCache->get('config', 'admin_email'));
+ }
+
+ /**
+ * Test the loadConfigFile() method with a .htconfig.php file
+ */
+ public function testLoadConfigFilesHtconfig()
+ {
+ $this->delConfigFile('local.config.php');
+
+ $file = dirname(__DIR__) . DIRECTORY_SEPARATOR .
+ '..' . DIRECTORY_SEPARATOR .
+ '..' . DIRECTORY_SEPARATOR .
+ 'datasets' . DIRECTORY_SEPARATOR .
+ 'config' . DIRECTORY_SEPARATOR .
+ '.htconfig.php';
+
+ vfsStream::newFile('.htconfig.php')
+ ->at($this->root)
+ ->setContent(file_get_contents($file));
+
+ $configFileLoader = new ConfigFileLoader($this->root->url(), $this->mode);
+ $configCache = new ConfigCache();
+
+ $configFileLoader->setupCache($configCache);
+
+ $this->assertEquals('testhost', $configCache->get('database', 'hostname'));
+ $this->assertEquals('testuser', $configCache->get('database', 'username'));
+ $this->assertEquals('testpw', $configCache->get('database', 'password'));
+ $this->assertEquals('testdb', $configCache->get('database', 'database'));
+ $this->assertEquals('anotherCharset', $configCache->get('database', 'charset'));
+
+ $this->assertEquals('/var/run/friendica.pid', $configCache->get('system', 'pidfile'));
+ $this->assertEquals('Europe/Berlin', $configCache->get('system', 'default_timezone'));
+ $this->assertEquals('fr', $configCache->get('system', 'language'));
+
+ $this->assertEquals('admin@test.it', $configCache->get('config', 'admin_email'));
+ $this->assertEquals('Friendly admin', $configCache->get('config', 'admin_nickname'));
+
+ $this->assertEquals('/another/php', $configCache->get('config', 'php_path'));
+ $this->assertEquals('999', $configCache->get('config', 'max_import_size'));
+ $this->assertEquals('666', $configCache->get('system', 'maximagesize'));
+
+ $this->assertEquals('quattro,vier,duepuntozero', $configCache->get('system', 'allowed_themes'));
+ $this->assertEquals('1', $configCache->get('system', 'no_regfullname'));
+ }
+
+ public function testLoadAddonConfig()
+ {
+ $structure = [
+ 'addon' => [
+ 'test' => [
+ 'config' => [],
+ ],
+ ],
+ ];
+
+ vfsStream::create($structure, $this->root);
+
+ $file = dirname(__DIR__) . DIRECTORY_SEPARATOR .
+ '..' . DIRECTORY_SEPARATOR .
+ '..' . DIRECTORY_SEPARATOR .
+ 'datasets' . DIRECTORY_SEPARATOR .
+ 'config' . DIRECTORY_SEPARATOR .
+ 'local.config.php';
+
+ vfsStream::newFile('test.config.php')
+ ->at($this->root->getChild('addon')->getChild('test')->getChild('config'))
+ ->setContent(file_get_contents($file));
+
+ $configFileLoader = new ConfigFileLoader($this->root->url(), $this->mode);
+
+ $conf = $configFileLoader->loadAddonConfig('test');
+
+ $this->assertEquals('testhost', $conf['database']['hostname']);
+ $this->assertEquals('testuser', $conf['database']['username']);
+ $this->assertEquals('testpw', $conf['database']['password']);
+ $this->assertEquals('testdb', $conf['database']['database']);
+
+ $this->assertEquals('admin@test.it', $conf['config']['admin_email']);
+ }
+}
--- /dev/null
+<?php
+
+namespace Friendica\Test\src\Util\Config;
+
+use Friendica\App;
+use Friendica\Core\Config\Cache\ConfigCache;
+use Friendica\Test\MockedTest;
+use Friendica\Test\Util\VFSTrait;
+use Friendica\Util\Config\ConfigFileLoader;
+use Friendica\Util\Config\ConfigFileSaver;
+use Mockery\MockInterface;
+use org\bovigo\vfs\vfsStream;
+
+class ConfigFileSaverTest extends MockedTest
+{
+ use VFSTrait;
+
+ /**
+ * @var App\Mode|MockInterface
+ */
+ private $mode;
+
+ protected function setUp()
+ {
+ parent::setUp();
+ $this->setUpVfsDir();
+ $this->mode = \Mockery::mock(App\Mode::class);
+ $this->mode->shouldReceive('isInstall')->andReturn(true);
+ }
+
+ public function dataConfigFiles()
+ {
+ return [
+ 'config' => [
+ 'fileName' => 'local.config.php',
+ 'filePath' => dirname(__DIR__) . DIRECTORY_SEPARATOR .
+ '..' . DIRECTORY_SEPARATOR .
+ '..' . DIRECTORY_SEPARATOR .
+ 'datasets' . DIRECTORY_SEPARATOR .
+ 'config',
+ 'relativePath' => 'config',
+ ],
+ 'ini' => [
+ 'fileName' => 'local.ini.php',
+ 'filePath' => dirname(__DIR__) . DIRECTORY_SEPARATOR .
+ '..' . DIRECTORY_SEPARATOR .
+ '..' . DIRECTORY_SEPARATOR .
+ 'datasets' . DIRECTORY_SEPARATOR .
+ 'config',
+ 'relativePath' => 'config',
+ ],
+ 'htconfig' => [
+ 'fileName' => '.htconfig.php',
+ 'filePath' => dirname(__DIR__) . DIRECTORY_SEPARATOR .
+ '..' . DIRECTORY_SEPARATOR .
+ '..' . DIRECTORY_SEPARATOR .
+ 'datasets' . DIRECTORY_SEPARATOR .
+ 'config',
+ 'relativePath' => '',
+ ],
+ ];
+ }
+
+ /**
+ * Test the saveToConfigFile() method
+ * @dataProvider dataConfigFiles
+ *
+ * @todo 20190324 [nupplaphil] for ini-configs, it isn't possible to use $ or ! inside values
+ */
+ public function testSaveToConfig($fileName, $filePath, $relativePath)
+ {
+ $this->delConfigFile('local.config.php');
+
+ if (empty($relativePath)) {
+ $root = $this->root;
+ $relativeFullName = $fileName;
+ } else {
+ $root = $this->root->getChild($relativePath);
+ $relativeFullName = $relativePath . DIRECTORY_SEPARATOR . $fileName;
+ }
+
+ vfsStream::newFile($fileName)
+ ->at($root)
+ ->setContent(file_get_contents($filePath . DIRECTORY_SEPARATOR . $fileName));
+
+ $configFileSaver = new ConfigFileSaver($this->root->url());
+ $configFileLoader = new ConfigFileLoader($this->root->url(), $this->mode);
+ $configCache = new ConfigCache();
+ $configFileLoader->setupCache($configCache);
+
+ $this->assertEquals('admin@test.it', $configCache->get('config', 'admin_email'));
+ $this->assertEquals('frio', $configCache->get('system', 'theme'));
+ $this->assertNull($configCache->get('config', 'test_val'));
+ $this->assertNull($configCache->get('system', 'test_val2'));
+
+ // update values (system and config value)
+ $configFileSaver->addConfigValue('config', 'admin_email', 'new@mail.it');
+ $configFileSaver->addConfigValue('system', 'theme', 'vier');
+
+ // insert values (system and config value)
+ $configFileSaver->addConfigValue('config', 'test_val', 'Testingwith@all.we can');
+ $configFileSaver->addConfigValue('system', 'test_val2', 'TestIt First');
+
+ // overwrite value
+ $configFileSaver->addConfigValue('system', 'test_val2', 'TestIt Now');
+
+ // save it
+ $this->assertTrue($configFileSaver->saveToConfigFile());
+
+ $newConfigCache = new ConfigCache();
+ $configFileLoader->setupCache($newConfigCache);
+
+ $this->assertEquals('new@mail.it', $newConfigCache->get('config', 'admin_email'));
+ $this->assertEquals('Testingwith@all.we can', $newConfigCache->get('config', 'test_val'));
+ $this->assertEquals('vier', $newConfigCache->get('system', 'theme'));
+ $this->assertEquals('TestIt Now', $newConfigCache->get('system', 'test_val2'));
+
+ $this->assertTrue($this->root->hasChild($relativeFullName));
+ $this->assertTrue($this->root->hasChild($relativeFullName . '.old'));
+ $this->assertFalse($this->root->hasChild($relativeFullName . '.tmp'));
+
+ $this->assertEquals(file_get_contents($filePath . DIRECTORY_SEPARATOR . $fileName), file_get_contents($this->root->getChild($relativeFullName . '.old')->url()));
+ }
+
+ /**
+ * Test the saveToConfigFile() method without permissions
+ * @dataProvider dataConfigFiles
+ */
+ public function testNoPermission($fileName, $filePath, $relativePath)
+ {
+ $this->delConfigFile('local.config.php');
+
+ if (empty($relativePath)) {
+ $root = $this->root;
+ $relativeFullName = $fileName;
+ } else {
+ $root = $this->root->getChild($relativePath);
+ $relativeFullName = $relativePath . DIRECTORY_SEPARATOR . $fileName;
+ }
+
+ $root->chmod(000);
+
+ vfsStream::newFile($fileName)
+ ->at($root)
+ ->setContent(file_get_contents($filePath . DIRECTORY_SEPARATOR . $fileName));
+
+ $configFileSaver = new ConfigFileSaver($this->root->url());
+
+ $configFileSaver->addConfigValue('system', 'test_val2', 'TestIt Now');
+
+ // wrong mod, so return false if nothing to write
+ $this->assertFalse($configFileSaver->saveToConfigFile());
+ }
+
+ /**
+ * Test the saveToConfigFile() method with nothing to do
+ * @dataProvider dataConfigFiles
+ */
+ public function testNothingToDo($fileName, $filePath, $relativePath)
+ {
+ $this->delConfigFile('local.config.php');
+
+ if (empty($relativePath)) {
+ $root = $this->root;
+ $relativeFullName = $fileName;
+ } else {
+ $root = $this->root->getChild($relativePath);
+ $relativeFullName = $relativePath . DIRECTORY_SEPARATOR . $fileName;
+ }
+
+ vfsStream::newFile($fileName)
+ ->at($root)
+ ->setContent(file_get_contents($filePath . DIRECTORY_SEPARATOR . $fileName));
+
+ $configFileSaver = new ConfigFileSaver($this->root->url());
+ $configFileLoader = new ConfigFileLoader($this->root->url(), $this->mode);
+ $configCache = new ConfigCache();
+ $configFileLoader->setupCache($configCache);
+
+ // save nothing
+ $this->assertTrue($configFileSaver->saveToConfigFile());
+
+ $this->assertTrue($this->root->hasChild($relativeFullName));
+ $this->assertFalse($this->root->hasChild($relativeFullName . '.old'));
+ $this->assertFalse($this->root->hasChild($relativeFullName . '.tmp'));
+
+ $this->assertEquals(file_get_contents($filePath . DIRECTORY_SEPARATOR . $fileName), file_get_contents($this->root->getChild($relativeFullName)->url()));
+ }
+}
<?php
+use Friendica\BaseObject;
use Friendica\Core\Addon;
use Friendica\Core\Config;
use Friendica\Core\L10n;
}
return Update::SUCCESS;
}
+
+/**
+ * @see https://github.com/friendica/friendica/pull/6920
+ * @return int Success
+ */
+function update_1307()
+{
+ $app = BaseObject::getApp();
+ if (Update::saveConfigToFile($app->getBasePath(), $app->getMode())) {
+ return Update::SUCCESS;
+ } else {
+ return Update::FAILED;
+ }
+}
/* General style rules .*/
.pull-right { float: right }
+details > summary {
+ cursor: pointer;
+}
+
/* General designing elements */
.btn {
outline: none;
this.deny_gid.length==0 && this.deny_cid.length==0);
};
-ACL.prototype.update_view = function(){
- if (this.is_show_all()){
- this.showall.addClass("selected");
- /* jot acl */
- $('#jot-perms-icon').removeClass('lock').addClass('unlock');
- $('#jot-public').show();
- $('.profile-jot-net input').attr('disabled', false);
- if(typeof editor != 'undefined' && editor != false) {
- $('#profile-jot-desc').html(ispublic);
- }
+ACL.prototype.update_view = function () {
+ if (this.is_show_all()) {
+ this.showall.addClass("selected");
+ /* jot acl */
+ $('#jot-perms-icon').removeClass('lock').addClass('unlock');
+ $('#jot-public').show();
+ $('.profile-jot-net input[type=checkbox]').each(function() {
+ // Restores checkbox state if it had been saved
+ if ($(this).attr('data-checked') !== undefined) {
+ $(this).prop('checked', $(this).attr('data-checked') === 'true');
+ }
+ });
+ $('.profile-jot-net input').attr('disabled', false);
+ if (typeof editor != 'undefined' && editor != false) {
+ $('#profile-jot-desc').html(ispublic);
+ }
} else {
- this.showall.removeClass("selected");
- /* jot acl */
- $('#jot-perms-icon').removeClass('unlock').addClass('lock');
- $('#jot-public').hide();
- $('.profile-jot-net input').attr('disabled', 'disabled');
- $('#profile-jot-desc').html(' ');
+ this.showall.removeClass("selected");
+ /* jot acl */
+ $('#jot-perms-icon').removeClass('unlock').addClass('lock');
+ $('#jot-public').hide();
+ $('.profile-jot-net input[type=checkbox]').each(function() {
+ // Saves current checkbox state
+ $(this)
+ .attr('data-checked', $(this).prop('checked'))
+ .prop('checked', false);
+ });
+ $('.profile-jot-net input').attr('disabled', 'disabled');
+ $('#profile-jot-desc').html(' ');
}
- $("#acl-list-content .acl-list-item").each(function(){
+
+ $("#acl-list-content .acl-list-item").each(function (index, element) {
$(this).removeClass("groupshow grouphide");
- });
- $("#acl-list-content .acl-list-item").each(function(index, element){
itemid = $(element).attr('id');
type = itemid[0];
id = parseInt(itemid.substr(1));
btshow = $(element).children(".acl-button-show").removeClass("selected");
bthide = $(element).children(".acl-button-hide").removeClass("selected");
- switch(type){
+ switch (type) {
case "g":
var uclass = "";
- if (this.allow_gid.indexOf(id)>=0){
+ if (this.allow_gid.indexOf(id) >= 0) {
btshow.addClass("selected");
bthide.removeClass("selected");
- uclass="groupshow";
+ uclass = "groupshow";
}
- if (this.deny_gid.indexOf(id)>=0){
+ if (this.deny_gid.indexOf(id) >= 0) {
btshow.removeClass("selected");
bthide.addClass("selected");
- uclass="grouphide";
+ uclass = "grouphide";
}
- $(this.group_uids[id]).each(function(i,v) {
- if(uclass == "grouphide")
- $("#c"+v).removeClass("groupshow");
- if(uclass != "") {
- var cls = $("#c"+v).attr('class');
- if( cls == undefined)
+ $(this.group_uids[id]).each(function (i, v) {
+ if (uclass == "grouphide")
+ $("#c" + v).removeClass("groupshow");
+ if (uclass != "") {
+ var cls = $("#c" + v).attr('class');
+ if (cls == undefined)
return true;
var hiding = cls.indexOf('grouphide');
- if(hiding == -1)
- $("#c"+v).addClass(uclass);
+ if (hiding == -1)
+ $("#c" + v).addClass(uclass);
}
});
break;
case "c":
- if (this.allow_cid.indexOf(id)>=0){
+ if (this.allow_cid.indexOf(id) >= 0) {
btshow.addClass("selected");
bthide.removeClass("selected");
}
- if (this.deny_cid.indexOf(id)>=0){
+ if (this.deny_cid.indexOf(id) >= 0) {
btshow.removeClass("selected");
bthide.addClass("selected");
}
}.bind(this));
-}
+};
ACL.prototype.get = function(start,count, search){
var postdata = {
<hr style="clear:both"/>
<div id="profile-jot-email-label">{{$emailcc}}</div><input type="text" name="emailcc" id="profile-jot-email" title="{{$emtitle}}" />
<div id="profile-jot-email-end"></div>
-{{if $jotnets}}
-{{$jotnets nofilter}}
-{{/if}}{{/if}}
+
+ {{if $jotnets_fields}}
+ {{if $jotnets_fields|count < 3}}
+<div class="profile-jot-net">
+ {{else}}
+<details class="profile-jot-net">
+ <summary>{{$jotnets_summary}}</summary>
+ {{/if}}
+
+ {{foreach $jotnets_fields as $jotnets_field}}
+ {{if $jotnets_field.type == 'checkbox'}}
+ {{include file="field_checkbox.tpl" field=$jotnets_field.field}}
+ {{elseif $jotnets_field.type == 'select'}}
+ {{include file="field_select.tpl" field=$jotnets_field.field}}
+ {{/if}}
+ {{/foreach}}
+
+ {{if $jotnets_fields|count >= 3}}
+</details>
+ {{else}}
+</div>
+ {{/if}}
+ {{/if}}
+{{/if}}
<script>
$(document).ready(function() {
<input type='hidden' name='form_security_token' value='{{$form_security_token}}'>
{{include file="field_input.tpl" field=$sitename}}
- {{include file="field_input.tpl" field=$hostname}}
{{include file="field_input.tpl" field=$sender_email}}
{{include file="field_textarea.tpl" field=$banner}}
{{include file="field_input.tpl" field=$shortcut_icon}}
{{include file="field_input.tpl" field=$optimize_fragmentation}}
{{include file="field_input.tpl" field=$abandon_days}}
{{include file="field_input.tpl" field=$temppath}}
- {{include file="field_input.tpl" field=$basepath}}
{{include file="field_checkbox.tpl" field=$suppress_tags}}
{{include file="field_checkbox.tpl" field=$nodeinfo}}
{{include file="field_select.tpl" field=$check_new_version_url}}
],
'system' => [
'urlpath' => '{{$urlpath}}',
+ 'basepath' => '{{$basepath}}',
'default_timezone' => '{{$timezone}}',
'language' => '{{$language}}',
],
</div>
<div id="profile-jot-email-end"></div>
-{{if $jotnets}}
-{{$jotnets nofilter}}
-{{/if}}{{/if}}
+ {{if $jotnets_fields}}
+ {{if $jotnets_fields|count < 3}}
+<div class="profile-jot-net">
+ {{else}}
+<details class="profile-jot-net">
+ <summary>{{$jotnets_summary}}</summary>
+ {{/if}}
+
+ {{foreach $jotnets_fields as $jotnets_field}}
+ {{if $jotnets_field.type == 'checkbox'}}
+ {{include file="field_checkbox.tpl" field=$jotnets_field.field}}
+ {{elseif $jotnets_field.type == 'select'}}
+ {{include file="field_select.tpl" field=$jotnets_field.field}}
+ {{/if}}
+ {{/foreach}}
+
+ {{if $jotnets_fields|count >= 3}}
+</details>
+ {{else}}
+</div>
+ {{/if}}
+ {{/if}}
+{{/if}}
<script type="text/javascript">
$(document).ready(function() {