Merge remote-tracking branch 'upstream/2019.03-RC' into worker2
This commit is contained in:
commit
fb371e1048
|
@ -32,10 +32,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Core\Config;
|
||||
use Friendica\Factory;
|
||||
use Friendica\Util\BasePath;
|
||||
use Friendica\Util\ExAuth;
|
||||
|
||||
if (sizeof($_SERVER["argv"]) == 0) {
|
||||
|
@ -54,12 +51,7 @@ chdir($directory);
|
|||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
$basedir = BasePath::create(dirname(__DIR__), $_SERVER);
|
||||
$configLoader = new Config\ConfigCacheLoader($basedir);
|
||||
$config = Factory\ConfigFactory::createCache($configLoader);
|
||||
$logger = Factory\LoggerFactory::create('auth_ejabberd', $config);
|
||||
|
||||
$a = new App($config, $logger);
|
||||
$a = Factory\DependencyFactory::setUp('auth_ejabbered', dirname(__DIR__));
|
||||
|
||||
if ($a->getMode()->isNormal()) {
|
||||
$oAuth = new ExAuth();
|
||||
|
|
|
@ -3,16 +3,9 @@
|
|||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
use Friendica\Core\Config;
|
||||
use Friendica\Factory;
|
||||
use Friendica\Util\BasePath;
|
||||
|
||||
$basedir = BasePath::create(dirname(__DIR__), $_SERVER);
|
||||
$configLoader = new Config\ConfigCacheLoader($basedir);
|
||||
$config = Factory\ConfigFactory::createCache($configLoader);
|
||||
$logger = Factory\LoggerFactory::create('console', $config);
|
||||
|
||||
$a = new Friendica\App($config, $logger);
|
||||
$a = Factory\DependencyFactory::setUp('console', dirname(__DIR__));
|
||||
\Friendica\BaseObject::setApp($a);
|
||||
|
||||
(new Friendica\Core\Console($argv))->execute();
|
||||
|
|
|
@ -7,12 +7,11 @@
|
|||
* This script was taken from http://php.net/manual/en/function.pcntl-fork.php
|
||||
*/
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Core\Config;
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\Worker;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Factory;
|
||||
use Friendica\Util\BasePath;
|
||||
|
||||
// Get options
|
||||
$shortopts = 'f';
|
||||
|
@ -33,12 +32,7 @@ if (!file_exists("boot.php") && (sizeof($_SERVER["argv"]) != 0)) {
|
|||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
$basedir = BasePath::create(dirname(__DIR__), $_SERVER);
|
||||
$configLoader = new Config\ConfigCacheLoader($basedir);
|
||||
$config = Factory\ConfigFactory::createCache($configLoader);
|
||||
$logger = Factory\LoggerFactory::create('daemon', $config);
|
||||
|
||||
$a = new App($config, $logger);
|
||||
$a = Factory\DependencyFactory::setUp('daemon', dirname(__DIR__));
|
||||
|
||||
if ($a->getMode()->isInstall()) {
|
||||
die("Friendica isn't properly installed yet.\n");
|
||||
|
@ -108,7 +102,7 @@ if ($mode == "stop") {
|
|||
|
||||
unlink($pidfile);
|
||||
|
||||
$logger->notice("Worker daemon process was killed", ["pid" => $pid]);
|
||||
Logger::notice("Worker daemon process was killed", ["pid" => $pid]);
|
||||
|
||||
Config::set('system', 'worker_daemon_mode', false);
|
||||
die("Worker daemon process $pid was killed.\n");
|
||||
|
@ -118,7 +112,7 @@ if (!empty($pid) && posix_kill($pid, 0)) {
|
|||
die("Daemon process $pid is already running.\n");
|
||||
}
|
||||
|
||||
$logger->notice('Starting worker daemon.', ["pid" => $pid]);
|
||||
Logger::notice('Starting worker daemon.', ["pid" => $pid]);
|
||||
|
||||
if (!$foreground) {
|
||||
echo "Starting worker daemon.\n";
|
||||
|
@ -150,7 +144,9 @@ if (!$foreground) {
|
|||
file_put_contents($pidfile, $pid);
|
||||
|
||||
// We lose the database connection upon forking
|
||||
$a->loadDatabase();
|
||||
/// @todo refactoring during https://github.com/friendica/friendica/issues/6720
|
||||
$basePath = \Friendica\Util\BasePath::create(dirname(__DIR__), $_SERVER);
|
||||
Factory\DBFactory::init($basePath, $a->getConfigCache(), $a->getProfiler(), $_SERVER);
|
||||
}
|
||||
|
||||
Config::set('system', 'worker_daemon_mode', true);
|
||||
|
@ -166,7 +162,7 @@ $last_cron = 0;
|
|||
// Now running as a daemon.
|
||||
while (true) {
|
||||
if (!$do_cron && ($last_cron + $wait_interval) < time()) {
|
||||
$logger->info('Forcing cron worker call.', ["pid" => $pid]);
|
||||
Logger::info('Forcing cron worker call.', ["pid" => $pid]);
|
||||
$do_cron = true;
|
||||
}
|
||||
|
||||
|
@ -180,7 +176,7 @@ while (true) {
|
|||
$last_cron = time();
|
||||
}
|
||||
|
||||
$logger->info("Sleeping", ["pid" => $pid]);
|
||||
Logger::info("Sleeping", ["pid" => $pid]);
|
||||
$start = time();
|
||||
do {
|
||||
$seconds = (time() - $start);
|
||||
|
@ -197,10 +193,10 @@ while (true) {
|
|||
|
||||
if ($timeout) {
|
||||
$do_cron = true;
|
||||
$logger->info("Woke up after $wait_interval seconds.", ["pid" => $pid, 'sleep' => $wait_interval]);
|
||||
Logger::info("Woke up after $wait_interval seconds.", ["pid" => $pid, 'sleep' => $wait_interval]);
|
||||
} else {
|
||||
$do_cron = false;
|
||||
$logger->info("Worker jobs are calling to be forked.", ["pid" => $pid]);
|
||||
Logger::info("Worker jobs are calling to be forked.", ["pid" => $pid]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ use Friendica\Core\Config;
|
|||
use Friendica\Core\Update;
|
||||
use Friendica\Core\Worker;
|
||||
use Friendica\Factory;
|
||||
use Friendica\Util\BasePath;
|
||||
|
||||
// Get options
|
||||
$shortopts = 'sn';
|
||||
|
@ -31,12 +30,7 @@ if (!file_exists("boot.php") && (sizeof($_SERVER["argv"]) != 0)) {
|
|||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
$basedir = BasePath::create(dirname(__DIR__), $_SERVER);
|
||||
$configLoader = new Config\ConfigCacheLoader($basedir);
|
||||
$config = Factory\ConfigFactory::createCache($configLoader);
|
||||
$logger = Factory\LoggerFactory::create('worker', $config);
|
||||
|
||||
$a = new App($config, $logger);
|
||||
$a = Factory\DependencyFactory::setUp('worker', dirname(__DIR__));
|
||||
|
||||
// Check the database structure and possibly fixes it
|
||||
Update::check($a->getBasePath(), true);
|
||||
|
|
39
boot.php
39
boot.php
|
@ -25,12 +25,13 @@ use Friendica\Core\Protocol;
|
|||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Term;
|
||||
use Friendica\Util\BasePath;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
|
||||
define('FRIENDICA_PLATFORM', 'Friendica');
|
||||
define('FRIENDICA_CODENAME', 'The Tazmans Flax-lily');
|
||||
define('FRIENDICA_VERSION', '2019.03-dev');
|
||||
define('FRIENDICA_VERSION', '2019.03-rc');
|
||||
define('DFRN_PROTOCOL_VERSION', '2.23');
|
||||
define('NEW_UPDATE_ROUTINE_VERSION', 1170);
|
||||
|
||||
|
@ -171,23 +172,27 @@ define('NOTIFY_SYSTEM', 32768);
|
|||
/* @}*/
|
||||
|
||||
|
||||
/**
|
||||
* @name Term
|
||||
*
|
||||
* Tag/term types
|
||||
* @{
|
||||
*/
|
||||
define('TERM_UNKNOWN', 0);
|
||||
define('TERM_HASHTAG', 1);
|
||||
define('TERM_MENTION', 2);
|
||||
define('TERM_CATEGORY', 3);
|
||||
define('TERM_PCATEGORY', 4);
|
||||
define('TERM_FILE', 5);
|
||||
define('TERM_SAVEDSEARCH', 6);
|
||||
define('TERM_CONVERSATION', 7);
|
||||
/** @deprecated since 2019.03, use Term::UNKNOWN instead */
|
||||
define('TERM_UNKNOWN', Term::UNKNOWN);
|
||||
/** @deprecated since 2019.03, use Term::HASHTAG instead */
|
||||
define('TERM_HASHTAG', Term::HASHTAG);
|
||||
/** @deprecated since 2019.03, use Term::MENTION instead */
|
||||
define('TERM_MENTION', Term::MENTION);
|
||||
/** @deprecated since 2019.03, use Term::CATEGORY instead */
|
||||
define('TERM_CATEGORY', Term::CATEGORY);
|
||||
/** @deprecated since 2019.03, use Term::PCATEGORY instead */
|
||||
define('TERM_PCATEGORY', Term::PCATEGORY);
|
||||
/** @deprecated since 2019.03, use Term::FILE instead */
|
||||
define('TERM_FILE', Term::FILE);
|
||||
/** @deprecated since 2019.03, use Term::SAVEDSEARCH instead */
|
||||
define('TERM_SAVEDSEARCH', Term::SAVEDSEARCH);
|
||||
/** @deprecated since 2019.03, use Term::CONVERSATION instead */
|
||||
define('TERM_CONVERSATION', Term::CONVERSATION);
|
||||
|
||||
define('TERM_OBJ_POST', 1);
|
||||
define('TERM_OBJ_PHOTO', 2);
|
||||
/** @deprecated since 2019.03, use Term::OBJECT_TYPE_POST instead */
|
||||
define('TERM_OBJ_POST', Term::OBJECT_TYPE_POST);
|
||||
/** @deprecated since 2019.03, use Term::OBJECT_TYPE_PHOTO instead */
|
||||
define('TERM_OBJ_PHOTO', Term::OBJECT_TYPE_PHOTO);
|
||||
|
||||
/**
|
||||
* @name Namespaces
|
||||
|
|
|
@ -34,23 +34,25 @@
|
|||
"lightopenid/lightopenid": "dev-master",
|
||||
"michelf/php-markdown": "^1.7",
|
||||
"mobiledetect/mobiledetectlib": "2.8.*",
|
||||
"monolog/monolog": "^1.24",
|
||||
"paragonie/random_compat": "^2.0",
|
||||
"pear/Text_LanguageDetect": "1.*",
|
||||
"pear/text_languagedetect": "1.*",
|
||||
"psr/container": "^1.0",
|
||||
"seld/cli-prompt": "^1.0",
|
||||
"smarty/smarty": "^3.1",
|
||||
"fxp/composer-asset-plugin": "~1.3",
|
||||
"bower-asset/base64": "^1.0",
|
||||
"bower-asset/Chart-js": "^2.7",
|
||||
"bower-asset/chart-js": "^2.7",
|
||||
"bower-asset/perfect-scrollbar": "^0.6",
|
||||
"bower-asset/vue": "^2.5",
|
||||
"npm-asset/jquery": "^2.0",
|
||||
"npm-asset/jquery-colorbox": "^1.6",
|
||||
"npm-asset/jquery-datetimepicker": "^2.4.0",
|
||||
"npm-asset/jgrowl": "^1.4",
|
||||
"npm-asset/moment": "^2.20.1",
|
||||
"npm-asset/fullcalendar": "^3.0.1",
|
||||
"npm-asset/cropperjs": "1.2.2",
|
||||
"npm-asset/imagesloaded": "4.1.4",
|
||||
"monolog/monolog": "^1.24"
|
||||
"npm-asset/imagesloaded": "4.1.4"
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
|
@ -96,7 +98,7 @@
|
|||
"phpunit/dbunit": "^2.0",
|
||||
"phpdocumentor/reflection-docblock": "^3.0.2",
|
||||
"phpunit/php-token-stream": "^1.4.2",
|
||||
"mikey179/vfsStream": "^1.6",
|
||||
"mikey179/vfsstream": "^1.6",
|
||||
"mockery/mockery": "^1.2",
|
||||
"johnkary/phpunit-speedtrap": "1.1"
|
||||
},
|
||||
|
|
87
composer.lock
generated
87
composer.lock
generated
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "b944adfb6ede89430ba3b7e9ebb45acb",
|
||||
"content-hash": "8897c1f6912cc9b889534a8c59deead1",
|
||||
"packages": [
|
||||
{
|
||||
"name": "asika/simple-console",
|
||||
|
@ -1026,32 +1026,18 @@
|
|||
},
|
||||
{
|
||||
"name": "npm-asset/fullcalendar",
|
||||
"version": "3.9.0",
|
||||
"version": "3.10.0",
|
||||
"dist": {
|
||||
"type": "tar",
|
||||
"url": "https://registry.npmjs.org/fullcalendar/-/fullcalendar-3.9.0.tgz",
|
||||
"url": "https://registry.npmjs.org/fullcalendar/-/fullcalendar-3.10.0.tgz",
|
||||
"reference": null,
|
||||
"shasum": "b608a9989f3416f0b1d526c6bdfeeaf2ac79eda5"
|
||||
},
|
||||
"require": {
|
||||
"npm-asset/jquery": ">=2,<4.0",
|
||||
"npm-asset/moment": ">=2.20.1,<3.0.0"
|
||||
"shasum": "cc5e87d518fd6550e142816a31dd191664847919"
|
||||
},
|
||||
"type": "npm-asset-library",
|
||||
"extra": {
|
||||
"npm-asset-bugs": {
|
||||
"url": "https://fullcalendar.io/wiki/Reporting-Bugs/"
|
||||
},
|
||||
"npm-asset-files": [
|
||||
"dist/*.js",
|
||||
"dist/*.css",
|
||||
"dist/*.d.ts",
|
||||
"dist/locale/*.js",
|
||||
"README.*",
|
||||
"LICENSE.*",
|
||||
"CHANGELOG.*",
|
||||
"CONTRIBUTING.*"
|
||||
],
|
||||
"npm-asset-main": "dist/fullcalendar.js",
|
||||
"npm-asset-directories": [],
|
||||
"npm-asset-repository": {
|
||||
|
@ -1061,7 +1047,7 @@
|
|||
"npm-asset-scripts": {
|
||||
"clean": "gulp clean",
|
||||
"dist": "gulp dist",
|
||||
"lint": "gulp lint",
|
||||
"lint": "gulp lint-and-example-repos",
|
||||
"test": "gulp test:single"
|
||||
}
|
||||
},
|
||||
|
@ -1083,7 +1069,7 @@
|
|||
"full-sized",
|
||||
"jquery-plugin"
|
||||
],
|
||||
"time": "2018-03-05T03:30:23+00:00"
|
||||
"time": "2019-01-11T02:39:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "npm-asset/imagesloaded",
|
||||
|
@ -1882,6 +1868,55 @@
|
|||
],
|
||||
"time": "2016-08-06T20:24:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/container",
|
||||
"version": "1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/container.git",
|
||||
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
|
||||
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Container\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "http://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common Container Interface (PHP FIG PSR-11)",
|
||||
"homepage": "https://github.com/php-fig/container",
|
||||
"keywords": [
|
||||
"PSR-11",
|
||||
"container",
|
||||
"container-interface",
|
||||
"container-interop",
|
||||
"psr"
|
||||
],
|
||||
"time": "2017-02-14T16:28:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/http-message",
|
||||
"version": "1.0.1",
|
||||
|
@ -2650,6 +2685,7 @@
|
|||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"abandoned": true,
|
||||
"time": "2016-12-02T14:39:14+00:00"
|
||||
},
|
||||
{
|
||||
|
@ -3040,6 +3076,7 @@
|
|||
"mock",
|
||||
"xunit"
|
||||
],
|
||||
"abandoned": true,
|
||||
"time": "2017-06-30T09:13:00+00:00"
|
||||
},
|
||||
{
|
||||
|
@ -3143,7 +3180,7 @@
|
|||
}
|
||||
],
|
||||
"description": "Provides the functionality to compare PHP values for equality",
|
||||
"homepage": "https://github.com/sebastianbergmann/comparator",
|
||||
"homepage": "http://www.github.com/sebastianbergmann/comparator",
|
||||
"keywords": [
|
||||
"comparator",
|
||||
"compare",
|
||||
|
@ -3245,7 +3282,7 @@
|
|||
}
|
||||
],
|
||||
"description": "Provides functionality to handle HHVM/PHP environments",
|
||||
"homepage": "https://github.com/sebastianbergmann/environment",
|
||||
"homepage": "http://www.github.com/sebastianbergmann/environment",
|
||||
"keywords": [
|
||||
"Xdebug",
|
||||
"environment",
|
||||
|
@ -3313,7 +3350,7 @@
|
|||
}
|
||||
],
|
||||
"description": "Provides the functionality to export PHP variables for visualization",
|
||||
"homepage": "https://github.com/sebastianbergmann/exporter",
|
||||
"homepage": "http://www.github.com/sebastianbergmann/exporter",
|
||||
"keywords": [
|
||||
"export",
|
||||
"exporter"
|
||||
|
@ -3365,7 +3402,7 @@
|
|||
}
|
||||
],
|
||||
"description": "Snapshotting of global state",
|
||||
"homepage": "https://github.com/sebastianbergmann/global-state",
|
||||
"homepage": "http://www.github.com/sebastianbergmann/global-state",
|
||||
"keywords": [
|
||||
"global state"
|
||||
],
|
||||
|
@ -3467,7 +3504,7 @@
|
|||
}
|
||||
],
|
||||
"description": "Provides functionality to recursively process PHP variables",
|
||||
"homepage": "https://github.com/sebastianbergmann/recursion-context",
|
||||
"homepage": "http://www.github.com/sebastianbergmann/recursion-context",
|
||||
"time": "2016-11-19T07:33:16+00:00"
|
||||
},
|
||||
{
|
||||
|
|
|
@ -135,9 +135,14 @@ return [
|
|||
// Disables the check if a mail address is in a valid format and can be resolved via DNS.
|
||||
'disable_email_validation' => false,
|
||||
|
||||
// disable_mentions_removal (Boolean)
|
||||
// Disables the automatic removal of implicit mentions in ActivityPub postings.
|
||||
'disable_mentions_removal' => false,
|
||||
// disable_implicit_mentions (Boolean) since 2019.03
|
||||
// Implicit mentions are mentions in the body of replies that are redundant in a thread-enabled system like Friendica.
|
||||
// This config key disables the gathering of implicit mentions in incoming and outgoing posts.
|
||||
// Also disables the default automatic removal of implicit mentions from the body of incoming posts.
|
||||
// Also disables the default automatic addition of implicit mentions in the body of outgoing posts.
|
||||
// Disabling implicit mentions also affects the "explicit_mentions" additional feature by limiting it
|
||||
// to the replied-to post author mention in the comment boxes.
|
||||
'disable_implicit_mentions' => false,
|
||||
|
||||
// disable_url_validation (Boolean)
|
||||
// Disables the DNS lookup of an URL.
|
||||
|
|
|
@ -18,10 +18,8 @@ If you do not have a Friendica account yet, you can register a temporary one at
|
|||
The account will expire after 7 days, but you can ask the server admin to keep your account longer, should the problem not be resolved after that.
|
||||
|
||||
Before you begin: Choose a domain name or subdomain name for your server.
|
||||
Put some thought into this. Changing it after installation is currently not supported.
|
||||
Things will break, and some of your friends may have difficulty communicating with you.
|
||||
We plan to address this limitation in a future release.
|
||||
|
||||
Put some thought into this.
|
||||
While changing it after installation is supported, things still might break.
|
||||
|
||||
Requirements
|
||||
---
|
||||
|
@ -57,7 +55,7 @@ The Linux commands to clone the repository into a directory "mywebsite" would be
|
|||
|
||||
git clone https://github.com/friendica/friendica.git -b master mywebsite
|
||||
cd mywebsite
|
||||
bin/composer.phar install
|
||||
bin/composer.phar install --no-dev
|
||||
|
||||
Make sure the folder *view/smarty3* exists and is writable by the webserver user, in this case `www-data`
|
||||
|
||||
|
|
|
@ -15,6 +15,6 @@ Remember the link at the top of this page will bring you back here.
|
|||
|
||||
Once you've added some groups, <a href="help/Quick-Start-andfinally">move on to the next section</a>.
|
||||
|
||||
<iframe src="http://dir.friendica.social/directory" width="950" height="600"></iframe>
|
||||
<iframe src="https://dir.friendica.social/forum" width="950" height="600"></iframe>
|
||||
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ You can get the latest changes at any time with
|
|||
|
||||
cd path/to/friendica
|
||||
git pull
|
||||
bin/composer.phar install
|
||||
bin/composer.phar install --no-dev
|
||||
|
||||
The addon tree has to be updated separately like so:
|
||||
|
||||
|
@ -69,4 +69,4 @@ DROP TABLE <table_name>;
|
|||
RENAME TABLE <table_name>_new TO <table_name>;
|
||||
```
|
||||
|
||||
This method is slower overall, but it is better suited for large numbers of duplicates.
|
||||
This method is slower overall, but it is better suited for large numbers of duplicates.
|
||||
|
|
|
@ -21,6 +21,6 @@ Solltest Du beim Stöbern durch die vielen Gruppen nicht wieder hierher zurück
|
|||
|
||||
Wenn Du einige Gruppen hinzugefügt hast, gehe <a href="help/Quick-Start-andfinally">weiter zum nächsten Schritt</a>.
|
||||
|
||||
<iframe src="https://dir.friendica.social/home" width="950" height="600"></iframe>
|
||||
<iframe src="https://dir.friendica.social/forum" width="950" height="600"></iframe>
|
||||
|
||||
|
||||
|
|
|
@ -326,69 +326,7 @@ function api_call(App $a)
|
|||
|
||||
Logger::info(API_LOG_PREFIX . 'username {username}', ['module' => 'api', 'action' => 'call', 'username' => $a->user['username'], 'duration' => round($duration, 2)]);
|
||||
|
||||
if (Config::get("system", "profiler")) {
|
||||
$duration = microtime(true)-$a->performance["start"];
|
||||
|
||||
/// @TODO round() really everywhere?
|
||||
Logger::debug(
|
||||
API_LOG_PREFIX . 'performance',
|
||||
[
|
||||
'module' => 'api',
|
||||
'action' => 'call',
|
||||
'database_read' => round($a->performance["database"] - $a->performance["database_write"], 3),
|
||||
'database_write' => round($a->performance["database_write"], 3),
|
||||
'cache_read' => round($a->performance["cache"], 3),
|
||||
'cache_write' => round($a->performance["cache_write"], 3),
|
||||
'network_io' => round($a->performance["network"], 2),
|
||||
'file_io' => round($a->performance["file"], 2),
|
||||
'other_io' => round($duration - ($a->performance["database"]
|
||||
+ $a->performance["cache"] + $a->performance["cache_write"]
|
||||
+ $a->performance["network"] + $a->performance["file"]), 2),
|
||||
'total' => round($duration, 2)
|
||||
]
|
||||
);
|
||||
|
||||
if (Config::get("rendertime", "callstack")) {
|
||||
$o = "Database Read:\n";
|
||||
foreach ($a->callstack["database"] as $func => $time) {
|
||||
$time = round($time, 3);
|
||||
if ($time > 0) {
|
||||
$o .= $func . ": " . $time . "\n";
|
||||
}
|
||||
}
|
||||
$o .= "\nDatabase Write:\n";
|
||||
foreach ($a->callstack["database_write"] as $func => $time) {
|
||||
$time = round($time, 3);
|
||||
if ($time > 0) {
|
||||
$o .= $func . ": " . $time . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
$o = "Cache Read:\n";
|
||||
foreach ($a->callstack["cache"] as $func => $time) {
|
||||
$time = round($time, 3);
|
||||
if ($time > 0) {
|
||||
$o .= $func . ": " . $time . "\n";
|
||||
}
|
||||
}
|
||||
$o .= "\nCache Write:\n";
|
||||
foreach ($a->callstack["cache_write"] as $func => $time) {
|
||||
$time = round($time, 3);
|
||||
if ($time > 0) {
|
||||
$o .= $func . ": " . $time . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
$o .= "\nNetwork:\n";
|
||||
foreach ($a->callstack["network"] as $func => $time) {
|
||||
$time = round($time, 3);
|
||||
if ($time > 0) {
|
||||
$o .= $func . ": " . $time . "\n";
|
||||
}
|
||||
}
|
||||
Logger::debug(API_LOG_PREFIX . $o, ['module' => 'api', 'action' => 'call']);
|
||||
}
|
||||
}
|
||||
$a->getProfiler()->saveLog($a->getLogger(), API_LOG_PREFIX . 'performance');
|
||||
|
||||
if (false === $return) {
|
||||
/*
|
||||
|
@ -1590,8 +1528,10 @@ function api_search($type)
|
|||
|
||||
if (api_user() === false || $user_info === false) { throw new ForbiddenException(); }
|
||||
|
||||
if (empty($_REQUEST['q'])) { throw new BadRequestException('q parameter is required.'); }
|
||||
|
||||
if (empty($_REQUEST['q'])) {
|
||||
throw new BadRequestException('q parameter is required.');
|
||||
}
|
||||
|
||||
$searchTerm = trim(rawurldecode($_REQUEST['q']));
|
||||
|
||||
$data = [];
|
||||
|
@ -4461,6 +4401,7 @@ function api_fr_photo_delete($type)
|
|||
if (api_user() === false) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
|
||||
// input params
|
||||
$photo_id = defaults($_REQUEST, 'photo_id', null);
|
||||
|
||||
|
@ -4469,11 +4410,12 @@ function api_fr_photo_delete($type)
|
|||
if ($photo_id == null) {
|
||||
throw new BadRequestException("no photo_id specified");
|
||||
}
|
||||
|
||||
// check if photo is existing in database
|
||||
$r = Photo::exists(['resource-id' => $photo_id, 'uid' => api_user()]);
|
||||
if (!$r) {
|
||||
if (!Photo::exists(['resource-id' => $photo_id, 'uid' => api_user()])) {
|
||||
throw new BadRequestException("photo not available");
|
||||
}
|
||||
|
||||
// now we can perform on the deletion of the photo
|
||||
$result = Photo::delete(['uid' => api_user(), 'resource-id' => $photo_id]);
|
||||
|
||||
|
|
|
@ -365,7 +365,7 @@ function localize_item(&$item)
|
|||
|
||||
// Only create a redirection to a magic link when logged in
|
||||
if (!empty($item['plink']) && (local_user() || remote_user())) {
|
||||
$item['plink'] = Contact::magicLinkbyContact($author, $item['plink']);
|
||||
$item['plink'] = Contact::magicLinkByContact($author, $item['plink']);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -625,7 +625,7 @@ function conversation(App $a, array $items, Pager $pager, $mode, $update, $previ
|
|||
|
||||
$author = ['uid' => 0, 'id' => $item['author-id'],
|
||||
'network' => $item['author-network'], 'url' => $item['author-link']];
|
||||
$profile_link = Contact::magicLinkbyContact($author);
|
||||
$profile_link = Contact::magicLinkByContact($author);
|
||||
|
||||
if (strpos($profile_link, 'redir/') === 0) {
|
||||
$sparkle = ' sparkle';
|
||||
|
@ -660,21 +660,12 @@ function conversation(App $a, array $items, Pager $pager, $mode, $update, $previ
|
|||
|
||||
list($categories, $folders) = get_cats_and_terms($item);
|
||||
|
||||
$profile_name_e = $profile_name;
|
||||
|
||||
if (!empty($item['content-warning']) && PConfig::get(local_user(), 'system', 'disable_cw', false)) {
|
||||
$title_e = ucfirst($item['content-warning']);
|
||||
$title = ucfirst($item['content-warning']);
|
||||
} else {
|
||||
$title_e = $item['title'];
|
||||
$title = $item['title'];
|
||||
}
|
||||
|
||||
$body_e = $body;
|
||||
$tags_e = $tags['tags'];
|
||||
$hashtags_e = $tags['hashtags'];
|
||||
$mentions_e = $tags['mentions'];
|
||||
$location_e = $location;
|
||||
$owner_name_e = $owner_name;
|
||||
|
||||
$tmp_item = [
|
||||
'template' => $tpl,
|
||||
'id' => ($preview ? 'P0' : $item['id']),
|
||||
|
@ -684,27 +675,28 @@ function conversation(App $a, array $items, Pager $pager, $mode, $update, $previ
|
|||
'linktitle' => L10n::t('View %s\'s profile @ %s', $profile_name, $item['author-link']),
|
||||
'profile_url' => $profile_link,
|
||||
'item_photo_menu' => item_photo_menu($item),
|
||||
'name' => $profile_name_e,
|
||||
'name' => $profile_name,
|
||||
'sparkle' => $sparkle,
|
||||
'lock' => $lock,
|
||||
'thumb' => System::removedBaseUrl(ProxyUtils::proxifyUrl($item['author-avatar'], false, ProxyUtils::SIZE_THUMB)),
|
||||
'title' => $title_e,
|
||||
'body' => $body_e,
|
||||
'tags' => $tags_e,
|
||||
'hashtags' => $hashtags_e,
|
||||
'mentions' => $mentions_e,
|
||||
'title' => $title,
|
||||
'body' => $body,
|
||||
'tags' => $tags['tags'],
|
||||
'hashtags' => $tags['hashtags'],
|
||||
'mentions' => $tags['mentions'],
|
||||
'implicit_mentions' => $tags['implicit_mentions'],
|
||||
'txt_cats' => L10n::t('Categories:'),
|
||||
'txt_folders' => L10n::t('Filed under:'),
|
||||
'has_cats' => ((count($categories)) ? 'true' : ''),
|
||||
'has_folders' => ((count($folders)) ? 'true' : ''),
|
||||
'categories' => $categories,
|
||||
'folders' => $folders,
|
||||
'text' => strip_tags($body_e),
|
||||
'text' => strip_tags($body),
|
||||
'localtime' => DateTimeFormat::local($item['created'], 'r'),
|
||||
'ago' => (($item['app']) ? L10n::t('%s from %s', Temporal::getRelativeDate($item['created']),$item['app']) : Temporal::getRelativeDate($item['created'])),
|
||||
'location' => $location_e,
|
||||
'location' => $location,
|
||||
'indent' => '',
|
||||
'owner_name' => $owner_name_e,
|
||||
'owner_name' => $owner_name,
|
||||
'owner_url' => $owner_url,
|
||||
'owner_photo' => System::removedBaseUrl(ProxyUtils::proxifyUrl($item['owner-avatar'], false, ProxyUtils::SIZE_THUMB)),
|
||||
'plink' => Item::getPlink($item),
|
||||
|
@ -858,7 +850,7 @@ function item_photo_menu($item) {
|
|||
|
||||
$author = ['uid' => 0, 'id' => $item['author-id'],
|
||||
'network' => $item['author-network'], 'url' => $item['author-link']];
|
||||
$profile_link = Contact::magicLinkbyContact($author);
|
||||
$profile_link = Contact::magicLinkByContact($author, $item['author-link']);
|
||||
$sparkle = (strpos($profile_link, 'redir/') === 0);
|
||||
|
||||
$cid = 0;
|
||||
|
@ -873,9 +865,9 @@ function item_photo_menu($item) {
|
|||
}
|
||||
|
||||
if ($sparkle) {
|
||||
$status_link = $profile_link . '?url=status';
|
||||
$photos_link = $profile_link . '?url=photos';
|
||||
$profile_link = $profile_link . '?url=profile';
|
||||
$status_link = $profile_link . '?tab=status';
|
||||
$photos_link = str_replace('/profile/', '/photos/', $profile_link);
|
||||
$profile_link = $profile_link . '?=profile';
|
||||
}
|
||||
|
||||
if ($cid && !$item['self']) {
|
||||
|
@ -966,7 +958,7 @@ function builtin_activity_puller($item, &$conv_responses) {
|
|||
if (activity_match($item['verb'], $verb) && ($item['id'] != $item['parent'])) {
|
||||
$author = ['uid' => 0, 'id' => $item['author-id'],
|
||||
'network' => $item['author-network'], 'url' => $item['author-link']];
|
||||
$url = Contact::magicLinkbyContact($author);
|
||||
$url = Contact::magicLinkByContact($author);
|
||||
if (strpos($url, 'redir/') === 0) {
|
||||
$sparkle = ' class="sparkle" ';
|
||||
}
|
||||
|
@ -1082,10 +1074,9 @@ function format_like($cnt, array $arr, $type, $id) {
|
|||
break;
|
||||
}
|
||||
|
||||
$expanded .= "\t" . '<div class="wall-item-' . $type . '-expanded" id="' . $type . 'list-' . $id . '" style="display: none;" >' . $explikers . EOL . '</div>';
|
||||
$expanded .= "\t" . '<p class="wall-item-' . $type . '-expanded" id="' . $type . 'list-' . $id . '" style="display: none;" >' . $explikers . EOL . '</p>';
|
||||
}
|
||||
|
||||
$phrase .= EOL;
|
||||
$o .= Renderer::replaceMacros(Renderer::getMarkupTemplate('voting_fakelink.tpl'), [
|
||||
'$phrase' => $phrase,
|
||||
'$type' => $type,
|
||||
|
|
|
@ -33,8 +33,8 @@ function notification($params)
|
|||
$a = \get_app();
|
||||
|
||||
// Temporary logging for finding the origin
|
||||
if (!isset($params['language']) || !isset($params['uid'])) {
|
||||
Logger::log('Missing parameters.' . System::callstack());
|
||||
if (!isset($params['uid'])) {
|
||||
Logger::notice('Missing parameters "uid".', ['params' => $params, 'callstack' => System::callstack()]);
|
||||
}
|
||||
|
||||
// Ensure that the important fields are set at any time
|
||||
|
@ -42,7 +42,7 @@ function notification($params)
|
|||
$user = DBA::selectFirst('user', $fields, ['uid' => $params['uid']]);
|
||||
|
||||
if (!DBA::isResult($user)) {
|
||||
Logger::log('Unknown user ' . $params['uid']);
|
||||
Logger::error('Unknown user', ['uid' => $params['uid']]);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
13
index.php
13
index.php
|
@ -4,10 +4,7 @@
|
|||
* Friendica
|
||||
*/
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Core\Config;
|
||||
use Friendica\Factory;
|
||||
use Friendica\Util\BasePath;
|
||||
|
||||
if (!file_exists(__DIR__ . '/vendor/autoload.php')) {
|
||||
die('Vendor path not found. Please execute "bin/composer.phar --no-dev install" on the command line in the web root.');
|
||||
|
@ -15,13 +12,7 @@ if (!file_exists(__DIR__ . '/vendor/autoload.php')) {
|
|||
|
||||
require __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
$basedir = BasePath::create(__DIR__, $_SERVER);
|
||||
$configLoader = new Config\ConfigCacheLoader($basedir);
|
||||
$config = Factory\ConfigFactory::createCache($configLoader);
|
||||
$logger = Factory\LoggerFactory::create('index', $config);
|
||||
|
||||
// We assume that the index.php is called by a frontend process
|
||||
// The value is set to "true" by default in App
|
||||
$a = new App($config, $logger, false);
|
||||
$a = Factory\DependencyFactory::setUp('index', __DIR__, false);
|
||||
|
||||
$a->runFrontend();
|
||||
|
||||
|
|
|
@ -1565,7 +1565,7 @@ function admin_page_site(App $a)
|
|||
|
||||
$storage_form = [];
|
||||
if (!is_null($storage_current_backend) && $storage_current_backend != "") {
|
||||
foreach($storage_current_backend::getOptions() as $name => $info) {
|
||||
foreach ($storage_current_backend::getOptions() as $name => $info) {
|
||||
$type = $info[0];
|
||||
$info[0] = $storage_form_prefix . '_' . $name;
|
||||
$info['type'] = $type;
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
<?php
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Group;
|
||||
|
||||
function contactgroup_content(App $a)
|
||||
{
|
||||
if (!local_user()) {
|
||||
exit();
|
||||
}
|
||||
|
||||
$change = null;
|
||||
if (($a->argc > 2) && intval($a->argv[1]) && intval($a->argv[2])) {
|
||||
$r = q("SELECT `id` FROM `contact` WHERE `id` = %d AND `uid` = %d and `self` = 0 and `blocked` = 0 AND `pending` = 0 LIMIT 1",
|
||||
intval($a->argv[2]),
|
||||
intval(local_user())
|
||||
);
|
||||
if (DBA::isResult($r)) {
|
||||
$change = intval($a->argv[2]);
|
||||
}
|
||||
}
|
||||
|
||||
if (($a->argc > 1) && (intval($a->argv[1]))) {
|
||||
$r = q("SELECT * FROM `group` WHERE `id` = %d AND `uid` = %d AND `deleted` = 0 LIMIT 1",
|
||||
intval($a->argv[1]),
|
||||
intval(local_user())
|
||||
);
|
||||
if (!DBA::isResult($r)) {
|
||||
exit();
|
||||
}
|
||||
|
||||
$group = $r[0];
|
||||
$members = Contact::getByGroupId($group['id']);
|
||||
$preselected = [];
|
||||
if (count($members)) {
|
||||
foreach ($members as $member) {
|
||||
$preselected[] = $member['id'];
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($change)) {
|
||||
if (in_array($change, $preselected)) {
|
||||
Group::removeMember($group['id'], $change);
|
||||
} else {
|
||||
Group::addMember($group['id'], $change);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit();
|
||||
}
|
|
@ -45,6 +45,8 @@ function directory_content(App $a)
|
|||
}
|
||||
|
||||
$o = '';
|
||||
$entries = [];
|
||||
|
||||
Nav::setSelected('directory');
|
||||
|
||||
if (!empty($a->data['search'])) {
|
||||
|
@ -98,7 +100,7 @@ function directory_content(App $a)
|
|||
$limit = $pager->getStart()."," . $pager->getItemsPerPage();
|
||||
|
||||
$r = DBA::p("SELECT `profile`.*, `profile`.`uid` AS `profile_uid`, `user`.`nickname`, `user`.`timezone` , `user`.`page-flags`,
|
||||
`contact`.`addr`, `contact`.`url` AS profile_url FROM `profile`
|
||||
`contact`.`addr`, `contact`.`url` AS `profile_url` FROM `profile`
|
||||
LEFT JOIN `user` ON `user`.`uid` = `profile`.`uid`
|
||||
LEFT JOIN `contact` ON `contact`.`uid` = `user`.`uid`
|
||||
WHERE `is-default` $publish AND NOT `user`.`blocked` AND NOT `user`.`account_removed` AND `contact`.`self`
|
||||
|
@ -111,115 +113,118 @@ function directory_content(App $a)
|
|||
$photo = 'photo';
|
||||
}
|
||||
|
||||
$entries = [];
|
||||
|
||||
while ($rr = DBA::fetch($r)) {
|
||||
$itemurl = (($rr['addr'] != "") ? $rr['addr'] : $rr['profile_url']);
|
||||
|
||||
$profile_link = $rr['profile_url'];
|
||||
|
||||
$pdesc = (($rr['pdesc']) ? $rr['pdesc'] . '<br />' : '');
|
||||
|
||||
$details = '';
|
||||
if (strlen($rr['locality'])) {
|
||||
$details .= $rr['locality'];
|
||||
}
|
||||
if (strlen($rr['region'])) {
|
||||
if (strlen($rr['locality'])) {
|
||||
$details .= ', ';
|
||||
}
|
||||
$details .= $rr['region'];
|
||||
}
|
||||
if (strlen($rr['country-name'])) {
|
||||
if (strlen($details)) {
|
||||
$details .= ', ';
|
||||
}
|
||||
$details .= $rr['country-name'];
|
||||
}
|
||||
// if(strlen($rr['dob'])) {
|
||||
// if(($years = age($rr['dob'],$rr['timezone'],'')) != 0)
|
||||
// $details .= '<br />' . L10n::t('Age: ') . $years;
|
||||
// }
|
||||
// if(strlen($rr['gender']))
|
||||
// $details .= '<br />' . L10n::t('Gender: ') . $rr['gender'];
|
||||
|
||||
$profile = $rr;
|
||||
|
||||
if (!empty($profile['address'])
|
||||
|| !empty($profile['locality'])
|
||||
|| !empty($profile['region'])
|
||||
|| !empty($profile['postal-code'])
|
||||
|| !empty($profile['country-name'])
|
||||
) {
|
||||
$location = L10n::t('Location:');
|
||||
} else {
|
||||
$location = '';
|
||||
}
|
||||
|
||||
$gender = (!empty($profile['gender']) ? L10n::t('Gender:') : false);
|
||||
$marital = (!empty($profile['marital']) ? L10n::t('Status:') : false);
|
||||
$homepage = (!empty($profile['homepage']) ? L10n::t('Homepage:') : false);
|
||||
$about = (!empty($profile['about']) ? L10n::t('About:') : false);
|
||||
|
||||
$location_e = $location;
|
||||
|
||||
$photo_menu = [
|
||||
'profile' => [L10n::t("View Profile"), Contact::magicLink($profile_link)]
|
||||
];
|
||||
|
||||
$entry = [
|
||||
'id' => $rr['id'],
|
||||
'url' => Contact::magicLInk($profile_link),
|
||||
'itemurl' => $itemurl,
|
||||
'thumb' => ProxyUtils::proxifyUrl($rr[$photo], false, ProxyUtils::SIZE_THUMB),
|
||||
'img_hover' => $rr['name'],
|
||||
'name' => $rr['name'],
|
||||
'details' => $details,
|
||||
'account_type' => Contact::getAccountType($rr),
|
||||
'profile' => $profile,
|
||||
'location' => $location_e,
|
||||
'tags' => $rr['pub_keywords'],
|
||||
'gender' => $gender,
|
||||
'pdesc' => $pdesc,
|
||||
'marital' => $marital,
|
||||
'homepage' => $homepage,
|
||||
'about' => $about,
|
||||
'photo_menu' => $photo_menu,
|
||||
|
||||
];
|
||||
|
||||
$arr = ['contact' => $rr, 'entry' => $entry];
|
||||
|
||||
Hook::callAll('directory_item', $arr);
|
||||
|
||||
unset($profile);
|
||||
unset($location);
|
||||
|
||||
if (!$arr['entry']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$entries[] = $arr['entry'];
|
||||
$entries[] = format_directory_entry($rr, $photo);
|
||||
}
|
||||
DBA::close($r);
|
||||
|
||||
$tpl = Renderer::getMarkupTemplate('directory_header.tpl');
|
||||
|
||||
$o .= Renderer::replaceMacros($tpl, [
|
||||
'$search' => $search,
|
||||
'$globaldir' => L10n::t('Global Directory'),
|
||||
'$gdirpath' => $gdirpath,
|
||||
'$desc' => L10n::t('Find on this site'),
|
||||
'$contacts' => $entries,
|
||||
'$finding' => L10n::t('Results for:'),
|
||||
'$findterm' => (strlen($search) ? $search : ""),
|
||||
'$title' => L10n::t('Site Directory'),
|
||||
'$submit' => L10n::t('Find'),
|
||||
'$paginate' => $pager->renderFull($total),
|
||||
]);
|
||||
} else {
|
||||
info(L10n::t("No entries \x28some entries may be hidden\x29.") . EOL);
|
||||
}
|
||||
|
||||
$tpl = Renderer::getMarkupTemplate('directory_header.tpl');
|
||||
|
||||
$o .= Renderer::replaceMacros($tpl, [
|
||||
'$search' => $search,
|
||||
'$globaldir' => L10n::t('Global Directory'),
|
||||
'$gdirpath' => $gdirpath,
|
||||
'$desc' => L10n::t('Find on this site'),
|
||||
'$contacts' => $entries,
|
||||
'$finding' => L10n::t('Results for:'),
|
||||
'$findterm' => (strlen($search) ? $search : ""),
|
||||
'$title' => L10n::t('Site Directory'),
|
||||
'$search_mod' => 'directory',
|
||||
'$submit' => L10n::t('Find'),
|
||||
'$paginate' => $pager->renderFull($total),
|
||||
]);
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format contact/profile/user data from the database into an usable
|
||||
* array for displaying directory entries.
|
||||
*
|
||||
* @param array $arr The directory entry from the database.
|
||||
* @param string $photo_size Avatar size (thumb, photo or micro).
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function format_directory_entry(array $arr, $photo_size = 'photo')
|
||||
{
|
||||
$itemurl = (($arr['addr'] != "") ? $arr['addr'] : $arr['profile_url']);
|
||||
|
||||
$profile_link = $arr['profile_url'];
|
||||
|
||||
$pdesc = (($arr['pdesc']) ? $arr['pdesc'] . '<br />' : '');
|
||||
|
||||
$details = '';
|
||||
if (strlen($arr['locality'])) {
|
||||
$details .= $arr['locality'];
|
||||
}
|
||||
if (strlen($arr['region'])) {
|
||||
if (strlen($arr['locality'])) {
|
||||
$details .= ', ';
|
||||
}
|
||||
$details .= $arr['region'];
|
||||
}
|
||||
if (strlen($arr['country-name'])) {
|
||||
if (strlen($details)) {
|
||||
$details .= ', ';
|
||||
}
|
||||
$details .= $arr['country-name'];
|
||||
}
|
||||
|
||||
$profile = $arr;
|
||||
|
||||
if (!empty($profile['address'])
|
||||
|| !empty($profile['locality'])
|
||||
|| !empty($profile['region'])
|
||||
|| !empty($profile['postal-code'])
|
||||
|| !empty($profile['country-name'])
|
||||
) {
|
||||
$location = L10n::t('Location:');
|
||||
} else {
|
||||
$location = '';
|
||||
}
|
||||
|
||||
$gender = (!empty($profile['gender']) ? L10n::t('Gender:') : false);
|
||||
$marital = (!empty($profile['marital']) ? L10n::t('Status:') : false);
|
||||
$homepage = (!empty($profile['homepage']) ? L10n::t('Homepage:') : false);
|
||||
$about = (!empty($profile['about']) ? L10n::t('About:') : false);
|
||||
|
||||
$location_e = $location;
|
||||
|
||||
$photo_menu = [
|
||||
'profile' => [L10n::t("View Profile"), Contact::magicLink($profile_link)]
|
||||
];
|
||||
|
||||
$entry = [
|
||||
'id' => $arr['id'],
|
||||
'url' => Contact::magicLInk($profile_link),
|
||||
'itemurl' => $itemurl,
|
||||
'thumb' => ProxyUtils::proxifyUrl($arr[$photo_size], false, ProxyUtils::SIZE_THUMB),
|
||||
'img_hover' => $arr['name'],
|
||||
'name' => $arr['name'],
|
||||
'details' => $details,
|
||||
'account_type' => Contact::getAccountType($arr),
|
||||
'profile' => $profile,
|
||||
'location' => $location_e,
|
||||
'tags' => $arr['pub_keywords'],
|
||||
'gender' => $gender,
|
||||
'pdesc' => $pdesc,
|
||||
'marital' => $marital,
|
||||
'homepage' => $homepage,
|
||||
'about' => $about,
|
||||
'photo_menu' => $photo_menu,
|
||||
|
||||
];
|
||||
|
||||
$hook = ['contact' => $arr, 'entry' => $entry];
|
||||
|
||||
Hook::callAll('directory_item', $hook);
|
||||
|
||||
unset($profile);
|
||||
unset($location);
|
||||
|
||||
return $hook['entry'];
|
||||
}
|
||||
|
|
|
@ -19,10 +19,10 @@ use Friendica\Model\Contact;
|
|||
use Friendica\Model\Group;
|
||||
use Friendica\Model\Item;
|
||||
use Friendica\Model\Profile;
|
||||
use Friendica\Module\Objects;
|
||||
use Friendica\Protocol\ActivityPub;
|
||||
use Friendica\Protocol\DFRN;
|
||||
use Friendica\Util\Strings;
|
||||
use Friendica\Module\Objects;
|
||||
|
||||
function display_init(App $a)
|
||||
{
|
||||
|
@ -283,22 +283,25 @@ function display_content(App $a, $update = false, $update_uid = 0)
|
|||
$is_remote_contact = false;
|
||||
$item_uid = local_user();
|
||||
|
||||
$parent = Item::selectFirst(['uid'], ['uri' => $item_parent_uri, 'wall' => true]);
|
||||
if (DBA::isResult($parent)) {
|
||||
$a->profile['uid'] = defaults($a->profile, 'uid', $parent['uid']);
|
||||
$a->profile['profile_uid'] = defaults($a->profile, 'profile_uid', $parent['uid']);
|
||||
$is_remote_contact = Contact::isFollower(remote_user(), $a->profile['profile_uid']);
|
||||
}
|
||||
if (isset($item_parent_uri)) {
|
||||
$parent = Item::selectFirst(['uid'], ['uri' => $item_parent_uri, 'wall' => true]);
|
||||
if (DBA::isResult($parent)) {
|
||||
$a->profile['uid'] = defaults($a->profile, 'uid', $parent['uid']);
|
||||
$a->profile['profile_uid'] = defaults($a->profile, 'profile_uid', $parent['uid']);
|
||||
$is_remote_contact = Contact::isFollower(remote_user(), $a->profile['profile_uid']);
|
||||
|
||||
if ($is_remote_contact) {
|
||||
$cdata = Contact::getPublicAndUserContacID(remote_user(), $a->profile['profile_uid']);
|
||||
if (!empty($cdata['user'])) {
|
||||
$groups = Group::getIdsByContactId($cdata['user']);
|
||||
$remote_cid = $cdata['user'];
|
||||
$item_uid = $parent['uid'];
|
||||
if ($is_remote_contact) {
|
||||
$cdata = Contact::getPublicAndUserContacID(remote_user(), $a->profile['profile_uid']);
|
||||
if (!empty($cdata['user'])) {
|
||||
$groups = Group::getIdsByContactId($cdata['user']);
|
||||
$remote_cid = $cdata['user'];
|
||||
$item_uid = $parent['uid'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$page_contact = DBA::selectFirst('contact', [], ['self' => true, 'uid' => $a->profile['uid']]);
|
||||
if (DBA::isResult($page_contact)) {
|
||||
$a->page_contact = $page_contact;
|
||||
|
|
313
mod/group.php
313
mod/group.php
|
@ -1,313 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @file mod/group.php
|
||||
* @brief The group module (create and rename contact groups, add and
|
||||
* remove contacts to the contact groups
|
||||
*/
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\BaseModule;
|
||||
use Friendica\Core\Config;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\PConfig;
|
||||
use Friendica\Core\Renderer;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Model;
|
||||
use Friendica\Module;
|
||||
use Friendica\Util\Strings;
|
||||
|
||||
function group_init(App $a) {
|
||||
if (local_user()) {
|
||||
$a->page['aside'] = Model\Group::sidebarWidget('contact', 'group', 'extended', (($a->argc > 1) ? $a->argv[1] : 'everyone'));
|
||||
}
|
||||
}
|
||||
|
||||
function group_post(App $a) {
|
||||
|
||||
if (!local_user()) {
|
||||
notice(L10n::t('Permission denied.') . EOL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (($a->argc == 2) && ($a->argv[1] === 'new')) {
|
||||
BaseModule::checkFormSecurityTokenRedirectOnError('/group/new', 'group_edit');
|
||||
|
||||
$name = Strings::escapeTags(trim($_POST['groupname']));
|
||||
$r = Model\Group::create(local_user(), $name);
|
||||
if ($r) {
|
||||
info(L10n::t('Group created.') . EOL);
|
||||
$r = Model\Group::getIdByName(local_user(), $name);
|
||||
if ($r) {
|
||||
$a->internalRedirect('group/' . $r);
|
||||
}
|
||||
} else {
|
||||
notice(L10n::t('Could not create group.') . EOL);
|
||||
}
|
||||
$a->internalRedirect('group');
|
||||
return; // NOTREACHED
|
||||
}
|
||||
|
||||
if (($a->argc == 2) && intval($a->argv[1])) {
|
||||
BaseModule::checkFormSecurityTokenRedirectOnError('/group', 'group_edit');
|
||||
|
||||
$r = q("SELECT * FROM `group` WHERE `id` = %d AND `uid` = %d LIMIT 1",
|
||||
intval($a->argv[1]),
|
||||
intval(local_user())
|
||||
);
|
||||
if (!DBA::isResult($r)) {
|
||||
notice(L10n::t('Group not found.') . EOL);
|
||||
$a->internalRedirect('contact');
|
||||
return; // NOTREACHED
|
||||
}
|
||||
$group = $r[0];
|
||||
$groupname = Strings::escapeTags(trim($_POST['groupname']));
|
||||
if (strlen($groupname) && ($groupname != $group['name'])) {
|
||||
$r = q("UPDATE `group` SET `name` = '%s' WHERE `uid` = %d AND `id` = %d",
|
||||
DBA::escape($groupname),
|
||||
intval(local_user()),
|
||||
intval($group['id'])
|
||||
);
|
||||
|
||||
if ($r) {
|
||||
info(L10n::t('Group name changed.') . EOL);
|
||||
}
|
||||
}
|
||||
|
||||
$a->page['aside'] = Model\Group::sidebarWidget();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
function group_content(App $a) {
|
||||
$change = false;
|
||||
|
||||
if (!local_user()) {
|
||||
notice(L10n::t('Permission denied') . EOL);
|
||||
return;
|
||||
}
|
||||
|
||||
// With no group number provided we jump to the unassigned contacts as a starting point
|
||||
if ($a->argc == 1) {
|
||||
$a->internalRedirect('group/none');
|
||||
}
|
||||
|
||||
// Switch to text mode interface if we have more than 'n' contacts or group members
|
||||
$switchtotext = PConfig::get(local_user(), 'system', 'groupedit_image_limit');
|
||||
if (is_null($switchtotext)) {
|
||||
$switchtotext = Config::get('system', 'groupedit_image_limit', 400);
|
||||
}
|
||||
|
||||
$tpl = Renderer::getMarkupTemplate('group_edit.tpl');
|
||||
|
||||
$context = [
|
||||
'$submit' => L10n::t('Save Group'),
|
||||
'$submit_filter' => L10n::t('Filter'),
|
||||
];
|
||||
|
||||
if (($a->argc == 2) && ($a->argv[1] === 'new')) {
|
||||
return Renderer::replaceMacros($tpl, $context + [
|
||||
'$title' => L10n::t('Create a group of contacts/friends.'),
|
||||
'$gname' => ['groupname', L10n::t('Group Name: '), '', ''],
|
||||
'$gid' => 'new',
|
||||
'$form_security_token' => BaseModule::getFormSecurityToken("group_edit"),
|
||||
]);
|
||||
|
||||
|
||||
}
|
||||
|
||||
$nogroup = false;
|
||||
|
||||
if (($a->argc == 2) && ($a->argv[1] === 'none')) {
|
||||
$id = -1;
|
||||
$nogroup = true;
|
||||
$group = [
|
||||
'id' => $id,
|
||||
'name' => L10n::t('Contacts not in any group'),
|
||||
];
|
||||
|
||||
$members = [];
|
||||
$preselected = [];
|
||||
|
||||
$context = $context + [
|
||||
'$title' => $group['name'],
|
||||
'$gname' => ['groupname', L10n::t('Group Name: '), $group['name'], ''],
|
||||
'$gid' => $id,
|
||||
'$editable' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
if (($a->argc == 3) && ($a->argv[1] === 'drop')) {
|
||||
BaseModule::checkFormSecurityTokenRedirectOnError('/group', 'group_drop', 't');
|
||||
|
||||
if (intval($a->argv[2])) {
|
||||
$r = q("SELECT `name` FROM `group` WHERE `id` = %d AND `uid` = %d LIMIT 1",
|
||||
intval($a->argv[2]),
|
||||
intval(local_user())
|
||||
);
|
||||
|
||||
$result = null;
|
||||
|
||||
if (DBA::isResult($r)) {
|
||||
$result = Model\Group::removeByName(local_user(), $r[0]['name']);
|
||||
}
|
||||
|
||||
if ($result) {
|
||||
info(L10n::t('Group removed.') . EOL);
|
||||
} else {
|
||||
notice(L10n::t('Unable to remove group.') . EOL);
|
||||
}
|
||||
}
|
||||
$a->internalRedirect('group');
|
||||
// NOTREACHED
|
||||
}
|
||||
|
||||
if (($a->argc > 2) && intval($a->argv[1]) && intval($a->argv[2])) {
|
||||
BaseModule::checkFormSecurityTokenForbiddenOnError('group_member_change', 't');
|
||||
|
||||
$r = q("SELECT `id` FROM `contact` WHERE `id` = %d AND `uid` = %d and `self` = 0 and `blocked` = 0 AND `pending` = 0 LIMIT 1",
|
||||
intval($a->argv[2]),
|
||||
intval(local_user())
|
||||
);
|
||||
if (DBA::isResult($r)) {
|
||||
$change = intval($a->argv[2]);
|
||||
}
|
||||
}
|
||||
|
||||
if (($a->argc > 1) && intval($a->argv[1])) {
|
||||
$r = q("SELECT * FROM `group` WHERE `id` = %d AND `uid` = %d AND `deleted` = 0 LIMIT 1",
|
||||
intval($a->argv[1]),
|
||||
intval(local_user())
|
||||
);
|
||||
|
||||
if (!DBA::isResult($r)) {
|
||||
notice(L10n::t('Group not found.') . EOL);
|
||||
$a->internalRedirect('contact');
|
||||
}
|
||||
|
||||
$group = $r[0];
|
||||
$members = Model\Contact::getByGroupId($group['id']);
|
||||
$preselected = [];
|
||||
|
||||
if (count($members)) {
|
||||
foreach ($members as $member) {
|
||||
$preselected[] = $member['id'];
|
||||
}
|
||||
}
|
||||
|
||||
if ($change) {
|
||||
if (in_array($change, $preselected)) {
|
||||
Model\Group::removeMember($group['id'], $change);
|
||||
} else {
|
||||
Model\Group::addMember($group['id'], $change);
|
||||
}
|
||||
|
||||
$members = Model\Contact::getByGroupId($group['id']);
|
||||
$preselected = [];
|
||||
if (count($members)) {
|
||||
foreach ($members as $member) {
|
||||
$preselected[] = $member['id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$drop_tpl = Renderer::getMarkupTemplate('group_drop.tpl');
|
||||
$drop_txt = Renderer::replaceMacros($drop_tpl, [
|
||||
'$id' => $group['id'],
|
||||
'$delete' => L10n::t('Delete Group'),
|
||||
'$form_security_token' => BaseModule::getFormSecurityToken("group_drop"),
|
||||
]);
|
||||
|
||||
|
||||
$context = $context + [
|
||||
'$title' => $group['name'],
|
||||
'$gname' => ['groupname', L10n::t('Group Name: '), $group['name'], ''],
|
||||
'$gid' => $group['id'],
|
||||
'$drop' => $drop_txt,
|
||||
'$form_security_token' => BaseModule::getFormSecurityToken('group_edit'),
|
||||
'$edit_name' => L10n::t('Edit Group Name'),
|
||||
'$editable' => 1,
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
if (!isset($group)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$groupeditor = [
|
||||
'label_members' => L10n::t('Members'),
|
||||
'members' => [],
|
||||
'label_contacts' => L10n::t('All Contacts'),
|
||||
'group_is_empty' => L10n::t('Group is empty'),
|
||||
'contacts' => [],
|
||||
];
|
||||
|
||||
$sec_token = addslashes(BaseModule::getFormSecurityToken('group_member_change'));
|
||||
|
||||
// Format the data of the group members
|
||||
foreach ($members as $member) {
|
||||
if ($member['url']) {
|
||||
$entry = Module\Contact::getContactTemplateVars($member);
|
||||
$entry['label'] = 'members';
|
||||
$entry['photo_menu'] = '';
|
||||
$entry['change_member'] = [
|
||||
'title' => L10n::t("Remove contact from group"),
|
||||
'gid' => $group['id'],
|
||||
'cid' => $member['id'],
|
||||
'sec_token' => $sec_token
|
||||
];
|
||||
|
||||
$groupeditor['members'][] = $entry;
|
||||
} else {
|
||||
Model\Group::removeMember($group['id'], $member['id']);
|
||||
}
|
||||
}
|
||||
|
||||
if ($nogroup) {
|
||||
$r = Model\Contact::getUngroupedList(local_user());
|
||||
} else {
|
||||
$r = q("SELECT * FROM `contact` WHERE `uid` = %d AND NOT `blocked` AND NOT `pending` AND NOT `self` ORDER BY `name` ASC",
|
||||
intval(local_user())
|
||||
);
|
||||
$context['$desc'] = L10n::t('Click on a contact to add or remove.');
|
||||
}
|
||||
|
||||
if (DBA::isResult($r)) {
|
||||
// Format the data of the contacts who aren't in the contact group
|
||||
foreach ($r as $member) {
|
||||
if (!in_array($member['id'], $preselected)) {
|
||||
$entry = Module\Contact::getContactTemplateVars($member);
|
||||
$entry['label'] = 'contacts';
|
||||
if (!$nogroup)
|
||||
$entry['photo_menu'] = [];
|
||||
|
||||
if (!$nogroup) {
|
||||
$entry['change_member'] = [
|
||||
'title' => L10n::t("Add contact to group"),
|
||||
'gid' => $group['id'],
|
||||
'cid' => $member['id'],
|
||||
'sec_token' => $sec_token
|
||||
];
|
||||
}
|
||||
|
||||
$groupeditor['contacts'][] = $entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$context['$groupeditor'] = $groupeditor;
|
||||
|
||||
// If there are to many contacts we could provide an alternative view mode
|
||||
$total = count($groupeditor['members']) + count($groupeditor['contacts']);
|
||||
$context['$shortmode'] = (($switchtotext && ($total > $switchtotext)) ? true : false);
|
||||
|
||||
if ($change) {
|
||||
$tpl = Renderer::getMarkupTemplate('groupeditor.tpl');
|
||||
echo Renderer::replaceMacros($tpl, $context);
|
||||
exit();
|
||||
}
|
||||
|
||||
return Renderer::replaceMacros($tpl, $context);
|
||||
|
||||
}
|
127
mod/item.php
127
mod/item.php
|
@ -33,6 +33,7 @@ use Friendica\Model\FileTag;
|
|||
use Friendica\Model\Item;
|
||||
use Friendica\Model\Photo;
|
||||
use Friendica\Model\Attach;
|
||||
use Friendica\Model\Term;
|
||||
use Friendica\Protocol\Diaspora;
|
||||
use Friendica\Protocol\Email;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
|
@ -83,13 +84,13 @@ function item_post(App $a) {
|
|||
}
|
||||
|
||||
// Is this a reply to something?
|
||||
$thr_parent = intval(defaults($_REQUEST, 'parent', 0));
|
||||
$toplevel_item_id = intval(defaults($_REQUEST, 'parent', 0));
|
||||
$thr_parent_uri = trim(defaults($_REQUEST, 'parent_uri', ''));
|
||||
|
||||
$thr_parent_contact = null;
|
||||
$thread_parent_id = 0;
|
||||
$thread_parent_contact = null;
|
||||
|
||||
$parent = 0;
|
||||
$parent_item = null;
|
||||
$toplevel_item = null;
|
||||
$parent_user = null;
|
||||
|
||||
$parent_contact = null;
|
||||
|
@ -98,25 +99,26 @@ function item_post(App $a) {
|
|||
$profile_uid = defaults($_REQUEST, 'profile_uid', local_user());
|
||||
$posttype = defaults($_REQUEST, 'post_type', Item::PT_ARTICLE);
|
||||
|
||||
if ($thr_parent || $thr_parent_uri) {
|
||||
if ($thr_parent) {
|
||||
$parent_item = Item::selectFirst([], ['id' => $thr_parent]);
|
||||
if ($toplevel_item_id || $thr_parent_uri) {
|
||||
if ($toplevel_item_id) {
|
||||
$toplevel_item = Item::selectFirst([], ['id' => $toplevel_item_id]);
|
||||
} elseif ($thr_parent_uri) {
|
||||
$parent_item = Item::selectFirst([], ['uri' => $thr_parent_uri, 'uid' => $profile_uid]);
|
||||
$toplevel_item = Item::selectFirst([], ['uri' => $thr_parent_uri, 'uid' => $profile_uid]);
|
||||
}
|
||||
|
||||
// if this isn't the real parent of the conversation, find it
|
||||
if (DBA::isResult($parent_item)) {
|
||||
// if this isn't the top-level parent of the conversation, find it
|
||||
if (DBA::isResult($toplevel_item)) {
|
||||
// The URI and the contact is taken from the direct parent which needn't to be the top parent
|
||||
$thr_parent_uri = $parent_item['uri'];
|
||||
$thr_parent_contact = Contact::getDetailsByURL($parent_item["author-link"]);
|
||||
$thread_parent_id = $toplevel_item['id'];
|
||||
$thr_parent_uri = $toplevel_item['uri'];
|
||||
$thread_parent_contact = Contact::getDetailsByURL($toplevel_item["author-link"]);
|
||||
|
||||
if ($parent_item['id'] != $parent_item['parent']) {
|
||||
$parent_item = Item::selectFirst(Item::ITEM_FIELDLIST, ['id' => $parent_item['parent']]);
|
||||
if ($toplevel_item['id'] != $toplevel_item['parent']) {
|
||||
$toplevel_item = Item::selectFirst(Item::ITEM_FIELDLIST, ['id' => $toplevel_item['parent']]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!DBA::isResult($parent_item)) {
|
||||
if (!DBA::isResult($toplevel_item)) {
|
||||
notice(L10n::t('Unable to locate original post.') . EOL);
|
||||
if (!empty($_REQUEST['return'])) {
|
||||
$a->internalRedirect($return_path);
|
||||
|
@ -124,14 +126,14 @@ function item_post(App $a) {
|
|||
exit();
|
||||
}
|
||||
|
||||
$parent = $parent_item['id'];
|
||||
$parent_user = $parent_item['uid'];
|
||||
$toplevel_item_id = $toplevel_item['id'];
|
||||
$parent_user = $toplevel_item['uid'];
|
||||
|
||||
$objecttype = ACTIVITY_OBJ_COMMENT;
|
||||
}
|
||||
|
||||
if ($parent) {
|
||||
Logger::log('mod_item: item_post parent=' . $parent);
|
||||
if ($toplevel_item_id) {
|
||||
Logger::info('mod_item: item_post parent=' . $toplevel_item_id);
|
||||
}
|
||||
|
||||
$post_id = intval(defaults($_REQUEST, 'post_id', 0));
|
||||
|
@ -160,7 +162,7 @@ function item_post(App $a) {
|
|||
}
|
||||
|
||||
// Allow commenting if it is an answer to a public post
|
||||
$allow_comment = local_user() && ($profile_uid == 0) && $parent && in_array($parent_item['network'], [Protocol::ACTIVITYPUB, Protocol::OSTATUS, Protocol::DIASPORA, Protocol::DFRN]);
|
||||
$allow_comment = local_user() && ($profile_uid == 0) && $toplevel_item_id && in_array($toplevel_item['network'], [Protocol::ACTIVITYPUB, Protocol::OSTATUS, Protocol::DIASPORA, Protocol::DFRN]);
|
||||
|
||||
// Now check that valid personal details have been provided
|
||||
if (!Security::canWriteToUserWall($profile_uid) && !$allow_comment) {
|
||||
|
@ -183,7 +185,7 @@ function item_post(App $a) {
|
|||
|
||||
$user = DBA::selectFirst('user', [], ['uid' => $profile_uid]);
|
||||
|
||||
if (!DBA::isResult($user) && !$parent) {
|
||||
if (!DBA::isResult($user) && !$toplevel_item_id) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -287,21 +289,21 @@ function item_post(App $a) {
|
|||
|
||||
// If this is a comment, set the permissions from the parent.
|
||||
|
||||
if ($parent_item) {
|
||||
if ($toplevel_item) {
|
||||
// for non native networks use the network of the original post as network of the item
|
||||
if (($parent_item['network'] != Protocol::DIASPORA)
|
||||
&& ($parent_item['network'] != Protocol::OSTATUS)
|
||||
if (($toplevel_item['network'] != Protocol::DIASPORA)
|
||||
&& ($toplevel_item['network'] != Protocol::OSTATUS)
|
||||
&& ($network == "")) {
|
||||
$network = $parent_item['network'];
|
||||
$network = $toplevel_item['network'];
|
||||
}
|
||||
|
||||
$str_contact_allow = $parent_item['allow_cid'];
|
||||
$str_group_allow = $parent_item['allow_gid'];
|
||||
$str_contact_deny = $parent_item['deny_cid'];
|
||||
$str_group_deny = $parent_item['deny_gid'];
|
||||
$private = $parent_item['private'];
|
||||
$str_contact_allow = $toplevel_item['allow_cid'];
|
||||
$str_group_allow = $toplevel_item['allow_gid'];
|
||||
$str_contact_deny = $toplevel_item['deny_cid'];
|
||||
$str_group_deny = $toplevel_item['deny_gid'];
|
||||
$private = $toplevel_item['private'];
|
||||
|
||||
$wall = $parent_item['wall'];
|
||||
$wall = $toplevel_item['wall'];
|
||||
}
|
||||
|
||||
$pubmail_enabled = defaults($_REQUEST, 'pubmail_enable', false) && !$private;
|
||||
|
@ -382,12 +384,8 @@ function item_post(App $a) {
|
|||
|
||||
$tags = BBCode::getTags($body);
|
||||
|
||||
// Add a tag if the parent contact is from ActivityPub or OStatus (This will notify them)
|
||||
if ($parent && in_array($thr_parent_contact['network'], [Protocol::OSTATUS, Protocol::ACTIVITYPUB])) {
|
||||
$contact = '@[url=' . $thr_parent_contact['url'] . ']' . $thr_parent_contact['nick'] . '[/url]';
|
||||
if (!stripos(implode($tags), '[url=' . $thr_parent_contact['url'] . ']')) {
|
||||
$tags[] = $contact;
|
||||
}
|
||||
if ($thread_parent_id && !\Friendica\Content\Feature::isEnabled($uid, 'explicit_mentions')) {
|
||||
$tags = item_add_implicit_mentions($tags, $thread_parent_contact, $thread_parent_id);
|
||||
}
|
||||
|
||||
$tagged = [];
|
||||
|
@ -400,7 +398,7 @@ function item_post(App $a) {
|
|||
foreach ($tags as $tag) {
|
||||
$tag_type = substr($tag, 0, 1);
|
||||
|
||||
if ($tag_type == '#') {
|
||||
if ($tag_type == Term::TAG_CHARACTER[Term::HASHTAG]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -425,9 +423,9 @@ function item_post(App $a) {
|
|||
$tagged[] = $tag;
|
||||
}
|
||||
// When the forum is private or the forum is addressed with a "!" make the post private
|
||||
if (is_array($success['contact']) && (!empty($success['contact']['prv']) || ($tag_type == '!'))) {
|
||||
if (is_array($success['contact']) && (!empty($success['contact']['prv']) || ($tag_type == Term::TAG_CHARACTER[Term::EXCLUSIVE_MENTION]))) {
|
||||
$private_forum = $success['contact']['prv'];
|
||||
$only_to_forum = ($tag_type == '!');
|
||||
$only_to_forum = ($tag_type == Term::TAG_CHARACTER[Term::EXCLUSIVE_MENTION]);
|
||||
$private_id = $success['contact']['id'];
|
||||
$forum_contact = $success['contact'];
|
||||
} elseif (is_array($success['contact']) && !empty($success['contact']['forum']) &&
|
||||
|
@ -442,7 +440,7 @@ function item_post(App $a) {
|
|||
|
||||
$original_contact_id = $contact_id;
|
||||
|
||||
if (!$parent && count($forum_contact) && ($private_forum || $only_to_forum)) {
|
||||
if (!$toplevel_item_id && count($forum_contact) && ($private_forum || $only_to_forum)) {
|
||||
// we tagged a forum in a top level post. Now we change the post
|
||||
$private = $private_forum;
|
||||
|
||||
|
@ -595,7 +593,7 @@ function item_post(App $a) {
|
|||
$network = Protocol::DFRN;
|
||||
}
|
||||
|
||||
$gravity = ($parent ? GRAVITY_COMMENT : GRAVITY_PARENT);
|
||||
$gravity = ($toplevel_item_id ? GRAVITY_COMMENT : GRAVITY_PARENT);
|
||||
|
||||
// even if the post arrived via API we are considering that it
|
||||
// originated on this site by default for determining relayability.
|
||||
|
@ -607,12 +605,12 @@ function item_post(App $a) {
|
|||
$origin = $_REQUEST['origin'];
|
||||
}
|
||||
|
||||
$notify_type = ($parent ? 'comment-new' : 'wall-new');
|
||||
$notify_type = ($toplevel_item_id ? 'comment-new' : 'wall-new');
|
||||
|
||||
$uri = ($message_id ? $message_id : Item::newURI($api_source ? $profile_uid : $uid, $guid));
|
||||
|
||||
// Fallback so that we alway have a parent uri
|
||||
if (!$thr_parent_uri || !$parent) {
|
||||
if (!$thr_parent_uri || !$toplevel_item_id) {
|
||||
$thr_parent_uri = $uri;
|
||||
}
|
||||
|
||||
|
@ -670,7 +668,7 @@ function item_post(App $a) {
|
|||
* 'self' if true indicates the owner is posting on their own wall
|
||||
* If parent is 0 it is a top-level post.
|
||||
*/
|
||||
$datarray['parent'] = $parent;
|
||||
$datarray['parent'] = $toplevel_item_id;
|
||||
$datarray['self'] = $self;
|
||||
|
||||
// This triggers posts via API and the mirror functions
|
||||
|
@ -788,7 +786,7 @@ function item_post(App $a) {
|
|||
FileTag::updatePconfig($uid, $categories_old, $categories_new, 'category');
|
||||
|
||||
// These notifications are sent if someone else is commenting other your wall
|
||||
if ($parent) {
|
||||
if ($toplevel_item_id) {
|
||||
if ($contact_record != $author) {
|
||||
notification([
|
||||
'type' => NOTIFY_COMMENT,
|
||||
|
@ -804,8 +802,8 @@ function item_post(App $a) {
|
|||
'source_photo' => $datarray['author-avatar'],
|
||||
'verb' => ACTIVITY_POST,
|
||||
'otype' => 'item',
|
||||
'parent' => $parent,
|
||||
'parent_uri' => $parent_item['uri']
|
||||
'parent' => $toplevel_item_id,
|
||||
'parent_uri' => $toplevel_item['uri']
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
|
@ -962,7 +960,7 @@ function handle_tag(&$body, &$inform, &$str_tags, $profile_uid, $tag, $network =
|
|||
$r = null;
|
||||
|
||||
//is it a person tag?
|
||||
if ((strpos($tag, '@') === 0) || (strpos($tag, '!') === 0)) {
|
||||
if (Term::isType($tag, Term::MENTION, Term::IMPLICIT_MENTION, Term::EXCLUSIVE_MENTION)) {
|
||||
$tag_type = substr($tag, 0, 1);
|
||||
//is it already replaced?
|
||||
if (strpos($tag, '[url=')) {
|
||||
|
@ -1099,3 +1097,34 @@ function handle_tag(&$body, &$inform, &$str_tags, $profile_uid, $tag, $network =
|
|||
|
||||
return ['replaced' => $replaced, 'contact' => $contact];
|
||||
}
|
||||
|
||||
function item_add_implicit_mentions(array $tags, array $thread_parent_contact, $thread_parent_id)
|
||||
{
|
||||
if (Config::get('system', 'disable_implicit_mentions')) {
|
||||
// Add a tag if the parent contact is from ActivityPub or OStatus (This will notify them)
|
||||
if (in_array($thread_parent_contact['network'], [Protocol::OSTATUS, Protocol::ACTIVITYPUB])) {
|
||||
$contact = Term::TAG_CHARACTER[Term::MENTION] . '[url=' . $thread_parent_contact['url'] . ']' . $thread_parent_contact['nick'] . '[/url]';
|
||||
if (!stripos(implode($tags), '[url=' . $thread_parent_contact['url'] . ']')) {
|
||||
$tags[] = $contact;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$implicit_mentions = [
|
||||
$thread_parent_contact['url'] => $thread_parent_contact['nick']
|
||||
];
|
||||
|
||||
$parent_terms = Term::tagArrayFromItemId($thread_parent_id, [Term::MENTION, Term::IMPLICIT_MENTION]);
|
||||
|
||||
foreach ($parent_terms as $parent_term) {
|
||||
$implicit_mentions[$parent_term['url']] = $parent_term['term'];
|
||||
}
|
||||
|
||||
foreach ($implicit_mentions as $url => $label) {
|
||||
if ($url != \Friendica\Model\Profile::getMyURL() && !stripos(implode($tags), '[url=' . $url . ']')) {
|
||||
$tags[] = Term::TAG_CHARACTER[Term::IMPLICIT_MENTION] . '[url=' . $url . ']' . $label . '[/url]';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $tags;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,12 @@ use Friendica\Core\Logger;
|
|||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Util\Network;
|
||||
|
||||
function nodeinfo_wellknown(App $a) {
|
||||
if (!Config::get('system', 'nodeinfo')) {
|
||||
System::httpExit(404);
|
||||
}
|
||||
|
||||
$nodeinfo = ['links' => [['rel' => 'http://nodeinfo.diaspora.software/ns/schema/1.0',
|
||||
'href' => System::baseUrl().'/nodeinfo/1.0']]];
|
||||
|
||||
|
|
|
@ -338,7 +338,7 @@ function profiles_post(App $a) {
|
|||
|
||||
$hide_friends = (($_POST['hide-friends'] == 1) ? 1: 0);
|
||||
|
||||
PConfig::set(local_user(), 'system', 'detailled_profile', (($_POST['detailled_profile'] == 1) ? 1: 0));
|
||||
PConfig::set(local_user(), 'system', 'detailled_profile', (($_POST['detailed_profile'] == 1) ? 1: 0));
|
||||
|
||||
$changes = [];
|
||||
if ($is_default) {
|
||||
|
@ -535,18 +535,18 @@ function profiles_content(App $a) {
|
|||
$personal_account = !(in_array($a->user["page-flags"],
|
||||
[User::PAGE_FLAGS_COMMUNITY, User::PAGE_FLAGS_PRVGROUP]));
|
||||
|
||||
$detailled_profile = (PConfig::get(local_user(), 'system', 'detailled_profile') AND $personal_account);
|
||||
$detailed_profile = (PConfig::get(local_user(), 'system', 'detailled_profile') AND $personal_account);
|
||||
|
||||
$is_default = (($r[0]['is-default']) ? 1 : 0);
|
||||
$tpl = Renderer::getMarkupTemplate("profile_edit.tpl");
|
||||
$o .= Renderer::replaceMacros($tpl, [
|
||||
'$personal_account' => $personal_account,
|
||||
'$detailled_profile' => $detailled_profile,
|
||||
'$detailled_profile' => $detailed_profile,
|
||||
|
||||
'$details' => [
|
||||
'detailled_profile', //Name
|
||||
'detailed_profile', //Name
|
||||
L10n::t('Show more profile fields:'), //Label
|
||||
$detailled_profile, //Value
|
||||
$detailed_profile, //Value
|
||||
'', //Help string
|
||||
[L10n::t('No'), L10n::t('Yes')] //Off - On strings
|
||||
],
|
||||
|
|
234
src/App.php
234
src/App.php
|
@ -8,11 +8,12 @@ use Detection\MobileDetect;
|
|||
use DOMDocument;
|
||||
use DOMXPath;
|
||||
use Exception;
|
||||
use Friendica\Core\Config\ConfigCache;
|
||||
use Friendica\Core\Config\ConfigCacheLoader;
|
||||
use Friendica\Core\Config\Cache\ConfigCacheLoader;
|
||||
use Friendica\Core\Config\Cache\IConfigCache;
|
||||
use Friendica\Core\Config\Configuration;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Factory\ConfigFactory;
|
||||
use Friendica\Network\HTTPException\InternalServerErrorException;
|
||||
use Friendica\Util\Profiler;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
|
@ -53,8 +54,6 @@ class App
|
|||
public $identities;
|
||||
public $is_mobile = false;
|
||||
public $is_tablet = false;
|
||||
public $performance = [];
|
||||
public $callstack = [];
|
||||
public $theme_info = [];
|
||||
public $category;
|
||||
// Allow themes to control internal parameters
|
||||
|
@ -110,23 +109,28 @@ class App
|
|||
public $mobileDetect;
|
||||
|
||||
/**
|
||||
* @var LoggerInterface The current logger of this App
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* @var ConfigCache The cached config
|
||||
* @var Configuration The config
|
||||
*/
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* @var LoggerInterface The logger
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* @var Profiler The profiler of this app
|
||||
*/
|
||||
private $profiler;
|
||||
|
||||
/**
|
||||
* Returns the current config cache of this node
|
||||
*
|
||||
* @return ConfigCache
|
||||
* @return IConfigCache
|
||||
*/
|
||||
public function getConfig()
|
||||
public function getConfigCache()
|
||||
{
|
||||
return $this->config;
|
||||
return $this->config->getCache();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -139,6 +143,26 @@ class App
|
|||
return $this->basePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Logger of this app
|
||||
*
|
||||
* @return LoggerInterface
|
||||
*/
|
||||
public function getLogger()
|
||||
{
|
||||
return $this->logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* The profiler of this app
|
||||
*
|
||||
* @return Profiler
|
||||
*/
|
||||
public function getProfiler()
|
||||
{
|
||||
return $this->profiler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a stylesheet file path to be included in the <head> tag of every page.
|
||||
* Inclusion is done in App->initHead().
|
||||
|
@ -173,7 +197,6 @@ class App
|
|||
$this->footerScripts[] = trim($url, '/');
|
||||
}
|
||||
|
||||
public $process_id;
|
||||
public $queue;
|
||||
private $scheme;
|
||||
private $hostname;
|
||||
|
@ -181,48 +204,33 @@ class App
|
|||
/**
|
||||
* @brief App constructor.
|
||||
*
|
||||
* @param ConfigCache $config The Cached Config
|
||||
* @param LoggerInterface $logger Logger of this application
|
||||
* @param string $basePath The basedir of the app
|
||||
* @param Configuration $config The Configuration
|
||||
* @param LoggerInterface $logger The current app logger
|
||||
* @param Profiler $profiler The profiler of this application
|
||||
* @param bool $isBackend Whether it is used for backend or frontend (Default true=backend)
|
||||
*
|
||||
* @throws Exception if the Basepath is not usable
|
||||
*/
|
||||
public function __construct(ConfigCache $config, LoggerInterface $logger, $isBackend = true)
|
||||
public function __construct($basePath, Configuration $config, LoggerInterface $logger, Profiler $profiler, $isBackend = true)
|
||||
{
|
||||
$this->config = $config;
|
||||
BaseObject::setApp($this);
|
||||
|
||||
$this->logger = $logger;
|
||||
$this->basePath = $this->config->get('system', 'basepath');
|
||||
$this->config = $config;
|
||||
$this->profiler = $profiler;
|
||||
$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.');
|
||||
throw new Exception('Basepath \'' . $this->basePath . '\' isn\'t usable.');
|
||||
}
|
||||
$this->basePath = rtrim($this->basePath, DIRECTORY_SEPARATOR);
|
||||
|
||||
BaseObject::setApp($this);
|
||||
|
||||
$this->checkBackend($isBackend);
|
||||
$this->checkFriendicaApp();
|
||||
|
||||
$this->performance['start'] = microtime(true);
|
||||
$this->performance['database'] = 0;
|
||||
$this->performance['database_write'] = 0;
|
||||
$this->performance['cache'] = 0;
|
||||
$this->performance['cache_write'] = 0;
|
||||
$this->performance['network'] = 0;
|
||||
$this->performance['file'] = 0;
|
||||
$this->performance['rendering'] = 0;
|
||||
$this->performance['parser'] = 0;
|
||||
$this->performance['marktime'] = 0;
|
||||
$this->performance['markstart'] = microtime(true);
|
||||
|
||||
$this->callstack['database'] = [];
|
||||
$this->callstack['database_write'] = [];
|
||||
$this->callstack['cache'] = [];
|
||||
$this->callstack['cache_write'] = [];
|
||||
$this->callstack['network'] = [];
|
||||
$this->callstack['file'] = [];
|
||||
$this->callstack['rendering'] = [];
|
||||
$this->callstack['parser'] = [];
|
||||
$this->profiler->reset();
|
||||
|
||||
$this->mode = new App\Mode($this->basePath);
|
||||
|
||||
|
@ -341,61 +349,30 @@ class App
|
|||
return $this->mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Logger of the Application
|
||||
*
|
||||
* @return LoggerInterface The Logger
|
||||
* @throws InternalServerErrorException when the logger isn't created
|
||||
*/
|
||||
public function getLogger()
|
||||
{
|
||||
if (empty($this->logger)) {
|
||||
throw new InternalServerErrorException('Logger of the Application is not defined');
|
||||
}
|
||||
|
||||
return $this->logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads the whole app instance
|
||||
*/
|
||||
public function reload()
|
||||
{
|
||||
Core\Config::init($this->config);
|
||||
Core\PConfig::init($this->config);
|
||||
|
||||
$this->loadDatabase();
|
||||
|
||||
$this->getMode()->determine($this->basePath);
|
||||
|
||||
$this->determineURLPath();
|
||||
|
||||
if ($this->getMode()->has(App\Mode::DBCONFIGAVAILABLE)) {
|
||||
$adapterType = $this->config->get('system', 'config_adapter');
|
||||
$adapter = ConfigFactory::createConfig($adapterType, $this->config);
|
||||
Core\Config::setAdapter($adapter);
|
||||
$adapterP = ConfigFactory::createPConfig($adapterType, $this->config);
|
||||
Core\PConfig::setAdapter($adapterP);
|
||||
Core\Config::load();
|
||||
}
|
||||
|
||||
// again because DB-config could change the config
|
||||
$this->getMode()->determine($this->basePath);
|
||||
|
||||
if ($this->getMode()->has(App\Mode::DBAVAILABLE)) {
|
||||
Core\Hook::loadHooks();
|
||||
$loader = new ConfigCacheLoader($this->basePath);
|
||||
$this->config->getCache()->load($loader->loadCoreConfig('addon'), true);
|
||||
|
||||
$this->profiler->update(
|
||||
$this->config->get('system', 'profiler', false),
|
||||
$this->config->get('rendertime', 'callstack', false));
|
||||
|
||||
Core\Hook::loadHooks();
|
||||
Core\Hook::callAll('load_config', $loader);
|
||||
$this->config->loadConfigArray($loader->loadCoreConfig('addon'), true);
|
||||
}
|
||||
|
||||
$this->loadDefaultTimezone();
|
||||
|
||||
Core\L10n::init();
|
||||
|
||||
$this->process_id = Core\System::processID('log');
|
||||
|
||||
Core\Logger::setLogger($this->logger);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -424,16 +401,25 @@ class App
|
|||
*/
|
||||
private function determineURLPath()
|
||||
{
|
||||
/*
|
||||
* The automatic path detection in this function is currently deactivated,
|
||||
* see issue https://github.com/friendica/friendica/issues/6679
|
||||
*
|
||||
* The problem is that the function seems to be confused with some url.
|
||||
* These then confuses the detection which changes the url path.
|
||||
*/
|
||||
|
||||
/* Relative script path to the web server root
|
||||
* Not all of those $_SERVER properties can be present, so we do by inverse priority order
|
||||
*/
|
||||
/*
|
||||
$relative_script_path = '';
|
||||
$relative_script_path = defaults($_SERVER, 'REDIRECT_URL' , $relative_script_path);
|
||||
$relative_script_path = defaults($_SERVER, 'REDIRECT_URI' , $relative_script_path);
|
||||
$relative_script_path = defaults($_SERVER, 'REDIRECT_SCRIPT_URL', $relative_script_path);
|
||||
$relative_script_path = defaults($_SERVER, 'SCRIPT_URL' , $relative_script_path);
|
||||
$relative_script_path = defaults($_SERVER, 'REQUEST_URI' , $relative_script_path);
|
||||
|
||||
*/
|
||||
$this->urlPath = $this->config->get('system', 'urlpath');
|
||||
|
||||
/* $relative_script_path gives /relative/path/to/friendica/module/parameter
|
||||
|
@ -441,6 +427,7 @@ class App
|
|||
*
|
||||
* To get /relative/path/to/friendica we perform dirname() for as many levels as there are slashes in the QUERY_STRING
|
||||
*/
|
||||
/*
|
||||
if (!empty($relative_script_path)) {
|
||||
// Module
|
||||
if (!empty($_SERVER['QUERY_STRING'])) {
|
||||
|
@ -454,49 +441,7 @@ class App
|
|||
$this->urlPath = $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function loadDatabase()
|
||||
{
|
||||
if (DBA::connected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$db_host = $this->config->get('database', 'hostname');
|
||||
$db_user = $this->config->get('database', 'username');
|
||||
$db_pass = $this->config->get('database', 'password');
|
||||
$db_data = $this->config->get('database', 'database');
|
||||
$charset = $this->config->get('database', 'charset');
|
||||
|
||||
// Use environment variables for mysql if they are set beforehand
|
||||
if (!empty(getenv('MYSQL_HOST'))
|
||||
&& !empty(getenv('MYSQL_USERNAME') || !empty(getenv('MYSQL_USER')))
|
||||
&& getenv('MYSQL_PASSWORD') !== false
|
||||
&& !empty(getenv('MYSQL_DATABASE')))
|
||||
{
|
||||
$db_host = getenv('MYSQL_HOST');
|
||||
if (!empty(getenv('MYSQL_PORT'))) {
|
||||
$db_host .= ':' . getenv('MYSQL_PORT');
|
||||
}
|
||||
if (!empty(getenv('MYSQL_USERNAME'))) {
|
||||
$db_user = getenv('MYSQL_USERNAME');
|
||||
} else {
|
||||
$db_user = getenv('MYSQL_USER');
|
||||
}
|
||||
$db_pass = (string) getenv('MYSQL_PASSWORD');
|
||||
$db_data = getenv('MYSQL_DATABASE');
|
||||
}
|
||||
|
||||
$stamp1 = microtime(true);
|
||||
|
||||
if (DBA::connect($this->config, $db_host, $db_user, $db_pass, $db_data, $charset)) {
|
||||
// Loads DB_UPDATE_VERSION constant
|
||||
Database\DBStructure::definition($this->basePath, false);
|
||||
}
|
||||
|
||||
unset($db_host, $db_user, $db_pass, $db_data, $charset);
|
||||
|
||||
$this->saveTimestamp($stamp1, 'network');
|
||||
*/
|
||||
}
|
||||
|
||||
public function getScheme()
|
||||
|
@ -663,8 +608,6 @@ class App
|
|||
'$local_user' => local_user(),
|
||||
'$generator' => 'Friendica' . ' ' . FRIENDICA_VERSION,
|
||||
'$delitem' => Core\L10n::t('Delete this item?'),
|
||||
'$showmore' => Core\L10n::t('show more'),
|
||||
'$showfewer' => Core\L10n::t('show fewer'),
|
||||
'$update_interval' => $interval,
|
||||
'$shortcut_icon' => $shortcut_icon,
|
||||
'$touch_icon' => $touch_icon,
|
||||
|
@ -742,41 +685,6 @@ class App
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a timestamp for a value - f.e. a call
|
||||
* Necessary for profiling Friendica
|
||||
*
|
||||
* @param int $timestamp the Timestamp
|
||||
* @param string $value A value to profile
|
||||
*/
|
||||
public function saveTimestamp($timestamp, $value)
|
||||
{
|
||||
$profiler = $this->config->get('system', 'profiler');
|
||||
|
||||
if (!isset($profiler) || !$profiler) {
|
||||
return;
|
||||
}
|
||||
|
||||
$duration = (float) (microtime(true) - $timestamp);
|
||||
|
||||
if (!isset($this->performance[$value])) {
|
||||
// Prevent ugly E_NOTICE
|
||||
$this->performance[$value] = 0;
|
||||
}
|
||||
|
||||
$this->performance[$value] += (float) $duration;
|
||||
$this->performance['marktime'] += (float) $duration;
|
||||
|
||||
$callstack = Core\System::callstack();
|
||||
|
||||
if (!isset($this->callstack[$value][$callstack])) {
|
||||
// Prevent ugly E_NOTICE
|
||||
$this->callstack[$value][$callstack] = 0;
|
||||
}
|
||||
|
||||
$this->callstack[$value][$callstack] += (float) $duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current UserAgent as a String
|
||||
*
|
||||
|
@ -1227,7 +1135,7 @@ class App
|
|||
if (!$this->isBackend()) {
|
||||
$stamp1 = microtime(true);
|
||||
session_start();
|
||||
$this->saveTimestamp($stamp1, 'parser');
|
||||
$this->profiler->saveTimestamp($stamp1, 'parser', Core\System::callstack());
|
||||
Core\L10n::setSessionVariable();
|
||||
Core\L10n::setLangFromSession();
|
||||
} else {
|
||||
|
|
|
@ -150,7 +150,7 @@ class ContactSelector
|
|||
{
|
||||
$o = '';
|
||||
$select = [
|
||||
'EMPTY' => '',
|
||||
'' => L10n::t('No answer'),
|
||||
'Male' => L10n::t('Male'),
|
||||
'Female' => L10n::t('Female'),
|
||||
'Currently Male' => L10n::t('Currently Male'),
|
||||
|
@ -190,7 +190,7 @@ class ContactSelector
|
|||
{
|
||||
$o = '';
|
||||
$select = [
|
||||
'EMPTY' => '',
|
||||
'' => L10n::t('No answer'),
|
||||
'Males' => L10n::t('Males'),
|
||||
'Females' => L10n::t('Females'),
|
||||
'Gay' => L10n::t('Gay'),
|
||||
|
@ -228,7 +228,7 @@ class ContactSelector
|
|||
{
|
||||
$o = '';
|
||||
$select = [
|
||||
'EMPTY' => '',
|
||||
'' => L10n::t('No answer'),
|
||||
'Single' => L10n::t('Single'),
|
||||
'Lonely' => L10n::t('Lonely'),
|
||||
'Available' => L10n::t('Available'),
|
||||
|
|
|
@ -67,6 +67,7 @@ class BBCode extends BaseObject
|
|||
$post["after"] = trim(substr($body, $pos + strlen($data[0])));
|
||||
} else {
|
||||
$post["text"] = trim(str_replace($data[0], "", $body));
|
||||
$post["after"] = '';
|
||||
}
|
||||
|
||||
$attacheddata = $data[2];
|
||||
|
@ -1027,7 +1028,7 @@ class BBCode extends BaseObject
|
|||
@curl_exec($ch);
|
||||
$curl_info = @curl_getinfo($ch);
|
||||
|
||||
$a->saveTimestamp($stamp1, "network");
|
||||
$a->getProfiler()->saveTimestamp($stamp1, "network", System::callstack());
|
||||
|
||||
if (substr($curl_info["content_type"], 0, 6) == "image/") {
|
||||
$text = "[url=" . $match[1] . "]" . $match[1] . "[/url]";
|
||||
|
@ -1086,7 +1087,7 @@ class BBCode extends BaseObject
|
|||
@curl_exec($ch);
|
||||
$curl_info = @curl_getinfo($ch);
|
||||
|
||||
$a->saveTimestamp($stamp1, "network");
|
||||
$a->getProfiler()->saveTimestamp($stamp1, "network", System::callstack());
|
||||
|
||||
// if its a link to a picture then embed this picture
|
||||
if (substr($curl_info["content_type"], 0, 6) == "image/") {
|
||||
|
@ -1915,7 +1916,7 @@ class BBCode extends BaseObject
|
|||
// unmask the special chars back to HTML
|
||||
$text = str_replace(['&\_lt\_;', '&\_gt\_;', '&\_amp\_;'], ['<', '>', '&'], $text);
|
||||
|
||||
$a->saveTimestamp($stamp1, "parser");
|
||||
$a->getProfiler()->saveTimestamp($stamp1, "parser", System::callstack());
|
||||
|
||||
// Libertree has a problem with escaped hashtags.
|
||||
$text = str_replace(['\#'], ['#'], $text);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
namespace Friendica\Content\Text;
|
||||
|
||||
use Friendica\BaseObject;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Model\Contact;
|
||||
use Michelf\MarkdownExtra;
|
||||
|
||||
|
@ -36,7 +37,7 @@ class Markdown extends BaseObject
|
|||
$html = $MarkdownParser->transform($text);
|
||||
$html = preg_replace('/<a(.*?)href="#/is', '<a$1href="' . ltrim($_SERVER['REQUEST_URI'], '/') . '#', $html);
|
||||
|
||||
self::getApp()->saveTimestamp($stamp1, "parser");
|
||||
self::getApp()->getProfiler()->saveTimestamp($stamp1, "parser", System::callstack());
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
|
|
@ -219,7 +219,7 @@ class Addon extends BaseObject
|
|||
|
||||
$stamp1 = microtime(true);
|
||||
$f = file_get_contents("addon/$addon/$addon.php");
|
||||
$a->saveTimestamp($stamp1, "file");
|
||||
$a->getProfiler()->saveTimestamp($stamp1, "file", System::callstack());
|
||||
|
||||
$r = preg_match("|/\*.*\*/|msU", $f, $m);
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ class Cache extends \Friendica\BaseObject
|
|||
|
||||
$return = self::getDriver()->getAllKeys($prefix);
|
||||
|
||||
self::getApp()->saveTimestamp($time, 'cache');
|
||||
self::getApp()->getProfiler()->saveTimestamp($time, 'cache', System::callstack());
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ class Cache extends \Friendica\BaseObject
|
|||
|
||||
$return = self::getDriver()->get($key);
|
||||
|
||||
self::getApp()->saveTimestamp($time, 'cache');
|
||||
self::getApp()->getProfiler()->saveTimestamp($time, 'cache', System::callstack());
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ class Cache extends \Friendica\BaseObject
|
|||
|
||||
$return = self::getDriver()->set($key, $value, $duration);
|
||||
|
||||
self::getApp()->saveTimestamp($time, 'cache_write');
|
||||
self::getApp()->getProfiler()->saveTimestamp($time, 'cache_write', System::callstack());
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ class Cache extends \Friendica\BaseObject
|
|||
|
||||
$return = self::getDriver()->delete($key);
|
||||
|
||||
self::getApp()->saveTimestamp($time, 'cache_write');
|
||||
self::getApp()->getProfiler()->saveTimestamp($time, 'cache_write', System::callstack());
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
|
|
@ -8,10 +8,6 @@
|
|||
*/
|
||||
namespace Friendica\Core;
|
||||
|
||||
use Friendica\Core\Config\ConfigCache;
|
||||
use Friendica\Core\Config\IConfigAdapter;
|
||||
use Friendica\Core\Config\IConfigCache;
|
||||
|
||||
/**
|
||||
* @brief Arbitrary system configuration storage
|
||||
*
|
||||
|
@ -22,116 +18,76 @@ use Friendica\Core\Config\IConfigCache;
|
|||
class Config
|
||||
{
|
||||
/**
|
||||
* @var Config\IConfigAdapter|null
|
||||
* @var Config\Configuration
|
||||
*/
|
||||
private static $adapter;
|
||||
private static $config;
|
||||
|
||||
/**
|
||||
* @var Config\IConfigCache
|
||||
*/
|
||||
private static $cache;
|
||||
|
||||
/**
|
||||
* Initialize the config with only the cache
|
||||
* Initialize the config
|
||||
*
|
||||
* @param Config\IConfigCache $cache The configuration cache
|
||||
* @param Config\Configuration $config
|
||||
*/
|
||||
public static function init(Config\IConfigCache $cache)
|
||||
public static function init(Config\Configuration $config)
|
||||
{
|
||||
self::$cache = $cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the adapter for DB-backend
|
||||
*
|
||||
* @param Config\IConfigAdapter $adapter
|
||||
*/
|
||||
public static function setAdapter(Config\IConfigAdapter $adapter)
|
||||
{
|
||||
self::$adapter = $adapter;
|
||||
self::$config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Loads all configuration values of family into a cached storage.
|
||||
*
|
||||
* All configuration values of the system are stored in the cache ( @see IConfigCache )
|
||||
*
|
||||
* @param string $family The category of the configuration value
|
||||
* @param string $cat The category of the configuration value
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function load($family = "config")
|
||||
public static function load($cat = "config")
|
||||
{
|
||||
if (!isset(self::$adapter) || !self::$adapter->isConnected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::$adapter->load($family);
|
||||
self::$config->load($cat);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a particular user's config variable given the category name
|
||||
* ($family) and a key.
|
||||
*
|
||||
* Get a particular config value from the given category ($family)
|
||||
* and the $key from a cached storage either from the self::$adapter
|
||||
* (@see IConfigAdapter ) or from the static::$cache (@see IConfigCache ).
|
||||
*
|
||||
* @param string $family The category of the configuration value
|
||||
* @param string $cat The category of the configuration value
|
||||
* @param string $key The configuration key to query
|
||||
* @param mixed $default_value optional, The value to return if key is not set (default: null)
|
||||
* @param boolean $refresh optional, If true the config is loaded from the db and not from the cache (default: false)
|
||||
*
|
||||
* @return mixed Stored value or null if it does not exist
|
||||
*/
|
||||
public static function get($family, $key, $default_value = null, $refresh = false)
|
||||
public static function get($cat, $key, $default_value = null, $refresh = false)
|
||||
{
|
||||
if (!isset(self::$adapter) || !self::$adapter->isConnected()) {
|
||||
return self::$cache->get($family, $key, $default_value);
|
||||
}
|
||||
|
||||
return self::$adapter->get($family, $key, $default_value, $refresh);
|
||||
return self::$config->get($cat, $key, $default_value, $refresh);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a configuration value for system config
|
||||
*
|
||||
* Stores a config value ($value) in the category ($family) under the key ($key)
|
||||
* Stores a config value ($value) in the category ($cat) under the key ($key)
|
||||
*
|
||||
* Note: Please do not store booleans - convert to 0/1 integer values!
|
||||
*
|
||||
* @param string $family The category of the configuration value
|
||||
* @param string $cat The category of the configuration value
|
||||
* @param string $key The configuration key to set
|
||||
* @param mixed $value The value to store
|
||||
*
|
||||
* @return bool Operation success
|
||||
*/
|
||||
public static function set($family, $key, $value)
|
||||
public static function set($cat, $key, $value)
|
||||
{
|
||||
if (!isset(self::$adapter) || !self::$adapter->isConnected()) {
|
||||
return self::$cache->set($family, $key, $value);
|
||||
}
|
||||
|
||||
return self::$adapter->set($family, $key, $value);
|
||||
return self::$config->set($cat, $key, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deletes the given key from the system configuration.
|
||||
*
|
||||
* Removes the configured value from the stored cache in self::$config
|
||||
* (@see ConfigCache ) and removes it from the database (@see IConfigAdapter ).
|
||||
*
|
||||
* @param string $family The category of the configuration value
|
||||
* @param string $cat The category of the configuration value
|
||||
* @param string $key The configuration key to delete
|
||||
*
|
||||
* @return mixed
|
||||
* @return bool
|
||||
*/
|
||||
public static function delete($family, $key)
|
||||
public static function delete($cat, $key)
|
||||
{
|
||||
if (!isset(self::$adapter) || !self::$adapter->isConnected()) {
|
||||
self::$cache->delete($family, $key);
|
||||
}
|
||||
|
||||
return self::$adapter->delete($family, $key);
|
||||
return self::$config->delete($cat, $key);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Config;
|
||||
|
||||
abstract class AbstractDbaConfigAdapter
|
||||
{
|
||||
/** @var bool */
|
||||
protected $connected = true;
|
||||
|
||||
public function isConnected()
|
||||
{
|
||||
return $this->connected;
|
||||
}
|
||||
}
|
83
src/Core/Config/Adapter/AbstractDbaConfigAdapter.php
Normal file
83
src/Core/Config/Adapter/AbstractDbaConfigAdapter.php
Normal file
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Config\Adapter;
|
||||
|
||||
use Friendica\Database\DBA;
|
||||
|
||||
abstract class AbstractDbaConfigAdapter
|
||||
{
|
||||
/**
|
||||
* The connection state of the adapter
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $connected = true;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->connected = DBA::connected();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the adapter is currently connected
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isConnected()
|
||||
{
|
||||
return $this->connected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a DB value to a config value
|
||||
* - null = The db-value isn't set
|
||||
* - bool = The db-value is either '0' or '1'
|
||||
* - array = The db-value is a serialized array
|
||||
* - string = The db-value is a string
|
||||
*
|
||||
* Keep in mind that there aren't any numeric/integer config values in the database
|
||||
*
|
||||
* @param null|string $value
|
||||
*
|
||||
* @return null|array|string
|
||||
*/
|
||||
protected function toConfigValue($value)
|
||||
{
|
||||
if (!isset($value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (true) {
|
||||
// manage array value
|
||||
case preg_match("|^a:[0-9]+:{.*}$|s", $value):
|
||||
return unserialize($value);
|
||||
|
||||
default:
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a config value to a DB value (string)
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function toDbValue($value)
|
||||
{
|
||||
// if not set, save an empty string
|
||||
if (!isset($value)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
switch (true) {
|
||||
// manage arrays
|
||||
case is_array($value):
|
||||
return serialize($value);
|
||||
|
||||
default:
|
||||
return (string)$value;
|
||||
}
|
||||
}
|
||||
}
|
73
src/Core/Config/Adapter/IConfigAdapter.php
Normal file
73
src/Core/Config/Adapter/IConfigAdapter.php
Normal file
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Config\Adapter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Hypolite Petovan <hypolite@mrpetovan.com>
|
||||
*/
|
||||
interface IConfigAdapter
|
||||
{
|
||||
/**
|
||||
* Loads all configuration values and returns the loaded category as an array.
|
||||
*
|
||||
* @param string $cat The category of the configuration values to load
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function load($cat = "config");
|
||||
|
||||
/**
|
||||
* Get a particular system-wide config variable given the category name
|
||||
* ($family) and a key.
|
||||
*
|
||||
* Note: Boolean variables are defined as 0/1 in the database
|
||||
*
|
||||
* @param string $cat The category of the configuration value
|
||||
* @param string $key The configuration key to query
|
||||
*
|
||||
* @return null|mixed Stored value or null if it does not exist
|
||||
*/
|
||||
public function get($cat, $key);
|
||||
|
||||
/**
|
||||
* Stores a config value ($value) in the category ($family) under the key ($key).
|
||||
*
|
||||
* Note: Please do not store booleans - convert to 0/1 integer values!
|
||||
*
|
||||
* @param string $cat The category of the configuration value
|
||||
* @param string $key The configuration key to set
|
||||
* @param mixed $value The value to store
|
||||
*
|
||||
* @return bool Operation success
|
||||
*/
|
||||
public function set($cat, $key, $value);
|
||||
|
||||
/**
|
||||
* Removes the configured value from the stored cache
|
||||
* and removes it from the database.
|
||||
*
|
||||
* @param string $cat The category of the configuration value
|
||||
* @param string $key The configuration key to delete
|
||||
*
|
||||
* @return bool Operation success
|
||||
*/
|
||||
public function delete($cat, $key);
|
||||
|
||||
/**
|
||||
* Checks, if the current adapter is connected to the backend
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isConnected();
|
||||
|
||||
/**
|
||||
* Checks, if a config key ($key) in the category ($cat) is already loaded.
|
||||
*
|
||||
* @param string $cat The configuration category
|
||||
* @param string $key The configuration key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isLoaded($cat, $key);
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
namespace Friendica\Core\Config;
|
||||
namespace Friendica\Core\Config\Adapter;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -15,12 +15,12 @@ namespace Friendica\Core\Config;
|
|||
interface IPConfigAdapter
|
||||
{
|
||||
/**
|
||||
* Loads all configuration values of a user's config family into a cached storage.
|
||||
* Loads all configuration values of a user's config family and returns the loaded category as an array.
|
||||
*
|
||||
* @param string $uid The user_id
|
||||
* @param string $cat The category of the configuration value
|
||||
*
|
||||
* @return void
|
||||
* @return array
|
||||
*/
|
||||
public function load($uid, $cat);
|
||||
|
||||
|
@ -28,15 +28,15 @@ interface IPConfigAdapter
|
|||
* Get a particular user's config variable given the category name
|
||||
* ($family) and a key.
|
||||
*
|
||||
* Note: Boolean variables are defined as 0/1 in the database
|
||||
*
|
||||
* @param string $uid The user_id
|
||||
* @param string $cat The category of the configuration value
|
||||
* @param string $k The configuration key to query
|
||||
* @param mixed $default_value optional, The value to return if key is not set (default: null)
|
||||
* @param boolean $refresh optional, If true the config is loaded from the db and not from the cache (default: false)
|
||||
* @param string $key The configuration key to query
|
||||
*
|
||||
* @return mixed Stored value or null if it does not exist
|
||||
* @return null|mixed Stored value or null if it does not exist
|
||||
*/
|
||||
public function get($uid, $cat, $k, $default_value = null, $refresh = false);
|
||||
public function get($uid, $cat, $key);
|
||||
|
||||
/**
|
||||
* Stores a config value ($value) in the category ($family) under the key ($key)
|
||||
|
@ -46,12 +46,12 @@ interface IPConfigAdapter
|
|||
*
|
||||
* @param string $uid The user_id
|
||||
* @param string $cat The category of the configuration value
|
||||
* @param string $k The configuration key to set
|
||||
* @param string $key The configuration key to set
|
||||
* @param string $value The value to store
|
||||
*
|
||||
* @return bool Operation success
|
||||
*/
|
||||
public function set($uid, $cat, $k, $value);
|
||||
public function set($uid, $cat, $key, $value);
|
||||
|
||||
/**
|
||||
* Removes the configured value from the stored cache
|
||||
|
@ -59,9 +59,27 @@ interface IPConfigAdapter
|
|||
*
|
||||
* @param string $uid The user_id
|
||||
* @param string $cat The category of the configuration value
|
||||
* @param string $k The configuration key to delete
|
||||
* @param string $key The configuration key to delete
|
||||
*
|
||||
* @return mixed
|
||||
* @return bool Operation success
|
||||
*/
|
||||
public function delete($uid, $cat, $k);
|
||||
public function delete($uid, $cat, $key);
|
||||
|
||||
/**
|
||||
* Checks, if the current adapter is connected to the backend
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isConnected();
|
||||
|
||||
/**
|
||||
* Checks, if a config key ($key) in the category ($cat) is already loaded for the user_id $uid.
|
||||
*
|
||||
* @param string $uid The user_id
|
||||
* @param string $cat The configuration category
|
||||
* @param string $key The configuration key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isLoaded($uid, $cat, $key);
|
||||
}
|
145
src/Core/Config/Adapter/JITConfigAdapter.php
Normal file
145
src/Core/Config/Adapter/JITConfigAdapter.php
Normal file
|
@ -0,0 +1,145 @@
|
|||
<?php
|
||||
namespace Friendica\Core\Config\Adapter;
|
||||
|
||||
use Friendica\Database\DBA;
|
||||
|
||||
/**
|
||||
* JustInTime Configuration Adapter
|
||||
*
|
||||
* Default Config Adapter. Provides the best performance for pages loading few configuration variables.
|
||||
*
|
||||
* @author Hypolite Petovan <hypolite@mrpetovan.com>
|
||||
*/
|
||||
class JITConfigAdapter extends AbstractDbaConfigAdapter implements IConfigAdapter
|
||||
{
|
||||
private $in_db;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load($cat = "config")
|
||||
{
|
||||
$return = [];
|
||||
|
||||
if (!$this->isConnected()) {
|
||||
return $return;
|
||||
}
|
||||
|
||||
// We don't preload "system" anymore.
|
||||
// This reduces the number of database reads a lot.
|
||||
if ($cat === 'system') {
|
||||
return $return;
|
||||
}
|
||||
|
||||
$configs = DBA::select('config', ['v', 'k'], ['cat' => $cat]);
|
||||
while ($config = DBA::fetch($configs)) {
|
||||
$key = $config['k'];
|
||||
$value = $this->toConfigValue($config['v']);
|
||||
|
||||
// The value was in the db, so don't check it again (unless you have to)
|
||||
$this->in_db[$cat][$key] = true;
|
||||
|
||||
// just save it in case it is set
|
||||
if (isset($value)) {
|
||||
$return[$key] = $value;
|
||||
}
|
||||
}
|
||||
DBA::close($configs);
|
||||
|
||||
return [$cat => $return];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param bool $mark if true, mark the selection of the current cat/key pair
|
||||
*/
|
||||
public function get($cat, $key, $mark = true)
|
||||
{
|
||||
if (!$this->isConnected()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// The value got checked, so mark it to avoid checking it over and over again
|
||||
if ($mark) {
|
||||
$this->in_db[$cat][$key] = true;
|
||||
}
|
||||
|
||||
$config = DBA::selectFirst('config', ['v'], ['cat' => $cat, 'k' => $key]);
|
||||
if (DBA::isResult($config)) {
|
||||
$value = $this->toConfigValue($config['v']);
|
||||
|
||||
// just return it in case it is set
|
||||
if (isset($value)) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function set($cat, $key, $value)
|
||||
{
|
||||
if (!$this->isConnected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We store our setting values in a string variable.
|
||||
// So we have to do the conversion here so that the compare below works.
|
||||
// The exception are array values.
|
||||
$compare_value = (!is_array($value) ? (string)$value : $value);
|
||||
$stored_value = $this->get($cat, $key, false);
|
||||
|
||||
if (!isset($this->in_db[$cat])) {
|
||||
$this->in_db[$cat] = [];
|
||||
}
|
||||
if (!isset($this->in_db[$cat][$key])) {
|
||||
$this->in_db[$cat][$key] = false;
|
||||
}
|
||||
|
||||
if (isset($stored_value) && ($stored_value === $compare_value) && $this->in_db[$cat][$key]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$dbvalue = $this->toDbValue($value);
|
||||
|
||||
$result = DBA::update('config', ['v' => $dbvalue], ['cat' => $cat, 'k' => $key], true);
|
||||
|
||||
$this->in_db[$cat][$key] = $result;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function delete($cat, $key)
|
||||
{
|
||||
if (!$this->isConnected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($this->cache[$cat][$key])) {
|
||||
unset($this->in_db[$cat][$key]);
|
||||
}
|
||||
|
||||
$result = DBA::delete('config', ['cat' => $cat, 'k' => $key]);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isLoaded($cat, $key)
|
||||
{
|
||||
if (!$this->isConnected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (isset($this->in_db[$cat][$key])) && $this->in_db[$cat][$key];
|
||||
}
|
||||
}
|
145
src/Core/Config/Adapter/JITPConfigAdapter.php
Normal file
145
src/Core/Config/Adapter/JITPConfigAdapter.php
Normal file
|
@ -0,0 +1,145 @@
|
|||
<?php
|
||||
namespace Friendica\Core\Config\Adapter;
|
||||
|
||||
use Friendica\Database\DBA;
|
||||
|
||||
/**
|
||||
* JustInTime User Configuration Adapter
|
||||
*
|
||||
* Default PConfig Adapter. Provides the best performance for pages loading few configuration variables.
|
||||
*
|
||||
* @author Hypolite Petovan <hypolite@mrpetovan.com>
|
||||
*/
|
||||
class JITPConfigAdapter extends AbstractDbaConfigAdapter implements IPConfigAdapter
|
||||
{
|
||||
private $in_db;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load($uid, $cat)
|
||||
{
|
||||
$return = [];
|
||||
|
||||
if (!$this->isConnected()) {
|
||||
return $return;
|
||||
}
|
||||
|
||||
$pconfigs = DBA::select('pconfig', ['v', 'k'], ['cat' => $cat, 'uid' => $uid]);
|
||||
if (DBA::isResult($pconfigs)) {
|
||||
while ($pconfig = DBA::fetch($pconfigs)) {
|
||||
$key = $pconfig['k'];
|
||||
$value = $this->toConfigValue($pconfig['v']);
|
||||
|
||||
// The value was in the db, so don't check it again (unless you have to)
|
||||
$this->in_db[$uid][$cat][$key] = true;
|
||||
|
||||
if (isset($value)) {
|
||||
$return[$key] = $value;
|
||||
}
|
||||
}
|
||||
} else if ($cat != 'config') {
|
||||
// Negative caching
|
||||
$return = null;
|
||||
}
|
||||
DBA::close($pconfigs);
|
||||
|
||||
return [$cat => $return];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param bool $mark if true, mark the selection of the current cat/key pair
|
||||
*/
|
||||
public function get($uid, $cat, $key, $mark = true)
|
||||
{
|
||||
if (!$this->isConnected()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// The value was in the db, so don't check it again (unless you have to)
|
||||
if ($mark) {
|
||||
$this->in_db[$uid][$cat][$key] = true;
|
||||
}
|
||||
|
||||
$pconfig = DBA::selectFirst('pconfig', ['v'], ['uid' => $uid, 'cat' => $cat, 'k' => $key]);
|
||||
if (DBA::isResult($pconfig)) {
|
||||
$value = $this->toConfigValue($pconfig['v']);
|
||||
|
||||
if (isset($value)) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
$this->in_db[$uid][$cat][$key] = false;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function set($uid, $cat, $key, $value)
|
||||
{
|
||||
if (!$this->isConnected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We store our setting values in a string variable.
|
||||
// So we have to do the conversion here so that the compare below works.
|
||||
// The exception are array values.
|
||||
$compare_value = (!is_array($value) ? (string)$value : $value);
|
||||
$stored_value = $this->get($uid, $cat, $key, false);
|
||||
|
||||
if (!isset($this->in_db[$uid])) {
|
||||
$this->in_db[$uid] = [];
|
||||
}
|
||||
if (!isset($this->in_db[$uid][$cat])) {
|
||||
$this->in_db[$uid][$cat] = [];
|
||||
}
|
||||
if (!isset($this->in_db[$uid][$cat][$key])) {
|
||||
$this->in_db[$uid][$cat][$key] = false;
|
||||
}
|
||||
|
||||
if (isset($stored_value) && ($stored_value === $compare_value) && $this->in_db[$uid][$cat][$key]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// manage array value
|
||||
$dbvalue = (is_array($value) ? serialize($value) : $value);
|
||||
|
||||
$result = DBA::update('pconfig', ['v' => $dbvalue], ['uid' => $uid, 'cat' => $cat, 'k' => $key], true);
|
||||
|
||||
$this->in_db[$uid][$cat][$key] = $result;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function delete($uid, $cat, $key)
|
||||
{
|
||||
if (!$this->isConnected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($this->in_db[$uid][$cat][$key])) {
|
||||
unset($this->in_db[$uid][$cat][$key]);
|
||||
}
|
||||
|
||||
return DBA::delete('pconfig', ['uid' => $uid, 'cat' => $cat, 'k' => $key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isLoaded($uid, $cat, $key)
|
||||
{
|
||||
if (!$this->isConnected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (isset($this->in_db[$uid][$cat][$key])) && $this->in_db[$uid][$cat][$key];
|
||||
}
|
||||
}
|
115
src/Core/Config/Adapter/PreloadConfigAdapter.php
Normal file
115
src/Core/Config/Adapter/PreloadConfigAdapter.php
Normal file
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Config\Adapter;
|
||||
|
||||
use Friendica\Database\DBA;
|
||||
|
||||
/**
|
||||
* Preload Configuration Adapter
|
||||
*
|
||||
* Minimizes the number of database queries to retrieve configuration values at the cost of memory.
|
||||
*
|
||||
* @author Hypolite Petovan <hypolite@mrpetovan.com>
|
||||
*/
|
||||
class PreloadConfigAdapter extends AbstractDbaConfigAdapter implements IConfigAdapter
|
||||
{
|
||||
private $config_loaded = false;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load($cat = 'config')
|
||||
{
|
||||
$return = [];
|
||||
|
||||
if (!$this->isConnected()) {
|
||||
return $return;
|
||||
}
|
||||
|
||||
if ($this->config_loaded) {
|
||||
return $return;
|
||||
}
|
||||
|
||||
$configs = DBA::select('config', ['cat', 'v', 'k']);
|
||||
while ($config = DBA::fetch($configs)) {
|
||||
$value = $this->toConfigValue($config['v']);
|
||||
if (isset($value)) {
|
||||
$return[$config['cat']][$config['k']] = $value;
|
||||
}
|
||||
}
|
||||
DBA::close($configs);
|
||||
|
||||
$this->config_loaded = true;
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get($cat, $key)
|
||||
{
|
||||
if (!$this->isConnected()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$config = DBA::selectFirst('config', ['v'], ['cat' => $cat, 'k' => $key]);
|
||||
if (DBA::isResult($config)) {
|
||||
$value = $this->toConfigValue($config['v']);
|
||||
|
||||
if (isset($value)) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function set($cat, $key, $value)
|
||||
{
|
||||
if (!$this->isConnected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We store our setting values as strings.
|
||||
// So we have to do the conversion here so that the compare below works.
|
||||
// The exception are array values.
|
||||
$compare_value = !is_array($value) ? (string)$value : $value;
|
||||
$stored_value = $this->get($cat, $key);
|
||||
|
||||
if (isset($stored_value) && $stored_value === $compare_value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$dbvalue = $this->toDbValue($value);
|
||||
|
||||
return DBA::update('config', ['v' => $dbvalue], ['cat' => $cat, 'k' => $key], true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function delete($cat, $key)
|
||||
{
|
||||
if (!$this->isConnected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return DBA::delete('config', ['cat' => $cat, 'k' => $key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isLoaded($cat, $key)
|
||||
{
|
||||
if (!$this->isConnected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->config_loaded;
|
||||
}
|
||||
}
|
142
src/Core/Config/Adapter/PreloadPConfigAdapter.php
Normal file
142
src/Core/Config/Adapter/PreloadPConfigAdapter.php
Normal file
|
@ -0,0 +1,142 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Config\Adapter;
|
||||
|
||||
use Friendica\Database\DBA;
|
||||
|
||||
/**
|
||||
* Preload User Configuration Adapter
|
||||
*
|
||||
* Minimizes the number of database queries to retrieve configuration values at the cost of memory.
|
||||
*
|
||||
* @author Hypolite Petovan <hypolite@mrpetovan.com>
|
||||
*/
|
||||
class PreloadPConfigAdapter extends AbstractDbaConfigAdapter implements IPConfigAdapter
|
||||
{
|
||||
/**
|
||||
* @var array true if config for user is loaded
|
||||
*/
|
||||
private $config_loaded;
|
||||
|
||||
/**
|
||||
* @param int $uid The UID of the current user
|
||||
*/
|
||||
public function __construct($uid = null)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->config_loaded = [];
|
||||
|
||||
if (isset($uid)) {
|
||||
$this->load($uid, 'config');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load($uid, $cat)
|
||||
{
|
||||
$return = [];
|
||||
|
||||
if (empty($uid)) {
|
||||
return $return;
|
||||
}
|
||||
|
||||
if (!$this->isLoaded($uid, $cat, null)) {
|
||||
return $return;
|
||||
}
|
||||
|
||||
$pconfigs = DBA::select('pconfig', ['cat', 'v', 'k'], ['uid' => $uid]);
|
||||
while ($pconfig = DBA::fetch($pconfigs)) {
|
||||
$value = $this->toConfigValue($pconfig['v']);
|
||||
if (isset($value)) {
|
||||
$return[$pconfig['cat']][$pconfig['k']] = $value;
|
||||
}
|
||||
}
|
||||
DBA::close($pconfigs);
|
||||
|
||||
$this->config_loaded[$uid] = true;
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get($uid, $cat, $key)
|
||||
{
|
||||
if (!$this->isConnected()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$this->isLoaded($uid, $cat, $key)) {
|
||||
$this->load($uid, $cat);
|
||||
}
|
||||
|
||||
$config = DBA::selectFirst('pconfig', ['v'], ['uid' => $uid, 'cat' => $cat, 'k' => $key]);
|
||||
if (DBA::isResult($config)) {
|
||||
$value = $this->toConfigValue($config['v']);
|
||||
|
||||
if (isset($value)) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function set($uid, $cat, $key, $value)
|
||||
{
|
||||
if (!$this->isConnected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->isLoaded($uid, $cat, $key)) {
|
||||
$this->load($uid, $cat);
|
||||
}
|
||||
// We store our setting values as strings.
|
||||
// So we have to do the conversion here so that the compare below works.
|
||||
// The exception are array values.
|
||||
$compare_value = !is_array($value) ? (string)$value : $value;
|
||||
$stored_value = $this->get($uid, $cat, $key);
|
||||
|
||||
if (isset($stored_value) && $stored_value === $compare_value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$dbvalue = $this->toDbValue($value);
|
||||
|
||||
return DBA::update('pconfig', ['v' => $dbvalue], ['uid' => $uid, 'cat' => $cat, 'k' => $key], true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function delete($uid, $cat, $key)
|
||||
{
|
||||
if (!$this->isConnected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->isLoaded($uid, $cat, $key)) {
|
||||
$this->load($uid, $cat);
|
||||
}
|
||||
|
||||
return DBA::delete('pconfig', ['uid' => $uid, 'cat' => $cat, 'k' => $key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isLoaded($uid, $cat, $key)
|
||||
{
|
||||
if (!$this->isConnected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isset($this->config_loaded[$uid]) && $this->config_loaded[$uid];
|
||||
}
|
||||
}
|
191
src/Core/Config/Cache/ConfigCache.php
Normal file
191
src/Core/Config/Cache/ConfigCache.php
Normal file
|
@ -0,0 +1,191 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Config\Cache;
|
||||
|
||||
/**
|
||||
* The Friendica config cache for the application
|
||||
* Initial, all *.config.php files are loaded into this cache with the
|
||||
* ConfigCacheLoader ( @see ConfigCacheLoader )
|
||||
*/
|
||||
class ConfigCache implements IConfigCache, IPConfigCache
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* @param array $config A initial config array
|
||||
*/
|
||||
public function __construct(array $config = [])
|
||||
{
|
||||
$this->load($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load(array $config, $overwrite = false)
|
||||
{
|
||||
$categories = array_keys($config);
|
||||
|
||||
foreach ($categories as $category) {
|
||||
if (isset($config[$category]) && is_array($config[$category])) {
|
||||
$keys = array_keys($config[$category]);
|
||||
|
||||
foreach ($keys as $key) {
|
||||
$value = $config[$category][$key];
|
||||
if (isset($value)) {
|
||||
if ($overwrite) {
|
||||
$this->set($category, $key, $value);
|
||||
} else {
|
||||
$this->setDefault($category, $key, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get($cat, $key = null)
|
||||
{
|
||||
if (isset($this->config[$cat][$key])) {
|
||||
return $this->config[$cat][$key];
|
||||
} elseif (!isset($key) && isset($this->config[$cat])) {
|
||||
return $this->config[$cat];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a default value in the config cache. Ignores already existing keys.
|
||||
*
|
||||
* @param string $cat Config category
|
||||
* @param string $k Config key
|
||||
* @param mixed $v Default value to set
|
||||
*/
|
||||
private function setDefault($cat, $k, $v)
|
||||
{
|
||||
if (!isset($this->config[$cat][$k])) {
|
||||
$this->set($cat, $k, $v);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function set($cat, $key, $value)
|
||||
{
|
||||
if (!isset($this->config[$cat])) {
|
||||
$this->config[$cat] = [];
|
||||
}
|
||||
|
||||
$this->config[$cat][$key] = $value;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function delete($cat, $key)
|
||||
{
|
||||
if (isset($this->config[$cat][$key])) {
|
||||
unset($this->config[$cat][$key]);
|
||||
if (count($this->config[$cat]) == 0) {
|
||||
unset($this->config[$cat]);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function loadP($uid, array $config)
|
||||
{
|
||||
$categories = array_keys($config);
|
||||
|
||||
foreach ($categories as $category) {
|
||||
if (isset($config[$category]) && is_array($config[$category])) {
|
||||
|
||||
$keys = array_keys($config[$category]);
|
||||
|
||||
foreach ($keys as $key) {
|
||||
$value = $config[$category][$key];
|
||||
if (isset($value)) {
|
||||
$this->setP($uid, $category, $key, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getP($uid, $cat, $key = null)
|
||||
{
|
||||
if (isset($this->config[$uid][$cat][$key])) {
|
||||
return $this->config[$uid][$cat][$key];
|
||||
} elseif (!isset($key) && isset($this->config[$uid][$cat])) {
|
||||
return $this->config[$uid][$cat];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setP($uid, $cat, $key, $value)
|
||||
{
|
||||
if (!isset($this->config[$uid]) || !is_array($this->config[$uid])) {
|
||||
$this->config[$uid] = [];
|
||||
}
|
||||
|
||||
if (!isset($this->config[$uid][$cat])) {
|
||||
$this->config[$uid][$cat] = [];
|
||||
}
|
||||
|
||||
$this->config[$uid][$cat][$key] = $value;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function deleteP($uid, $cat, $key)
|
||||
{
|
||||
if (isset($this->config[$uid][$cat][$key])) {
|
||||
unset($this->config[$uid][$cat][$key]);
|
||||
if (count($this->config[$uid][$cat]) == 0) {
|
||||
unset($this->config[$uid][$cat]);
|
||||
if (count($this->config[$uid]) == 0) {
|
||||
unset($this->config[$uid]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the whole configuration
|
||||
*
|
||||
* @return array The configuration
|
||||
*/
|
||||
public function getAll()
|
||||
{
|
||||
return $this->config;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Config;
|
||||
namespace Friendica\Core\Config\Cache;
|
||||
|
||||
use Friendica\Core\Addon;
|
||||
|
||||
|
@ -37,16 +37,13 @@ class ConfigCacheLoader
|
|||
*/
|
||||
public function loadConfigFiles(ConfigCache $config)
|
||||
{
|
||||
// Setting at least the basepath we know
|
||||
$config->set('system', 'basepath', $this->baseDir);
|
||||
$config->load($this->loadCoreConfig('defaults'));
|
||||
$config->load($this->loadCoreConfig('settings'));
|
||||
|
||||
$config->loadConfigArray($this->loadCoreConfig('defaults'));
|
||||
$config->loadConfigArray($this->loadCoreConfig('settings'));
|
||||
$config->load($this->loadLegacyConfig('htpreconfig'), true);
|
||||
$config->load($this->loadLegacyConfig('htconfig'), true);
|
||||
|
||||
$config->loadConfigArray($this->loadLegacyConfig('htpreconfig'), true);
|
||||
$config->loadConfigArray($this->loadLegacyConfig('htconfig'), true);
|
||||
|
||||
$config->loadConfigArray($this->loadCoreConfig('local'), true);
|
||||
$config->load($this->loadCoreConfig('local'), true);
|
||||
}
|
||||
|
||||
/**
|
56
src/Core/Config/Cache/IConfigCache.php
Normal file
56
src/Core/Config/Cache/IConfigCache.php
Normal file
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Config\Cache;
|
||||
|
||||
/**
|
||||
* The interface for a system-wide ConfigCache
|
||||
*/
|
||||
interface IConfigCache
|
||||
{
|
||||
/**
|
||||
* Tries to load the specified configuration array into the config array.
|
||||
* Doesn't overwrite previously set values by default to prevent default config files to supersede DB Config.
|
||||
*
|
||||
* @param array $config
|
||||
* @param bool $overwrite Force value overwrite if the config key already exists
|
||||
*/
|
||||
function load(array $config, $overwrite = false);
|
||||
|
||||
/**
|
||||
* Gets a value from the config cache.
|
||||
*
|
||||
* @param string $cat Config category
|
||||
* @param string $key Config key
|
||||
*
|
||||
* @return null|mixed Returns the value of the Config entry or null if not set
|
||||
*/
|
||||
function get($cat, $key = null);
|
||||
|
||||
/**
|
||||
* Sets a value in the config cache. Accepts raw output from the config table
|
||||
*
|
||||
* @param string $cat Config category
|
||||
* @param string $key Config key
|
||||
* @param mixed $value Value to set
|
||||
*
|
||||
* @return bool True, if the value is set
|
||||
*/
|
||||
function set($cat, $key, $value);
|
||||
|
||||
/**
|
||||
* Deletes a value from the config cache.
|
||||
*
|
||||
* @param string $cat Config category
|
||||
* @param string $key Config key
|
||||
*
|
||||
* @return bool true, if deleted
|
||||
*/
|
||||
function delete($cat, $key);
|
||||
|
||||
/**
|
||||
* Returns the whole configuration cache
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getAll();
|
||||
}
|
|
@ -1,23 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Config;
|
||||
namespace Friendica\Core\Config\Cache;
|
||||
|
||||
/**
|
||||
* The interface for a user-specific config cache
|
||||
*/
|
||||
interface IPConfigCache
|
||||
{
|
||||
/**
|
||||
* Tries to load the specified configuration array into the user specific config array.
|
||||
* Doesn't overwrite previously set values by default to prevent default config files to supersede DB Config.
|
||||
*
|
||||
* @param int $uid
|
||||
* @param array $config
|
||||
*/
|
||||
function loadP($uid, array $config);
|
||||
|
||||
/**
|
||||
* Retrieves a value from the user config cache
|
||||
*
|
||||
* @param int $uid User Id
|
||||
* @param string $cat Config category
|
||||
* @param string $key Config key
|
||||
* @param mixed $default Default value if key isn't set
|
||||
*
|
||||
* @return string The value of the config entry
|
||||
* @return null|string The value of the config entry or null if not set
|
||||
*/
|
||||
function getP($uid, $cat, $key = null, $default = null);
|
||||
function getP($uid, $cat, $key = null);
|
||||
|
||||
/**
|
||||
* Sets a value in the user config cache
|
||||
|
@ -37,8 +45,15 @@ interface IPConfigCache
|
|||
* @param int $uid User Id
|
||||
* @param string $cat Config category
|
||||
* @param string $key Config key
|
||||
*
|
||||
* @return bool true, if deleted
|
||||
*/
|
||||
function deleteP($uid, $cat, $key);
|
||||
|
||||
/**
|
||||
* Returns the whole configuration cache
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getAll();
|
||||
}
|
|
@ -1,184 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Config;
|
||||
|
||||
/**
|
||||
* The Friendica config cache for the application
|
||||
* Initial, all *.config.php files are loaded into this cache with the
|
||||
* ConfigCacheLoader ( @see ConfigCacheLoader )
|
||||
*
|
||||
* Is used for further caching operations too (depending on the ConfigAdapter )
|
||||
*/
|
||||
class ConfigCache implements IConfigCache, IPConfigCache
|
||||
{
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* @param array $config A initial config array
|
||||
*/
|
||||
public function __construct(array $config = [])
|
||||
{
|
||||
$this->loadConfigArray($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to load the specified configuration array into the App->config array.
|
||||
* Doesn't overwrite previously set values by default to prevent default config files to supersede DB Config.
|
||||
*
|
||||
* @param array $config
|
||||
* @param bool $overwrite Force value overwrite if the config key already exists
|
||||
*/
|
||||
public function loadConfigArray(array $config, $overwrite = false)
|
||||
{
|
||||
foreach ($config as $category => $values) {
|
||||
foreach ($values as $key => $value) {
|
||||
if ($overwrite) {
|
||||
$this->set($category, $key, $value);
|
||||
} else {
|
||||
$this->setDefault($category, $key, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get($cat, $key = null, $default = null)
|
||||
{
|
||||
$return = $default;
|
||||
|
||||
if ($cat === 'config') {
|
||||
if (isset($this->config[$key])) {
|
||||
$return = $this->config[$key];
|
||||
}
|
||||
} else {
|
||||
if (isset($this->config[$cat][$key])) {
|
||||
$return = $this->config[$cat][$key];
|
||||
} elseif ($key == null && isset($this->config[$cat])) {
|
||||
$return = $this->config[$cat];
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a default value in the config cache. Ignores already existing keys.
|
||||
*
|
||||
* @param string $cat Config category
|
||||
* @param string $k Config key
|
||||
* @param mixed $v Default value to set
|
||||
*/
|
||||
private function setDefault($cat, $k, $v)
|
||||
{
|
||||
if (!isset($this->config[$cat][$k])) {
|
||||
$this->set($cat, $k, $v);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function set($cat, $key, $value)
|
||||
{
|
||||
// Only arrays are serialized in database, so we have to unserialize sparingly
|
||||
$value = is_string($value) && preg_match("|^a:[0-9]+:{.*}$|s", $value) ? unserialize($value) : $value;
|
||||
|
||||
if ($cat === 'config') {
|
||||
$this->config[$key] = $value;
|
||||
} else {
|
||||
if (!isset($this->config[$cat])) {
|
||||
$this->config[$cat] = [];
|
||||
}
|
||||
|
||||
$this->config[$cat][$key] = $value;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function delete($cat, $key)
|
||||
{
|
||||
if ($cat === 'config') {
|
||||
if (isset($this->config[$key])) {
|
||||
unset($this->config[$key]);
|
||||
}
|
||||
} else {
|
||||
if (isset($this->config[$cat][$key])) {
|
||||
unset($this->config[$cat][$key]);
|
||||
if (count($this->config[$cat]) == 0) {
|
||||
unset($this->config[$cat]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getP($uid, $cat, $key = null, $default = null)
|
||||
{
|
||||
$return = $default;
|
||||
|
||||
if (isset($this->config[$uid][$cat][$key])) {
|
||||
$return = $this->config[$uid][$cat][$key];
|
||||
} elseif ($key === null && isset($this->config[$uid][$cat])) {
|
||||
$return = $this->config[$uid][$cat];
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setP($uid, $cat, $key, $value)
|
||||
{
|
||||
// Only arrays are serialized in database, so we have to unserialize sparingly
|
||||
$value = is_string($value) && preg_match("|^a:[0-9]+:{.*}$|s", $value) ? unserialize($value) : $value;
|
||||
|
||||
if (!isset($this->config[$uid]) || !is_array($this->config[$uid])) {
|
||||
$this->config[$uid] = [];
|
||||
}
|
||||
|
||||
if (!isset($this->config[$uid][$cat]) || !is_array($this->config[$uid][$cat])) {
|
||||
$this->config[$uid][$cat] = [];
|
||||
}
|
||||
|
||||
if ($key === null) {
|
||||
$this->config[$uid][$cat] = $value;
|
||||
} else {
|
||||
$this->config[$uid][$cat][$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function deleteP($uid, $cat, $key)
|
||||
{
|
||||
if (isset($this->config[$uid][$cat][$key])) {
|
||||
unset($this->config[$uid][$cat][$key]);
|
||||
if (count($this->config[$uid][$cat]) == 0) {
|
||||
unset($this->config[$uid][$cat]);
|
||||
if (count($this->config[$uid]) == 0) {
|
||||
unset($this->config[$uid]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the whole configuration
|
||||
*
|
||||
* @return array The configuration
|
||||
*/
|
||||
public function getAll()
|
||||
{
|
||||
return $this->config;
|
||||
}
|
||||
}
|
152
src/Core/Config/Configuration.php
Normal file
152
src/Core/Config/Configuration.php
Normal file
|
@ -0,0 +1,152 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Config;
|
||||
|
||||
/**
|
||||
* This class is responsible for all system-wide configuration values in Friendica
|
||||
* There are two types of storage
|
||||
* - The Config-Files (loaded into the FileCache @see Cache\IConfigCache )
|
||||
* - The Config-DB-Table (per Config-DB-adapter @see Adapter\IConfigAdapter )
|
||||
*/
|
||||
class Configuration
|
||||
{
|
||||
/**
|
||||
* @var Cache\IConfigCache
|
||||
*/
|
||||
private $configCache;
|
||||
|
||||
/**
|
||||
* @var Adapter\IConfigAdapter
|
||||
*/
|
||||
private $configAdapter;
|
||||
|
||||
/**
|
||||
* @param Cache\IConfigCache $configCache The configuration cache (based on the config-files)
|
||||
* @param Adapter\IConfigAdapter $configAdapter The configuration DB-backend
|
||||
*/
|
||||
public function __construct(Cache\IConfigCache $configCache, Adapter\IConfigAdapter $configAdapter)
|
||||
{
|
||||
$this->configCache = $configCache;
|
||||
$this->configAdapter = $configAdapter;
|
||||
|
||||
$this->load();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Config Cache
|
||||
*
|
||||
* @return Cache\IConfigCache
|
||||
*/
|
||||
public function getCache()
|
||||
{
|
||||
return $this->configCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Loads all configuration values of family into a cached storage.
|
||||
*
|
||||
* All configuration values of the system are stored in the cache ( @see IConfigCache )
|
||||
*
|
||||
* @param string $cat The category of the configuration value
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function load($cat = 'config')
|
||||
{
|
||||
// If not connected, do nothing
|
||||
if (!$this->configAdapter->isConnected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// load the whole category out of the DB into the cache
|
||||
$this->configCache->load($this->configAdapter->load($cat), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a particular user's config variable given the category name
|
||||
* ($cat) and a $key.
|
||||
*
|
||||
* Get a particular config value from the given category ($cat)
|
||||
* and the $key from a cached storage either from the $this->configAdapter
|
||||
* (@see IConfigAdapter ) or from the $this->configCache (@see IConfigCache ).
|
||||
*
|
||||
* @param string $cat The category of the configuration value
|
||||
* @param string $key The configuration key to query
|
||||
* @param mixed $default_value optional, The value to return if key is not set (default: null)
|
||||
* @param boolean $refresh optional, If true the config is loaded from the db and not from the cache (default: false)
|
||||
*
|
||||
* @return mixed Stored value or null if it does not exist
|
||||
*/
|
||||
public function get($cat, $key, $default_value = null, $refresh = false)
|
||||
{
|
||||
// if the value isn't loaded or refresh is needed, load it to the cache
|
||||
if ($this->configAdapter->isConnected() &&
|
||||
(!$this->configAdapter->isLoaded($cat, $key) ||
|
||||
$refresh)) {
|
||||
|
||||
$dbvalue = $this->configAdapter->get($cat, $key);
|
||||
|
||||
if (isset($dbvalue)) {
|
||||
$this->configCache->set($cat, $key, $dbvalue);
|
||||
return $dbvalue;
|
||||
}
|
||||
}
|
||||
|
||||
// use the config cache for return
|
||||
$result = $this->configCache->get($cat, $key);
|
||||
|
||||
return (isset($result)) ? $result : $default_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a configuration value for system config
|
||||
*
|
||||
* Stores a config value ($value) in the category ($cat) under the key ($key)
|
||||
*
|
||||
* Note: Please do not store booleans - convert to 0/1 integer values!
|
||||
*
|
||||
* @param string $cat The category of the configuration value
|
||||
* @param string $key The configuration key to set
|
||||
* @param mixed $value The value to store
|
||||
*
|
||||
* @return bool Operation success
|
||||
*/
|
||||
public function set($cat, $key, $value)
|
||||
{
|
||||
// set the cache first
|
||||
$cached = $this->configCache->set($cat, $key, $value);
|
||||
|
||||
// If there is no connected adapter, we're finished
|
||||
if (!$this->configAdapter->isConnected()) {
|
||||
return $cached;
|
||||
}
|
||||
|
||||
$stored = $this->configAdapter->set($cat, $key, $value);
|
||||
|
||||
return $cached && $stored;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deletes the given key from the system configuration.
|
||||
*
|
||||
* Removes the configured value from the stored cache in $this->configCache
|
||||
* (@see ConfigCache ) and removes it from the database (@see IConfigAdapter ).
|
||||
*
|
||||
* @param string $cat The category of the configuration value
|
||||
* @param string $key The configuration key to delete
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function delete($cat, $key)
|
||||
{
|
||||
$cacheRemoved = $this->configCache->delete($cat, $key);
|
||||
|
||||
if (!$this->configAdapter->isConnected()) {
|
||||
return $cacheRemoved;
|
||||
}
|
||||
|
||||
$storeRemoved = $this->configAdapter->delete($cat, $key);
|
||||
|
||||
return $cacheRemoved || $storeRemoved;
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Config;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Hypolite Petovan <hypolite@mrpetovan.com>
|
||||
*/
|
||||
interface IConfigAdapter
|
||||
{
|
||||
/**
|
||||
* Loads all configuration values into a cached storage.
|
||||
*
|
||||
* @param string $cat The category of the configuration values to load
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function load($cat = "config");
|
||||
|
||||
/**
|
||||
* Get a particular user's config variable given the category name
|
||||
* ($family) and a key.
|
||||
*
|
||||
* @param string $cat The category of the configuration value
|
||||
* @param string $k The configuration key to query
|
||||
* @param mixed $default_value optional, The value to return if key is not set (default: null)
|
||||
* @param boolean $refresh optional, If true the config is loaded from the db and not from the cache (default: false)
|
||||
*
|
||||
* @return mixed Stored value or null if it does not exist
|
||||
*/
|
||||
public function get($cat, $k, $default_value = null, $refresh = false);
|
||||
|
||||
/**
|
||||
* Stores a config value ($value) in the category ($family) under the key ($key)
|
||||
* for the user_id $uid.
|
||||
*
|
||||
* Note: Please do not store booleans - convert to 0/1 integer values!
|
||||
*
|
||||
* @param string $cat The category of the configuration value
|
||||
* @param string $k The configuration key to set
|
||||
* @param mixed $value The value to store
|
||||
*
|
||||
* @return bool Operation success
|
||||
*/
|
||||
public function set($cat, $k, $value);
|
||||
|
||||
/**
|
||||
* Removes the configured value from the stored cache
|
||||
* and removes it from the database.
|
||||
*
|
||||
* @param string $cat The category of the configuration value
|
||||
* @param string $k The configuration key to delete
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function delete($cat, $k);
|
||||
|
||||
/**
|
||||
* Checks, if the current adapter is connected to the backend
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isConnected();
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Config;
|
||||
|
||||
/**
|
||||
* The interface for a system-wide ConfigCache
|
||||
*/
|
||||
interface IConfigCache
|
||||
{
|
||||
/**
|
||||
* @param string $cat Config category
|
||||
* @param string $key Config key
|
||||
* @param mixed $default Default value if it isn't set
|
||||
*
|
||||
* @return mixed Returns the value of the Config entry
|
||||
*/
|
||||
function get($cat, $key = null, $default = null);
|
||||
|
||||
/**
|
||||
* Sets a value in the config cache. Accepts raw output from the config table
|
||||
*
|
||||
* @param string $cat Config category
|
||||
* @param string $key Config key
|
||||
* @param mixed $value Value to set
|
||||
*
|
||||
* @return bool True, if the value is set
|
||||
*/
|
||||
function set($cat, $key, $value);
|
||||
|
||||
/**
|
||||
* Deletes a value from the config cache
|
||||
*
|
||||
* @param string $cat Config category
|
||||
* @param string $key Config key
|
||||
*/
|
||||
function delete($cat, $key);
|
||||
|
||||
function getAll();
|
||||
}
|
|
@ -1,172 +0,0 @@
|
|||
<?php
|
||||
namespace Friendica\Core\Config;
|
||||
|
||||
use Friendica\Database\DBA;
|
||||
|
||||
/**
|
||||
* JustInTime Configuration Adapter
|
||||
*
|
||||
* Default Config Adapter. Provides the best performance for pages loading few configuration variables.
|
||||
*
|
||||
* @author Hypolite Petovan <hypolite@mrpetovan.com>
|
||||
*/
|
||||
class JITConfigAdapter extends AbstractDbaConfigAdapter implements IConfigAdapter
|
||||
{
|
||||
private $cache;
|
||||
private $in_db;
|
||||
|
||||
/**
|
||||
* @var IConfigCache The config cache of this driver
|
||||
*/
|
||||
private $configCache;
|
||||
|
||||
/**
|
||||
* @param IConfigCache $configCache The config cache of this driver
|
||||
*/
|
||||
public function __construct(IConfigCache $configCache)
|
||||
{
|
||||
$this->configCache = $configCache;
|
||||
$this->connected = DBA::connected();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load($cat = "config")
|
||||
{
|
||||
if (!$this->isConnected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We don't preload "system" anymore.
|
||||
// This reduces the number of database reads a lot.
|
||||
if ($cat === 'system') {
|
||||
return;
|
||||
}
|
||||
|
||||
$configs = DBA::select('config', ['v', 'k'], ['cat' => $cat]);
|
||||
while ($config = DBA::fetch($configs)) {
|
||||
$k = $config['k'];
|
||||
|
||||
$this->configCache->set($cat, $k, $config['v']);
|
||||
|
||||
if ($cat !== 'config') {
|
||||
$this->cache[$cat][$k] = $config['v'];
|
||||
$this->in_db[$cat][$k] = true;
|
||||
}
|
||||
}
|
||||
DBA::close($configs);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get($cat, $k, $default_value = null, $refresh = false)
|
||||
{
|
||||
if (!$this->isConnected()) {
|
||||
return $default_value;
|
||||
}
|
||||
|
||||
if (!$refresh) {
|
||||
// Do we have the cached value? Then return it
|
||||
if (isset($this->cache[$cat][$k])) {
|
||||
if ($this->cache[$cat][$k] === '!<unset>!') {
|
||||
return $default_value;
|
||||
} else {
|
||||
return $this->cache[$cat][$k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$config = DBA::selectFirst('config', ['v'], ['cat' => $cat, 'k' => $k]);
|
||||
if (DBA::isResult($config)) {
|
||||
// manage array value
|
||||
$value = (preg_match("|^a:[0-9]+:{.*}$|s", $config['v']) ? unserialize($config['v']) : $config['v']);
|
||||
|
||||
// Assign the value from the database to the cache
|
||||
$this->cache[$cat][$k] = $value;
|
||||
$this->in_db[$cat][$k] = true;
|
||||
return $value;
|
||||
} elseif ($this->configCache->get($cat, $k) !== null) {
|
||||
// Assign the value (mostly) from config/local.config.php file to the cache
|
||||
$this->cache[$cat][$k] = $this->configCache->get($cat, $k);
|
||||
$this->in_db[$cat][$k] = false;
|
||||
|
||||
return $this->configCache->get($cat, $k);
|
||||
} elseif ($this->configCache->get('config', $k) !== null) {
|
||||
// Assign the value (mostly) from config/local.config.php file to the cache
|
||||
$this->cache[$k] = $this->configCache->get('config', $k);
|
||||
$this->in_db[$k] = false;
|
||||
|
||||
return $this->configCache->get('config', $k);
|
||||
}
|
||||
|
||||
$this->cache[$cat][$k] = '!<unset>!';
|
||||
$this->in_db[$cat][$k] = false;
|
||||
|
||||
return $default_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function set($cat, $k, $value)
|
||||
{
|
||||
if (!$this->isConnected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We store our setting values in a string variable.
|
||||
// So we have to do the conversion here so that the compare below works.
|
||||
// The exception are array values.
|
||||
$dbvalue = (!is_array($value) ? (string)$value : $value);
|
||||
|
||||
$stored = $this->get($cat, $k, null, true);
|
||||
|
||||
if (!isset($this->in_db[$cat])) {
|
||||
$this->in_db[$cat] = [];
|
||||
}
|
||||
if (!isset($this->in_db[$cat][$k])) {
|
||||
$this->in_db[$cat] = false;
|
||||
}
|
||||
|
||||
if (($stored === $dbvalue) && $this->in_db[$cat][$k]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->configCache->set($cat, $k, $value);
|
||||
|
||||
// Assign the just added value to the cache
|
||||
$this->cache[$cat][$k] = $dbvalue;
|
||||
|
||||
// manage array value
|
||||
$dbvalue = (is_array($value) ? serialize($value) : $dbvalue);
|
||||
|
||||
$result = DBA::update('config', ['v' => $dbvalue], ['cat' => $cat, 'k' => $k], true);
|
||||
|
||||
if ($result) {
|
||||
$this->in_db[$cat][$k] = true;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function delete($cat, $k)
|
||||
{
|
||||
if (!$this->isConnected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($this->cache[$cat][$k])) {
|
||||
unset($this->cache[$cat][$k]);
|
||||
unset($this->in_db[$cat][$k]);
|
||||
}
|
||||
|
||||
$result = DBA::delete('config', ['cat' => $cat, 'k' => $k]);
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
|
@ -1,136 +0,0 @@
|
|||
<?php
|
||||
namespace Friendica\Core\Config;
|
||||
|
||||
use Friendica\Database\DBA;
|
||||
|
||||
/**
|
||||
* JustInTime User Configuration Adapter
|
||||
*
|
||||
* Default PConfig Adapter. Provides the best performance for pages loading few configuration variables.
|
||||
*
|
||||
* @author Hypolite Petovan <hypolite@mrpetovan.com>
|
||||
*/
|
||||
class JITPConfigAdapter implements IPConfigAdapter
|
||||
{
|
||||
private $in_db;
|
||||
|
||||
/**
|
||||
* The config cache of this adapter
|
||||
* @var IPConfigCache
|
||||
*/
|
||||
private $configCache;
|
||||
|
||||
/**
|
||||
* @param IPConfigCache $configCache The config cache of this adapter
|
||||
*/
|
||||
public function __construct(IPConfigCache $configCache)
|
||||
{
|
||||
$this->configCache = $configCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load($uid, $cat)
|
||||
{
|
||||
$pconfigs = DBA::select('pconfig', ['v', 'k'], ['cat' => $cat, 'uid' => $uid]);
|
||||
if (DBA::isResult($pconfigs)) {
|
||||
while ($pconfig = DBA::fetch($pconfigs)) {
|
||||
$k = $pconfig['k'];
|
||||
|
||||
$this->configCache->setP($uid, $cat, $k, $pconfig['v']);
|
||||
|
||||
$this->in_db[$uid][$cat][$k] = true;
|
||||
}
|
||||
} else if ($cat != 'config') {
|
||||
// Negative caching
|
||||
$this->configCache->setP($uid, $cat, null, "!<unset>!");
|
||||
}
|
||||
DBA::close($pconfigs);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get($uid, $cat, $k, $default_value = null, $refresh = false)
|
||||
{
|
||||
if (!$refresh) {
|
||||
// Looking if the whole family isn't set
|
||||
if ($this->configCache->getP($uid, $cat) !== null) {
|
||||
if ($this->configCache->getP($uid, $cat) === '!<unset>!') {
|
||||
return $default_value;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->configCache->getP($uid, $cat, $k) !== null) {
|
||||
if ($this->configCache->getP($uid, $cat, $k) === '!<unset>!') {
|
||||
return $default_value;
|
||||
}
|
||||
return $this->configCache->getP($uid, $cat, $k);
|
||||
}
|
||||
}
|
||||
|
||||
$pconfig = DBA::selectFirst('pconfig', ['v'], ['uid' => $uid, 'cat' => $cat, 'k' => $k]);
|
||||
if (DBA::isResult($pconfig)) {
|
||||
$val = (preg_match("|^a:[0-9]+:{.*}$|s", $pconfig['v']) ? unserialize($pconfig['v']) : $pconfig['v']);
|
||||
|
||||
$this->configCache->setP($uid, $cat, $k, $val);
|
||||
|
||||
$this->in_db[$uid][$cat][$k] = true;
|
||||
|
||||
return $val;
|
||||
} else {
|
||||
$this->configCache->setP($uid, $cat, $k, '!<unset>!');
|
||||
|
||||
$this->in_db[$uid][$cat][$k] = false;
|
||||
|
||||
return $default_value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function set($uid, $cat, $k, $value)
|
||||
{
|
||||
// We store our setting values in a string variable.
|
||||
// So we have to do the conversion here so that the compare below works.
|
||||
// The exception are array values.
|
||||
$dbvalue = (!is_array($value) ? (string)$value : $value);
|
||||
|
||||
$stored = $this->get($uid, $cat, $k, null, true);
|
||||
|
||||
if (($stored === $dbvalue) && $this->in_db[$uid][$cat][$k]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->configCache->setP($uid, $cat, $k, $value);
|
||||
|
||||
// manage array value
|
||||
$dbvalue = (is_array($value) ? serialize($value) : $dbvalue);
|
||||
|
||||
$result = DBA::update('pconfig', ['v' => $dbvalue], ['uid' => $uid, 'cat' => $cat, 'k' => $k], true);
|
||||
|
||||
if ($result) {
|
||||
$this->in_db[$uid][$cat][$k] = true;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function delete($uid, $cat, $k)
|
||||
{
|
||||
$this->configCache->deleteP($uid, $cat, $k);
|
||||
|
||||
if (!empty($this->in_db[$uid][$cat][$k])) {
|
||||
unset($this->in_db[$uid][$cat][$k]);
|
||||
}
|
||||
|
||||
$result = DBA::delete('pconfig', ['uid' => $uid, 'cat' => $cat, 'k' => $k]);
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
146
src/Core/Config/PConfiguration.php
Normal file
146
src/Core/Config/PConfiguration.php
Normal file
|
@ -0,0 +1,146 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Config;
|
||||
|
||||
/**
|
||||
* This class is responsible for the user-specific configuration values in Friendica
|
||||
* The values are set through the Config-DB-Table (per Config-DB-adapter @see Adapter\IPConfigAdapter )
|
||||
*
|
||||
* The configuration cache (@see Cache\IPConfigCache ) is used for temporary caching of database calls. This will
|
||||
* increase the performance.
|
||||
*/
|
||||
class PConfiguration
|
||||
{
|
||||
/**
|
||||
* @var Cache\IPConfigCache
|
||||
*/
|
||||
private $configCache;
|
||||
|
||||
/**
|
||||
* @var Adapter\IPConfigAdapter
|
||||
*/
|
||||
private $configAdapter;
|
||||
|
||||
/**
|
||||
* @param Cache\IPConfigCache $configCache The configuration cache
|
||||
* @param Adapter\IPConfigAdapter $configAdapter The configuration DB-backend
|
||||
*/
|
||||
public function __construct(Cache\IPConfigCache $configCache, Adapter\IPConfigAdapter $configAdapter)
|
||||
{
|
||||
$this->configCache = $configCache;
|
||||
$this->configAdapter = $configAdapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Loads all configuration values of a user's config family into a cached storage.
|
||||
*
|
||||
* All configuration values of the given user are stored with the $uid in
|
||||
* the cache ( @see IPConfigCache )
|
||||
*
|
||||
* @param string $uid The user_id
|
||||
* @param string $cat The category of the configuration value
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function load($uid, $cat = 'config')
|
||||
{
|
||||
// If not connected, do nothing
|
||||
if (!$this->configAdapter->isConnected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// load the whole category out of the DB into the cache
|
||||
$this->configCache->loadP($uid, $this->configAdapter->load($uid, $cat));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a particular user's config variable given the category name
|
||||
* ($cat) and a key.
|
||||
*
|
||||
* Get a particular user's config value from the given category ($cat)
|
||||
* and the $key with the $uid from a cached storage either from the $this->configAdapter
|
||||
* (@see IConfigAdapter ) or from the $this->configCache (@see IConfigCache ).
|
||||
*
|
||||
* @param string $uid The user_id
|
||||
* @param string $cat The category of the configuration value
|
||||
* @param string $key The configuration key to query
|
||||
* @param mixed $default_value optional, The value to return if key is not set (default: null)
|
||||
* @param boolean $refresh optional, If true the config is loaded from the db and not from the cache (default: false)
|
||||
*
|
||||
* @return mixed Stored value or null if it does not exist
|
||||
*/
|
||||
public function get($uid, $cat, $key, $default_value = null, $refresh = false)
|
||||
{
|
||||
// if the value isn't loaded or refresh is needed, load it to the cache
|
||||
if ($this->configAdapter->isConnected() &&
|
||||
(!$this->configAdapter->isLoaded($uid, $cat, $key) ||
|
||||
$refresh)) {
|
||||
$dbValue = $this->configAdapter->get($uid, $cat, $key);
|
||||
|
||||
if (isset($dbValue)) {
|
||||
$this->configCache->setP($uid, $cat, $key, $dbValue);
|
||||
return $dbValue;
|
||||
}
|
||||
}
|
||||
|
||||
// use the config cache for return
|
||||
$result = $this->configCache->getP($uid, $cat, $key);
|
||||
return (isset($result)) ? $result : $default_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a configuration value for a user
|
||||
*
|
||||
* Stores a config value ($value) in the category ($family) under the key ($key)
|
||||
* for the user_id $uid.
|
||||
*
|
||||
* @note Please do not store booleans - convert to 0/1 integer values!
|
||||
*
|
||||
* @param string $uid The user_id
|
||||
* @param string $cat The category of the configuration value
|
||||
* @param string $key The configuration key to set
|
||||
* @param mixed $value The value to store
|
||||
*
|
||||
* @return bool Operation success
|
||||
*/
|
||||
public function set($uid, $cat, $key, $value)
|
||||
{
|
||||
// set the cache first
|
||||
$cached = $this->configCache->setP($uid, $cat, $key, $value);
|
||||
|
||||
// If there is no connected adapter, we're finished
|
||||
if (!$this->configAdapter->isConnected()) {
|
||||
return $cached;
|
||||
}
|
||||
|
||||
$stored = $this->configAdapter->set($uid, $cat, $key, $value);
|
||||
|
||||
return $cached && $stored;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deletes the given key from the users's configuration.
|
||||
*
|
||||
* Removes the configured value from the stored cache in $this->configCache
|
||||
* (@see ConfigCache ) and removes it from the database (@see IConfigAdapter )
|
||||
* with the given $uid.
|
||||
*
|
||||
* @param string $uid The user_id
|
||||
* @param string $cat The category of the configuration value
|
||||
* @param string $key The configuration key to delete
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function delete($uid, $cat, $key)
|
||||
{
|
||||
$cacheRemoved = $this->configCache->deleteP($uid, $cat, $key);
|
||||
|
||||
if (!$this->configAdapter->isConnected()) {
|
||||
return $cacheRemoved;
|
||||
}
|
||||
|
||||
$storeRemoved = $this->configAdapter->delete($uid, $cat, $key);
|
||||
|
||||
return $cacheRemoved || $storeRemoved;
|
||||
}
|
||||
}
|
|
@ -1,123 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Config;
|
||||
|
||||
use Exception;
|
||||
use Friendica\Database\DBA;
|
||||
|
||||
/**
|
||||
* Preload Configuration Adapter
|
||||
*
|
||||
* Minimizes the number of database queries to retrieve configuration values at the cost of memory.
|
||||
*
|
||||
* @author Hypolite Petovan <hypolite@mrpetovan.com>
|
||||
*/
|
||||
class PreloadConfigAdapter extends AbstractDbaConfigAdapter implements IConfigAdapter
|
||||
{
|
||||
private $config_loaded = false;
|
||||
|
||||
/**
|
||||
* @var IConfigCache The config cache of this driver
|
||||
*/
|
||||
private $configCache;
|
||||
|
||||
/**
|
||||
* @param IConfigCache $configCache The config cache of this driver
|
||||
*/
|
||||
public function __construct(IConfigCache $configCache)
|
||||
{
|
||||
$this->configCache = $configCache;
|
||||
$this->connected = DBA::connected();
|
||||
$this->load();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load($family = 'config')
|
||||
{
|
||||
if (!$this->isConnected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->config_loaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
$configs = DBA::select('config', ['cat', 'v', 'k']);
|
||||
while ($config = DBA::fetch($configs)) {
|
||||
$this->configCache->set($config['cat'], $config['k'], $config['v']);
|
||||
}
|
||||
DBA::close($configs);
|
||||
|
||||
$this->config_loaded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get($cat, $k, $default_value = null, $refresh = false)
|
||||
{
|
||||
if (!$this->isConnected()) {
|
||||
return $default_value;
|
||||
}
|
||||
|
||||
if ($refresh) {
|
||||
$config = DBA::selectFirst('config', ['v'], ['cat' => $cat, 'k' => $k]);
|
||||
if (DBA::isResult($config)) {
|
||||
$this->configCache->set($cat, $k, $config['v']);
|
||||
}
|
||||
}
|
||||
|
||||
$return = $this->configCache->get($cat, $k, $default_value);
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function set($cat, $k, $value)
|
||||
{
|
||||
if (!$this->isConnected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We store our setting values as strings.
|
||||
// So we have to do the conversion here so that the compare below works.
|
||||
// The exception are array values.
|
||||
$compare_value = !is_array($value) ? (string)$value : $value;
|
||||
|
||||
if ($this->configCache->get($cat, $k) === $compare_value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->configCache->set($cat, $k, $value);
|
||||
|
||||
// manage array value
|
||||
$dbvalue = is_array($value) ? serialize($value) : $value;
|
||||
|
||||
$result = DBA::update('config', ['v' => $dbvalue], ['cat' => $cat, 'k' => $k], true);
|
||||
if (!$result) {
|
||||
throw new Exception('Unable to store config value in [' . $cat . '][' . $k . ']');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function delete($cat, $k)
|
||||
{
|
||||
if (!$this->isConnected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->configCache->delete($cat, $k);
|
||||
|
||||
$result = DBA::delete('config', ['cat' => $cat, 'k' => $k]);
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
|
@ -1,125 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Config;
|
||||
|
||||
use Exception;
|
||||
use Friendica\Database\DBA;
|
||||
|
||||
/**
|
||||
* Preload User Configuration Adapter
|
||||
*
|
||||
* Minimizes the number of database queries to retrieve configuration values at the cost of memory.
|
||||
*
|
||||
* @author Hypolite Petovan <hypolite@mrpetovan.com>
|
||||
*/
|
||||
class PreloadPConfigAdapter implements IPConfigAdapter
|
||||
{
|
||||
private $config_loaded = false;
|
||||
|
||||
/**
|
||||
* The config cache of this adapter
|
||||
* @var IPConfigCache
|
||||
*/
|
||||
private $configCache;
|
||||
|
||||
/**
|
||||
* @param IPConfigCache $configCache The config cache of this adapter
|
||||
* @param int $uid The UID of the current user
|
||||
*/
|
||||
public function __construct(IPConfigCache $configCache, $uid = null)
|
||||
{
|
||||
$this->configCache = $configCache;
|
||||
if (isset($uid)) {
|
||||
$this->load($uid, 'config');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load($uid, $family)
|
||||
{
|
||||
if ($this->config_loaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($uid)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$pconfigs = DBA::select('pconfig', ['cat', 'v', 'k'], ['uid' => $uid]);
|
||||
while ($pconfig = DBA::fetch($pconfigs)) {
|
||||
$this->configCache->setP($uid, $pconfig['cat'], $pconfig['k'], $pconfig['v']);
|
||||
}
|
||||
DBA::close($pconfigs);
|
||||
|
||||
$this->config_loaded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get($uid, $cat, $k, $default_value = null, $refresh = false)
|
||||
{
|
||||
if (!$this->config_loaded) {
|
||||
$this->load($uid, $cat);
|
||||
}
|
||||
|
||||
if ($refresh) {
|
||||
$config = DBA::selectFirst('pconfig', ['v'], ['uid' => $uid, 'cat' => $cat, 'k' => $k]);
|
||||
if (DBA::isResult($config)) {
|
||||
$this->configCache->setP($uid, $cat, $k, $config['v']);
|
||||
} else {
|
||||
$this->configCache->deleteP($uid, $cat, $k);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->configCache->getP($uid, $cat, $k, $default_value);;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function set($uid, $cat, $k, $value)
|
||||
{
|
||||
if (!$this->config_loaded) {
|
||||
$this->load($uid, $cat);
|
||||
}
|
||||
// We store our setting values as strings.
|
||||
// So we have to do the conversion here so that the compare below works.
|
||||
// The exception are array values.
|
||||
$compare_value = !is_array($value) ? (string)$value : $value;
|
||||
|
||||
if ($this->configCache->getP($uid, $cat, $k) === $compare_value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->configCache->setP($uid, $cat, $k, $value);
|
||||
|
||||
// manage array value
|
||||
$dbvalue = is_array($value) ? serialize($value) : $value;
|
||||
|
||||
$result = DBA::update('pconfig', ['v' => $dbvalue], ['uid' => $uid, 'cat' => $cat, 'k' => $k], true);
|
||||
if (!$result) {
|
||||
throw new Exception('Unable to store config value in [' . $uid . '][' . $cat . '][' . $k . ']');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function delete($uid, $cat, $k)
|
||||
{
|
||||
if (!$this->config_loaded) {
|
||||
$this->load($uid, $cat);
|
||||
}
|
||||
|
||||
$this->configCache->deleteP($uid, $cat, $k);
|
||||
|
||||
$result = DBA::delete('pconfig', ['uid' => $uid, 'cat' => $cat, 'k' => $k]);
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
|
@ -100,10 +100,10 @@ HELP;
|
|||
}
|
||||
}
|
||||
|
||||
$db_host = $a->getConfig()->get('database', 'hostname');
|
||||
$db_user = $a->getConfig()->get('database', 'username');
|
||||
$db_pass = $a->getConfig()->get('database', 'password');
|
||||
$db_data = $a->getConfig()->get('database', 'database');
|
||||
$db_host = $a->getConfigCache()->get('database', 'hostname');
|
||||
$db_user = $a->getConfigCache()->get('database', 'username');
|
||||
$db_pass = $a->getConfigCache()->get('database', 'password');
|
||||
$db_data = $a->getConfigCache()->get('database', 'database');
|
||||
} else {
|
||||
// Creating config file
|
||||
$this->out("Creating config file...\n");
|
||||
|
@ -146,7 +146,7 @@ HELP;
|
|||
|
||||
$installer->resetChecks();
|
||||
|
||||
if (!$installer->checkDB($a->getConfig(), $db_host, $db_user, $db_pass, $db_data)) {
|
||||
if (!$installer->checkDB($a->getBasePath(), $a->getConfigCache(), $a->getProfiler(), $db_host, $db_user, $db_pass, $db_data)) {
|
||||
$errorMessage = $this->extractErrors($installer->getChecks());
|
||||
throw new RuntimeException($errorMessage);
|
||||
}
|
||||
|
|
|
@ -124,9 +124,9 @@ HELP;
|
|||
$cat = $this->getArgument(0);
|
||||
Core\Config::load($cat);
|
||||
|
||||
if ($a->getConfig()->get($cat) !== null) {
|
||||
if ($a->getConfigCache()->get($cat) !== null) {
|
||||
$this->out("[{$cat}]");
|
||||
$catVal = $a->getConfig()->get($cat);
|
||||
$catVal = $a->getConfigCache()->get($cat);
|
||||
foreach ($catVal as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $k => $v) {
|
||||
|
@ -148,7 +148,7 @@ HELP;
|
|||
$this->out('Warning: The JIT (Just In Time) Config adapter doesn\'t support loading the entire configuration, showing file config only');
|
||||
}
|
||||
|
||||
$config = $a->getConfig()->getAll();
|
||||
$config = $a->getConfigCache()->getAll();
|
||||
foreach ($config as $cat => $section) {
|
||||
if (is_array($section)) {
|
||||
foreach ($section as $key => $value) {
|
||||
|
|
|
@ -31,9 +31,10 @@ Commands
|
|||
toinnodb Convert all tables from MyISAM to InnoDB
|
||||
|
||||
Options
|
||||
-h|--help|-? Show help information
|
||||
-v Show more debug information.
|
||||
-f|--force Force the command in case of "update" (Ignore failed updates/running updates)
|
||||
-h|--help|-? Show help information
|
||||
-v Show more debug information.
|
||||
-f|--force Force the update command (Even if the database structure matches)
|
||||
-o|--override Override running or stalling updates
|
||||
HELP;
|
||||
return $help;
|
||||
}
|
||||
|
@ -68,8 +69,9 @@ HELP;
|
|||
$output = DBStructure::update($a->getBasePath(), true, false);
|
||||
break;
|
||||
case "update":
|
||||
$force = $this->getOption(['f', 'force'], false);
|
||||
$output = Update::run($a->getBasePath(), $force, true, false);
|
||||
$force = $this->getOption(['f', 'force'], false);
|
||||
$override = $this->getOption(['o', 'override'], false);
|
||||
$output = Update::run($a->getBasePath(), $force, $override,true, false);
|
||||
break;
|
||||
case "dumpsql":
|
||||
ob_start();
|
||||
|
@ -89,5 +91,4 @@ HELP;
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ HELP;
|
|||
}
|
||||
|
||||
echo L10n::t('Check for pending update actions.') . "\n";
|
||||
Update::run($a->getBasePath(), true, true, false);
|
||||
Update::run($a->getBasePath(), true, false, true, false);
|
||||
echo L10n::t('Done.') . "\n";
|
||||
|
||||
echo L10n::t('Execute pending post updates.') . "\n";
|
||||
|
|
|
@ -43,7 +43,7 @@ HELP;
|
|||
throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');
|
||||
}
|
||||
|
||||
$php_path = BaseObject::getApp()->getConfig()->get('config', 'php_path', 'php');
|
||||
$php_path = BaseObject::getApp()->getConfigCache()->get('config', 'php_path', 'php');
|
||||
|
||||
if ($this->getOption('v')) {
|
||||
$this->out('Directory: src');
|
||||
|
|
|
@ -6,11 +6,12 @@ namespace Friendica\Core;
|
|||
|
||||
use DOMDocument;
|
||||
use Exception;
|
||||
use Friendica\Core\Config\ConfigCache;
|
||||
use Friendica\Core\Config\Cache\IConfigCache;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Database\DBStructure;
|
||||
use Friendica\Object\Image;
|
||||
use Friendica\Util\Network;
|
||||
use Friendica\Util\Profiler;
|
||||
use Friendica\Util\Strings;
|
||||
|
||||
/**
|
||||
|
@ -357,6 +358,7 @@ class Installer
|
|||
* - mb_string
|
||||
* - XML
|
||||
* - iconv
|
||||
* - fileinfo
|
||||
* - POSIX
|
||||
*
|
||||
* @return bool false if something required failed
|
||||
|
@ -452,6 +454,13 @@ class Installer
|
|||
);
|
||||
$returnVal = $returnVal ? $status : false;
|
||||
|
||||
$status = $this->checkFunction('finfo_open',
|
||||
L10n::t('File Information PHP module'),
|
||||
L10n::t('Error: File Information PHP module required but not installed.'),
|
||||
true
|
||||
);
|
||||
$returnVal = $returnVal ? $status : false;
|
||||
|
||||
return $returnVal;
|
||||
}
|
||||
|
||||
|
@ -582,7 +591,9 @@ class Installer
|
|||
/**
|
||||
* Checking the Database connection and if it is available for the current installation
|
||||
*
|
||||
* @param ConfigCache $configCache The configuration cache
|
||||
* @param string $basePath The basepath of this call
|
||||
* @param IConfigCache $configCache The configuration cache
|
||||
* @param Profiler $profiler The profiler of this app
|
||||
* @param string $dbhost Hostname/IP of the Friendica Database
|
||||
* @param string $dbuser Username of the Database connection credentials
|
||||
* @param string $dbpass Password of the Database connection credentials
|
||||
|
@ -591,9 +602,9 @@ class Installer
|
|||
* @return bool true if the check was successful, otherwise false
|
||||
* @throws Exception
|
||||
*/
|
||||
public function checkDB(ConfigCache $configCache, $dbhost, $dbuser, $dbpass, $dbdata)
|
||||
public function checkDB($basePath, IConfigCache $configCache, Profiler $profiler, $dbhost, $dbuser, $dbpass, $dbdata)
|
||||
{
|
||||
if (!DBA::connect($configCache, $dbhost, $dbuser, $dbpass, $dbdata)) {
|
||||
if (!DBA::connect($basePath, $configCache, $profiler, $dbhost, $dbuser, $dbpass, $dbdata)) {
|
||||
$this->addCheck(L10n::t('Could not connect to database.'), false, true, '');
|
||||
|
||||
return false;
|
||||
|
|
|
@ -122,12 +122,13 @@ class Lock
|
|||
/**
|
||||
* @brief Releases a lock if it was set by us
|
||||
*
|
||||
* @param string $key Name of the lock
|
||||
* @param string $key Name of the lock
|
||||
* @param bool $override Overrides the lock to get releases
|
||||
* @return void
|
||||
*/
|
||||
public static function release($key)
|
||||
public static function release($key, $override = false)
|
||||
{
|
||||
self::getDriver()->releaseLock($key);
|
||||
self::getDriver()->releaseLock($key, $override);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -61,11 +61,15 @@ class CacheLockDriver extends AbstractLockDriver
|
|||
/**
|
||||
* (@inheritdoc)
|
||||
*/
|
||||
public function releaseLock($key)
|
||||
public function releaseLock($key, $override = false)
|
||||
{
|
||||
$cachekey = self::getLockKey($key);
|
||||
|
||||
$this->cache->compareDelete($cachekey, getmypid());
|
||||
if ($override) {
|
||||
$this->cache->delete($cachekey);
|
||||
} else {
|
||||
$this->cache->compareDelete($cachekey, getmypid());
|
||||
}
|
||||
$this->markRelease($key);
|
||||
}
|
||||
|
||||
|
|
|
@ -68,9 +68,15 @@ class DatabaseLockDriver extends AbstractLockDriver
|
|||
/**
|
||||
* (@inheritdoc)
|
||||
*/
|
||||
public function releaseLock($key)
|
||||
public function releaseLock($key, $override = false)
|
||||
{
|
||||
DBA::delete('locks', ['name' => $key, 'pid' => $this->pid]);
|
||||
if ($override) {
|
||||
$where = ['name' => $key];
|
||||
} else {
|
||||
$where = ['name' => $key, 'pid' => $this->pid];
|
||||
}
|
||||
|
||||
DBA::delete('locks', $where);
|
||||
|
||||
$this->markRelease($key);
|
||||
|
||||
|
|
|
@ -33,11 +33,12 @@ interface ILockDriver
|
|||
/**
|
||||
* Releases a lock if it was set by us
|
||||
*
|
||||
* @param string $key The Name of the lock
|
||||
* @param string $key The Name of the lock
|
||||
* @param bool $override Overrides the lock to get released
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function releaseLock($key);
|
||||
public function releaseLock($key, $override = false);
|
||||
|
||||
/**
|
||||
* Releases all lock that were set by us
|
||||
|
|
|
@ -50,7 +50,7 @@ class SemaphoreLockDriver extends AbstractLockDriver
|
|||
/**
|
||||
* (@inheritdoc)
|
||||
*/
|
||||
public function releaseLock($key)
|
||||
public function releaseLock($key, $override = false)
|
||||
{
|
||||
if (empty(self::$semaphore[$key])) {
|
||||
return false;
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
namespace Friendica\Core;
|
||||
|
||||
use Friendica\BaseObject;
|
||||
use Friendica\Factory\LoggerFactory;
|
||||
use Friendica\Network\HTTPException\InternalServerErrorException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\LogLevel;
|
||||
|
||||
|
@ -67,73 +65,22 @@ class Logger extends BaseObject
|
|||
|
||||
/**
|
||||
* Sets the default logging handler for Friendica.
|
||||
* @todo Can be combined with other handlers too if necessary, could be configurable.
|
||||
*
|
||||
* @param LoggerInterface $logger The Logger instance of this Application
|
||||
*
|
||||
* @throws InternalServerErrorException if the logger factory is incompatible to this logger
|
||||
*/
|
||||
public static function setLogger($logger)
|
||||
public static function init(LoggerInterface $logger)
|
||||
{
|
||||
$debugging = Config::get('system', 'debugging');
|
||||
$logfile = Config::get('system', 'logfile');
|
||||
$loglevel = Config::get('system', 'loglevel');
|
||||
|
||||
if (!$debugging || !$logfile) {
|
||||
return;
|
||||
}
|
||||
|
||||
$loglevel = self::mapLegacyConfigDebugLevel((string)$loglevel);
|
||||
|
||||
LoggerFactory::addStreamHandler($logger, $logfile, $loglevel);
|
||||
|
||||
self::$logger = $logger;
|
||||
|
||||
$logfile = Config::get('system', 'dlogfile');
|
||||
|
||||
if (!$logfile) {
|
||||
return;
|
||||
}
|
||||
|
||||
$developIp = Config::get('system', 'dlogip');
|
||||
|
||||
self::$devLogger = LoggerFactory::createDev('develop', $developIp);
|
||||
LoggerFactory::addStreamHandler(self::$devLogger, $logfile, LogLevel::DEBUG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mapping a legacy level to the PSR-3 compliant levels
|
||||
* @see https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md#5-psrlogloglevel
|
||||
* Sets the default dev-logging handler for Friendica.
|
||||
*
|
||||
* @param string $level the level to be mapped
|
||||
*
|
||||
* @return string the PSR-3 compliant level
|
||||
* @param LoggerInterface $logger The Logger instance of this Application
|
||||
*/
|
||||
private static function mapLegacyConfigDebugLevel($level)
|
||||
public static function setDevLogger(LoggerInterface $logger)
|
||||
{
|
||||
switch ($level) {
|
||||
// legacy WARNING
|
||||
case "0":
|
||||
return LogLevel::ERROR;
|
||||
// legacy INFO
|
||||
case "1":
|
||||
return LogLevel::WARNING;
|
||||
// legacy TRACE
|
||||
case "2":
|
||||
return LogLevel::NOTICE;
|
||||
// legacy DEBUG
|
||||
case "3":
|
||||
return LogLevel::INFO;
|
||||
// legacy DATA
|
||||
case "4":
|
||||
return LogLevel::DEBUG;
|
||||
// legacy ALL
|
||||
case "5":
|
||||
return LogLevel::DEBUG;
|
||||
// default if nothing set
|
||||
default:
|
||||
return $level;
|
||||
}
|
||||
self::$devLogger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -155,7 +102,7 @@ class Logger extends BaseObject
|
|||
|
||||
$stamp1 = microtime(true);
|
||||
self::$logger->emergency($message, $context);
|
||||
self::getApp()->saveTimestamp($stamp1, 'file');
|
||||
self::getApp()->GetProfiler()->saveTimestamp($stamp1, 'file', System::callstack());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -179,7 +126,7 @@ class Logger extends BaseObject
|
|||
|
||||
$stamp1 = microtime(true);
|
||||
self::$logger->alert($message, $context);
|
||||
self::getApp()->saveTimestamp($stamp1, 'file');
|
||||
self::getApp()->getProfiler()->saveTimestamp($stamp1, 'file', System::callstack());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -202,7 +149,7 @@ class Logger extends BaseObject
|
|||
|
||||
$stamp1 = microtime(true);
|
||||
self::$logger->critical($message, $context);
|
||||
self::getApp()->saveTimestamp($stamp1, 'file');
|
||||
self::getApp()->getProfiler()->saveTimestamp($stamp1, 'file', System::callstack());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -225,7 +172,7 @@ class Logger extends BaseObject
|
|||
|
||||
$stamp1 = microtime(true);
|
||||
self::$logger->error($message, $context);
|
||||
self::getApp()->saveTimestamp($stamp1, 'file');
|
||||
self::getApp()->getProfiler()->saveTimestamp($stamp1, 'file', System::callstack());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -249,7 +196,7 @@ class Logger extends BaseObject
|
|||
|
||||
$stamp1 = microtime(true);
|
||||
self::$logger->warning($message, $context);
|
||||
self::getApp()->saveTimestamp($stamp1, 'file');
|
||||
self::getApp()->getProfiler()->saveTimestamp($stamp1, 'file', System::callstack());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -270,7 +217,7 @@ class Logger extends BaseObject
|
|||
|
||||
$stamp1 = microtime(true);
|
||||
self::$logger->notice($message, $context);
|
||||
self::getApp()->saveTimestamp($stamp1, 'file');
|
||||
self::getApp()->getProfiler()->saveTimestamp($stamp1, 'file', System::callstack());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -293,7 +240,7 @@ class Logger extends BaseObject
|
|||
|
||||
$stamp1 = microtime(true);
|
||||
self::$logger->info($message, $context);
|
||||
self::getApp()->saveTimestamp($stamp1, 'file');
|
||||
self::getApp()->getProfiler()->saveTimestamp($stamp1, 'file', System::callstack());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -314,28 +261,28 @@ class Logger extends BaseObject
|
|||
|
||||
$stamp1 = microtime(true);
|
||||
self::$logger->debug($message, $context);
|
||||
self::getApp()->saveTimestamp($stamp1, 'file');
|
||||
self::getApp()->getProfiler()->saveTimestamp($stamp1, 'file', System::callstack());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Logs the given message at the given log level
|
||||
*
|
||||
* @param string $msg
|
||||
* @param string $level
|
||||
/**
|
||||
* @brief Logs the given message at the given log level
|
||||
*
|
||||
* @param string $msg
|
||||
* @param string $level
|
||||
*
|
||||
* @throws \Exception
|
||||
* @deprecated since 2019.03 Use Logger::debug() Logger::info() , ... instead
|
||||
*/
|
||||
public static function log($msg, $level = LogLevel::INFO)
|
||||
{
|
||||
*/
|
||||
public static function log($msg, $level = LogLevel::INFO)
|
||||
{
|
||||
if (!isset(self::$logger)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$stamp1 = microtime(true);
|
||||
$stamp1 = microtime(true);
|
||||
self::$logger->log($level, $msg);
|
||||
self::getApp()->saveTimestamp($stamp1, "file");
|
||||
}
|
||||
self::getApp()->getProfiler()->saveTimestamp($stamp1, "file", System::callstack());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief An alternative logger for development.
|
||||
|
@ -347,14 +294,14 @@ class Logger extends BaseObject
|
|||
* @param string $level
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function devLog($msg, $level = LogLevel::DEBUG)
|
||||
{
|
||||
public static function devLog($msg, $level = LogLevel::DEBUG)
|
||||
{
|
||||
if (!isset(self::$logger)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$stamp1 = microtime(true);
|
||||
self::$devLogger->log($level, $msg);
|
||||
self::getApp()->saveTimestamp($stamp1, "file");
|
||||
}
|
||||
$stamp1 = microtime(true);
|
||||
self::$devLogger->log($level, $msg);
|
||||
self::getApp()->getProfiler()->saveTimestamp($stamp1, "file", System::callstack());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,123 +18,76 @@ namespace Friendica\Core;
|
|||
class PConfig
|
||||
{
|
||||
/**
|
||||
* @var Config\IPConfigAdapter
|
||||
* @var Config\PConfiguration
|
||||
*/
|
||||
private static $adapter;
|
||||
|
||||
/**
|
||||
* @var Config\IPConfigCache
|
||||
*/
|
||||
private static $cache;
|
||||
private static $config;
|
||||
|
||||
/**
|
||||
* Initialize the config with only the cache
|
||||
*
|
||||
* @param Config\IPConfigCache $cache The configuration cache
|
||||
* @param Config\PConfiguration $config The configuration cache
|
||||
*/
|
||||
public static function init(Config\IPConfigCache $cache)
|
||||
public static function init(Config\PConfiguration $config)
|
||||
{
|
||||
self::$cache = $cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the adapter for DB-backend
|
||||
*
|
||||
* @param Config\IPConfigAdapter $adapter
|
||||
*/
|
||||
public static function setAdapter(Config\IPConfigAdapter $adapter)
|
||||
{
|
||||
self::$adapter = $adapter;
|
||||
self::$config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Loads all configuration values of a user's config family into a cached storage.
|
||||
*
|
||||
* All configuration values of the given user are stored with the $uid in
|
||||
* the cache ( @see IPConfigCache )
|
||||
*
|
||||
* @param string $uid The user_id
|
||||
* @param string $family The category of the configuration value
|
||||
* @param string $uid The user_id
|
||||
* @param string $cat The category of the configuration value
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function load($uid, $family)
|
||||
public static function load($uid, $cat)
|
||||
{
|
||||
if (!isset(self::$adapter)) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::$adapter->load($uid, $family);
|
||||
self::$config->load($uid, $cat);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a particular user's config variable given the category name
|
||||
* ($family) and a key.
|
||||
*
|
||||
* Get a particular user's config value from the given category ($family)
|
||||
* and the $key with the $uid from a cached storage either from the self::$adapter
|
||||
* (@see IConfigAdapter ) or from the static::$cache (@see IConfigCache ).
|
||||
* ($cat) and a key.
|
||||
*
|
||||
* @param string $uid The user_id
|
||||
* @param string $family The category of the configuration value
|
||||
* @param string $cat The category of the configuration value
|
||||
* @param string $key The configuration key to query
|
||||
* @param mixed $default_value optional, The value to return if key is not set (default: null)
|
||||
* @param boolean $refresh optional, If true the config is loaded from the db and not from the cache (default: false)
|
||||
*
|
||||
* @return mixed Stored value or null if it does not exist
|
||||
*/
|
||||
public static function get($uid, $family, $key, $default_value = null, $refresh = false)
|
||||
public static function get($uid, $cat, $key, $default_value = null, $refresh = false)
|
||||
{
|
||||
if (!isset(self::$adapter)) {
|
||||
return self::$cache->getP($uid, $family, $key, $default_value);
|
||||
}
|
||||
|
||||
return self::$adapter->get($uid, $family, $key, $default_value, $refresh);
|
||||
return self::$config->get($uid, $cat, $key, $default_value, $refresh);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a configuration value for a user
|
||||
*
|
||||
* Stores a config value ($value) in the category ($family) under the key ($key)
|
||||
* for the user_id $uid.
|
||||
*
|
||||
* @note Please do not store booleans - convert to 0/1 integer values!
|
||||
*
|
||||
* @param string $uid The user_id
|
||||
* @param string $family The category of the configuration value
|
||||
* @param string $cat The category of the configuration value
|
||||
* @param string $key The configuration key to set
|
||||
* @param mixed $value The value to store
|
||||
*
|
||||
* @return bool Operation success
|
||||
*/
|
||||
public static function set($uid, $family, $key, $value)
|
||||
public static function set($uid, $cat, $key, $value)
|
||||
{
|
||||
if (!isset(self::$adapter)) {
|
||||
return self::$cache->setP($uid, $family, $key, $value);
|
||||
}
|
||||
|
||||
return self::$adapter->set($uid, $family, $key, $value);
|
||||
return self::$config->set($uid, $cat, $key, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deletes the given key from the users's configuration.
|
||||
*
|
||||
* Removes the configured value from the stored cache in self::$config
|
||||
* (@see ConfigCache ) and removes it from the database (@see IConfigAdapter )
|
||||
* with the given $uid.
|
||||
* @param string $uid The user_id
|
||||
* @param string $cat The category of the configuration value
|
||||
* @param string $key The configuration key to delete
|
||||
*
|
||||
* @param string $uid The user_id
|
||||
* @param string $family The category of the configuration value
|
||||
* @param string $key The configuration key to delete
|
||||
*
|
||||
* @return mixed
|
||||
* @return bool
|
||||
*/
|
||||
public static function delete($uid, $family, $key)
|
||||
public static function delete($uid, $cat, $key)
|
||||
{
|
||||
if (!isset(self::$adapter)) {
|
||||
return self::$cache->deleteP($uid, $family, $key);
|
||||
}
|
||||
|
||||
return self::$adapter->delete($uid, $family, $key);
|
||||
return self::$config->delete($uid, $cat, $key);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ class Renderer extends BaseObject
|
|||
exit();
|
||||
}
|
||||
|
||||
$a->saveTimestamp($stamp1, "rendering");
|
||||
$a->getProfiler()->saveTimestamp($stamp1, "rendering", System::callstack());
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ class Renderer extends BaseObject
|
|||
exit();
|
||||
}
|
||||
|
||||
$a->saveTimestamp($stamp1, "file");
|
||||
$a->getProfiler()->saveTimestamp($stamp1, "file", System::callstack());
|
||||
|
||||
return $template;
|
||||
}
|
||||
|
|
|
@ -176,6 +176,12 @@ class System extends BaseObject
|
|||
exit();
|
||||
}
|
||||
|
||||
public static function jsonError($httpCode, $data, $content_type = 'application/json')
|
||||
{
|
||||
header($_SERVER["SERVER_PROTOCOL"] . ' ' . $httpCode);
|
||||
self::jsonExit($data, $content_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Encodes content to json.
|
||||
*
|
||||
|
@ -234,21 +240,6 @@ class System extends BaseObject
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a process identifier for the logging
|
||||
*
|
||||
* @param string $prefix A given prefix
|
||||
*
|
||||
* @return string a generated process identifier
|
||||
*/
|
||||
public static function processID($prefix)
|
||||
{
|
||||
// We aren't calling any other function here.
|
||||
// Doing so could easily create an endless loop
|
||||
$trailer = $prefix . ':' . getmypid() . ':';
|
||||
return substr($trailer . uniqid('') . mt_rand(), 0, 26);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current Load of the System
|
||||
*
|
||||
|
|
|
@ -51,7 +51,7 @@ class Theme
|
|||
$a = \get_app();
|
||||
$stamp1 = microtime(true);
|
||||
$theme_file = file_get_contents("view/theme/$theme/theme.php");
|
||||
$a->saveTimestamp($stamp1, "file");
|
||||
$a->getProfiler()->saveTimestamp($stamp1, "file", System::callstack());
|
||||
|
||||
$result = preg_match("|/\*.*\*/|msU", $theme_file, $matches);
|
||||
|
||||
|
|
|
@ -37,9 +37,13 @@ class Update
|
|||
}
|
||||
|
||||
if ($build < DB_UPDATE_VERSION) {
|
||||
// When we cannot execute the database update via the worker, we will do it directly
|
||||
if (!Worker::add(PRIORITY_CRITICAL, 'DBUpdate') && $via_worker) {
|
||||
if ($via_worker) {
|
||||
// Calling the database update directly via the worker enables us to perform database changes to the workerqueue table itself.
|
||||
// This is a fallback, since normally the database update will be performed by a worker job.
|
||||
// This worker job doesn't work for changes to the "workerqueue" table itself.
|
||||
self::run($basePath);
|
||||
} else {
|
||||
Worker::add(PRIORITY_CRITICAL, 'DBUpdate');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,19 +52,20 @@ class Update
|
|||
* Automatic database updates
|
||||
*
|
||||
* @param string $basePath The base path of this application
|
||||
* @param bool $force Force the Update-Check even if the lock is set
|
||||
* @param bool $force Force the Update-Check even if the database version doesn't match
|
||||
* @param bool $override Overrides any running/stuck updates
|
||||
* @param bool $verbose Run the Update-Check verbose
|
||||
* @param bool $sendMail Sends a Mail to the administrator in case of success/failure
|
||||
*
|
||||
* @return string Empty string if the update is successful, error messages otherwise
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public static function run($basePath, $force = false, $verbose = false, $sendMail = true)
|
||||
public static function run($basePath, $force = false, $override = false, $verbose = false, $sendMail = true)
|
||||
{
|
||||
// In force mode, we release the dbupdate lock first
|
||||
// Necessary in case of an stuck update
|
||||
if ($force) {
|
||||
Lock::release('dbupdate');
|
||||
if ($override) {
|
||||
Lock::release('dbupdate', true);
|
||||
}
|
||||
|
||||
$build = Config::get('system', 'build');
|
||||
|
@ -70,12 +75,12 @@ class Update
|
|||
Config::set('system', 'build', $build);
|
||||
}
|
||||
|
||||
if ($build != DB_UPDATE_VERSION) {
|
||||
if ($build != DB_UPDATE_VERSION || $force) {
|
||||
require_once 'update.php';
|
||||
|
||||
$stored = intval($build);
|
||||
$current = intval(DB_UPDATE_VERSION);
|
||||
if ($stored < $current) {
|
||||
if ($stored < $current || $force) {
|
||||
Config::load('database');
|
||||
|
||||
Logger::log('Update from \'' . $stored . '\' to \'' . $current . '\' - starting', Logger::DEBUG);
|
||||
|
@ -94,7 +99,7 @@ class Update
|
|||
|
||||
// update the structure in one call
|
||||
$retval = DBStructure::update($basePath, $verbose, true);
|
||||
if ($retval) {
|
||||
if (!empty($retval)) {
|
||||
if ($sendMail) {
|
||||
self::updateFailed(
|
||||
DB_UPDATE_VERSION,
|
||||
|
@ -126,8 +131,6 @@ class Update
|
|||
Lock::release('dbupdate');
|
||||
}
|
||||
}
|
||||
} elseif ($force) {
|
||||
DBStructure::update($basePath, $verbose, true);
|
||||
}
|
||||
|
||||
return '';
|
||||
|
|
|
@ -8,6 +8,7 @@ use Friendica\BaseObject;
|
|||
use Friendica\Database\DBA;
|
||||
use Friendica\Model\Process;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
use Friendica\Util\Logger\WorkerLogger;
|
||||
use Friendica\Util\Network;
|
||||
|
||||
/**
|
||||
|
@ -360,39 +361,19 @@ class Worker
|
|||
{
|
||||
$a = \get_app();
|
||||
|
||||
$mypid = getmypid();
|
||||
|
||||
$argc = count($argv);
|
||||
|
||||
// Currently deactivated, since the new logger doesn't support this
|
||||
//$new_process_id = System::processID("wrk");
|
||||
$new_process_id = '';
|
||||
$logger = $a->getLogger();
|
||||
$workerLogger = new WorkerLogger($logger, $funcname);
|
||||
|
||||
Logger::log("Process ".$mypid." - Prio ".$queue["priority"]." - ID ".$queue["id"].": ".$funcname." ".$queue["parameter"]." - Process PID: ".$new_process_id);
|
||||
$workerLogger ->info("Process start.", ['priority' => $queue["priority"], 'id' => $queue["id"]]);
|
||||
|
||||
$stamp = (float)microtime(true);
|
||||
|
||||
// We use the callstack here to analyze the performance of executed worker entries.
|
||||
// For this reason the variables have to be initialized.
|
||||
if (Config::get("system", "profiler")) {
|
||||
$a->performance["start"] = microtime(true);
|
||||
$a->performance["database"] = 0;
|
||||
$a->performance["database_write"] = 0;
|
||||
$a->performance["cache"] = 0;
|
||||
$a->performance["cache_write"] = 0;
|
||||
$a->performance["network"] = 0;
|
||||
$a->performance["file"] = 0;
|
||||
$a->performance["rendering"] = 0;
|
||||
$a->performance["parser"] = 0;
|
||||
$a->performance["marktime"] = 0;
|
||||
$a->performance["markstart"] = microtime(true);
|
||||
$a->callstack = [];
|
||||
}
|
||||
$a->getProfiler()->reset();
|
||||
|
||||
// For better logging create a new process id for every worker call
|
||||
// But preserve the old one for the worker
|
||||
$old_process_id = $a->process_id;
|
||||
$a->process_id = $new_process_id;
|
||||
$a->queue = $queue;
|
||||
|
||||
$up_duration = microtime(true) - self::$up_start;
|
||||
|
@ -400,13 +381,15 @@ class Worker
|
|||
// Reset global data to avoid interferences
|
||||
unset($_SESSION);
|
||||
|
||||
// Set the workerLogger as new default logger
|
||||
Logger::init($workerLogger);
|
||||
if ($method_call) {
|
||||
call_user_func_array(sprintf('Friendica\Worker\%s::execute', $funcname), $argv);
|
||||
} else {
|
||||
$funcname($argv, $argc);
|
||||
}
|
||||
Logger::init($logger);
|
||||
|
||||
$a->process_id = $old_process_id;
|
||||
unset($a->queue);
|
||||
|
||||
$duration = (microtime(true) - $stamp);
|
||||
|
@ -425,7 +408,7 @@ class Worker
|
|||
$rest = round(max(0, $up_duration - (self::$db_duration + self::$lock_duration)), 2);
|
||||
$exec = round($duration, 2);
|
||||
|
||||
Logger::info('Performance:', ['mode' => self::$mode, 'count' => $dbcount, 'stat' => $dbstat, 'write' => $dbwrite, 'lock' => $dblock, 'total' => $dbtotal, 'rest' => $rest, 'exec' => $exec]);
|
||||
$logger->info('Performance log.', ['mode' => self::$mode, 'count' => $dbcount, 'stat' => $dbstat, 'write' => $dbwrite, 'lock' => $dblock, 'total' => $dbtotal, 'rest' => $rest, 'exec' => $exec]);
|
||||
|
||||
self::$up_start = microtime(true);
|
||||
self::$db_duration = 0;
|
||||
|
@ -436,92 +419,23 @@ class Worker
|
|||
self::$mode = 2;
|
||||
|
||||
if ($duration > 3600) {
|
||||
Logger::log("Prio ".$queue["priority"].": ".$queue["parameter"]." - longer than 1 hour (".round($duration/60, 3).")", Logger::DEBUG);
|
||||
$logger->info('Longer than 1 hour.', ['priority' => $queue["priority"], 'id' => $queue["id"], 'duration' => round($duration/60, 3)]);
|
||||
} elseif ($duration > 600) {
|
||||
Logger::log("Prio ".$queue["priority"].": ".$queue["parameter"]." - longer than 10 minutes (".round($duration/60, 3).")", Logger::DEBUG);
|
||||
$logger->info('Longer than 10 minutes.', ['priority' => $queue["priority"], 'id' => $queue["id"], 'duration' => round($duration/60, 3)]);
|
||||
} elseif ($duration > 300) {
|
||||
Logger::log("Prio ".$queue["priority"].": ".$queue["parameter"]." - longer than 5 minutes (".round($duration/60, 3).")", Logger::DEBUG);
|
||||
$logger->info('Longer than 5 minutes.', ['priority' => $queue["priority"], 'id' => $queue["id"], 'duration' => round($duration/60, 3)]);
|
||||
} elseif ($duration > 120) {
|
||||
Logger::log("Prio ".$queue["priority"].": ".$queue["parameter"]." - longer than 2 minutes (".round($duration/60, 3).")", Logger::DEBUG);
|
||||
$logger->info('Longer than 2 minutes.', ['priority' => $queue["priority"], 'id' => $queue["id"], 'duration' => round($duration/60, 3)]);
|
||||
}
|
||||
|
||||
Logger::log("Process ".$mypid." - Prio ".$queue["priority"]." - ID ".$queue["id"].": ".$funcname." - done in ".number_format($duration, 4)." seconds. Process PID: ".$new_process_id);
|
||||
$workerLogger->info('Process done. ', ['priority' => $queue["priority"], 'id' => $queue["id"], 'duration' => number_format($duration, 4)]);
|
||||
|
||||
// Write down the performance values into the log
|
||||
if (Config::get("system", "profiler")) {
|
||||
$duration = microtime(true)-$a->performance["start"];
|
||||
|
||||
$o = '';
|
||||
if (Config::get("rendertime", "callstack")) {
|
||||
if (isset($a->callstack["database"])) {
|
||||
$o .= "\nDatabase Read:\n";
|
||||
foreach ($a->callstack["database"] as $func => $time) {
|
||||
$time = round($time, 3);
|
||||
if ($time > 0) {
|
||||
$o .= $func.": ".$time."\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($a->callstack["database_write"])) {
|
||||
$o .= "\nDatabase Write:\n";
|
||||
foreach ($a->callstack["database_write"] as $func => $time) {
|
||||
$time = round($time, 3);
|
||||
if ($time > 0) {
|
||||
$o .= $func.": ".$time."\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($a->callstack["dache"])) {
|
||||
$o .= "\nCache Read:\n";
|
||||
foreach ($a->callstack["dache"] as $func => $time) {
|
||||
$time = round($time, 3);
|
||||
if ($time > 0) {
|
||||
$o .= $func.": ".$time."\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($a->callstack["dache_write"])) {
|
||||
$o .= "\nCache Write:\n";
|
||||
foreach ($a->callstack["dache_write"] as $func => $time) {
|
||||
$time = round($time, 3);
|
||||
if ($time > 0) {
|
||||
$o .= $func.": ".$time."\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($a->callstack["network"])) {
|
||||
$o .= "\nNetwork:\n";
|
||||
foreach ($a->callstack["network"] as $func => $time) {
|
||||
$time = round($time, 3);
|
||||
if ($time > 0) {
|
||||
$o .= $func.": ".$time."\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Logger::log(
|
||||
"ID ".$queue["id"].": ".$funcname.": ".sprintf(
|
||||
"DB: %s/%s, Cache: %s/%s, Net: %s, I/O: %s, Other: %s, Total: %s".$o,
|
||||
number_format($a->performance["database"] - $a->performance["database_write"], 2),
|
||||
number_format($a->performance["database_write"], 2),
|
||||
number_format($a->performance["cache"], 2),
|
||||
number_format($a->performance["cache_write"], 2),
|
||||
number_format($a->performance["network"], 2),
|
||||
number_format($a->performance["file"], 2),
|
||||
number_format($duration - ($a->performance["database"]
|
||||
+ $a->performance["cache"] + $a->performance["cache_write"]
|
||||
+ $a->performance["network"] + $a->performance["file"]), 2),
|
||||
number_format($duration, 2)
|
||||
),
|
||||
Logger::DEBUG
|
||||
);
|
||||
}
|
||||
$a->getProfiler()->saveLog($a->getLogger(), "ID " . $queue["id"] . ": " . $funcname);
|
||||
|
||||
$cooldown = Config::get("system", "worker_cooldown", 0);
|
||||
|
||||
if ($cooldown > 0) {
|
||||
Logger::log("Process ".$mypid." - Prio ".$queue["priority"]." - ID ".$queue["id"].": ".$funcname." - in cooldown for ".$cooldown." seconds");
|
||||
$logger->info('Cooldown.', ['priority' => $queue["priority"], 'id' => $queue["id"], 'cooldown' => $cooldown]);
|
||||
sleep($cooldown);
|
||||
}
|
||||
}
|
||||
|
@ -943,7 +857,7 @@ class Worker
|
|||
}
|
||||
|
||||
if (!empty($waiting)) {
|
||||
$priority = array_shift(array_keys($waiting));
|
||||
$priority = array_keys($waiting)[0];
|
||||
Logger::info('No underassigned priority found, now taking the highest priority.', ['priority' => $priority]);
|
||||
return $priority;
|
||||
}
|
||||
|
|
|
@ -2,10 +2,11 @@
|
|||
|
||||
namespace Friendica\Database;
|
||||
|
||||
use Friendica\Core\Config\IConfigCache;
|
||||
use Friendica\Core\Config\Cache\IConfigCache;
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
use Friendica\Util\Profiler;
|
||||
use mysqli;
|
||||
use mysqli_result;
|
||||
use mysqli_stmt;
|
||||
|
@ -35,6 +36,14 @@ class DBA
|
|||
* @var IConfigCache
|
||||
*/
|
||||
private static $configCache;
|
||||
/**
|
||||
* @var Profiler
|
||||
*/
|
||||
private static $profiler;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private static $basePath;
|
||||
private static $server_info = '';
|
||||
private static $connection;
|
||||
private static $driver;
|
||||
|
@ -50,14 +59,16 @@ class DBA
|
|||
private static $db_name = '';
|
||||
private static $db_charset = '';
|
||||
|
||||
public static function connect($configCache, $serveraddr, $user, $pass, $db, $charset = null)
|
||||
public static function connect($basePath, IConfigCache $configCache, Profiler $profiler, $serveraddr, $user, $pass, $db, $charset = null)
|
||||
{
|
||||
if (!is_null(self::$connection) && self::connected()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// We are storing these values for being able to perform a reconnect
|
||||
self::$basePath = $basePath;
|
||||
self::$configCache = $configCache;
|
||||
self::$profiler = $profiler;
|
||||
self::$db_serveraddr = $serveraddr;
|
||||
self::$db_user = $user;
|
||||
self::$db_pass = $pass;
|
||||
|
@ -158,7 +169,7 @@ class DBA
|
|||
public static function reconnect() {
|
||||
self::disconnect();
|
||||
|
||||
$ret = self::connect(self::$configCache, self::$db_serveraddr, self::$db_user, self::$db_pass, self::$db_name, self::$db_charset);
|
||||
$ret = self::connect(self::$basePath, self::$configCache, self::$profiler, self::$db_serveraddr, self::$db_user, self::$db_pass, self::$db_name, self::$db_charset);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
@ -392,7 +403,6 @@ class DBA
|
|||
* @throws \Exception
|
||||
*/
|
||||
public static function p($sql) {
|
||||
$a = \get_app();
|
||||
|
||||
$stamp1 = microtime(true);
|
||||
|
||||
|
@ -415,7 +425,7 @@ class DBA
|
|||
|
||||
if ((substr_count($sql, '?') != count($args)) && (count($args) > 0)) {
|
||||
// Question: Should we continue or stop the query here?
|
||||
Logger::log('Parameter mismatch. Query "'.$sql.'" - Parameters '.print_r($args, true), Logger::DEBUG);
|
||||
Logger::warning('Query parameters mismatch.', ['query' => $sql, 'args' => $args, 'callstack' => System::callstack()]);
|
||||
}
|
||||
|
||||
$sql = self::cleanQuery($sql);
|
||||
|
@ -582,7 +592,7 @@ class DBA
|
|||
self::$errorno = $errorno;
|
||||
}
|
||||
|
||||
$a->saveTimestamp($stamp1, 'database');
|
||||
self::$profiler->saveTimestamp($stamp1, 'database', System::callstack());
|
||||
|
||||
if (self::$configCache->get('system', 'db_log')) {
|
||||
$stamp2 = microtime(true);
|
||||
|
@ -611,7 +621,6 @@ class DBA
|
|||
* @throws \Exception
|
||||
*/
|
||||
public static function e($sql) {
|
||||
$a = \get_app();
|
||||
|
||||
$stamp = microtime(true);
|
||||
|
||||
|
@ -654,7 +663,7 @@ class DBA
|
|||
self::$errorno = $errorno;
|
||||
}
|
||||
|
||||
$a->saveTimestamp($stamp, "database_write");
|
||||
self::$profiler->saveTimestamp($stamp, "database_write", System::callstack());
|
||||
|
||||
return $retval;
|
||||
}
|
||||
|
@ -777,7 +786,6 @@ class DBA
|
|||
* @return array current row
|
||||
*/
|
||||
public static function fetch($stmt) {
|
||||
$a = \get_app();
|
||||
|
||||
$stamp1 = microtime(true);
|
||||
|
||||
|
@ -824,7 +832,7 @@ class DBA
|
|||
}
|
||||
}
|
||||
|
||||
$a->saveTimestamp($stamp1, 'database');
|
||||
self::$profiler->saveTimestamp($stamp1, 'database', System::callstack());
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
@ -1031,7 +1039,7 @@ class DBA
|
|||
* This process must only be started once, since the value is cached.
|
||||
*/
|
||||
private static function buildRelationData() {
|
||||
$definition = DBStructure::definition(self::$configCache->get('system', 'basepath'));
|
||||
$definition = DBStructure::definition(self::$basePath);
|
||||
|
||||
foreach ($definition AS $table => $structure) {
|
||||
foreach ($structure['fields'] AS $field => $field_struct) {
|
||||
|
@ -1534,7 +1542,6 @@ class DBA
|
|||
* @return boolean was the close successful?
|
||||
*/
|
||||
public static function close($stmt) {
|
||||
$a = \get_app();
|
||||
|
||||
$stamp1 = microtime(true);
|
||||
|
||||
|
@ -1562,7 +1569,7 @@ class DBA
|
|||
break;
|
||||
}
|
||||
|
||||
$a->saveTimestamp($stamp1, 'database');
|
||||
self::$profiler->saveTimestamp($stamp1, 'database', System::callstack());
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
|
|
@ -2,51 +2,66 @@
|
|||
|
||||
namespace Friendica\Factory;
|
||||
|
||||
use Friendica\Core;
|
||||
use Friendica\Core\Config;
|
||||
use Friendica\Core\Config\Adapter;
|
||||
use Friendica\Core\Config\Cache;
|
||||
|
||||
class ConfigFactory
|
||||
{
|
||||
/**
|
||||
* @param Config\ConfigCacheLoader $loader The Config Cache loader (INI/config/.htconfig)
|
||||
* @param Cache\ConfigCacheLoader $loader The Config Cache loader (INI/config/.htconfig)
|
||||
*
|
||||
* @return Config\ConfigCache
|
||||
* @return Cache\ConfigCache
|
||||
*/
|
||||
public static function createCache(Config\ConfigCacheLoader $loader)
|
||||
public static function createCache(Cache\ConfigCacheLoader $loader)
|
||||
{
|
||||
$configCache = new Config\ConfigCache();
|
||||
$configCache = new Cache\ConfigCache();
|
||||
$loader->loadConfigFiles($configCache);
|
||||
|
||||
return $configCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type The adapter type
|
||||
* @param Config\IConfigCache $config The config cache of this adapter
|
||||
* @param Cache\ConfigCache $configCache The config cache of this adapter
|
||||
*
|
||||
* @return Config\IConfigAdapter
|
||||
* @return Config\Configuration
|
||||
*/
|
||||
public static function createConfig($type, Config\IConfigCache $config)
|
||||
public static function createConfig(Cache\ConfigCache $configCache)
|
||||
{
|
||||
if ($type == 'preload') {
|
||||
return new Config\PreloadConfigAdapter($config);
|
||||
if ($configCache->get('system', 'config_adapter') === 'preload') {
|
||||
$configAdapter = new Adapter\PreloadConfigAdapter();
|
||||
} else {
|
||||
return new Config\JITConfigAdapter($config);
|
||||
$configAdapter = new Adapter\JITConfigAdapter();
|
||||
}
|
||||
|
||||
$configuration = new Config\Configuration($configCache, $configAdapter);
|
||||
|
||||
// Set the config in the static container for legacy usage
|
||||
Core\Config::init($configuration);
|
||||
|
||||
return $configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type The adapter type
|
||||
* @param Config\IPConfigCache $config The config cache of this adapter
|
||||
* @param int $uid The UID of the current user
|
||||
* @param Cache\ConfigCache $configCache The config cache of this adapter
|
||||
* @param int $uid The UID of the current user
|
||||
*
|
||||
* @return Config\IPConfigAdapter
|
||||
* @return Config\PConfiguration
|
||||
*/
|
||||
public static function createPConfig($type, Config\IPConfigCache $config, $uid = null)
|
||||
public static function createPConfig(Cache\ConfigCache $configCache, $uid = null)
|
||||
{
|
||||
if ($type == 'preload') {
|
||||
return new Config\PreloadPConfigAdapter($config, $uid);
|
||||
if ($configCache->get('system', 'config_adapter') === 'preload') {
|
||||
$configAdapter = new Adapter\PreloadPConfigAdapter($uid);
|
||||
} else {
|
||||
return new Config\JITPConfigAdapter($config);
|
||||
$configAdapter = new Adapter\JITPConfigAdapter();
|
||||
}
|
||||
|
||||
$configuration = new Config\PConfiguration($configCache, $configAdapter);
|
||||
|
||||
// Set the config in the static container for legacy usage
|
||||
Core\PConfig::init($configuration);
|
||||
|
||||
return $configuration;
|
||||
}
|
||||
}
|
||||
|
|
61
src/Factory/DBFactory.php
Normal file
61
src/Factory/DBFactory.php
Normal file
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Factory;
|
||||
|
||||
use Friendica\Core\Config\Cache;
|
||||
use Friendica\Database;
|
||||
use Friendica\Util\Profiler;
|
||||
|
||||
class DBFactory
|
||||
{
|
||||
/**
|
||||
* Initialize the DBA connection
|
||||
*
|
||||
* @param string $basePath The basepath of the application
|
||||
* @param Cache\IConfigCache $configCache The configuration cache
|
||||
* @param Profiler $profiler The profiler
|
||||
* @param array $server The $_SERVER variables
|
||||
*
|
||||
* @throws \Exception if connection went bad
|
||||
*
|
||||
* @todo refactor basedir during https://github.com/friendica/friendica/issues/6720
|
||||
*/
|
||||
public static function init($basePath, Cache\IConfigCache $configCache, Profiler $profiler, array $server)
|
||||
{
|
||||
if (Database\DBA::connected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$db_host = $configCache->get('database', 'hostname');
|
||||
$db_user = $configCache->get('database', 'username');
|
||||
$db_pass = $configCache->get('database', 'password');
|
||||
$db_data = $configCache->get('database', 'database');
|
||||
$charset = $configCache->get('database', 'charset');
|
||||
|
||||
// Use environment variables for mysql if they are set beforehand
|
||||
if (!empty($server['MYSQL_HOST'])
|
||||
&& !empty($server['MYSQL_USERNAME'] || !empty($server['MYSQL_USER']))
|
||||
&& $server['MYSQL_PASSWORD'] !== false
|
||||
&& !empty($server['MYSQL_DATABASE']))
|
||||
{
|
||||
$db_host = $server['MYSQL_HOST'];
|
||||
if (!empty($server['MYSQL_PORT'])) {
|
||||
$db_host .= ':' . $server['MYSQL_PORT'];
|
||||
}
|
||||
if (!empty($server['MYSQL_USERNAME'])) {
|
||||
$db_user = $server['MYSQL_USERNAME'];
|
||||
} else {
|
||||
$db_user = $server['MYSQL_USER'];
|
||||
}
|
||||
$db_pass = (string) $server['MYSQL_PASSWORD'];
|
||||
$db_data = $server['MYSQL_DATABASE'];
|
||||
}
|
||||
|
||||
if (Database\DBA::connect($basePath, $configCache, $profiler, $db_host, $db_user, $db_pass, $db_data, $charset)) {
|
||||
// Loads DB_UPDATE_VERSION constant
|
||||
Database\DBStructure::definition($basePath, false);
|
||||
}
|
||||
|
||||
unset($db_host, $db_user, $db_pass, $db_data, $charset);
|
||||
}
|
||||
}
|
37
src/Factory/DependencyFactory.php
Normal file
37
src/Factory/DependencyFactory.php
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Factory;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Core\Config\Cache;
|
||||
use Friendica\Factory;
|
||||
use Friendica\Util\BasePath;
|
||||
|
||||
class DependencyFactory
|
||||
{
|
||||
/**
|
||||
* Setting all default-dependencies of a friendica execution
|
||||
*
|
||||
* @param string $channel The channel of this execution
|
||||
* @param string $directory The base directory
|
||||
* @param bool $isBackend True, if it's a backend execution, otherwise false (Default true)
|
||||
*
|
||||
* @return App The application
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function setUp($channel, $directory, $isBackend = true)
|
||||
{
|
||||
$basePath = BasePath::create($directory, $_SERVER);
|
||||
$configLoader = new Cache\ConfigCacheLoader($basePath);
|
||||
$configCache = Factory\ConfigFactory::createCache($configLoader);
|
||||
$profiler = Factory\ProfilerFactory::create($configCache);
|
||||
Factory\DBFactory::init($basePath, $configCache, $profiler, $_SERVER);
|
||||
$config = Factory\ConfigFactory::createConfig($configCache);
|
||||
// needed to call PConfig::init()
|
||||
Factory\ConfigFactory::createPConfig($configCache);
|
||||
$logger = Factory\LoggerFactory::create($channel, $config);
|
||||
|
||||
return new App($basePath, $config, $logger, $profiler, $isBackend);
|
||||
}
|
||||
}
|
|
@ -2,10 +2,13 @@
|
|||
|
||||
namespace Friendica\Factory;
|
||||
|
||||
use Friendica\Core\Config\ConfigCache;
|
||||
use Friendica\Core\Config\Configuration;
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Network\HTTPException\InternalServerErrorException;
|
||||
use Friendica\Util\Logger\FriendicaDevelopHandler;
|
||||
use Friendica\Util\Logger\FriendicaIntrospectionProcessor;
|
||||
use Friendica\Util\Logger\WorkerLogger;
|
||||
use Friendica\Util\Profiler;
|
||||
use Monolog;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\LogLevel;
|
||||
|
@ -17,32 +20,45 @@ use Psr\Log\LogLevel;
|
|||
*/
|
||||
class LoggerFactory
|
||||
{
|
||||
/**
|
||||
* A list of classes, which shouldn't get logged
|
||||
* @var array
|
||||
*/
|
||||
private static $ignoreClassList = [
|
||||
Logger::class,
|
||||
Profiler::class,
|
||||
WorkerLogger::class
|
||||
];
|
||||
|
||||
/**
|
||||
* Creates a new PSR-3 compliant logger instances
|
||||
*
|
||||
* @param string $channel The channel of the logger instance
|
||||
* @param ConfigCache $config The config
|
||||
* @param string $channel The channel of the logger instance
|
||||
* @param Configuration $config The config
|
||||
*
|
||||
* @return LoggerInterface The PSR-3 compliant logger instance
|
||||
*/
|
||||
public static function create($channel, ConfigCache $config = null)
|
||||
public static function create($channel, Configuration $config)
|
||||
{
|
||||
$logger = new Monolog\Logger($channel);
|
||||
$logger->pushProcessor(new Monolog\Processor\PsrLogMessageProcessor());
|
||||
$logger->pushProcessor(new Monolog\Processor\ProcessIdProcessor());
|
||||
$logger->pushProcessor(new Monolog\Processor\UidProcessor());
|
||||
$logger->pushProcessor(new FriendicaIntrospectionProcessor(LogLevel::DEBUG, ['Friendica\\Core\\Logger']));
|
||||
$logger->pushProcessor(new FriendicaIntrospectionProcessor(LogLevel::DEBUG, self::$ignoreClassList));
|
||||
|
||||
if (isset($config)) {
|
||||
$debugging = $config->get('system', 'debugging');
|
||||
$stream = $config->get('system', 'logfile');
|
||||
$level = $config->get('system', 'loglevel');
|
||||
$debugging = $config->get('system', 'debugging');
|
||||
$stream = $config->get('system', 'logfile');
|
||||
$level = $config->get('system', 'loglevel');
|
||||
|
||||
if ($debugging) {
|
||||
static::addStreamHandler($logger, $stream, $level);
|
||||
}
|
||||
if ($debugging) {
|
||||
$loglevel = self::mapLegacyConfigDebugLevel((string)$level);
|
||||
static::addStreamHandler($logger, $stream, $loglevel);
|
||||
} else {
|
||||
static::addVoidHandler($logger);
|
||||
}
|
||||
|
||||
Logger::init($logger);
|
||||
|
||||
return $logger;
|
||||
}
|
||||
|
||||
|
@ -54,25 +70,71 @@ class LoggerFactory
|
|||
*
|
||||
* It should never get filled during normal usage of Friendica
|
||||
*
|
||||
* @param string $channel The channel of the logger instance
|
||||
* @param string $developerIp The IP of the developer who wants to use the logger
|
||||
* @param string $channel The channel of the logger instance
|
||||
* @param Configuration $config The config
|
||||
*
|
||||
* @return LoggerInterface The PSR-3 compliant logger instance
|
||||
*/
|
||||
public static function createDev($channel, $developerIp)
|
||||
public static function createDev($channel, Configuration $config)
|
||||
{
|
||||
$debugging = $config->get('system', 'debugging');
|
||||
$stream = $config->get('system', 'dlogfile');
|
||||
$developerIp = $config->get('system', 'dlogip');
|
||||
|
||||
if (!isset($developerIp) || !$debugging) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$logger = new Monolog\Logger($channel);
|
||||
$logger->pushProcessor(new Monolog\Processor\PsrLogMessageProcessor());
|
||||
$logger->pushProcessor(new Monolog\Processor\ProcessIdProcessor());
|
||||
$logger->pushProcessor(new Monolog\Processor\UidProcessor());
|
||||
$logger->pushProcessor(new FriendicaIntrospectionProcessor(LogLevel::DEBUG, ['Friendica\\Core\\Logger']));
|
||||
|
||||
$logger->pushProcessor(new FriendicaIntrospectionProcessor(LogLevel::DEBUG, self::$ignoreClassList));
|
||||
|
||||
$logger->pushHandler(new FriendicaDevelopHandler($developerIp));
|
||||
|
||||
static::addStreamHandler($logger, $stream, LogLevel::DEBUG);
|
||||
|
||||
Logger::setDevLogger($logger);
|
||||
|
||||
return $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mapping a legacy level to the PSR-3 compliant levels
|
||||
* @see https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md#5-psrlogloglevel
|
||||
*
|
||||
* @param string $level the level to be mapped
|
||||
*
|
||||
* @return string the PSR-3 compliant level
|
||||
*/
|
||||
private static function mapLegacyConfigDebugLevel($level)
|
||||
{
|
||||
switch ($level) {
|
||||
// legacy WARNING
|
||||
case "0":
|
||||
return LogLevel::ERROR;
|
||||
// legacy INFO
|
||||
case "1":
|
||||
return LogLevel::WARNING;
|
||||
// legacy TRACE
|
||||
case "2":
|
||||
return LogLevel::NOTICE;
|
||||
// legacy DEBUG
|
||||
case "3":
|
||||
return LogLevel::INFO;
|
||||
// legacy DATA
|
||||
case "4":
|
||||
return LogLevel::DEBUG;
|
||||
// legacy ALL
|
||||
case "5":
|
||||
return LogLevel::DEBUG;
|
||||
// default if nothing set
|
||||
default:
|
||||
return $level;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adding a handler to a given logger instance
|
||||
*
|
||||
|
@ -94,6 +156,7 @@ class LoggerFactory
|
|||
if (!is_int($loglevel)) {
|
||||
$loglevel = LogLevel::NOTICE;
|
||||
}
|
||||
|
||||
$fileHandler = new Monolog\Handler\StreamHandler($stream, $loglevel);
|
||||
|
||||
$formatter = new Monolog\Formatter\LineFormatter("%datetime% %channel% [%level_name%]: %message% %context% %extra%\n");
|
||||
|
@ -105,31 +168,10 @@ class LoggerFactory
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method enables the test mode of a given logger
|
||||
*
|
||||
* @param LoggerInterface $logger The logger
|
||||
*
|
||||
* @return Monolog\Handler\TestHandler the Handling for tests
|
||||
*
|
||||
* @throws InternalServerErrorException if the logger is incompatible to the logger factory
|
||||
*/
|
||||
public static function enableTest($logger)
|
||||
public static function addVoidHandler($logger)
|
||||
{
|
||||
if ($logger instanceof Monolog\Logger) {
|
||||
// disable every handler so far
|
||||
$logger->pushHandler(new Monolog\Handler\NullHandler());
|
||||
|
||||
// enable the test handler
|
||||
$fileHandler = new Monolog\Handler\TestHandler();
|
||||
$formatter = new Monolog\Formatter\LineFormatter("%datetime% %channel% [%level_name%]: %message% %context% %extra%\n");
|
||||
$fileHandler->setFormatter($formatter);
|
||||
|
||||
$logger->pushHandler($fileHandler);
|
||||
|
||||
return $fileHandler;
|
||||
} else {
|
||||
throw new InternalServerErrorException('Logger instance incompatible for MonologFactory');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
26
src/Factory/ProfilerFactory.php
Normal file
26
src/Factory/ProfilerFactory.php
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Factory;
|
||||
|
||||
use Friendica\Core\Config\Cache\IConfigCache;
|
||||
use Friendica\Util\Profiler;
|
||||
|
||||
class ProfilerFactory
|
||||
{
|
||||
/**
|
||||
* Creates a Profiler for the current execution
|
||||
*
|
||||
* @param IConfigCache $configCache The configuration cache
|
||||
*
|
||||
* @return Profiler
|
||||
*/
|
||||
public static function create(IConfigCache $configCache)
|
||||
{
|
||||
$enabled = $configCache->get('system', 'profiler');
|
||||
$enabled = isset($enabled) && $enabled !== '0';
|
||||
$renderTime = $configCache->get('rendertime', 'callstack');
|
||||
$renderTime = isset($renderTime) && $renderTime !== '0';
|
||||
|
||||
return new Profiler($enabled, $renderTime);
|
||||
}
|
||||
}
|
|
@ -232,6 +232,11 @@ class Contact extends BaseObject
|
|||
}
|
||||
|
||||
DBA::update('user-contact', ['blocked' => $blocked], ['cid' => $cdata['public'], 'uid' => $uid], true);
|
||||
|
||||
if ($blocked) {
|
||||
// Blocked contact can't be in any group
|
||||
self::removeFromGroups($cid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1001,7 +1006,7 @@ class Contact extends BaseObject
|
|||
$sparkle = false;
|
||||
if (($contact['network'] === Protocol::DFRN) && !$contact['self']) {
|
||||
$sparkle = true;
|
||||
$profile_link = System::baseUrl() . '/redir/' . $contact['id'];
|
||||
$profile_link = System::baseUrl() . '/redir/' . $contact['id'] . '?url=' . $contact['url'];
|
||||
} else {
|
||||
$profile_link = $contact['url'];
|
||||
}
|
||||
|
@ -1011,9 +1016,9 @@ class Contact extends BaseObject
|
|||
}
|
||||
|
||||
if ($sparkle) {
|
||||
$status_link = $profile_link . '?url=status';
|
||||
$photos_link = $profile_link . '?url=photos';
|
||||
$profile_link = $profile_link . '?url=profile';
|
||||
$status_link = $profile_link . '?tab=status';
|
||||
$photos_link = str_replace('/profile/', '/photos/', $profile_link);
|
||||
$profile_link = $profile_link . '?tab=profile';
|
||||
}
|
||||
|
||||
if (in_array($contact['network'], [Protocol::DFRN, Protocol::DIASPORA]) && !$contact['self']) {
|
||||
|
@ -2184,7 +2189,7 @@ class Contact extends BaseObject
|
|||
{
|
||||
$contact = DBA::selectFirst('contact', ['id', 'network', 'url', 'uid'], ['id' => $cid]);
|
||||
|
||||
return self::magicLinkbyContact($contact, $url);
|
||||
return self::magicLinkByContact($contact, $url);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2197,7 +2202,7 @@ class Contact extends BaseObject
|
|||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
public static function magicLinkbyContact($contact, $url = '')
|
||||
public static function magicLinkByContact($contact, $url = '')
|
||||
{
|
||||
if ((!local_user() && !remote_user()) || ($contact['network'] != Protocol::DFRN)) {
|
||||
return $url ?: $contact['url']; // Equivalent to ($url != '') ? $url : $contact['url'];
|
||||
|
@ -2220,4 +2225,9 @@ class Contact extends BaseObject
|
|||
|
||||
return $redirect;
|
||||
}
|
||||
|
||||
public static function removeFromGroups($contact_id)
|
||||
{
|
||||
return DBA::delete('group_member', ['contact-id' => $contact_id]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,26 @@ use Friendica\Database\DBA;
|
|||
*/
|
||||
class Group extends BaseObject
|
||||
{
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param int $group_id
|
||||
* @return bool
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function exists($group_id, $uid = null)
|
||||
{
|
||||
$condition = ['id' => $group_id, 'deleted' => false];
|
||||
|
||||
if (isset($uid)) {
|
||||
$condition = [
|
||||
'uid' => $uid
|
||||
];
|
||||
}
|
||||
|
||||
return DBA::exists('group', $condition);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a new contact group
|
||||
*
|
||||
|
|
|
@ -1336,7 +1336,11 @@ class Item extends BaseObject
|
|||
$expire_date = time() - ($expire_interval * 86400);
|
||||
$created_date = strtotime($item['created']);
|
||||
if ($created_date < $expire_date) {
|
||||
Logger::log('item-store: item created ('.date('c', $created_date).') before expiration time ('.date('c', $expire_date).'). ignored. ' . print_r($item,true), Logger::DEBUG);
|
||||
Logger::notice('Item created before expiration interval.', [
|
||||
'created' => date('c', $created_date),
|
||||
'expired' => date('c', $expire_date),
|
||||
'$item' => $item
|
||||
]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1354,7 +1358,13 @@ class Item extends BaseObject
|
|||
if (DBA::isResult($existing)) {
|
||||
// We only log the entries with a different user id than 0. Otherwise we would have too many false positives
|
||||
if ($uid != 0) {
|
||||
Logger::log("Item with uri ".$item['uri']." already existed for user ".$uid." with id ".$existing["id"]." target network ".$existing["network"]." - new network: ".$item['network']);
|
||||
Logger::notice('Item already existed for user', [
|
||||
'uri' => $item['uri'],
|
||||
'uid' => $uid,
|
||||
'network' => $item['network'],
|
||||
'existing_id' => $existing["id"],
|
||||
'existing_network' => $existing["network"]
|
||||
]);
|
||||
}
|
||||
|
||||
return $existing["id"];
|
||||
|
@ -1405,7 +1415,7 @@ class Item extends BaseObject
|
|||
|
||||
// When there is no content then we don't post it
|
||||
if ($item['body'].$item['title'] == '') {
|
||||
Logger::log('No body, no title.');
|
||||
Logger::notice('No body, no title.');
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1432,7 +1442,7 @@ class Item extends BaseObject
|
|||
$item['author-id'] = defaults($item, 'author-id', Contact::getIdForURL($item["author-link"], 0, false, $default));
|
||||
|
||||
if (Contact::isBlocked($item["author-id"])) {
|
||||
Logger::log('Contact '.$item["author-id"].' is blocked, item '.$item["uri"].' will not be stored');
|
||||
Logger::notice('Author is blocked node-wide', ['author-link' => $item["author-link"], 'item-uri' => $item["uri"]]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1442,22 +1452,27 @@ class Item extends BaseObject
|
|||
$item['owner-id'] = defaults($item, 'owner-id', Contact::getIdForURL($item["owner-link"], 0, false, $default));
|
||||
|
||||
if (Contact::isBlocked($item["owner-id"])) {
|
||||
Logger::log('Contact '.$item["owner-id"].' is blocked, item '.$item["uri"].' will not be stored');
|
||||
Logger::notice('Owner is blocked node-wide', ['owner-link' => $item["owner-link"], 'item-uri' => $item["uri"]]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($item['network'] == Protocol::PHANTOM) {
|
||||
Logger::log('Missing network. Called by: '.System::callstack(), Logger::DEBUG);
|
||||
|
||||
$item['network'] = Protocol::DFRN;
|
||||
Logger::log("Set network to " . $item["network"] . " for " . $item["uri"], Logger::DEBUG);
|
||||
Logger::notice('Missing network, setting to {network}.', [
|
||||
'uri' => $item["uri"],
|
||||
'network' => $item['network'],
|
||||
'callstack' => System::callstack()
|
||||
]);
|
||||
}
|
||||
|
||||
// Checking if there is already an item with the same guid
|
||||
Logger::log('Checking for an item for user '.$item['uid'].' on network '.$item['network'].' with the guid '.$item['guid'], Logger::DEBUG);
|
||||
$condition = ['guid' => $item['guid'], 'network' => $item['network'], 'uid' => $item['uid']];
|
||||
if (self::exists($condition)) {
|
||||
Logger::log('found item with guid '.$item['guid'].' for user '.$item['uid'].' on network '.$item['network'], Logger::DEBUG);
|
||||
Logger::notice('Found already existing item', [
|
||||
'guid' => $item['guid'],
|
||||
'uid' => $item['uid'],
|
||||
'network' => $item['network']
|
||||
]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
namespace Friendica\Model;
|
||||
|
||||
use Friendica\Database\DBA;
|
||||
use \BadMethodCallException;
|
||||
|
||||
class ItemDeliveryData
|
||||
{
|
||||
|
@ -71,7 +72,7 @@ class ItemDeliveryData
|
|||
public static function insert($item_id, array $fields)
|
||||
{
|
||||
if (empty($item_id)) {
|
||||
throw new \BadMethodCallException('Empty item_id');
|
||||
throw new BadMethodCallException('Empty item_id');
|
||||
}
|
||||
|
||||
$fields['iid'] = $item_id;
|
||||
|
@ -92,7 +93,7 @@ class ItemDeliveryData
|
|||
public static function update($item_id, array $fields)
|
||||
{
|
||||
if (empty($item_id)) {
|
||||
throw new \BadMethodCallException('Empty item_id');
|
||||
throw new BadMethodCallException('Empty item_id');
|
||||
}
|
||||
|
||||
if (empty($fields)) {
|
||||
|
@ -113,7 +114,7 @@ class ItemDeliveryData
|
|||
public static function delete($item_id)
|
||||
{
|
||||
if (empty($item_id)) {
|
||||
throw new \BadMethodCallException('Empty item_id');
|
||||
throw new BadMethodCallException('Empty item_id');
|
||||
}
|
||||
|
||||
return DBA::delete('item-delivery-data', ['iid' => $item_id]);
|
||||
|
|
|
@ -10,8 +10,8 @@ use Friendica\BaseObject;
|
|||
use Friendica\Core\Cache;
|
||||
use Friendica\Core\Config;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Core\StorageManager;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Database\DBStructure;
|
||||
use Friendica\Model\Storage\IStorage;
|
||||
|
@ -173,6 +173,8 @@ class Photo extends BaseObject
|
|||
*/
|
||||
public static function getImageForPhoto(array $photo)
|
||||
{
|
||||
$data = "";
|
||||
|
||||
if ($photo["backend-class"] == "") {
|
||||
// legacy data storage in "data" column
|
||||
$i = self::selectFirst(["data"], ["id" => $photo["id"]]);
|
||||
|
@ -189,6 +191,7 @@ class Photo extends BaseObject
|
|||
if ($data === "") {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Image($data, $photo["type"]);
|
||||
}
|
||||
|
||||
|
@ -200,7 +203,7 @@ class Photo extends BaseObject
|
|||
*/
|
||||
private static function getFields()
|
||||
{
|
||||
$allfields = DBStructure::definition(false);
|
||||
$allfields = DBStructure::definition(self::getApp()->getBasePath(), false);
|
||||
$fields = array_keys($allfields["photo"]["fields"]);
|
||||
array_splice($fields, array_search("data", $fields), 1);
|
||||
return $fields;
|
||||
|
@ -219,11 +222,13 @@ class Photo extends BaseObject
|
|||
{
|
||||
$fields = self::getFields();
|
||||
$values = array_fill(0, count($fields), "");
|
||||
|
||||
$photo = array_combine($fields, $values);
|
||||
$photo["backend-class"] = Storage\SystemResource::class;
|
||||
$photo["backend-ref"] = $filename;
|
||||
$photo["type"] = $mimetype;
|
||||
$photo["cacheable"] = false;
|
||||
|
||||
return $photo;
|
||||
}
|
||||
|
||||
|
|
|
@ -787,7 +787,7 @@ class Profile
|
|||
$profile['marital']['with'] = $a->profile['with'];
|
||||
}
|
||||
|
||||
if (strlen($a->profile['howlong']) && $a->profile['howlong'] >= DBA::NULL_DATETIME) {
|
||||
if (strlen($a->profile['howlong']) && $a->profile['howlong'] > DBA::NULL_DATETIME) {
|
||||
$profile['howlong'] = Temporal::getRelativeDate($a->profile['howlong'], L10n::t('for %1$d %2$s'));
|
||||
}
|
||||
|
||||
|
|
|
@ -50,8 +50,14 @@ class Database implements IStorage
|
|||
{
|
||||
return DBA::delete('storage', ['id' => $ref]);
|
||||
}
|
||||
|
||||
public static function getOptions() { return []; }
|
||||
|
||||
public static function saveOptions($data) { return []; }
|
||||
|
||||
public static function getOptions()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public static function saveOptions($data)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
namespace Friendica\Model\Storage;
|
||||
|
||||
use \BadMethodCallException;
|
||||
|
||||
/**
|
||||
* @brief System resource storage class
|
||||
*
|
||||
|
@ -32,12 +34,12 @@ class SystemResource implements IStorage
|
|||
|
||||
public static function put($data, $filename = "")
|
||||
{
|
||||
throw new \BadMethodCallException();
|
||||
throw new BadMethodCallException();
|
||||
}
|
||||
|
||||
public static function delete($filename)
|
||||
{
|
||||
throw new \BadMethodCallException();
|
||||
throw new BadMethodCallException();
|
||||
}
|
||||
|
||||
public static function getOptions()
|
||||
|
|
|
@ -1,37 +1,82 @@
|
|||
<?php
|
||||
/**
|
||||
* @file src/Model/Term
|
||||
* @file src/Model/Term.php
|
||||
*/
|
||||
namespace Friendica\Model;
|
||||
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Util\Strings;
|
||||
|
||||
/**
|
||||
* Class Term
|
||||
*
|
||||
* This Model class handles term table interactions.
|
||||
* This tables stores relevant terms related to posts, photos and searches, like hashtags, mentions and
|
||||
* user-applied categories.
|
||||
*
|
||||
* @package Friendica\Model
|
||||
*/
|
||||
class Term
|
||||
{
|
||||
public static function tagTextFromItemId($itemid)
|
||||
{
|
||||
$tag_text = '';
|
||||
$condition = ['otype' => TERM_OBJ_POST, 'oid' => $itemid, 'type' => [TERM_HASHTAG, TERM_MENTION]];
|
||||
$tags = DBA::select('term', [], $condition);
|
||||
while ($tag = DBA::fetch($tags)) {
|
||||
if ($tag_text != '') {
|
||||
$tag_text .= ',';
|
||||
}
|
||||
const UNKNOWN = 0;
|
||||
const HASHTAG = 1;
|
||||
const MENTION = 2;
|
||||
const CATEGORY = 3;
|
||||
const PCATEGORY = 4;
|
||||
const FILE = 5;
|
||||
const SAVEDSEARCH = 6;
|
||||
const CONVERSATION = 7;
|
||||
/**
|
||||
* An implicit mention is a mention in a comment body that is redundant with the threading information.
|
||||
*/
|
||||
const IMPLICIT_MENTION = 8;
|
||||
/**
|
||||
* An exclusive mention transfers the ownership of the post to the target account, usually a forum.
|
||||
*/
|
||||
const EXCLUSIVE_MENTION = 9;
|
||||
|
||||
if ($tag['type'] == 1) {
|
||||
$tag_text .= '#';
|
||||
} else {
|
||||
$tag_text .= '@';
|
||||
}
|
||||
$tag_text .= '[url=' . $tag['url'] . ']' . $tag['term'] . '[/url]';
|
||||
const TAG_CHARACTER = [
|
||||
self::HASHTAG => '#',
|
||||
self::MENTION => '@',
|
||||
self::IMPLICIT_MENTION => '%',
|
||||
self::EXCLUSIVE_MENTION => '!',
|
||||
];
|
||||
|
||||
const OBJECT_TYPE_POST = 1;
|
||||
const OBJECT_TYPE_PHOTO = 2;
|
||||
|
||||
/**
|
||||
* Generates the legacy item.tag field comma-separated BBCode string from an item ID.
|
||||
* Includes only hashtags, implicit and explicit mentions.
|
||||
*
|
||||
* @param int $item_id
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function tagTextFromItemId($item_id)
|
||||
{
|
||||
$tag_list = [];
|
||||
$tags = self::tagArrayFromItemId($item_id, [self::HASHTAG, self::MENTION, self::IMPLICIT_MENTION]);
|
||||
foreach ($tags as $tag) {
|
||||
$tag_list[] = self::TAG_CHARACTER[$tag['type']] . '[url=' . $tag['url'] . ']' . $tag['term'] . '[/url]';
|
||||
}
|
||||
return $tag_text;
|
||||
|
||||
return implode(',', $tag_list);
|
||||
}
|
||||
|
||||
public static function tagArrayFromItemId($itemid, $type = [TERM_HASHTAG, TERM_MENTION])
|
||||
/**
|
||||
* Retrieves the terms from the provided type(s) associated with the provided item ID.
|
||||
*
|
||||
* @param int $item_id
|
||||
* @param int|array $type
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function tagArrayFromItemId($item_id, $type = [self::HASHTAG, self::MENTION])
|
||||
{
|
||||
$condition = ['otype' => TERM_OBJ_POST, 'oid' => $itemid, 'type' => $type];
|
||||
$condition = ['otype' => self::OBJECT_TYPE_POST, 'oid' => $item_id, 'type' => $type];
|
||||
$tags = DBA::select('term', ['type', 'term', 'url'], $condition);
|
||||
if (!DBA::isResult($tags)) {
|
||||
return [];
|
||||
|
@ -40,22 +85,39 @@ class Term
|
|||
return DBA::toArray($tags);
|
||||
}
|
||||
|
||||
public static function fileTextFromItemId($itemid)
|
||||
/**
|
||||
* Generates the legacy item.file field string from an item ID.
|
||||
* Includes only file and category terms.
|
||||
*
|
||||
* @param int $item_id
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function fileTextFromItemId($item_id)
|
||||
{
|
||||
$file_text = '';
|
||||
$condition = ['otype' => TERM_OBJ_POST, 'oid' => $itemid, 'type' => [TERM_FILE, TERM_CATEGORY]];
|
||||
$tags = DBA::select('term', [], $condition);
|
||||
while ($tag = DBA::fetch($tags)) {
|
||||
if ($tag['type'] == TERM_CATEGORY) {
|
||||
$tags = self::tagArrayFromItemId($item_id, [self::FILE, self::CATEGORY]);
|
||||
foreach ($tags as $tag) {
|
||||
if ($tag['type'] == self::CATEGORY) {
|
||||
$file_text .= '<' . $tag['term'] . '>';
|
||||
} else {
|
||||
$file_text .= '[' . $tag['term'] . ']';
|
||||
}
|
||||
}
|
||||
|
||||
return $file_text;
|
||||
}
|
||||
|
||||
public static function insertFromTagFieldByItemId($itemid, $tags)
|
||||
/**
|
||||
* Inserts new terms for the provided item ID based on the legacy item.tag field BBCode content.
|
||||
* Deletes all previous tag terms for the same item ID.
|
||||
* Sets both the item.mention and thread.mentions field flags if a mention concerning the item UID is found.
|
||||
*
|
||||
* @param int $item_id
|
||||
* @param string $tag_str
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public static function insertFromTagFieldByItemId($item_id, $tag_str)
|
||||
{
|
||||
$profile_base = System::baseUrl();
|
||||
$profile_data = parse_url($profile_base);
|
||||
|
@ -64,32 +126,32 @@ class Term
|
|||
$profile_base_diaspora = $profile_data['host'] . $profile_path . '/u/';
|
||||
|
||||
$fields = ['guid', 'uid', 'id', 'edited', 'deleted', 'created', 'received', 'title', 'body', 'parent'];
|
||||
$message = Item::selectFirst($fields, ['id' => $itemid]);
|
||||
if (!DBA::isResult($message)) {
|
||||
$item = Item::selectFirst($fields, ['id' => $item_id]);
|
||||
if (!DBA::isResult($item)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$message['tag'] = $tags;
|
||||
$item['tag'] = $tag_str;
|
||||
|
||||
// Clean up all tags
|
||||
self::deleteByItemId($itemid);
|
||||
self::deleteByItemId($item_id);
|
||||
|
||||
if ($message['deleted']) {
|
||||
if ($item['deleted']) {
|
||||
return;
|
||||
}
|
||||
|
||||
$taglist = explode(',', $message['tag']);
|
||||
$taglist = explode(',', $item['tag']);
|
||||
|
||||
$tags_string = '';
|
||||
foreach ($taglist as $tag) {
|
||||
if ((substr(trim($tag), 0, 1) == '#') || (substr(trim($tag), 0, 1) == '@') || (substr(trim($tag), 0, 1) == '!')) {
|
||||
if (Strings::startsWith($tag, self::TAG_CHARACTER)) {
|
||||
$tags_string .= ' ' . trim($tag);
|
||||
} else {
|
||||
$tags_string .= ' #' . trim($tag);
|
||||
}
|
||||
}
|
||||
|
||||
$data = ' ' . $message['title'] . ' ' . $message['body'] . ' ' . $tags_string . ' ';
|
||||
$data = ' ' . $item['title'] . ' ' . $item['body'] . ' ' . $tags_string . ' ';
|
||||
|
||||
// ignore anything in a code block
|
||||
$data = preg_replace('/\[code\](.*?)\[\/code\]/sm', '', $data);
|
||||
|
@ -103,11 +165,15 @@ class Term
|
|||
}
|
||||
}
|
||||
|
||||
$pattern = '/\W([\#@!])\[url\=(.*?)\](.*?)\[\/url\]/ism';
|
||||
$pattern = '/\W([\#@!%])\[url\=(.*?)\](.*?)\[\/url\]/ism';
|
||||
if (preg_match_all($pattern, $data, $matches, PREG_SET_ORDER)) {
|
||||
foreach ($matches as $match) {
|
||||
|
||||
if (($match[1] == '@') || ($match[1] == '!')) {
|
||||
if (in_array($match[1], [
|
||||
self::TAG_CHARACTER[self::MENTION],
|
||||
self::TAG_CHARACTER[self::IMPLICIT_MENTION],
|
||||
self::TAG_CHARACTER[self::EXCLUSIVE_MENTION]
|
||||
])) {
|
||||
$contact = Contact::getDetailsByURL($match[2], 0);
|
||||
if (!empty($contact['addr'])) {
|
||||
$match[3] = $contact['addr'];
|
||||
|
@ -118,12 +184,12 @@ class Term
|
|||
}
|
||||
}
|
||||
|
||||
$tags[$match[1] . trim($match[3], ',.:;[]/\"?!')] = $match[2];
|
||||
$tags[$match[2]] = $match[1] . trim($match[3], ',.:;[]/\"?!');
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($tags as $tag => $link) {
|
||||
if (substr(trim($tag), 0, 1) == '#') {
|
||||
foreach ($tags as $link => $tag) {
|
||||
if (self::isType($tag, self::HASHTAG)) {
|
||||
// try to ignore #039 or #1 or anything like that
|
||||
if (ctype_digit(substr(trim($tag), 1))) {
|
||||
continue;
|
||||
|
@ -134,11 +200,15 @@ class Term
|
|||
continue;
|
||||
}
|
||||
|
||||
$type = TERM_HASHTAG;
|
||||
$type = self::HASHTAG;
|
||||
$term = substr($tag, 1);
|
||||
$link = '';
|
||||
} elseif ((substr(trim($tag), 0, 1) == '@') || (substr(trim($tag), 0, 1) == '!')) {
|
||||
$type = TERM_MENTION;
|
||||
} elseif (self::isType($tag, self::MENTION, self::EXCLUSIVE_MENTION, self::IMPLICIT_MENTION)) {
|
||||
if (self::isType($tag, self::MENTION, self::EXCLUSIVE_MENTION)) {
|
||||
$type = self::MENTION;
|
||||
} else {
|
||||
$type = self::IMPLICIT_MENTION;
|
||||
}
|
||||
|
||||
$contact = Contact::getDetailsByURL($link, 0);
|
||||
if (!empty($contact['name'])) {
|
||||
|
@ -147,43 +217,51 @@ class Term
|
|||
$term = substr($tag, 1);
|
||||
}
|
||||
} else { // This shouldn't happen
|
||||
$type = TERM_HASHTAG;
|
||||
$type = self::HASHTAG;
|
||||
$term = $tag;
|
||||
$link = '';
|
||||
|
||||
Logger::notice('Unknown term type', ['tag' => $tag]);
|
||||
}
|
||||
|
||||
if (DBA::exists('term', ['uid' => $message['uid'], 'otype' => TERM_OBJ_POST, 'oid' => $itemid, 'term' => $term])) {
|
||||
if (DBA::exists('term', ['uid' => $item['uid'], 'otype' => self::OBJECT_TYPE_POST, 'oid' => $item_id, 'term' => $term, 'type' => $type])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($message['uid'] == 0) {
|
||||
if ($item['uid'] == 0) {
|
||||
$global = true;
|
||||
DBA::update('term', ['global' => true], ['otype' => TERM_OBJ_POST, 'guid' => $message['guid']]);
|
||||
DBA::update('term', ['global' => true], ['otype' => self::OBJECT_TYPE_POST, 'guid' => $item['guid']]);
|
||||
} else {
|
||||
$global = DBA::exists('term', ['uid' => 0, 'otype' => TERM_OBJ_POST, 'guid' => $message['guid']]);
|
||||
$global = DBA::exists('term', ['uid' => 0, 'otype' => self::OBJECT_TYPE_POST, 'guid' => $item['guid']]);
|
||||
}
|
||||
|
||||
DBA::insert('term', [
|
||||
'uid' => $message['uid'],
|
||||
'oid' => $itemid,
|
||||
'otype' => TERM_OBJ_POST,
|
||||
'uid' => $item['uid'],
|
||||
'oid' => $item_id,
|
||||
'otype' => self::OBJECT_TYPE_POST,
|
||||
'type' => $type,
|
||||
'term' => $term,
|
||||
'url' => $link,
|
||||
'guid' => $message['guid'],
|
||||
'created' => $message['created'],
|
||||
'received' => $message['received'],
|
||||
'guid' => $item['guid'],
|
||||
'created' => $item['created'],
|
||||
'received' => $item['received'],
|
||||
'global' => $global
|
||||
]);
|
||||
|
||||
// Search for mentions
|
||||
if (((substr($tag, 0, 1) == '@') || (substr($tag, 0, 1) == '!')) && (strpos($link, $profile_base_friendica) || strpos($link, $profile_base_diaspora))) {
|
||||
$users = q("SELECT `uid` FROM `contact` WHERE self AND (`url` = '%s' OR `nurl` = '%s')", $link, $link);
|
||||
if (self::isType($tag, self::MENTION, self::EXCLUSIVE_MENTION)
|
||||
&& (
|
||||
strpos($link, $profile_base_friendica) !== false
|
||||
|| strpos($link, $profile_base_diaspora) !== false
|
||||
)
|
||||
) {
|
||||
$users_stmt = DBA::p("SELECT `uid` FROM `contact` WHERE self AND (`url` = ? OR `nurl` = ?)", $link, $link);
|
||||
$users = DBA::toArray($users_stmt);
|
||||
foreach ($users AS $user) {
|
||||
if ($user['uid'] == $message['uid']) {
|
||||
/// @todo This function is called frim Item::update - so we mustn't call that function here
|
||||
DBA::update('item', ['mention' => true], ['id' => $itemid]);
|
||||
DBA::update('thread', ['mention' => true], ['iid' => $message['parent']]);
|
||||
if ($user['uid'] == $item['uid']) {
|
||||
/// @todo This function is called from Item::update - so we mustn't call that function here
|
||||
DBA::update('item', ['mention' => true], ['id' => $item_id]);
|
||||
DBA::update('thread', ['mention' => true], ['iid' => $item['parent']]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -191,20 +269,23 @@ class Term
|
|||
}
|
||||
|
||||
/**
|
||||
* @param integer $itemid item id
|
||||
* Inserts new terms for the provided item ID based on the legacy item.file field BBCode content.
|
||||
* Deletes all previous file terms for the same item ID.
|
||||
*
|
||||
* @param integer $item_id item id
|
||||
* @param $files
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function insertFromFileFieldByItemId($itemid, $files)
|
||||
public static function insertFromFileFieldByItemId($item_id, $files)
|
||||
{
|
||||
$message = Item::selectFirst(['uid', 'deleted'], ['id' => $itemid]);
|
||||
$message = Item::selectFirst(['uid', 'deleted'], ['id' => $item_id]);
|
||||
if (!DBA::isResult($message)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clean up all tags
|
||||
DBA::delete('term', ['otype' => TERM_OBJ_POST, 'oid' => $itemid, 'type' => [TERM_FILE, TERM_CATEGORY]]);
|
||||
DBA::delete('term', ['otype' => self::OBJECT_TYPE_POST, 'oid' => $item_id, 'type' => [self::FILE, self::CATEGORY]]);
|
||||
|
||||
if ($message["deleted"]) {
|
||||
return;
|
||||
|
@ -216,9 +297,9 @@ class Term
|
|||
foreach ($files[1] as $file) {
|
||||
DBA::insert('term', [
|
||||
'uid' => $message["uid"],
|
||||
'oid' => $itemid,
|
||||
'otype' => TERM_OBJ_POST,
|
||||
'type' => TERM_FILE,
|
||||
'oid' => $item_id,
|
||||
'otype' => self::OBJECT_TYPE_POST,
|
||||
'type' => self::FILE,
|
||||
'term' => $file
|
||||
]);
|
||||
}
|
||||
|
@ -228,9 +309,9 @@ class Term
|
|||
foreach ($files[1] as $file) {
|
||||
DBA::insert('term', [
|
||||
'uid' => $message["uid"],
|
||||
'oid' => $itemid,
|
||||
'otype' => TERM_OBJ_POST,
|
||||
'type' => TERM_CATEGORY,
|
||||
'oid' => $item_id,
|
||||
'otype' => self::OBJECT_TYPE_POST,
|
||||
'type' => self::CATEGORY,
|
||||
'term' => $file
|
||||
]);
|
||||
}
|
||||
|
@ -252,6 +333,7 @@ class Term
|
|||
'tags' => [],
|
||||
'hashtags' => [],
|
||||
'mentions' => [],
|
||||
'implicit_mentions' => [],
|
||||
];
|
||||
|
||||
$searchpath = System::baseUrl() . "/search?tag=";
|
||||
|
@ -259,10 +341,9 @@ class Term
|
|||
$taglist = DBA::select(
|
||||
'term',
|
||||
['type', 'term', 'url'],
|
||||
["`otype` = ? AND `oid` = ? AND `type` IN (?, ?)", TERM_OBJ_POST, $item['id'], TERM_HASHTAG, TERM_MENTION],
|
||||
['otype' => self::OBJECT_TYPE_POST, 'oid' => $item['id'], 'type' => [self::HASHTAG, self::MENTION, self::IMPLICIT_MENTION]],
|
||||
['order' => ['tid']]
|
||||
);
|
||||
|
||||
while ($tag = DBA::fetch($taglist)) {
|
||||
if ($tag['url'] == '') {
|
||||
$tag['url'] = $searchpath . rawurlencode($tag['term']);
|
||||
|
@ -270,24 +351,25 @@ class Term
|
|||
|
||||
$orig_tag = $tag['url'];
|
||||
|
||||
$author = ['uid' => 0, 'id' => $item['author-id'],
|
||||
'network' => $item['author-network'], 'url' => $item['author-link']];
|
||||
$tag['url'] = Contact::magicLinkByContact($author, $tag['url']);
|
||||
$prefix = self::TAG_CHARACTER[$tag['type']];
|
||||
switch($tag['type']) {
|
||||
case self::HASHTAG:
|
||||
if ($orig_tag != $tag['url']) {
|
||||
$item['body'] = str_replace($orig_tag, $tag['url'], $item['body']);
|
||||
}
|
||||
|
||||
$prefix = '';
|
||||
if ($tag['type'] == TERM_HASHTAG) {
|
||||
if ($orig_tag != $tag['url']) {
|
||||
$item['body'] = str_replace($orig_tag, $tag['url'], $item['body']);
|
||||
}
|
||||
|
||||
$return['hashtags'][] = '#<a href="' . $tag['url'] . '" target="_blank">' . $tag['term'] . '</a>';
|
||||
$prefix = '#';
|
||||
} elseif ($tag['type'] == TERM_MENTION) {
|
||||
$return['mentions'][] = '@<a href="' . $tag['url'] . '" target="_blank">' . $tag['term'] . '</a>';
|
||||
$prefix = '@';
|
||||
$return['hashtags'][] = $prefix . '<a href="' . $tag['url'] . '" target="_blank">' . $tag['term'] . '</a>';
|
||||
$return['tags'][] = $prefix . '<a href="' . $tag['url'] . '" target="_blank">' . $tag['term'] . '</a>';
|
||||
break;
|
||||
case self::MENTION:
|
||||
$tag['url'] = Contact::magicLink($tag['url']);
|
||||
$return['mentions'][] = $prefix . '<a href="' . $tag['url'] . '" target="_blank">' . $tag['term'] . '</a>';
|
||||
$return['tags'][] = $prefix . '<a href="' . $tag['url'] . '" target="_blank">' . $tag['term'] . '</a>';
|
||||
break;
|
||||
case self::IMPLICIT_MENTION:
|
||||
$return['implicit_mentions'][] = $prefix . $tag['term'];
|
||||
break;
|
||||
}
|
||||
|
||||
$return['tags'][] = $prefix . '<a href="' . $tag['url'] . '" target="_blank">' . $tag['term'] . '</a>';
|
||||
}
|
||||
DBA::close($taglist);
|
||||
|
||||
|
@ -295,20 +377,38 @@ class Term
|
|||
}
|
||||
|
||||
/**
|
||||
* Delete all tags from an item
|
||||
* Delete tags of the specific type(s) from an item
|
||||
*
|
||||
* @param int itemid - choose from which item the tags will be removed
|
||||
* @param array $type
|
||||
* @param int $item_id
|
||||
* @param int|array $type
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function deleteByItemId($itemid, $type = [TERM_HASHTAG, TERM_MENTION])
|
||||
public static function deleteByItemId($item_id, $type = [self::HASHTAG, self::MENTION, self::IMPLICIT_MENTION])
|
||||
{
|
||||
if (empty($itemid)) {
|
||||
if (empty($item_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clean up all tags
|
||||
DBA::delete('term', ['otype' => TERM_OBJ_POST, 'oid' => $itemid, 'type' => $type]);
|
||||
DBA::delete('term', ['otype' => self::OBJECT_TYPE_POST, 'oid' => $item_id, 'type' => $type]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the provided tag is of one of the provided term types.
|
||||
*
|
||||
* @param string $tag
|
||||
* @param int ...$types
|
||||
* @return bool
|
||||
*/
|
||||
public static function isType($tag, ...$types)
|
||||
{
|
||||
$tag_chars = [];
|
||||
foreach ($types as $type) {
|
||||
if (isset(self::TAG_CHARACTER[$type])) {
|
||||
$tag_chars[] = self::TAG_CHARACTER[$type];
|
||||
}
|
||||
}
|
||||
|
||||
return Strings::startsWith($tag, $tag_chars);
|
||||
}
|
||||
}
|
||||
|
|
350
src/Module/Group.php
Normal file
350
src/Module/Group.php
Normal file
|
@ -0,0 +1,350 @@
|
|||
<?php
|
||||
/**
|
||||
* @file src/Module/Group.php
|
||||
*/
|
||||
|
||||
namespace Friendica\Module;
|
||||
|
||||
use Friendica\BaseModule;
|
||||
use Friendica\Core\Config;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\PConfig;
|
||||
use Friendica\Core\Renderer;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Model;
|
||||
use Friendica\Util\Strings;
|
||||
|
||||
require_once 'boot.php';
|
||||
|
||||
class Group extends BaseModule
|
||||
{
|
||||
public static function post()
|
||||
{
|
||||
$a = self::getApp();
|
||||
|
||||
if ($a->isAjax()) {
|
||||
self::ajaxPost();
|
||||
}
|
||||
|
||||
if (!local_user()) {
|
||||
notice(L10n::t('Permission denied.'));
|
||||
$a->internalRedirect();
|
||||
}
|
||||
|
||||
if (($a->argc == 2) && ($a->argv[1] === 'new')) {
|
||||
BaseModule::checkFormSecurityTokenRedirectOnError('/group/new', 'group_edit');
|
||||
|
||||
$name = Strings::escapeTags(trim($_POST['groupname']));
|
||||
$r = Model\Group::create(local_user(), $name);
|
||||
if ($r) {
|
||||
info(L10n::t('Group created.'));
|
||||
$r = Model\Group::getIdByName(local_user(), $name);
|
||||
if ($r) {
|
||||
$a->internalRedirect('group/' . $r);
|
||||
}
|
||||
} else {
|
||||
notice(L10n::t('Could not create group.'));
|
||||
}
|
||||
$a->internalRedirect('group');
|
||||
}
|
||||
|
||||
if (($a->argc == 2) && intval($a->argv[1])) {
|
||||
BaseModule::checkFormSecurityTokenRedirectOnError('/group', 'group_edit');
|
||||
|
||||
$group = DBA::selectFirst('group', ['id', 'name'], ['id' => $a->argv[1], 'uid' => local_user()]);
|
||||
if (!DBA::isResult($group)) {
|
||||
notice(L10n::t('Group not found.'));
|
||||
$a->internalRedirect('contact');
|
||||
}
|
||||
$groupname = Strings::escapeTags(trim($_POST['groupname']));
|
||||
if (strlen($groupname) && ($groupname != $group['name'])) {
|
||||
if (Model\Group::update($group['id'], $groupname)) {
|
||||
info(L10n::t('Group name changed.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function ajaxPost()
|
||||
{
|
||||
try {
|
||||
$a = self::getApp();
|
||||
|
||||
if (!local_user()) {
|
||||
throw new \Exception(L10n::t('Permission denied.'), 403);
|
||||
}
|
||||
|
||||
// POST /group/123/add/123
|
||||
// POST /group/123/remove/123
|
||||
if ($a->argc == 4) {
|
||||
list($group_id, $command, $contact_id) = array_slice($a->argv, 1);
|
||||
|
||||
if (!Model\Group::exists($group_id, local_user())) {
|
||||
throw new \Exception(L10n::t('Unknown group.'), 404);
|
||||
}
|
||||
|
||||
$contact = DBA::selectFirst('contact', ['pending', 'blocked', 'deleted'], ['id' => $contact_id, 'uid' => local_user()]);
|
||||
if (!DBA::isResult($contact)) {
|
||||
throw new \Exception(L10n::t('Contact not found.'), 404);
|
||||
}
|
||||
|
||||
if ($contact['pending']) {
|
||||
throw new \Exception(L10n::t('Contact is unavailable.'), 400);
|
||||
}
|
||||
|
||||
if ($contact['deleted']) {
|
||||
throw new \Exception(L10n::t('Contact is deleted.'), 410);
|
||||
}
|
||||
|
||||
switch($command) {
|
||||
case 'add':
|
||||
if ($contact['blocked']) {
|
||||
throw new \Exception(L10n::t('Contact is blocked, unable to add it to a group.'), 400);
|
||||
}
|
||||
|
||||
if (!Model\Group::addMember($group_id, $contact_id)) {
|
||||
throw new \Exception(L10n::t('Unable to add the contact to the group.'), 500);
|
||||
}
|
||||
$message = L10n::t('Contact successfully added to group.');
|
||||
break;
|
||||
case 'remove':
|
||||
if (!Model\Group::removeMember($group_id, $contact_id)) {
|
||||
throw new \Exception(L10n::t('Unable to remove the contact from the group.'), 500);
|
||||
}
|
||||
$message = L10n::t('Contact successfully removed from group.');
|
||||
break;
|
||||
default:
|
||||
throw new \Exception(L10n::t('Unknown group command.'), 400);
|
||||
}
|
||||
} else {
|
||||
throw new \Exception(L10n::t('Bad request.'), 400);
|
||||
}
|
||||
|
||||
notice($message);
|
||||
System::jsonExit(['status' => 'OK', 'message' => $message]);
|
||||
} catch (\Exception $e) {
|
||||
notice($e->getMessage());
|
||||
System::jsonError($e->getCode(), ['status' => 'error', 'message' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
public static function content()
|
||||
{
|
||||
$change = false;
|
||||
|
||||
if (!local_user()) {
|
||||
System::httpExit(403);
|
||||
}
|
||||
|
||||
$a = self::getApp();
|
||||
|
||||
$a->page['aside'] = Model\Group::sidebarWidget('contact', 'group', 'extended', (($a->argc > 1) ? $a->argv[1] : 'everyone'));
|
||||
|
||||
// With no group number provided we jump to the unassigned contacts as a starting point
|
||||
if ($a->argc == 1) {
|
||||
$a->internalRedirect('group/none');
|
||||
}
|
||||
|
||||
// Switch to text mode interface if we have more than 'n' contacts or group members
|
||||
$switchtotext = PConfig::get(local_user(), 'system', 'groupedit_image_limit');
|
||||
if (is_null($switchtotext)) {
|
||||
$switchtotext = Config::get('system', 'groupedit_image_limit', 200);
|
||||
}
|
||||
|
||||
$tpl = Renderer::getMarkupTemplate('group_edit.tpl');
|
||||
|
||||
|
||||
$context = [
|
||||
'$submit' => L10n::t('Save Group'),
|
||||
'$submit_filter' => L10n::t('Filter'),
|
||||
];
|
||||
|
||||
if (($a->argc == 2) && ($a->argv[1] === 'new')) {
|
||||
return Renderer::replaceMacros($tpl, $context + [
|
||||
'$title' => L10n::t('Create a group of contacts/friends.'),
|
||||
'$gname' => ['groupname', L10n::t('Group Name: '), '', ''],
|
||||
'$gid' => 'new',
|
||||
'$form_security_token' => BaseModule::getFormSecurityToken("group_edit"),
|
||||
]);
|
||||
}
|
||||
|
||||
$nogroup = false;
|
||||
|
||||
if (($a->argc == 2) && ($a->argv[1] === 'none')) {
|
||||
$id = -1;
|
||||
$nogroup = true;
|
||||
$group = [
|
||||
'id' => $id,
|
||||
'name' => L10n::t('Contacts not in any group'),
|
||||
];
|
||||
|
||||
$members = [];
|
||||
$preselected = [];
|
||||
|
||||
$context = $context + [
|
||||
'$title' => $group['name'],
|
||||
'$gname' => ['groupname', L10n::t('Group Name: '), $group['name'], ''],
|
||||
'$gid' => $id,
|
||||
'$editable' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
if (($a->argc == 3) && ($a->argv[1] === 'drop')) {
|
||||
BaseModule::checkFormSecurityTokenRedirectOnError('/group', 'group_drop', 't');
|
||||
|
||||
if (intval($a->argv[2])) {
|
||||
if (!Model\Group::exists($a->argv[2], local_user())) {
|
||||
notice(L10n::t('Group not found.'));
|
||||
$a->internalRedirect('contact');
|
||||
}
|
||||
|
||||
if (Model\Group::remove($a->argv[2])) {
|
||||
info(L10n::t('Group removed.'));
|
||||
} else {
|
||||
notice(L10n::t('Unable to remove group.'));
|
||||
}
|
||||
}
|
||||
$a->internalRedirect('group');
|
||||
}
|
||||
|
||||
if (($a->argc > 2) && intval($a->argv[1]) && intval($a->argv[2])) {
|
||||
BaseModule::checkFormSecurityTokenForbiddenOnError('group_member_change', 't');
|
||||
|
||||
if (DBA::exists('contact', ['id' => $a->argv[2], 'uid' => local_user(), 'self' => false, 'pending' => false, 'blocked' => false])) {
|
||||
$change = intval($a->argv[2]);
|
||||
}
|
||||
}
|
||||
|
||||
if (($a->argc > 1) && intval($a->argv[1])) {
|
||||
$group = DBA::selectFirst('group', ['id', 'name'], ['id' => $a->argv[1], 'uid' => local_user(), 'deleted' => false]);
|
||||
if (!DBA::isResult($group)) {
|
||||
notice(L10n::t('Group not found.'));
|
||||
$a->internalRedirect('contact');
|
||||
}
|
||||
|
||||
$members = Model\Contact::getByGroupId($group['id']);
|
||||
$preselected = [];
|
||||
|
||||
if (count($members)) {
|
||||
foreach ($members as $member) {
|
||||
$preselected[] = $member['id'];
|
||||
}
|
||||
}
|
||||
|
||||
if ($change) {
|
||||
if (in_array($change, $preselected)) {
|
||||
Model\Group::removeMember($group['id'], $change);
|
||||
} else {
|
||||
Model\Group::addMember($group['id'], $change);
|
||||
}
|
||||
|
||||
$members = Model\Contact::getByGroupId($group['id']);
|
||||
$preselected = [];
|
||||
if (count($members)) {
|
||||
foreach ($members as $member) {
|
||||
$preselected[] = $member['id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$drop_tpl = Renderer::getMarkupTemplate('group_drop.tpl');
|
||||
$drop_txt = Renderer::replaceMacros($drop_tpl, [
|
||||
'$id' => $group['id'],
|
||||
'$delete' => L10n::t('Delete Group'),
|
||||
'$form_security_token' => BaseModule::getFormSecurityToken("group_drop"),
|
||||
]);
|
||||
|
||||
$context = $context + [
|
||||
'$title' => $group['name'],
|
||||
'$gname' => ['groupname', L10n::t('Group Name: '), $group['name'], ''],
|
||||
'$gid' => $group['id'],
|
||||
'$drop' => $drop_txt,
|
||||
'$form_security_token' => BaseModule::getFormSecurityToken('group_edit'),
|
||||
'$edit_name' => L10n::t('Edit Group Name'),
|
||||
'$editable' => 1,
|
||||
];
|
||||
}
|
||||
|
||||
if (!isset($group)) {
|
||||
System::httpExit(400);
|
||||
}
|
||||
|
||||
$groupeditor = [
|
||||
'label_members' => L10n::t('Members'),
|
||||
'members' => [],
|
||||
'label_contacts' => L10n::t('All Contacts'),
|
||||
'group_is_empty' => L10n::t('Group is empty'),
|
||||
'contacts' => [],
|
||||
];
|
||||
|
||||
$sec_token = addslashes(BaseModule::getFormSecurityToken('group_member_change'));
|
||||
|
||||
// Format the data of the group members
|
||||
foreach ($members as $member) {
|
||||
if ($member['url']) {
|
||||
$entry = Contact::getContactTemplateVars($member);
|
||||
$entry['label'] = 'members';
|
||||
$entry['photo_menu'] = '';
|
||||
$entry['change_member'] = [
|
||||
'title' => L10n::t("Remove contact from group"),
|
||||
'gid' => $group['id'],
|
||||
'cid' => $member['id'],
|
||||
'sec_token' => $sec_token
|
||||
];
|
||||
|
||||
$groupeditor['members'][] = $entry;
|
||||
} else {
|
||||
Model\Group::removeMember($group['id'], $member['id']);
|
||||
}
|
||||
}
|
||||
|
||||
if ($nogroup) {
|
||||
$contacts = Model\Contact::getUngroupedList(local_user());
|
||||
} else {
|
||||
$contacts_stmt = DBA::select('contact', [],
|
||||
['uid' => local_user(), 'pending' => false, 'blocked' => false, 'self' => false],
|
||||
['order' => ['name']]
|
||||
);
|
||||
$contacts = DBA::toArray($contacts_stmt);
|
||||
$context['$desc'] = L10n::t('Click on a contact to add or remove.');
|
||||
}
|
||||
|
||||
if (DBA::isResult($contacts)) {
|
||||
// Format the data of the contacts who aren't in the contact group
|
||||
foreach ($contacts as $member) {
|
||||
if (!in_array($member['id'], $preselected)) {
|
||||
$entry = Contact::getContactTemplateVars($member);
|
||||
$entry['label'] = 'contacts';
|
||||
if (!$nogroup)
|
||||
$entry['photo_menu'] = [];
|
||||
|
||||
if (!$nogroup) {
|
||||
$entry['change_member'] = [
|
||||
'title' => L10n::t("Add contact to group"),
|
||||
'gid' => $group['id'],
|
||||
'cid' => $member['id'],
|
||||
'sec_token' => $sec_token
|
||||
];
|
||||
}
|
||||
|
||||
$groupeditor['contacts'][] = $entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$context['$groupeditor'] = $groupeditor;
|
||||
|
||||
// If there are to many contacts we could provide an alternative view mode
|
||||
$total = count($groupeditor['members']) + count($groupeditor['contacts']);
|
||||
$context['$shortmode'] = (($switchtotext && ($total > $switchtotext)) ? true : false);
|
||||
|
||||
if ($change) {
|
||||
$tpl = Renderer::getMarkupTemplate('groupeditor.tpl');
|
||||
echo Renderer::replaceMacros($tpl, $context);
|
||||
exit();
|
||||
}
|
||||
|
||||
return Renderer::replaceMacros($tpl, $context);
|
||||
}
|
||||
}
|
|
@ -43,6 +43,10 @@ class Install extends BaseModule
|
|||
{
|
||||
$a = self::getApp();
|
||||
|
||||
if (!$a->getMode()->isInstall()) {
|
||||
Core\System::httpExit(403);
|
||||
}
|
||||
|
||||
// route: install/testrwrite
|
||||
// $baseurl/install/testrwrite to test if rewrite in .htaccess is working
|
||||
if ($a->getArgumentValue(1, '') == 'testrewrite') {
|
||||
|
@ -75,7 +79,7 @@ class Install extends BaseModule
|
|||
$dbdata = Strings::escapeTags(trim(defaults($_POST, 'dbdata', '')));
|
||||
|
||||
// If we cannot connect to the database, return to the previous step
|
||||
if (!self::$installer->checkDB($a->getConfig(), $dbhost, $dbuser, $dbpass, $dbdata)) {
|
||||
if (!self::$installer->checkDB($a->getBasePath(), $a->getConfigCache(), $a->getProfiler(), $dbhost, $dbuser, $dbpass, $dbdata)) {
|
||||
self::$currentWizardStep = self::DATABASE_CONFIG;
|
||||
}
|
||||
|
||||
|
@ -92,7 +96,7 @@ class Install extends BaseModule
|
|||
$adminmail = Strings::escapeTags(trim(defaults($_POST, 'adminmail', '')));
|
||||
|
||||
// If we cannot connect to the database, return to the Database config wizard
|
||||
if (!self::$installer->checkDB($a->getConfig(), $dbhost, $dbuser, $dbpass, $dbdata)) {
|
||||
if (!self::$installer->checkDB($a->getBasePath(), $a->getConfigCache(), $a->getProfiler(), $dbhost, $dbuser, $dbpass, $dbdata)) {
|
||||
self::$currentWizardStep = self::DATABASE_CONFIG;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -2,9 +2,12 @@
|
|||
|
||||
namespace Friendica\Module;
|
||||
|
||||
use Friendica\Content\Text\HTML;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\Renderer;
|
||||
use Friendica\Model;
|
||||
use Friendica\Protocol\ActivityPub\Processor;
|
||||
use Friendica\Protocol\Diaspora;
|
||||
|
||||
/**
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
|
@ -27,20 +30,27 @@ class Itemsource extends \Friendica\BaseModule
|
|||
|
||||
$source = '';
|
||||
$item_uri = '';
|
||||
$item_id = '';
|
||||
$terms = [];
|
||||
if (!empty($guid)) {
|
||||
$item = Model\Item::selectFirst([], ['guid' => $guid]);
|
||||
$item = Model\Item::selectFirst(['id', 'guid', 'uri'], ['guid' => $guid]);
|
||||
|
||||
$conversation = Model\Conversation::getByItemUri($item['uri']);
|
||||
|
||||
$guid = $item['guid'];
|
||||
$item_id = $item['id'];
|
||||
$item_uri = $item['uri'];
|
||||
$source = $conversation['source'];
|
||||
$terms = Model\Term::tagArrayFromItemId($item['id'], [Model\Term::HASHTAG, Model\Term::MENTION, Model\Term::IMPLICIT_MENTION]);
|
||||
}
|
||||
|
||||
$tpl = Renderer::getMarkupTemplate('debug/itemsource.tpl');
|
||||
$o = Renderer::replaceMacros($tpl, [
|
||||
'$guid' => ['guid', L10n::t('Item Guid'), defaults($_REQUEST, 'guid', ''), ''],
|
||||
'$guid' => ['guid', L10n::t('Item Guid'), $guid, ''],
|
||||
'$source' => $source,
|
||||
'$item_uri' => $item_uri
|
||||
'$item_uri' => $item_uri,
|
||||
'$item_id' => $item_id,
|
||||
'$terms' => $terms,
|
||||
]);
|
||||
|
||||
return $o;
|
||||
|
|
|
@ -156,7 +156,7 @@ class Probe
|
|||
continue;
|
||||
}
|
||||
|
||||
if (($attributes["rel"] == "lrdd") && !empty($attributes["template"])) {
|
||||
if (!empty($attributes["rel"]) && $attributes["rel"] == "lrdd" && !empty($attributes["template"])) {
|
||||
$type = (empty($attributes["type"]) ? '' : $attributes["type"]);
|
||||
|
||||
$lrdd[$type] = $attributes["template"];
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
namespace Friendica\Object;
|
||||
|
||||
use Exception;
|
||||
use Friendica\App;
|
||||
use Friendica\Core\Cache;
|
||||
use Friendica\Core\Config;
|
||||
|
@ -14,7 +15,6 @@ use Friendica\Core\System;
|
|||
use Friendica\Database\DBA;
|
||||
use Friendica\Model\Photo;
|
||||
use Friendica\Util\Network;
|
||||
use Exception;
|
||||
use Imagick;
|
||||
use ImagickPixel;
|
||||
|
||||
|
@ -656,7 +656,7 @@ class Image
|
|||
|
||||
$stamp1 = microtime(true);
|
||||
file_put_contents($path, $string);
|
||||
$a->saveTimestamp($stamp1, "file");
|
||||
$a->getProfiler()->saveTimestamp($stamp1, "file", System::callstack());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -802,7 +802,7 @@ class Image
|
|||
$a = \get_app();
|
||||
$stamp1 = microtime(true);
|
||||
file_put_contents($tempfile, $img_str);
|
||||
$a->saveTimestamp($stamp1, "file");
|
||||
$a->getProfiler()->saveTimestamp($stamp1, "file", System::callstack());
|
||||
|
||||
$data = getimagesize($tempfile);
|
||||
unlink($tempfile);
|
||||
|
@ -910,7 +910,7 @@ class Image
|
|||
|
||||
$stamp1 = microtime(true);
|
||||
$imagedata = @file_get_contents($url);
|
||||
$a->saveTimestamp($stamp1, "file");
|
||||
$a->getProfiler()->saveTimestamp($stamp1, "file", System::callstack());
|
||||
}
|
||||
|
||||
$maximagesize = Config::get('system', 'maximagesize');
|
||||
|
@ -924,7 +924,7 @@ class Image
|
|||
|
||||
$stamp1 = microtime(true);
|
||||
file_put_contents($tempfile, $imagedata);
|
||||
$a->saveTimestamp($stamp1, "file");
|
||||
$a->getProfiler()->saveTimestamp($stamp1, "file", System::callstack());
|
||||
|
||||
$data = getimagesize($tempfile);
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ use Friendica\Database\DBA;
|
|||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Item;
|
||||
use Friendica\Model\Term;
|
||||
use Friendica\Model\User;
|
||||
use Friendica\Util\Crypto;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
use Friendica\Util\Proxy as ProxyUtils;
|
||||
|
@ -82,7 +83,7 @@ class Post extends BaseObject
|
|||
$author = ['uid' => 0, 'id' => $this->getDataValue('author-id'),
|
||||
'network' => $this->getDataValue('author-network'),
|
||||
'url' => $this->getDataValue('author-link')];
|
||||
$this->redirect_url = Contact::magicLinkbyContact($author);
|
||||
$this->redirect_url = Contact::magicLinkByContact($author);
|
||||
if (!$this->isToplevel()) {
|
||||
$this->threaded = true;
|
||||
}
|
||||
|
@ -223,7 +224,7 @@ class Post extends BaseObject
|
|||
'network' => $item['author-network'], 'url' => $item['author-link']];
|
||||
|
||||
if (local_user() || remote_user()) {
|
||||
$profile_link = Contact::magicLinkbyContact($author);
|
||||
$profile_link = Contact::magicLinkByContact($author);
|
||||
} else {
|
||||
$profile_link = $item['author-link'];
|
||||
}
|
||||
|
@ -365,6 +366,7 @@ class Post extends BaseObject
|
|||
'tags' => $tags['tags'],
|
||||
'hashtags' => $tags['hashtags'],
|
||||
'mentions' => $tags['mentions'],
|
||||
'implicit_mentions' => $tags['implicit_mentions'],
|
||||
'txt_cats' => L10n::t('Categories:'),
|
||||
'txt_folders' => L10n::t('Filed under:'),
|
||||
'has_cats' => ((count($categories)) ? 'true' : ''),
|
||||
|
@ -415,6 +417,7 @@ class Post extends BaseObject
|
|||
'dislike' => $responses['dislike']['output'],
|
||||
'responses' => $responses,
|
||||
'switchcomment' => L10n::t('Comment'),
|
||||
'reply_label' => L10n::t('Reply to %s', $name_e),
|
||||
'comment' => $comment,
|
||||
'previewing' => $conv->isPreview() ? ' preview ' : '',
|
||||
'wait' => L10n::t('Please wait'),
|
||||
|
@ -449,13 +452,13 @@ class Post extends BaseObject
|
|||
foreach ($children as $child) {
|
||||
$result['children'][] = $child->getTemplateData($conv_responses, $thread_level + 1);
|
||||
}
|
||||
|
||||
// Collapse
|
||||
if (($nb_children > 2) || ($thread_level > 1)) {
|
||||
$result['children'][0]['comment_firstcollapsed'] = true;
|
||||
$result['children'][0]['num_comments'] = L10n::tt('%d comment', '%d comments', $total_children);
|
||||
$result['children'][0]['hidden_comments_num'] = $total_children;
|
||||
$result['children'][0]['hidden_comments_text'] = L10n::tt('comment', 'comments', $total_children);
|
||||
$result['children'][0]['hide_text'] = L10n::t('show more');
|
||||
$result['children'][0]['show_text'] = L10n::t('Show more');
|
||||
$result['children'][0]['hide_text'] = L10n::t('Show fewer');
|
||||
if ($thread_level > 1) {
|
||||
$result['children'][$nb_children - 1]['comment_lastcollapsed'] = true;
|
||||
} else {
|
||||
|
@ -780,10 +783,12 @@ class Post extends BaseObject
|
|||
{
|
||||
$a = self::getApp();
|
||||
|
||||
if (!local_user() || empty($a->profile['addr'])) {
|
||||
if (!local_user()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$owner = User::getOwnerDataById($a->user['uid']);
|
||||
|
||||
if (!Feature::isEnabled(local_user(), 'explicit_mentions')) {
|
||||
return '';
|
||||
}
|
||||
|
@ -794,18 +799,18 @@ class Post extends BaseObject
|
|||
return '';
|
||||
}
|
||||
|
||||
if ($item['author-addr'] != $a->profile['addr']) {
|
||||
if ($item['author-addr'] != $owner['addr']) {
|
||||
$text = '@' . $item['author-addr'] . ' ';
|
||||
} else {
|
||||
$text = '';
|
||||
}
|
||||
|
||||
$terms = Term::tagArrayFromItemId($this->getId(), TERM_MENTION);
|
||||
$terms = Term::tagArrayFromItemId($this->getId(), [Term::MENTION, Term::IMPLICIT_MENTION]);
|
||||
|
||||
foreach ($terms as $term) {
|
||||
$profile = Contact::getDetailsByURL($term['url']);
|
||||
if (!empty($profile['addr']) && ($profile['contact-type'] != Contact::TYPE_COMMUNITY) &&
|
||||
($profile['addr'] != $a->profile['addr']) && !strstr($text, $profile['addr'])) {
|
||||
if (!empty($profile['addr']) && !empty($profile['contact-type']) && ($profile['contact-type'] != Contact::TYPE_COMMUNITY) &&
|
||||
($profile['addr'] != $owner['addr']) && !strstr($text, $profile['addr'])) {
|
||||
$text .= '@' . $profile['addr'] . ' ';
|
||||
}
|
||||
}
|
||||
|
@ -944,7 +949,7 @@ class Post extends BaseObject
|
|||
$owner = ['uid' => 0, 'id' => $this->getDataValue('owner-id'),
|
||||
'network' => $this->getDataValue('owner-network'),
|
||||
'url' => $this->getDataValue('owner-link')];
|
||||
$this->owner_url = Contact::magicLinkbyContact($owner);
|
||||
$this->owner_url = Contact::magicLinkByContact($owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ class Processor
|
|||
* @param array $implicit_mentions List of profile URLs to skip
|
||||
* @return string with tags
|
||||
*/
|
||||
private static function constructTagString($tags, $sensitive, array $implicit_mentions)
|
||||
private static function constructTagString(array $tags, $sensitive)
|
||||
{
|
||||
if (empty($tags)) {
|
||||
return '';
|
||||
|
@ -73,7 +73,7 @@ class Processor
|
|||
|
||||
$tag_text = '';
|
||||
foreach ($tags as $tag) {
|
||||
if (in_array(defaults($tag, 'type', ''), ['Mention', 'Hashtag']) && !in_array($tag['href'], $implicit_mentions)) {
|
||||
if (in_array(defaults($tag, 'type', ''), ['Mention', 'Hashtag'])) {
|
||||
if (!empty($tag_text)) {
|
||||
$tag_text .= ',';
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ class Processor
|
|||
*/
|
||||
public static function updateItem($activity)
|
||||
{
|
||||
$item = Item::selectFirst(['uri', 'parent-uri', 'gravity'], ['uri' => $activity['id']]);
|
||||
$item = Item::selectFirst(['uri', 'thr-parent', 'gravity'], ['uri' => $activity['id']]);
|
||||
if (!DBA::isResult($item)) {
|
||||
Logger::warning('Unknown item', ['uri' => $activity['id']]);
|
||||
return;
|
||||
|
@ -144,20 +144,20 @@ class Processor
|
|||
$content = self::replaceEmojis($content, $activity['emojis']);
|
||||
$content = self::convertMentions($content);
|
||||
|
||||
$implicit_mentions = [];
|
||||
if (($item['parent-uri'] != $item['uri']) && ($item['gravity'] == GRAVITY_COMMENT)) {
|
||||
$parent = Item::selectFirst(['id', 'author-link', 'alias'], ['uri' => $item['parent-uri']]);
|
||||
if (($item['thr-parent'] != $item['uri']) && ($item['gravity'] == GRAVITY_COMMENT)) {
|
||||
$parent = Item::selectFirst(['id', 'author-link', 'alias'], ['uri' => $item['thr-parent']]);
|
||||
if (!DBA::isResult($parent)) {
|
||||
Logger::warning('Unknown parent item.', ['uri' => $item['parent-uri']]);
|
||||
Logger::warning('Unknown parent item.', ['uri' => $item['thr-parent']]);
|
||||
return;
|
||||
}
|
||||
|
||||
$implicit_mentions = self::getImplicitMentionList($parent);
|
||||
$content = self::removeImplicitMentionsFromBody($content, $implicit_mentions);
|
||||
$potential_implicit_mentions = self::getImplicitMentionList($parent);
|
||||
$content = self::removeImplicitMentionsFromBody($content, $potential_implicit_mentions);
|
||||
$activity['tags'] = self::convertImplicitMentionsInTags($activity['tags'], $potential_implicit_mentions);
|
||||
}
|
||||
|
||||
$item['body'] = $content;
|
||||
$item['tag'] = self::constructTagString($activity['tags'], $activity['sensitive'], $implicit_mentions);
|
||||
$item['tag'] = self::constructTagString($activity['tags'], $activity['sensitive']);
|
||||
|
||||
Item::update($item, ['uri' => $activity['id']]);
|
||||
}
|
||||
|
@ -173,7 +173,7 @@ class Processor
|
|||
{
|
||||
$item = [];
|
||||
$item['verb'] = ACTIVITY_POST;
|
||||
$item['parent-uri'] = $activity['reply-to-id'];
|
||||
$item['thr-parent'] = $activity['reply-to-id'];
|
||||
|
||||
if ($activity['reply-to-id'] == $activity['id']) {
|
||||
$item['gravity'] = GRAVITY_PARENT;
|
||||
|
@ -220,7 +220,7 @@ class Processor
|
|||
{
|
||||
$item = [];
|
||||
$item['verb'] = $verb;
|
||||
$item['parent-uri'] = $activity['object_id'];
|
||||
$item['thr-parent'] = $activity['object_id'];
|
||||
$item['gravity'] = GRAVITY_ACTIVITY;
|
||||
$item['object-type'] = ACTIVITY_OBJ_NOTE;
|
||||
|
||||
|
@ -275,8 +275,8 @@ class Processor
|
|||
{
|
||||
/// @todo What to do with $activity['context']?
|
||||
|
||||
if (($item['gravity'] != GRAVITY_PARENT) && !Item::exists(['uri' => $item['parent-uri']])) {
|
||||
Logger::log('Parent ' . $item['parent-uri'] . ' not found, message will be discarded.', Logger::DEBUG);
|
||||
if (($item['gravity'] != GRAVITY_PARENT) && !Item::exists(['uri' => $item['thr-parent']])) {
|
||||
Logger::info('Parent not found, message will be discarded.', ['thr-parent' => $item['thr-parent']]);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -289,7 +289,7 @@ class Processor
|
|||
$item['owner-link'] = $activity['actor'];
|
||||
$item['owner-id'] = Contact::getIdForURL($activity['actor'], 0, true);
|
||||
} else {
|
||||
Logger::log('Ignoring actor because of thread completion.', Logger::DEBUG);
|
||||
Logger::info('Ignoring actor because of thread completion.');
|
||||
$item['owner-link'] = $item['author-link'];
|
||||
$item['owner-id'] = $item['author-id'];
|
||||
}
|
||||
|
@ -299,21 +299,20 @@ class Processor
|
|||
$content = self::replaceEmojis($content, $activity['emojis']);
|
||||
$content = self::convertMentions($content);
|
||||
|
||||
$implicit_mentions = [];
|
||||
|
||||
if (($item['parent-uri'] != $item['uri']) && ($item['gravity'] == GRAVITY_COMMENT)) {
|
||||
if (($item['thr-parent'] != $item['uri']) && ($item['gravity'] == GRAVITY_COMMENT)) {
|
||||
$item_private = !in_array(0, $activity['item_receiver']);
|
||||
$parent = Item::selectFirst(['id', 'private', 'author-link', 'alias'], ['uri' => $item['parent-uri']]);
|
||||
$parent = Item::selectFirst(['id', 'private', 'author-link', 'alias'], ['uri' => $item['thr-parent']]);
|
||||
if (!DBA::isResult($parent)) {
|
||||
return;
|
||||
}
|
||||
if ($item_private && !$parent['private']) {
|
||||
Logger::log('Item ' . $item['uri'] . ' is private but the parent ' . $item['parent-uri'] . ' is not. So we drop it.');
|
||||
Logger::warning('Item is private but the parent is not. Dropping.', ['item-uri' => $item['uri'], 'thr-parent' => $item['thr-parent']]);
|
||||
return;
|
||||
}
|
||||
|
||||
$implicit_mentions = self::getImplicitMentionList($parent);
|
||||
$content = self::removeImplicitMentionsFromBody($content, $implicit_mentions);
|
||||
$potential_implicit_mentions = self::getImplicitMentionList($parent);
|
||||
$content = self::removeImplicitMentionsFromBody($content, $potential_implicit_mentions);
|
||||
$activity['tags'] = self::convertImplicitMentionsInTags($activity['tags'], $potential_implicit_mentions);
|
||||
}
|
||||
|
||||
$item['created'] = $activity['published'];
|
||||
|
@ -333,7 +332,7 @@ class Processor
|
|||
$item['coord'] = $item['latitude'] . ' ' . $item['longitude'];
|
||||
}
|
||||
|
||||
$item['tag'] = self::constructTagString($activity['tags'], $activity['sensitive'], $implicit_mentions);
|
||||
$item['tag'] = self::constructTagString($activity['tags'], $activity['sensitive']);
|
||||
$item['app'] = $activity['generator'];
|
||||
$item['plink'] = defaults($activity, 'alternate-url', $item['uri']);
|
||||
|
||||
|
@ -358,7 +357,11 @@ class Processor
|
|||
}
|
||||
|
||||
$item_id = Item::insert($item);
|
||||
Logger::log('Storing for user ' . $item['uid'] . ': ' . $item_id);
|
||||
if ($item_id) {
|
||||
Logger::info('Item insertion successful', ['user' => $item['uid'], 'item_id' => $item_id]);
|
||||
} else {
|
||||
Logger::notice('Item insertion aborted', ['user' => $item['uid']]);
|
||||
}
|
||||
|
||||
if ($item['uid'] == 0) {
|
||||
$stored = $item_id;
|
||||
|
@ -658,13 +661,24 @@ class Processor
|
|||
*/
|
||||
private static function getImplicitMentionList(array $parent)
|
||||
{
|
||||
$parent_terms = Term::tagArrayFromItemId($parent['id'], [TERM_MENTION]);
|
||||
if (Config::get('system', 'disable_implicit_mentions')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$implicit_mentions = [
|
||||
$parent['author-link']
|
||||
];
|
||||
$parent_terms = Term::tagArrayFromItemId($parent['id'], [Term::MENTION, Term::IMPLICIT_MENTION]);
|
||||
|
||||
if ($parent['alias']) {
|
||||
$parent_author = Contact::getDetailsByURL($parent['author-link'], 0);
|
||||
|
||||
$implicit_mentions = [];
|
||||
if (empty($parent_author)) {
|
||||
Logger::notice('Author public contact unknown.', ['author-link' => $parent['author-link'], 'item-id' => $parent['id']]);
|
||||
} else {
|
||||
$implicit_mentions[] = $parent_author['url'];
|
||||
$implicit_mentions[] = $parent_author['nurl'];
|
||||
$implicit_mentions[] = $parent_author['alias'];
|
||||
}
|
||||
|
||||
if (!empty($parent['alias'])) {
|
||||
$implicit_mentions[] = $parent['alias'];
|
||||
}
|
||||
|
||||
|
@ -684,12 +698,12 @@ class Processor
|
|||
* Strips from the body prepended implicit mentions
|
||||
*
|
||||
* @param string $body
|
||||
* @param array $implicit_mentions List of profile URLs
|
||||
* @param array $potential_mentions
|
||||
* @return string
|
||||
*/
|
||||
private static function removeImplicitMentionsFromBody($body, array $implicit_mentions)
|
||||
private static function removeImplicitMentionsFromBody($body, array $potential_mentions)
|
||||
{
|
||||
if (Config::get('system', 'disable_mentions_removal')) {
|
||||
if (Config::get('system', 'disable_implicit_mentions')) {
|
||||
return $body;
|
||||
}
|
||||
|
||||
|
@ -697,7 +711,7 @@ class Processor
|
|||
|
||||
// Extract one prepended mention at a time from the body
|
||||
while(preg_match('#^(@\[url=([^\]]+)].*?\[\/url]\s)(.*)#mis', $body, $matches)) {
|
||||
if (!in_array($matches[2], $implicit_mentions) ) {
|
||||
if (!in_array($matches[2], $potential_mentions) ) {
|
||||
$kept_mentions[] = $matches[1];
|
||||
}
|
||||
|
||||
|
@ -709,4 +723,50 @@ class Processor
|
|||
|
||||
return implode('', $kept_mentions);
|
||||
}
|
||||
|
||||
private static function convertImplicitMentionsInTags($activity_tags, array $potential_mentions)
|
||||
{
|
||||
if (Config::get('system', 'disable_implicit_mentions')) {
|
||||
return $activity_tags;
|
||||
}
|
||||
|
||||
foreach ($activity_tags as $index => $tag) {
|
||||
if (in_array($tag['href'], $potential_mentions)) {
|
||||
$activity_tags[$index]['name'] = preg_replace(
|
||||
'/' . preg_quote(Term::TAG_CHARACTER[Term::MENTION], '/') . '/',
|
||||
Term::TAG_CHARACTER[Term::IMPLICIT_MENTION],
|
||||
$activity_tags[$index]['name'],
|
||||
1
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $activity_tags;
|
||||
}
|
||||
|
||||
public static function testImplicitMentions($item, $source)
|
||||
{
|
||||
$parent = Item::selectFirst(['id', 'guid', 'author-link', 'alias'], ['uri' => $item['thr-parent']]);
|
||||
|
||||
$implicit_mentions = self::getImplicitMentionList($parent);
|
||||
var_dump($implicit_mentions);
|
||||
|
||||
$object = json_decode($source, true)['object'];
|
||||
var_dump($object);
|
||||
|
||||
$content = HTML::toBBCode($object['content']);
|
||||
$content = self::convertMentions($content);
|
||||
|
||||
$activity = [
|
||||
'tags' => $object['tag'],
|
||||
'content' => $content
|
||||
];
|
||||
|
||||
var_dump($activity);
|
||||
|
||||
$activity['content'] = Processor::removeImplicitMentionsFromBody($activity['content'], $implicit_mentions);
|
||||
$activity['tags'] = Processor::convertImplicitMentionsInTags($activity['tags'], $implicit_mentions);
|
||||
|
||||
return $activity;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,16 +62,16 @@ class Receiver
|
|||
{
|
||||
$http_signer = HTTPSignature::getSigner($body, $header);
|
||||
if (empty($http_signer)) {
|
||||
Logger::log('Invalid HTTP signature, message will be discarded.', Logger::DEBUG);
|
||||
Logger::warning('Invalid HTTP signature, message will be discarded.');
|
||||
return;
|
||||
} else {
|
||||
Logger::log('HTTP signature is signed by ' . $http_signer, Logger::DEBUG);
|
||||
Logger::info('Valid HTTP signature', ['signer' => $http_signer]);
|
||||
}
|
||||
|
||||
$activity = json_decode($body, true);
|
||||
|
||||
if (empty($activity)) {
|
||||
Logger::log('Invalid body.', Logger::DEBUG);
|
||||
Logger::warning('Invalid body.');
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,7 @@ class Receiver
|
|||
|
||||
$actor = JsonLD::fetchElement($ldactivity, 'as:actor');
|
||||
|
||||
Logger::log('Message for user ' . $uid . ' is from actor ' . $actor, Logger::DEBUG);
|
||||
Logger::info('Message for user ' . $uid . ' is from actor ' . $actor);
|
||||
|
||||
if (LDSignature::isSigned($activity)) {
|
||||
$ld_signer = LDSignature::getSigner($activity);
|
||||
|
|
|
@ -343,7 +343,7 @@ class Transmitter
|
|||
$actor_profile = APContact::getByURL($item['author-link']);
|
||||
}
|
||||
|
||||
$terms = Term::tagArrayFromItemId($item['id'], TERM_MENTION);
|
||||
$terms = Term::tagArrayFromItemId($item['id'], [Term::MENTION, Term::IMPLICIT_MENTION]);
|
||||
|
||||
if (!$item['private']) {
|
||||
$data = array_merge($data, self::fetchPermissionBlockFromConversation($item));
|
||||
|
@ -807,12 +807,12 @@ class Transmitter
|
|||
{
|
||||
$tags = [];
|
||||
|
||||
$terms = Term::tagArrayFromItemId($item['id']);
|
||||
$terms = Term::tagArrayFromItemId($item['id'], [Term::HASHTAG, Term::MENTION, Term::IMPLICIT_MENTION]);
|
||||
foreach ($terms as $term) {
|
||||
if ($term['type'] == TERM_HASHTAG) {
|
||||
if ($term['type'] == Term::HASHTAG) {
|
||||
$url = System::baseUrl() . '/search?tag=' . urlencode($term['term']);
|
||||
$tags[] = ['type' => 'Hashtag', 'href' => $url, 'name' => '#' . $term['term']];
|
||||
} elseif ($term['type'] == TERM_MENTION) {
|
||||
} elseif ($term['type'] == Term::MENTION || $term['type'] == Term::IMPLICIT_MENTION) {
|
||||
$contact = Contact::getDetailsByURL($term['url']);
|
||||
if (!empty($contact['addr'])) {
|
||||
$mention = '@' . $contact['addr'];
|
||||
|
@ -1439,6 +1439,10 @@ class Transmitter
|
|||
|
||||
private static function prependMentions($body, array $permission_block)
|
||||
{
|
||||
if (Config::get('system', 'disable_implicit_mentions')) {
|
||||
return $body;
|
||||
}
|
||||
|
||||
$mentions = [];
|
||||
|
||||
foreach ($permission_block['to'] as $profile_url) {
|
||||
|
|
|
@ -119,7 +119,9 @@ class DFRN
|
|||
$item["entry:cid"] = defaults($item, "entry:cid", 0);
|
||||
|
||||
$entry = self::entry($doc, "text", $item, $owner, $item["entry:comment-allow"], $item["entry:cid"]);
|
||||
$root->appendChild($entry);
|
||||
if (isset($entry)) {
|
||||
$root->appendChild($entry);
|
||||
}
|
||||
}
|
||||
|
||||
return trim($doc->saveXML());
|
||||
|
@ -323,7 +325,9 @@ class DFRN
|
|||
}
|
||||
|
||||
$entry = self::entry($doc, $type, $item, $owner, true);
|
||||
$root->appendChild($entry);
|
||||
if (isset($entry)) {
|
||||
$root->appendChild($entry);
|
||||
}
|
||||
}
|
||||
|
||||
$atom = trim($doc->saveXML());
|
||||
|
@ -390,7 +394,9 @@ class DFRN
|
|||
|
||||
foreach ($items as $item) {
|
||||
$entry = self::entry($doc, $type, $item, $owner, true, 0);
|
||||
$root->appendChild($entry);
|
||||
if (isset($entry)) {
|
||||
$root->appendChild($entry);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$root = self::entry($doc, $type, $item, $owner, true, 0, true);
|
||||
|
@ -763,31 +769,33 @@ class DFRN
|
|||
*/
|
||||
private static function addEntryAuthor(DOMDocument $doc, $element, $contact_url, $item)
|
||||
{
|
||||
$contact = Contact::getDetailsByURL($contact_url, $item["uid"]);
|
||||
|
||||
$author = $doc->createElement($element);
|
||||
XML::addElement($doc, $author, "name", $contact["name"]);
|
||||
XML::addElement($doc, $author, "uri", $contact["url"]);
|
||||
XML::addElement($doc, $author, "dfrn:handle", $contact["addr"]);
|
||||
|
||||
/// @Todo
|
||||
/// - Check real image type and image size
|
||||
/// - Check which of these boths elements we should use
|
||||
$attributes = [
|
||||
$contact = Contact::getDetailsByURL($contact_url, $item["uid"]);
|
||||
if (!empty($contact)) {
|
||||
XML::addElement($doc, $author, "name", $contact["name"]);
|
||||
XML::addElement($doc, $author, "uri", $contact["url"]);
|
||||
XML::addElement($doc, $author, "dfrn:handle", $contact["addr"]);
|
||||
|
||||
/// @Todo
|
||||
/// - Check real image type and image size
|
||||
/// - Check which of these boths elements we should use
|
||||
$attributes = [
|
||||
"rel" => "photo",
|
||||
"type" => "image/jpeg",
|
||||
"media:width" => 80,
|
||||
"media:height" => 80,
|
||||
"href" => $contact["photo"]];
|
||||
XML::addElement($doc, $author, "link", "", $attributes);
|
||||
XML::addElement($doc, $author, "link", "", $attributes);
|
||||
|
||||
$attributes = [
|
||||
$attributes = [
|
||||
"rel" => "avatar",
|
||||
"type" => "image/jpeg",
|
||||
"media:width" => 80,
|
||||
"media:height" => 80,
|
||||
"href" => $contact["photo"]];
|
||||
XML::addElement($doc, $author, "link", "", $attributes);
|
||||
XML::addElement($doc, $author, "link", "", $attributes);
|
||||
}
|
||||
|
||||
return $author;
|
||||
}
|
||||
|
@ -906,7 +914,7 @@ class DFRN
|
|||
* @param int $cid Contact ID of the recipient
|
||||
* @param bool $single If set, the entry is created as an XML document with a single "entry" element
|
||||
*
|
||||
* @return \DOMElement XML entry object
|
||||
* @return null|\DOMElement XML entry object
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
* @todo Find proper type-hints
|
||||
|
@ -916,7 +924,8 @@ class DFRN
|
|||
$mentioned = [];
|
||||
|
||||
if (!$item['parent']) {
|
||||
return;
|
||||
Logger::notice('Item without parent found.', ['type' => $type, 'item' => $item]);
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($item['deleted']) {
|
||||
|
@ -1546,7 +1555,7 @@ class DFRN
|
|||
$author["network"] = $contact_old["network"];
|
||||
} else {
|
||||
if (!$onlyfetch) {
|
||||
Logger::log("Contact ".$author["link"]." wasn't found for user ".$importer["importer_uid"]." XML: ".$xml, Logger::DEBUG);
|
||||
Logger::debug("Contact ".$author["link"]." wasn't found for user ".$importer["importer_uid"]." XML: ".$xml);
|
||||
}
|
||||
|
||||
$author["contact-unknown"] = true;
|
||||
|
@ -1596,6 +1605,7 @@ class DFRN
|
|||
|
||||
if (empty($author['avatar'])) {
|
||||
Logger::log('Empty author: ' . $xml);
|
||||
$author['avatar'] = '';
|
||||
}
|
||||
|
||||
if (DBA::isResult($contact_old) && !$onlyfetch) {
|
||||
|
|
|
@ -942,7 +942,7 @@ class Diaspora
|
|||
|
||||
$person = DBA::selectFirst('fcontact', [], ['network' => Protocol::DIASPORA, 'addr' => $handle]);
|
||||
if (DBA::isResult($person)) {
|
||||
Logger::log("In cache " . print_r($person, true), Logger::DEBUG);
|
||||
Logger::debug("In cache " . print_r($person, true));
|
||||
|
||||
// update record occasionally so it doesn't get stale
|
||||
$d = strtotime($person["updated"]." +00:00");
|
||||
|
@ -3675,7 +3675,7 @@ class Diaspora
|
|||
&& !strstr($body, $profile['addr'])
|
||||
&& !strstr($body, $profile_url)
|
||||
) {
|
||||
$body = '@[url=' . $profile_url . ']' . $profile['nick'] . '[/url] ' . $body;
|
||||
$body = '@[url=' . $profile_url . ']' . $profile['name'] . '[/url] ' . $body;
|
||||
}
|
||||
|
||||
return $body;
|
||||
|
@ -3776,7 +3776,7 @@ class Diaspora
|
|||
* @param array $item The item that will be exported
|
||||
* @param array $owner the array of the item owner
|
||||
*
|
||||
* @return array The data for a comment
|
||||
* @return array|false The data for a comment
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
private static function constructComment(array $item, array $owner)
|
||||
|
@ -3788,30 +3788,40 @@ class Diaspora
|
|||
return $result;
|
||||
}
|
||||
|
||||
$parent = Item::selectFirst(['guid', 'author-link'], ['id' => $item["parent"], 'parent' => $item["parent"]]);
|
||||
if (!DBA::isResult($parent)) {
|
||||
$toplevel_item = Item::selectFirst(['guid', 'author-link'], ['id' => $item["parent"], 'parent' => $item["parent"]]);
|
||||
if (!DBA::isResult($toplevel_item)) {
|
||||
Logger::error('Missing parent conversation item', ['parent' => $item["parent"]]);
|
||||
return false;
|
||||
}
|
||||
|
||||
$thread_parent_item = $toplevel_item;
|
||||
if ($item['thr-parent'] != $item['parent-uri']) {
|
||||
$thread_parent_item = Item::selectFirst(['guid', 'author-link'], ['uri' => $item['thr-parent'], 'uid' => $item['uid']]);
|
||||
}
|
||||
|
||||
$body = $item["body"];
|
||||
|
||||
if (empty($item['uid']) || !Feature::isEnabled($item['uid'], 'explicit_mentions')) {
|
||||
$body = self::prependParentAuthorMention($body, $parent['author-link']);
|
||||
if ((empty($item['uid']) || !Feature::isEnabled($item['uid'], 'explicit_mentions'))
|
||||
&& !Config::get('system', 'disable_implicit_mentions')
|
||||
) {
|
||||
$body = self::prependParentAuthorMention($body, $thread_parent_item['author-link']);
|
||||
}
|
||||
|
||||
$text = html_entity_decode(BBCode::toMarkdown($body));
|
||||
$created = DateTimeFormat::utc($item["created"], DateTimeFormat::ATOM);
|
||||
|
||||
$comment = ["author" => self::myHandle($owner),
|
||||
"guid" => $item["guid"],
|
||||
"created_at" => $created,
|
||||
"parent_guid" => $parent["guid"],
|
||||
"text" => $text,
|
||||
"author_signature" => ""];
|
||||
$comment = [
|
||||
"author" => self::myHandle($owner),
|
||||
"guid" => $item["guid"],
|
||||
"created_at" => $created,
|
||||
"parent_guid" => $toplevel_item["guid"],
|
||||
"text" => $text,
|
||||
"author_signature" => ""
|
||||
];
|
||||
|
||||
// Send the thread parent guid only if it is a threaded comment
|
||||
if ($item['thr-parent'] != $item['parent-uri']) {
|
||||
$comment['thread_parent_guid'] = self::getGuidFromUri($item['thr-parent'], $item['uid']);
|
||||
$comment['thread_parent_guid'] = $thread_parent_item['guid'];
|
||||
}
|
||||
|
||||
Cache::set($cachekey, $comment, Cache::QUARTER_HOUR);
|
||||
|
|
|
@ -1763,20 +1763,17 @@ class OStatus
|
|||
$verb = NAMESPACE_ACTIVITY_SCHEMA."favorite";
|
||||
self::entryContent($doc, $entry, $item, $owner, "Favorite", $verb, false);
|
||||
|
||||
$as_object = $doc->createElement("activity:object");
|
||||
|
||||
$parent = Item::selectFirst([], ['uri' => $item["thr-parent"], 'uid' => $item["uid"]]);
|
||||
if (DBA::isResult($parent)) {
|
||||
$as_object = $doc->createElement("activity:object");
|
||||
|
||||
if (!$parent) {
|
||||
$parent = [];
|
||||
XML::addElement($doc, $as_object, "activity:object-type", self::constructObjecttype($parent));
|
||||
|
||||
self::entryContent($doc, $as_object, $parent, $owner, "New entry");
|
||||
|
||||
$entry->appendChild($as_object);
|
||||
}
|
||||
|
||||
XML::addElement($doc, $as_object, "activity:object-type", self::constructObjecttype($parent));
|
||||
|
||||
self::entryContent($doc, $as_object, $parent, $owner, "New entry");
|
||||
|
||||
$entry->appendChild($as_object);
|
||||
|
||||
self::entryFooter($doc, $entry, $item, $owner);
|
||||
|
||||
return $entry;
|
||||
|
|
|
@ -505,8 +505,15 @@ class PortableContact
|
|||
$last_updated = "";
|
||||
|
||||
foreach ($entries as $entry) {
|
||||
$published = DateTimeFormat::utc($xpath->query('atom:published/text()', $entry)->item(0)->nodeValue);
|
||||
$updated = DateTimeFormat::utc($xpath->query('atom:updated/text()' , $entry)->item(0)->nodeValue);
|
||||
$published_item = $xpath->query('atom:published/text()', $entry)->item(0);
|
||||
$updated_item = $xpath->query('atom:updated/text()' , $entry)->item(0);
|
||||
$published = isset($published_item->nodeValue) ? DateTimeFormat::utc($published_item->nodeValue) : null;
|
||||
$updated = isset($updated_item->nodeValue) ? DateTimeFormat::utc($updated_item->nodeValue) : null;
|
||||
|
||||
if (!isset($published) || !isset($updated)) {
|
||||
Logger::notice('Invalid entry for XPath.', ['entry' => $entry, 'profile' => $profile]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($last_updated < $published) {
|
||||
$last_updated = $published;
|
||||
|
|
|
@ -68,7 +68,7 @@ class JsonLD
|
|||
}
|
||||
catch (Exception $e) {
|
||||
$normalized = false;
|
||||
Logger::log('normalise error:' . print_r($e, true), Logger::DEBUG);
|
||||
Logger::log('normalise error:' . substr(print_r($e, true), 0, 10000), Logger::DEBUG);
|
||||
}
|
||||
|
||||
return $normalized;
|
||||
|
@ -115,7 +115,7 @@ class JsonLD
|
|||
}
|
||||
catch (Exception $e) {
|
||||
$compacted = false;
|
||||
Logger::log('compacting error:' . print_r($e, true), Logger::DEBUG);
|
||||
Logger::log('compacting error:' . substr(print_r($e, true), 0, 10000), Logger::DEBUG);
|
||||
}
|
||||
|
||||
$json = json_decode(json_encode($compacted, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE), true);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue