diff --git a/.gitattributes b/.gitattributes index 4be1c91852..18ba9e0758 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,2 @@ -# Disable LF normalization for all files -* -text \ No newline at end of file +# Disable LF normalization for all files +* -text diff --git a/.gitignore b/.gitignore index 9e6504184c..de0fbc3d76 100644 --- a/.gitignore +++ b/.gitignore @@ -1,61 +1,65 @@ -favicon.* -.htconfig.php -.htpreconfig.php -\#* -include/jquery-1.4.2.min.js -*.log -*.out -*.version* -favicon.* -home.html -addon -*.orig -*~ -robots.txt - -#ignore documentation, it should be newly built -doc/html - -#ignore reports, should be generted with every build -report/ - -#ignore config files from eclipse, we don't want IDE files in our repository -.project -.buildpath -.externalToolBuilders -.settings -#ignore OSX .DS_Store files -.DS_Store - -/nbproject/private/ - -#ignore smarty cache -/view/smarty3/compiled/ - -#ignore cache folders -/privacy_image_cache/ -/photo/ -/proxy/ -nbproject - -#ignore vagrant dir -.vagrant/ - -#ignore local folder -/local/ - -#ignore config files from Visual Studio -/.vs/ -/php_friendica.phpproj -/php_friendica.sln -/php_friendica.phpproj.user - -#ignore things from transifex-client -venv/ - -#ignore Composer dependencies -/vendor -/view/asset - -#ignore config files from JetBrains -/.idea +favicon.* +.htconfig.php +.htpreconfig.php +\#* +include/jquery-1.4.2.min.js +*.log +*.out +*.version* +favicon.* +home.html +addon +*~ +robots.txt + +#ignore documentation, it should be newly built +doc/html + +#ignore reports, should be generted with every build +report/ + +#ignore config files from eclipse, we don't want IDE files in our repository +.project +.buildpath +.externalToolBuilders +.settings + +#ignore OSX .DS_Store files +.DS_Store + +#ignore NetBeans IDE's private files (at least) +/nbproject/private/ + +#ignore smarty cache +/view/smarty3/compiled/ + +#ignore cache folders +/privacy_image_cache/ +/photo/ +/proxy/ +nbproject + +#ignore vagrant dir +.vagrant/ + +#ignore local folder +/local/ + +#ignore config files from Visual Studio +/.vs/ +/php_friendica.phpproj +/php_friendica.sln +/php_friendica.phpproj.user + +#ignore things from transifex-client +venv/ + +#ignore Composer dependencies +/vendor +/view/asset + +#ignore config files from JetBrains +/.idea + +#ignore addons/ directory +addons/ diff --git a/.htaccess b/.htaccess index 2348cdc38b..a671cc680a 100644 --- a/.htaccess +++ b/.htaccess @@ -4,7 +4,7 @@ AddType audio/ogg .oga #AddHandler php53-cgi .php - + #Apache 2.4 Require all denied @@ -38,4 +38,3 @@ AddType audio/ogg .oga RewriteRule ^(.*)$ index.php?pagename=$1 [E=REMOTE_USER:%{HTTP:Authorization},L,QSA] - diff --git a/.travis.yml b/.travis.yml index d68b7727e8..82b5a5d218 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,4 +7,14 @@ php: - 7.1 - 7.2 -install: composer install +services: + - mysql +env: + - USER=travis DB=test + +install: + - composer install +before_script: + - mysql -e 'CREATE DATABASE IF NOT EXISTS test;' + # In order to avoid bin/worker.php warnings + - touch .htconfig.php diff --git a/CHANGELOG b/CHANGELOG index cc7eedfff5..6385d22bb1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,105 @@ +Version 2018.05 (2018-06-01) + Friendica Core: + Update to the translations (DE, EN-GB, EN-US, FI, IS, IT, NL, PL, RU, ZN CH) [translation teams] + Update to the documentation [andyhee, annando, fabrixxm, M-arcus, MrPedovan, rudloff, tobiasd] + Enhancements to the DB handling [annando] + Enhancements to the relay system [annando] + Enhancements to the handling of URL that contain unicode characters [annando] + Enhancements to the Vagrant VM configuration [fabrixxm, tobiasd] + Enhancementa to the Babel module [MrPetovan] + Enhancements to the display of the [code] elements [MrPetovan] + Enhancements to the federation (OStatus, diaspora) [annando] + Enhancements to the PHP7.2 compatibility [Alkarex, MrPetovan, Quix0r] + Enhancements to the themes (frio, vier) [astifter, fabrixxm, koyuawsmbrtn, M-arcus, MrPetovan, Quix0r, rabuzarus] + Enhancements to the accessibility using the frio theme [annando] + Enhancements to the display of the registration note and the privacy statements on the registration page [tobiasd] + Enhancements to the UI by clarification of the wording (deletion of items, network widget, invitations) [annando, tobiasd] + Enhancements to the background worker [annando] + Enhancements to the forum display in the sidebar [annando] + Enhancements to the testing system [rudloff, tobiasd] + Enhancements to the display of events [MrPetovan] + Enhancements to the language detection of postings [MrPetovan] + Enhancements to the memcached handling [MrPetovan] + Enhancements to the Dandelion app support [annando] + Enhancements to the API [rudloff] + Enhancements to the systemd timer example [ben-utzer] + Enhancements to the notification emails to better integrate the securemail addon [tobiasd] + Enhancements to the caching/loading mechanisms [MrPetovan] + Enhancements to the sample-nginx configfile to not use $uri in the rewrite rules [anmol26s] + Fixed a bug in the relocation process of a Friendica instance [annando] + Fixed a bug in the shell wrapper for the console [MrPetovan] + Fixed a bug with the console tool po2php [MrPetovan] + Fixed a bug with the console tool blockaccounts [MrPetovan] + Fixed a bug in the ACL [annando, MrPetovan] + Fixed a bug that prevented the deletion of contact groups [annando] + Fixed a bug that made edited mentions and hashtags plaintext [annando] + Fixed a bug that caused the /display page to receive constandly new updates [annando] + Fixed wrong version of a dependency preventing the usage of PHP 5.6 [MrPetovan] + Fixed a bug in OpenID authentification [Quix0r] + Fixed a bug in the item deletion [annando] + Fixed a bug that prevented public comments from being distributed [annando] + Fixed a bug that caused empty profile pictures for public contacts [annando] + Fixed a bug that prevented the display of some postings in the network stream [annando] + Fixed a bug in the display of videos with parameters [annando] + Fixed a bug that caused the display of blocked contacts under some conditions [annando] + Fixed bugs in the installer [annando, M-arcus] + Fixed a bug in the installer running on nginx [astifter] + Fixed a bug with reshares from diaspora* [annando] + Fixed a bug that accounts from diaspora* could join private forums automatically [annando] + Fixed a bug that prevented the selection of displayed profiles for other Friendica contacts [MrPetovan] + Fixed the version sorting in the federation statistics page [annando] + Fixed a bug in the nodeinfo calculation of total comments [annando] + Fixed a bug during registration that prevented the detected language to be saved [tobiasd] + Added an optional module to display the Terms of Service [rabuzarus, tobiasd] + Added testfeed module [MrPetovan] + Added hashtag autocomplete (ported from Hubzilla) [rabuzarus] + Added password exposed check [MrPetovan] + Added preloading config adapter [MrPetovan] + Added a console to unify the PHP utility scripts [MrPetovan] + Added a tool to set user passwords to the console [annando] + Added memcached support [MrPetovan] + Added password exposure check [MrPetovan] + Added hashtag autocompletion [rabuzarus] + Added feedtest module [MrPetovan] + Added dbclean options to the admin panel [annando] + Added the possibility to add the remote_self flag to contacts from diaspora* and Twitter [annando] + Added the possibility of automatic installations [M-arcus] + Added the sending of a notification mail to the admin when a user deletes their account [tobiasd] + Added examples for home.html and home.css files [tobiasd] + Added an option to define after how many days a contact should be archived [annando] + Added parts of the list API [rudloff] + Added support of ALT texts for images [annando] + Removed the connection postings [annando] + Corrected a long standing typo in config variable names; should your bandwidth saver mode stop working please turn it off and on again [abanink] + The execute-ables were moved from /util to /bin [MrPetovan] + The execute-ables for the developers were moved from /util to /bin/dev [MrPetovan] + The last year deprecated themes frost and frost mobile got removed from the Friendica repository. They can be found in the dedicated repository for deprecated themes [tobiasd] + General code refactoring and beautification work [annando, MrPetovan, rudloff] + Switched to cropperjs to better support touch screen devices [rabuzarus] + Use the diaspora transport layer for the DFRN protocol as well [annando] + + Friendica Addons: + Updates to the translations (DE, EN_GB, EN_US, ES, FI, FR, IS, IT, NL, PL, RU, ZH_CN) [translation teams] + advancedcontentfilter: new addon with advanced filter capabilities [MrPetova] + catavatar: new addon for profile pictures based on David Revoy's cat-avatar generator [annando, fabrixxm, tobiasd] + languagefilter: better help text [andyhee] + mathjax: fixed the config form and adopted new CDN URL [tobiasd] + NSFW: add hashtag only hiding [MrPetovan] + notifyall: fixed a bug in handling the sender name [tobiasd] + Twitter: fixed a bug during the creation of public contacts [annando] + Twitter: remote self now also works for Twitter contacts [annando] + Twitter: optimizations for sending media [annando] + + Closed Issues: + 839, 1186, 1729, 2115, 2247, 2781, 2880, 3174, 3395, 3409, 3412, + 3611, 3834, 3837, 3979, 4146, 4572, 4601, 4616, 4629, 4647, 4660, + 4661, 4663, 4664, 4665, 4666, 4669, 4670, 4681, 4695, 4670, 4689, + 4730, 4749, 4760, 4772, 4786, 4790, 4791, 4816, 4867, 4878, 4819, + 4860, 4876, 4879, 4886, 4898, 4899, 4902, 4921, 4926, 4927, 4928, + 4938, 4943, 4946, 4947, 4965, 4976, 4966, 4994, 4997, 5002, 5014, + 5033, 5043, 5050, 5051, 5056, 5063, 5067, 5010, 5111, 5116, 5128, + 5137, 5147 + Version 3.6 (2018-03-23) Friendica Core: Updates to the translations (DE, EN_GB, EN_US, ES, FR, IT, ZH_CN) [translation teams] @@ -93,6 +195,8 @@ Version 3.6 (2018-03-23) Updates to the translations (DE, EN_GB, ES, FR, IT, NL, ZH_CN) [translation teams] all bridges don't relay postings anymore that are posted to a public forum [annando] DAV addon marked unsupported [tobiasd] + communityhome addon marked unsupported [MrPetovan] + yourls addon makrked unsupported [MrPetovan] Current Weather: fixing a problem with the weathermap link [zeroadam] NSFW added config examples, reworked the description, now ignores the CW from Mastodon [andyhee, annando, rebeka-catalina] Twitter support 280 chars limit [annando] @@ -102,7 +206,7 @@ Version 3.6 (2018-03-23) Public Server reworked [annando] pageheader settings beautifications [tobiasd] mailstream settings beautifications [tobiasd] - Membersince is now part of the core [rabuzarus] + Membersince is now part of the core, addon marked unsupported [rabuzarus] Forum posts are not transmitted over the connectors anymore [annando] Friendica Dir: diff --git a/VERSION b/VERSION index a8428e9db4..607ef5eb6a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2018.05-rc +2018.08-dev diff --git a/bin/daemon.php b/bin/daemon.php index 6b0e377a3a..b8c8d2e342 100755 --- a/bin/daemon.php +++ b/bin/daemon.php @@ -6,8 +6,38 @@ * * This script was taken from http://php.net/manual/en/function.pcntl-fork.php */ -function shutdown() { - posix_kill(posix_getpid(), SIGHUP); + +use Friendica\App; +use Friendica\BaseObject; +use Friendica\Core\Config; +use Friendica\Core\Worker; + +// Ensure that daemon.php is executed from the base path of the installation +if (!file_exists("boot.php") && (sizeof($_SERVER["argv"]) != 0)) { + $directory = dirname($_SERVER["argv"][0]); + + if (substr($directory, 0, 1) != "/") { + $directory = $_SERVER["PWD"]."/".$directory; + } + $directory = realpath($directory."/.."); + + chdir($directory); +} + +require_once "boot.php"; +require_once "include/dba.php"; + +$a = new App(dirname(__DIR__)); +BaseObject::setApp($a); + +require_once ".htconfig.php"; +dba::connect($db_host, $db_user, $db_pass, $db_data); + +Config::load(); + +if (!isset($pidfile)) { + die('Please specify a pid file in the variable $pidfile in the .htconfig.php. For example:'."\n". + '$pidfile = "/path/to/daemon.pid";'."\n"); } if (in_array("start", $_SERVER["argv"])) { @@ -30,27 +60,11 @@ if (empty($_SERVER["argv"][0])) { die("Unexpected script behaviour. This message should never occur.\n"); } -// Fetch the base directory -$directory = dirname($_SERVER["argv"][0]); +$pid = @file_get_contents($pidfile); -if (substr($directory, 0, 1) != "/") { - $directory = $_SERVER["PWD"]."/".$directory; -} -$directory = realpath($directory."/.."); - -@include($directory."/.htconfig.php"); - -if (!isset($pidfile)) { - die('Please specify a pid file in the variable $pidfile in the .htconfig.php. For example:'."\n". - '$pidfile = "/path/to/daemon.pid";'."\n"); -} - -if (in_array($mode, array("stop", "status"))) { - $pid = @file_get_contents($pidfile); - - if (!$pid) { - die("Pidfile wasn't found. Is the daemon running?\n"); - } +if (empty($pid) && in_array($mode, ["stop", "status"])) { + Config::set('system', 'worker_daemon_mode', false); + die("Pidfile wasn't found. Is the daemon running?\n"); } if ($mode == "status") { @@ -60,6 +74,7 @@ if ($mode == "status") { unlink($pidfile); + Config::set('system', 'worker_daemon_mode', false); die("Daemon process $pid isn't running.\n"); } @@ -68,59 +83,89 @@ if ($mode == "stop") { unlink($pidfile); + logger("Worker daemon process $pid was killed.", LOGGER_DEBUG); + + Config::set('system', 'worker_daemon_mode', false); die("Worker daemon process $pid was killed.\n"); } -echo "Starting worker daemon.\n"; - -if (isset($a->config['php_path'])) { - $php = $a->config['php_path']; -} else { - $php = "php"; +if (!empty($pid) && posix_kill($pid, 0)) { + die("Daemon process $pid is already running.\n"); } +logger('Starting worker daemon.', LOGGER_DEBUG); +echo "Starting worker daemon.\n"; + // Switch over to daemon mode. -if ($pid = pcntl_fork()) +if ($pid = pcntl_fork()) { return; // Parent +} fclose(STDIN); // Close all of the standard fclose(STDOUT); // file descriptors as we fclose(STDERR); // are running as a daemon. +dba::disconnect(); + register_shutdown_function('shutdown'); -if (posix_setsid() < 0) +if (posix_setsid() < 0) { return; +} -if ($pid = pcntl_fork()) +if ($pid = pcntl_fork()) { return; // Parent +} + +// We lose the database connection upon forking +dba::connect($db_host, $db_user, $db_pass, $db_data); + +Config::set('system', 'worker_daemon_mode', true); + +// Just to be sure that this script really runs endlessly +set_time_limit(0); $pid = getmypid(); file_put_contents($pidfile, $pid); +$wait_interval = intval(Config::get('system', 'cron_interval', 5)) * 60; + +$do_cron = true; +$last_cron = 0; + // Now running as a daemon. while (true) { - // Just to be sure that this script really runs endlessly - set_time_limit(0); - - // Call the worker - $cmdline = $php.' bin/worker.php'; - - $executed = false; - - if (function_exists('proc_open')) { - $resource = proc_open($cmdline . ' &', array(), $foo, $directory); - - if (is_resource($resource)) { - $executed = true; - proc_close($resource); - } + if (!$do_cron && ($last_cron + $wait_interval) < time()) { + logger('Forcing cron worker call.', LOGGER_DEBUG); + $do_cron = true; } - if (!$executed) { - exec($cmdline.' spawn'); + Worker::spawnWorker($do_cron); + + if ($do_cron) { + // We force a disconnect and reconnect of the database connection. + // This is done to ensure that the connection don't get lost over time. + dba::disconnect(); + dba::connect($db_host, $db_user, $db_pass, $db_data); + + $last_cron = time(); } - // Now sleep for 5 minutes - sleep(300); + logger("Sleeping", LOGGER_DEBUG); + $i = 0; + do { + sleep(1); + } while (($i++ < $wait_interval) && !Worker::IPCJobsExists()); + + if ($i >= $wait_interval) { + $do_cron = true; + logger("Woke up after $wait_interval seconds.", LOGGER_DEBUG); + } else { + $do_cron = false; + logger("Worker jobs are calling to be forked.", LOGGER_DEBUG); + } +} + +function shutdown() { + posix_kill(posix_getpid(), SIGHUP); } diff --git a/boot.php b/boot.php index 78bd68f3e4..79ec53abf5 100644 --- a/boot.php +++ b/boot.php @@ -39,9 +39,9 @@ require_once 'include/text.php'; define('FRIENDICA_PLATFORM', 'Friendica'); define('FRIENDICA_CODENAME', 'The Tazmans Flax-lily'); -define('FRIENDICA_VERSION', '2018.05-rc'); +define('FRIENDICA_VERSION', '2018.08-dev'); define('DFRN_PROTOCOL_VERSION', '2.23'); -define('DB_UPDATE_VERSION', 1265); +define('DB_UPDATE_VERSION', 1268); define('NEW_UPDATE_ROUTINE_VERSION', 1170); /** @@ -1076,6 +1076,7 @@ function is_site_admin() $adminlist = explode(",", str_replace(" ", "", $a->config['admin_email'])); //if(local_user() && x($a->user,'email') && x($a->config,'admin_email') && ($a->user['email'] === $a->config['admin_email'])) + /// @TODO This if() + 2 returns can be shrinked into one return if (local_user() && x($a->user, 'email') && x($a->config, 'admin_email') && in_array($a->user['email'], $adminlist)) { return true; } @@ -1173,7 +1174,7 @@ function random_digits($digits) { $rn = ''; for ($i = 0; $i < $digits; $i++) { - /// @TODO rand() is different to mt_rand() and maybe lesser "random" + /// @TODO Avoid rand/mt_rand, when it comes to cryptography, they are generating predictable (seedable) numbers. $rn .= rand(0, 9); } return $rn; @@ -1187,7 +1188,7 @@ function get_server() $server = "https://dir.friendica.social"; } - return($server); + return $server; } function get_temppath() @@ -1236,7 +1237,7 @@ function get_cachefile($file, $writemode = true) $cache = get_itemcachepath(); if ((!$cache) || (!is_dir($cache))) { - return(""); + return ""; } $subfolder = $cache . "/" . substr($file, 0, 2); @@ -1250,7 +1251,6 @@ function get_cachefile($file, $writemode = true) } } - /// @TODO no need to put braces here return $cachepath; } @@ -1357,7 +1357,6 @@ function get_spoolpath() return ""; } - if (!function_exists('exif_imagetype')) { function exif_imagetype($file) { @@ -1395,7 +1394,7 @@ function validate_include(&$file) } // Simply return flag - return ($valid); + return $valid; } function current_load() diff --git a/composer.json b/composer.json index b7cd645bdb..9668b9341c 100644 --- a/composer.json +++ b/composer.json @@ -47,7 +47,8 @@ ], "autoload": { "psr-4": { - "Friendica\\": "src/" + "Friendica\\": "src/", + "Friendica\\Test\\": "tests/" }, "psr-0": { "": "library/" @@ -68,5 +69,13 @@ "exclude": [ "log", "cache", "/photo", "/proxy" ] + }, + "require-dev": { + "phpunit/dbunit": "^2.0", + "phpdocumentor/reflection-docblock": "^3.0.2", + "phpunit/php-token-stream": "^1.4.2" + }, + "scripts": { + "test": "phpunit" } } diff --git a/composer.lock b/composer.lock index f294c16ef5..dd2665ebbe 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "f97245142e60a521f048a667bec4e436", + "content-hash": "ab5a551aff0505691c4836d063fc5171", "packages": [ { "name": "asika/simple-console", @@ -2090,7 +2090,1382 @@ "time": "2016-12-14T21:57:25+00:00" } ], - "packages-dev": [], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "shasum": "" + }, + "require": { + "php": ">=5.3,<8.0-DEV" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2015-06-14T21:17:01+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.7.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", + "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "doctrine/collections": "^1.0", + "doctrine/common": "^2.6", + "phpunit/phpunit": "^4.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + }, + "files": [ + "src/DeepCopy/deep_copy.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "time": "2017-10-19T19:58:43+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "time": "2017-09-11T18:02:19+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "3.3.2", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "bf329f6c1aadea3299f08ee804682b7c45b326a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/bf329f6c1aadea3299f08ee804682b7c45b326a2", + "reference": "bf329f6c1aadea3299f08ee804682b7c45b326a2", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0", + "phpdocumentor/reflection-common": "^1.0.0", + "phpdocumentor/type-resolver": "^0.4.0", + "webmozart/assert": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^4.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "time": "2017-11-10T14:09:06+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "0.4.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", + "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", + "shasum": "" + }, + "require": { + "php": "^5.5 || ^7.0", + "phpdocumentor/reflection-common": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^5.2||^4.8.24" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "time": "2017-07-14T14:27:02+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "1.7.6", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/33a7e3c4fda54e912ff6338c48823bd5c0f0b712", + "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", + "sebastian/comparator": "^1.1|^2.0|^3.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0" + }, + "require-dev": { + "phpspec/phpspec": "^2.5|^3.2", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.7.x-dev" + } + }, + "autoload": { + "psr-0": { + "Prophecy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2018-04-18T13:57:24+00:00" + }, + { + "name": "phpunit/dbunit", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/dbunit.git", + "reference": "5c35d74549c21ba55d0ea74ba89d191a51f8cf25" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/dbunit/zipball/5c35d74549c21ba55d0ea74ba89d191a51f8cf25", + "reference": "5c35d74549c21ba55d0ea74ba89d191a51f8cf25", + "shasum": "" + }, + "require": { + "ext-pdo": "*", + "ext-simplexml": "*", + "php": "^5.4 || ^7.0", + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0", + "symfony/yaml": "^2.1 || ^3.0" + }, + "bin": [ + "dbunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "DbUnit port for PHP/PHPUnit to support database interaction testing.", + "homepage": "https://github.com/sebastianbergmann/dbunit/", + "keywords": [ + "database", + "testing", + "xunit" + ], + "time": "2016-12-02T14:39:14+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "4.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ef7b2f56815df854e66ceaee8ebe9393ae36a40d", + "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-xmlwriter": "*", + "php": "^5.6 || ^7.0", + "phpunit/php-file-iterator": "^1.3", + "phpunit/php-text-template": "^1.2", + "phpunit/php-token-stream": "^1.4.2 || ^2.0", + "sebastian/code-unit-reverse-lookup": "^1.0", + "sebastian/environment": "^1.3.2 || ^2.0", + "sebastian/version": "^1.0 || ^2.0" + }, + "require-dev": { + "ext-xdebug": "^2.1.4", + "phpunit/phpunit": "^5.7" + }, + "suggest": { + "ext-xdebug": "^2.5.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2017-04-02T07:44:40+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.4.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2017-11-27T13:52:08+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2015-06-21T13:50:34+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.9", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2017-02-26T11:10:40+00:00" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.4.12", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1ce90ba27c42e4e44e6d8458241466380b51fa16", + "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2017-12-04T08:55:13+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "5.7.27", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c", + "reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "myclabs/deep-copy": "~1.3", + "php": "^5.6 || ^7.0", + "phpspec/prophecy": "^1.6.2", + "phpunit/php-code-coverage": "^4.0.4", + "phpunit/php-file-iterator": "~1.4", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": "^1.0.6", + "phpunit/phpunit-mock-objects": "^3.2", + "sebastian/comparator": "^1.2.4", + "sebastian/diff": "^1.4.3", + "sebastian/environment": "^1.3.4 || ^2.0", + "sebastian/exporter": "~2.0", + "sebastian/global-state": "^1.1", + "sebastian/object-enumerator": "~2.0", + "sebastian/resource-operations": "~1.0", + "sebastian/version": "^1.0.6|^2.0.1", + "symfony/yaml": "~2.1|~3.0|~4.0" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "3.0.2" + }, + "require-dev": { + "ext-pdo": "*" + }, + "suggest": { + "ext-xdebug": "*", + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.7.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2018-02-01T05:50:59+00:00" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "3.4.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "a23b761686d50a560cc56233b9ecf49597cc9118" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/a23b761686d50a560cc56233b9ecf49597cc9118", + "reference": "a23b761686d50a560cc56233b9ecf49597cc9118", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.6 || ^7.0", + "phpunit/php-text-template": "^1.2", + "sebastian/exporter": "^1.2 || ^2.0" + }, + "conflict": { + "phpunit/phpunit": "<5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.4" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2017-06-30T09:13:00+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "time": "2017-03-04T06:30:41+00:00" + }, + { + "name": "sebastian/comparator", + "version": "1.2.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", + "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/diff": "~1.2", + "sebastian/exporter": "~1.2 || ~2.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2017-01-29T09:50:25+00:00" + }, + { + "name": "sebastian/diff", + "version": "1.4.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4", + "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2017-05-22T07:24:03+00:00" + }, + { + "name": "sebastian/environment", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5795ffe5dc5b02460c3e34222fee8cbe245d8fac", + "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2016-11-26T07:53:53+00:00" + }, + { + "name": "sebastian/exporter", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", + "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/recursion-context": "~2.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2016-11-19T08:54:04+00:00" + }, + { + "name": "sebastian/global-state", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2015-10-12T03:26:01+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1311872ac850040a79c3c058bea3e22d0f09cbb7", + "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7", + "shasum": "" + }, + "require": { + "php": ">=5.6", + "sebastian/recursion-context": "~2.0" + }, + "require-dev": { + "phpunit/phpunit": "~5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "time": "2017-02-18T15:18:39+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/2c3ba150cbec723aa057506e73a8d33bdb286c9a", + "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2016-11-19T07:33:16+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "shasum": "" + }, + "require": { + "php": ">=5.6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "time": "2015-07-28T20:34:47+00:00" + }, + { + "name": "sebastian/version", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2016-10-03T07:35:21+00:00" + }, + { + "name": "symfony/yaml", + "version": "v3.4.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "a42f9da85c7c38d59f5e53f076fe81a091f894d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/a42f9da85c7c38d59f5e53f076fe81a091f894d0", + "reference": "a42f9da85c7c38d59f5e53f076fe81a091f894d0", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8" + }, + "conflict": { + "symfony/console": "<3.4" + }, + "require-dev": { + "symfony/console": "~3.4|~4.0" + }, + "suggest": { + "symfony/console": "For validating YAML files using the lint command" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "https://symfony.com", + "time": "2018-04-03T05:14:20+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/assert.git", + "reference": "0df1908962e7a3071564e857d86874dad1ef204a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a", + "reference": "0df1908962e7a3071564e857d86874dad1ef204a", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "time": "2018-01-29T19:49:41+00:00" + } + ], "aliases": [], "minimum-stability": "stable", "stability-flags": { diff --git a/database.sql b/database.sql index 64ac656fd9..b186c0c0aa 100644 --- a/database.sql +++ b/database.sql @@ -1,6 +1,6 @@ -- ------------------------------------------ --- Friendica 2018.05-rc (The Tazmans Flax-lily) --- DB_UPDATE_VERSION 1265 +-- Friendica 2018.08-dev (The Tazmans Flax-lily) +-- DB_UPDATE_VERSION 1268 -- ------------------------------------------ @@ -9,35 +9,35 @@ -- CREATE TABLE IF NOT EXISTS `addon` ( `id` int unsigned NOT NULL auto_increment COMMENT '', - `name` varchar(50) NOT NULL DEFAULT '' COMMENT '', - `version` varchar(50) NOT NULL DEFAULT '' COMMENT '', - `installed` boolean NOT NULL DEFAULT '0' COMMENT '', - `hidden` boolean NOT NULL DEFAULT '0' COMMENT '', - `timestamp` int unsigned NOT NULL DEFAULT 0 COMMENT '', - `plugin_admin` boolean NOT NULL DEFAULT '0' COMMENT '', + `name` varchar(50) NOT NULL DEFAULT '' COMMENT 'addon base (file)name', + `version` varchar(50) NOT NULL DEFAULT '' COMMENT 'currently unused', + `installed` boolean NOT NULL DEFAULT '0' COMMENT 'currently always 1', + `hidden` boolean NOT NULL DEFAULT '0' COMMENT 'currently unused', + `timestamp` int unsigned NOT NULL DEFAULT 0 COMMENT 'file timestamp to check for reloads', + `plugin_admin` boolean NOT NULL DEFAULT '0' COMMENT '1 = has admin config, 0 = has no admin config', PRIMARY KEY(`id`), UNIQUE INDEX `name` (`name`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='registered addons'; -- -- TABLE attach -- CREATE TABLE IF NOT EXISTS `attach` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', - `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id', - `hash` varchar(64) NOT NULL DEFAULT '' COMMENT '', - `filename` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `filetype` varchar(64) NOT NULL DEFAULT '' COMMENT '', - `filesize` int unsigned NOT NULL DEFAULT 0 COMMENT '', - `data` longblob NOT NULL COMMENT '', - `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', - `edited` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', - `allow_cid` mediumtext COMMENT '', - `allow_gid` mediumtext COMMENT '', - `deny_cid` mediumtext COMMENT '', - `deny_gid` mediumtext COMMENT '', + `id` int unsigned NOT NULL auto_increment COMMENT 'generated index', + `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'Owner User id', + `hash` varchar(64) NOT NULL DEFAULT '' COMMENT 'hash', + `filename` varchar(255) NOT NULL DEFAULT '' COMMENT 'filename of original', + `filetype` varchar(64) NOT NULL DEFAULT '' COMMENT 'mimetype', + `filesize` int unsigned NOT NULL DEFAULT 0 COMMENT 'size in bytes', + `data` longblob NOT NULL COMMENT 'file data', + `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'creation time', + `edited` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'last edit time', + `allow_cid` mediumtext COMMENT 'Access Control - list of allowed contact.id \'<19><78>', + `allow_gid` mediumtext COMMENT 'Access Control - list of allowed groups', + `deny_cid` mediumtext COMMENT 'Access Control - list of denied contact.id', + `deny_gid` mediumtext COMMENT 'Access Control - list of denied groups', PRIMARY KEY(`id`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='file attachments'; -- -- TABLE auth_codes @@ -49,7 +49,7 @@ CREATE TABLE IF NOT EXISTS `auth_codes` ( `expires` int NOT NULL DEFAULT 0 COMMENT '', `scope` varchar(250) NOT NULL DEFAULT '' COMMENT '', PRIMARY KEY(`id`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='OAuth usage'; -- -- TABLE cache @@ -61,20 +61,20 @@ CREATE TABLE IF NOT EXISTS `cache` ( `updated` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'datetime of cache insertion', PRIMARY KEY(`k`), INDEX `k_expires` (`k`,`expires`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Stores temporary data'; -- -- TABLE challenge -- CREATE TABLE IF NOT EXISTS `challenge` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', + `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', `challenge` varchar(255) NOT NULL DEFAULT '' COMMENT '', `dfrn-id` varchar(255) NOT NULL DEFAULT '' COMMENT '', `expire` int unsigned NOT NULL DEFAULT 0 COMMENT '', `type` varchar(255) NOT NULL DEFAULT '' COMMENT '', `last_update` varchar(255) NOT NULL DEFAULT '' COMMENT '', PRIMARY KEY(`id`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT=''; -- -- TABLE clients @@ -87,7 +87,7 @@ CREATE TABLE IF NOT EXISTS `clients` ( `icon` text COMMENT '', `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id', PRIMARY KEY(`client_id`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='OAuth usage'; -- -- TABLE config @@ -99,32 +99,32 @@ CREATE TABLE IF NOT EXISTS `config` ( `v` mediumtext COMMENT '', PRIMARY KEY(`id`), UNIQUE INDEX `cat_k` (`cat`,`k`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='main configuration storage'; -- -- TABLE contact -- CREATE TABLE IF NOT EXISTS `contact` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', - `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id', + `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', + `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'Owner User id', `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', - `self` boolean NOT NULL DEFAULT '0' COMMENT '', + `self` boolean NOT NULL DEFAULT '0' COMMENT '1 if the contact is the user him/her self', `remote_self` boolean NOT NULL DEFAULT '0' COMMENT '', - `rel` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '', + `rel` tinyint unsigned NOT NULL DEFAULT 0 COMMENT 'The kind of the relation between the user and the contact', `duplex` boolean NOT NULL DEFAULT '0' COMMENT '', - `network` char(4) NOT NULL DEFAULT '' COMMENT '', - `name` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `nick` varchar(255) NOT NULL DEFAULT '' COMMENT '', + `network` char(4) NOT NULL DEFAULT '' COMMENT 'Network protocol of the contact', + `name` varchar(255) NOT NULL DEFAULT '' COMMENT 'Name that this contact is known by', + `nick` varchar(255) NOT NULL DEFAULT '' COMMENT 'Nick- and user name of the contact', `location` varchar(255) NOT NULL DEFAULT '' COMMENT '', `about` text COMMENT '', - `keywords` text COMMENT '', + `keywords` text COMMENT 'public keywords (interests) of the contact', `gender` varchar(32) NOT NULL DEFAULT '' COMMENT '', `xmpp` varchar(255) NOT NULL DEFAULT '' COMMENT '', `attag` varchar(255) NOT NULL DEFAULT '' COMMENT '', `avatar` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `photo` varchar(255) DEFAULT '' COMMENT '', - `thumb` varchar(255) DEFAULT '' COMMENT '', - `micro` varchar(255) DEFAULT '' COMMENT '', + `photo` varchar(255) DEFAULT '' COMMENT 'Link to the profile photo of the contact', + `thumb` varchar(255) DEFAULT '' COMMENT 'Link to the profile photo (thumb size)', + `micro` varchar(255) DEFAULT '' COMMENT 'Link to the profile photo (micro size)', `site-pubkey` text COMMENT '', `issued-id` varchar(255) NOT NULL DEFAULT '' COMMENT '', `dfrn-id` varchar(255) NOT NULL DEFAULT '' COMMENT '', @@ -132,8 +132,8 @@ CREATE TABLE IF NOT EXISTS `contact` ( `nurl` varchar(255) NOT NULL DEFAULT '' COMMENT '', `addr` varchar(255) NOT NULL DEFAULT '' COMMENT '', `alias` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `pubkey` text COMMENT '', - `prvkey` text COMMENT '', + `pubkey` text COMMENT 'RSA public key 4096 bit', + `prvkey` text COMMENT 'RSA private key 4096 bit', `batch` varchar(255) NOT NULL DEFAULT '' COMMENT '', `request` varchar(255) COMMENT '', `notify` varchar(255) COMMENT '', @@ -145,20 +145,20 @@ CREATE TABLE IF NOT EXISTS `contact` ( `usehub` boolean NOT NULL DEFAULT '0' COMMENT '', `subhub` boolean NOT NULL DEFAULT '0' COMMENT '', `hub-verify` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `last-update` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', - `success_update` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', - `failure_update` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', + `last-update` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Date of the last try to update the contact info', + `success_update` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Date of the last successful contact update', + `failure_update` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Date of the last failed update', `name-date` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', `uri-date` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', `avatar-date` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', `term-date` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', - `last-item` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', + `last-item` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'date of the last post', `priority` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '', `blocked` boolean NOT NULL DEFAULT '1' COMMENT '', - `readonly` boolean NOT NULL DEFAULT '0' COMMENT '', + `readonly` boolean NOT NULL DEFAULT '0' COMMENT 'posts of the contact are readonly', `writable` boolean NOT NULL DEFAULT '0' COMMENT '', - `forum` boolean NOT NULL DEFAULT '0' COMMENT '', - `prv` boolean NOT NULL DEFAULT '0' COMMENT '', + `forum` boolean NOT NULL DEFAULT '0' COMMENT 'contact is a forum', + `prv` boolean NOT NULL DEFAULT '0' COMMENT 'contact is a private group', `contact-type` tinyint NOT NULL DEFAULT 0 COMMENT '', `hidden` boolean NOT NULL DEFAULT '0' COMMENT '', `archive` boolean NOT NULL DEFAULT '0' COMMENT '', @@ -186,74 +186,74 @@ CREATE TABLE IF NOT EXISTS `contact` ( INDEX `nick_uid` (`nick`(32),`uid`), INDEX `dfrn-id` (`dfrn-id`(64)), INDEX `issued-id` (`issued-id`(64)) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='contact table'; -- -- TABLE conv -- CREATE TABLE IF NOT EXISTS `conv` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', - `guid` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `recips` text COMMENT '', - `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id', - `creator` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', - `updated` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', - `subject` text COMMENT '', + `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', + `guid` varchar(255) NOT NULL DEFAULT '' COMMENT 'A unique identifier for this conversation', + `recips` text COMMENT 'sender_handle;recipient_handle', + `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'Owner User id', + `creator` varchar(255) NOT NULL DEFAULT '' COMMENT 'handle of creator', + `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'creation timestamp', + `updated` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'edited timestamp', + `subject` text COMMENT 'subject of initial message', PRIMARY KEY(`id`), INDEX `uid` (`uid`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='private messages'; -- -- TABLE conversation -- CREATE TABLE IF NOT EXISTS `conversation` ( - `item-uri` varbinary(255) NOT NULL COMMENT '', - `reply-to-uri` varbinary(255) NOT NULL DEFAULT '' COMMENT '', - `conversation-uri` varbinary(255) NOT NULL DEFAULT '' COMMENT '', - `conversation-href` varbinary(255) NOT NULL DEFAULT '' COMMENT '', - `protocol` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '', - `source` mediumtext COMMENT '', - `received` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', + `item-uri` varbinary(255) NOT NULL COMMENT 'URI of the item', + `reply-to-uri` varbinary(255) NOT NULL DEFAULT '' COMMENT 'URI to which this item is a reply', + `conversation-uri` varbinary(255) NOT NULL DEFAULT '' COMMENT 'GNU Social conversation URI', + `conversation-href` varbinary(255) NOT NULL DEFAULT '' COMMENT 'GNU Social conversation link', + `protocol` tinyint unsigned NOT NULL DEFAULT 0 COMMENT 'The protocol of the item', + `source` mediumtext COMMENT 'Original source', + `received` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Receiving date', PRIMARY KEY(`item-uri`), INDEX `conversation-uri` (`conversation-uri`), INDEX `received` (`received`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Raw data and structure information for messages'; -- -- TABLE event -- CREATE TABLE IF NOT EXISTS `event` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', + `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', `guid` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id', - `cid` int unsigned NOT NULL DEFAULT 0 COMMENT '', + `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'Owner User id', + `cid` int unsigned NOT NULL DEFAULT 0 COMMENT 'contact_id (ID of the contact in contact table)', `uri` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', - `edited` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', - `start` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', - `finish` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', - `summary` text COMMENT '', - `desc` text COMMENT '', - `location` text COMMENT '', - `type` varchar(20) NOT NULL DEFAULT '' COMMENT '', - `nofinish` boolean NOT NULL DEFAULT '0' COMMENT '', - `adjust` boolean NOT NULL DEFAULT '1' COMMENT '', - `ignore` boolean NOT NULL DEFAULT '0' COMMENT '', - `allow_cid` mediumtext COMMENT '', - `allow_gid` mediumtext COMMENT '', - `deny_cid` mediumtext COMMENT '', - `deny_gid` mediumtext COMMENT '', + `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'creation time', + `edited` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'last edit time', + `start` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'event start time', + `finish` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'event end time', + `summary` text COMMENT 'short description or title of the event', + `desc` text COMMENT 'event description', + `location` text COMMENT 'event location', + `type` varchar(20) NOT NULL DEFAULT '' COMMENT 'event or birthday', + `nofinish` boolean NOT NULL DEFAULT '0' COMMENT 'if event does have no end this is 1', + `adjust` boolean NOT NULL DEFAULT '1' COMMENT 'adjust to timezone of the recipient (0 or 1)', + `ignore` boolean NOT NULL DEFAULT '0' COMMENT '0 or 1', + `allow_cid` mediumtext COMMENT 'Access Control - list of allowed contact.id \'<19><78>\'', + `allow_gid` mediumtext COMMENT 'Access Control - list of allowed groups', + `deny_cid` mediumtext COMMENT 'Access Control - list of denied contact.id', + `deny_gid` mediumtext COMMENT 'Access Control - list of denied groups', PRIMARY KEY(`id`), INDEX `uid_start` (`uid`,`start`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Events'; -- -- TABLE fcontact -- CREATE TABLE IF NOT EXISTS `fcontact` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', - `guid` varchar(255) NOT NULL DEFAULT '' COMMENT '', + `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', + `guid` varchar(255) NOT NULL DEFAULT '' COMMENT 'unique id', `url` varchar(255) NOT NULL DEFAULT '' COMMENT '', `name` varchar(255) NOT NULL DEFAULT '' COMMENT '', `photo` varchar(255) NOT NULL DEFAULT '' COMMENT '', @@ -272,7 +272,7 @@ CREATE TABLE IF NOT EXISTS `fcontact` ( PRIMARY KEY(`id`), INDEX `addr` (`addr`(32)), UNIQUE INDEX `url` (`url`(190)) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Diaspora compatible contacts - used in the Diaspora implementation'; -- -- TABLE fsuggest @@ -288,30 +288,30 @@ CREATE TABLE IF NOT EXISTS `fsuggest` ( `note` text COMMENT '', `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', PRIMARY KEY(`id`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='friend suggestion stuff'; -- -- TABLE gcign -- CREATE TABLE IF NOT EXISTS `gcign` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', - `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id', - `gcid` int unsigned NOT NULL DEFAULT 0 COMMENT '', + `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', + `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'Local User id', + `gcid` int unsigned NOT NULL DEFAULT 0 COMMENT 'gcontact.id of ignored contact', PRIMARY KEY(`id`), INDEX `uid` (`uid`), INDEX `gcid` (`gcid`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='contacts ignored by friend suggestions'; -- -- TABLE gcontact -- CREATE TABLE IF NOT EXISTS `gcontact` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', - `name` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `nick` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `url` varchar(255) NOT NULL DEFAULT '' COMMENT '', + `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', + `name` varchar(255) NOT NULL DEFAULT '' COMMENT 'Name that this contact is known by', + `nick` varchar(255) NOT NULL DEFAULT '' COMMENT 'Nick- and user name of the contact', + `url` varchar(255) NOT NULL DEFAULT '' COMMENT 'Link to the contacts profile page', `nurl` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `photo` varchar(255) NOT NULL DEFAULT '' COMMENT '', + `photo` varchar(255) NOT NULL DEFAULT '' COMMENT 'Link to the profile photo', `connect` varchar(255) NOT NULL DEFAULT '' COMMENT '', `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', `updated` datetime DEFAULT '0001-01-01 00:00:00' COMMENT '', @@ -319,19 +319,19 @@ CREATE TABLE IF NOT EXISTS `gcontact` ( `last_failure` datetime DEFAULT '0001-01-01 00:00:00' COMMENT '', `location` varchar(255) NOT NULL DEFAULT '' COMMENT '', `about` text COMMENT '', - `keywords` text COMMENT '', + `keywords` text COMMENT 'puplic keywords (interests)', `gender` varchar(32) NOT NULL DEFAULT '' COMMENT '', `birthday` varchar(32) NOT NULL DEFAULT '0001-01-01' COMMENT '', - `community` boolean NOT NULL DEFAULT '0' COMMENT '', + `community` boolean NOT NULL DEFAULT '0' COMMENT '1 if contact is forum account', `contact-type` tinyint NOT NULL DEFAULT -1 COMMENT '', - `hide` boolean NOT NULL DEFAULT '0' COMMENT '', - `nsfw` boolean NOT NULL DEFAULT '0' COMMENT '', - `network` char(4) NOT NULL DEFAULT '' COMMENT '', + `hide` boolean NOT NULL DEFAULT '0' COMMENT '1 = should be hidden from search', + `nsfw` boolean NOT NULL DEFAULT '0' COMMENT '1 = contact posts nsfw content', + `network` char(4) NOT NULL DEFAULT '' COMMENT 'social network protocol', `addr` varchar(255) NOT NULL DEFAULT '' COMMENT '', `notify` varchar(255) COMMENT '', `alias` varchar(255) NOT NULL DEFAULT '' COMMENT '', `generation` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '', - `server_url` varchar(255) NOT NULL DEFAULT '' COMMENT '', + `server_url` varchar(255) NOT NULL DEFAULT '' COMMENT 'baseurl of the contacts server', PRIMARY KEY(`id`), UNIQUE INDEX `nurl` (`nurl`(190)), INDEX `name` (`name`(64)), @@ -339,13 +339,13 @@ CREATE TABLE IF NOT EXISTS `gcontact` ( INDEX `addr` (`addr`(64)), INDEX `hide_network_updated` (`hide`,`network`,`updated`), INDEX `updated` (`updated`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='global contacts'; -- -- TABLE glink -- CREATE TABLE IF NOT EXISTS `glink` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', + `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', `cid` int unsigned NOT NULL DEFAULT 0 COMMENT '', `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id', `gcid` int unsigned NOT NULL DEFAULT 0 COMMENT '', @@ -354,45 +354,45 @@ CREATE TABLE IF NOT EXISTS `glink` ( PRIMARY KEY(`id`), UNIQUE INDEX `cid_uid_gcid_zcid` (`cid`,`uid`,`gcid`,`zcid`), INDEX `gcid` (`gcid`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='\'friends of friends\' linkages derived from poco'; -- -- TABLE group -- CREATE TABLE IF NOT EXISTS `group` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', - `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id', - `visible` boolean NOT NULL DEFAULT '0' COMMENT '', - `deleted` boolean NOT NULL DEFAULT '0' COMMENT '', - `name` varchar(255) NOT NULL DEFAULT '' COMMENT '', + `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', + `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'Owner User id', + `visible` boolean NOT NULL DEFAULT '0' COMMENT '1 indicates the member list is not private', + `deleted` boolean NOT NULL DEFAULT '0' COMMENT '1 indicates the group has been deleted', + `name` varchar(255) NOT NULL DEFAULT '' COMMENT 'human readable name of group', PRIMARY KEY(`id`), INDEX `uid` (`uid`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='privacy groups, group info'; -- -- TABLE group_member -- CREATE TABLE IF NOT EXISTS `group_member` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', - `gid` int unsigned NOT NULL DEFAULT 0 COMMENT '', - `contact-id` int unsigned NOT NULL DEFAULT 0 COMMENT '', + `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', + `gid` int unsigned NOT NULL DEFAULT 0 COMMENT 'groups.id of the associated group', + `contact-id` int unsigned NOT NULL DEFAULT 0 COMMENT 'contact.id of the member assigned to the associated group', PRIMARY KEY(`id`), INDEX `contactid` (`contact-id`), UNIQUE INDEX `gid_contactid` (`gid`,`contact-id`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='privacy groups, member info'; -- -- TABLE gserver -- CREATE TABLE IF NOT EXISTS `gserver` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', + `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', `url` varchar(255) NOT NULL DEFAULT '' COMMENT '', `nurl` varchar(255) NOT NULL DEFAULT '' COMMENT '', `version` varchar(255) NOT NULL DEFAULT '' COMMENT '', `site_name` varchar(255) NOT NULL DEFAULT '' COMMENT '', `info` text COMMENT '', `register_policy` tinyint NOT NULL DEFAULT 0 COMMENT '', - `registered-users` int unsigned NOT NULL DEFAULT 0 COMMENT '', + `registered-users` int unsigned NOT NULL DEFAULT 0 COMMENT 'Number of registered users', `poco` varchar(255) NOT NULL DEFAULT '' COMMENT '', `noscrape` varchar(255) NOT NULL DEFAULT '' COMMENT '', `network` char(4) NOT NULL DEFAULT '' COMMENT '', @@ -405,7 +405,7 @@ CREATE TABLE IF NOT EXISTS `gserver` ( `last_failure` datetime DEFAULT '0001-01-01 00:00:00' COMMENT '', PRIMARY KEY(`id`), UNIQUE INDEX `nurl` (`nurl`(190)) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Global servers'; -- -- TABLE gserver-tag @@ -415,26 +415,26 @@ CREATE TABLE IF NOT EXISTS `gserver-tag` ( `tag` varchar(100) NOT NULL DEFAULT '' COMMENT 'Tag that the server has subscribed', PRIMARY KEY(`gserver-id`,`tag`), INDEX `tag` (`tag`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Tags that the server has subscribed'; -- -- TABLE hook -- CREATE TABLE IF NOT EXISTS `hook` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', - `hook` varbinary(100) NOT NULL DEFAULT '' COMMENT '', - `file` varbinary(200) NOT NULL DEFAULT '' COMMENT '', - `function` varbinary(200) NOT NULL DEFAULT '' COMMENT '', - `priority` smallint unsigned NOT NULL DEFAULT 0 COMMENT '', + `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', + `hook` varbinary(100) NOT NULL DEFAULT '' COMMENT 'name of hook', + `file` varbinary(200) NOT NULL DEFAULT '' COMMENT 'relative filename of hook handler', + `function` varbinary(200) NOT NULL DEFAULT '' COMMENT 'function name of hook handler', + `priority` smallint unsigned NOT NULL DEFAULT 0 COMMENT 'not yet implemented - can be used to sort conflicts in hook handling by calling handlers in priority order', PRIMARY KEY(`id`), UNIQUE INDEX `hook_file_function` (`hook`,`file`,`function`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='addon hook registry'; -- -- TABLE intro -- CREATE TABLE IF NOT EXISTS `intro` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', + `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id', `fid` int unsigned NOT NULL DEFAULT 0 COMMENT '', `contact-id` int unsigned NOT NULL DEFAULT 0 COMMENT '', @@ -446,75 +446,74 @@ CREATE TABLE IF NOT EXISTS `intro` ( `blocked` boolean NOT NULL DEFAULT '1' COMMENT '', `ignore` boolean NOT NULL DEFAULT '0' COMMENT '', PRIMARY KEY(`id`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT=''; -- -- TABLE item -- CREATE TABLE IF NOT EXISTS `item` ( `id` int unsigned NOT NULL auto_increment, - `guid` varchar(255) NOT NULL DEFAULT '' COMMENT '', + `guid` varchar(255) NOT NULL DEFAULT '' COMMENT 'A unique identifier for this item', `uri` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id', - `contact-id` int unsigned NOT NULL DEFAULT 0 COMMENT '', + `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'Owner id which owns this copy of the item', + `contact-id` int unsigned NOT NULL DEFAULT 0 COMMENT 'contact.id', `type` varchar(20) NOT NULL DEFAULT '' COMMENT '', - `wall` boolean NOT NULL DEFAULT '0' COMMENT '', + `wall` boolean NOT NULL DEFAULT '0' COMMENT 'This item was posted to the wall of uid', `gravity` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '', - `parent` int unsigned NOT NULL DEFAULT 0 COMMENT '', - `parent-uri` varchar(255) NOT NULL DEFAULT '' COMMENT '', + `parent` int unsigned NOT NULL DEFAULT 0 COMMENT 'item.id of the parent to this item if it is a reply of some form; otherwise this must be set to the id of this item', + `parent-uri` varchar(255) NOT NULL DEFAULT '' COMMENT 'uri of the parent to this item', `extid` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `thr-parent` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', - `edited` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', - `commented` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', - `received` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', - `changed` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', - `owner-id` int unsigned NOT NULL DEFAULT 0 COMMENT '', - `owner-name` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `owner-link` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `owner-avatar` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `author-id` int unsigned NOT NULL DEFAULT 0 COMMENT '', - `author-name` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `author-link` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `author-avatar` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `title` varchar(255) NOT NULL DEFAULT '' COMMENT '', + `thr-parent` varchar(255) NOT NULL DEFAULT '' COMMENT 'If the parent of this item is not the top-level item in the conversation, the uri of the immediate parent; otherwise set to parent-uri', + `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Creation timestamp.', + `edited` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Date of last edit (default is created)', + `commented` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Date of last comment/reply to this item', + `received` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'datetime', + `changed` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Date that something in the conversation changed, indicating clients should fetch the conversation again', + `owner-id` int unsigned NOT NULL DEFAULT 0 COMMENT 'Link to the contact table with uid=0 of the owner of this item', + `owner-name` varchar(255) NOT NULL DEFAULT '' COMMENT 'Name of the owner of this item', + `owner-link` varchar(255) NOT NULL DEFAULT '' COMMENT 'Link to the profile page of the owner of this item', + `owner-avatar` varchar(255) NOT NULL DEFAULT '' COMMENT 'Link to the avatar picture of the owner of this item', + `author-id` int unsigned NOT NULL DEFAULT 0 COMMENT 'Link to the contact table with uid=0 of the author of this item', + `author-name` varchar(255) NOT NULL DEFAULT '' COMMENT 'Name of the author of this item', + `author-link` varchar(255) NOT NULL DEFAULT '' COMMENT 'Link to the profile page of the author of this item', + `author-avatar` varchar(255) NOT NULL DEFAULT '' COMMENT 'Link to the avatar picture of the author of this item', + `title` varchar(255) NOT NULL DEFAULT '' COMMENT 'item title', `content-warning` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `body` mediumtext COMMENT '', - `app` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `verb` varchar(100) NOT NULL DEFAULT '' COMMENT '', - `object-type` varchar(100) NOT NULL DEFAULT '' COMMENT '', - `object` text COMMENT '', - `target-type` varchar(100) NOT NULL DEFAULT '' COMMENT '', - `target` text COMMENT '', - `postopts` text COMMENT '', - `plink` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `resource-id` varchar(32) NOT NULL DEFAULT '' COMMENT '', - `event-id` int unsigned NOT NULL DEFAULT 0 COMMENT '', + `body` mediumtext COMMENT 'item body content', + `app` varchar(255) NOT NULL DEFAULT '' COMMENT 'application which generated this item', + `verb` varchar(100) NOT NULL DEFAULT '' COMMENT 'ActivityStreams verb', + `object-type` varchar(100) NOT NULL DEFAULT '' COMMENT 'ActivityStreams object type', + `object` text COMMENT 'JSON encoded object structure unless it is an implied object (normal post)', + `target-type` varchar(100) NOT NULL DEFAULT '' COMMENT 'ActivityStreams target type if applicable (URI)', + `target` text COMMENT 'JSON encoded target structure if used', + `postopts` text COMMENT 'External post connectors add their network name to this comma-separated string to identify that they should be delivered to these networks during delivery', + `plink` varchar(255) NOT NULL DEFAULT '' COMMENT 'permalink or URL to a displayable copy of the message at its source', + `resource-id` varchar(32) NOT NULL DEFAULT '' COMMENT 'Used to link other tables to items, it identifies the linked resource (e.g. photo) and if set must also set resource_type', + `event-id` int unsigned NOT NULL DEFAULT 0 COMMENT 'Used to link to the event.id', `tag` mediumtext COMMENT '', - `attach` mediumtext COMMENT '', + `attach` mediumtext COMMENT 'JSON structure representing attachments to this item', `inform` mediumtext COMMENT '', `file` mediumtext COMMENT '', - `location` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `coord` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `allow_cid` mediumtext COMMENT '', - `allow_gid` mediumtext COMMENT '', - `deny_cid` mediumtext COMMENT '', - `deny_gid` mediumtext COMMENT '', - `private` boolean NOT NULL DEFAULT '0' COMMENT '', + `location` varchar(255) NOT NULL DEFAULT '' COMMENT 'text location where this item originated', + `coord` varchar(255) NOT NULL DEFAULT '' COMMENT 'longitude/latitude pair representing location where this item originated', + `allow_cid` mediumtext COMMENT 'Access Control - list of allowed contact.id \'<19><78>\'', + `allow_gid` mediumtext COMMENT 'Access Control - list of allowed groups', + `deny_cid` mediumtext COMMENT 'Access Control - list of denied contact.id', + `deny_gid` mediumtext COMMENT 'Access Control - list of denied groups', + `private` boolean NOT NULL DEFAULT '0' COMMENT 'distribution is restricted', `pubmail` boolean NOT NULL DEFAULT '0' COMMENT '', `moderated` boolean NOT NULL DEFAULT '0' COMMENT '', `visible` boolean NOT NULL DEFAULT '0' COMMENT '', - `spam` boolean NOT NULL DEFAULT '0' COMMENT '', - `starred` boolean NOT NULL DEFAULT '0' COMMENT '', - `bookmark` boolean NOT NULL DEFAULT '0' COMMENT '', - `unseen` boolean NOT NULL DEFAULT '1' COMMENT '', - `deleted` boolean NOT NULL DEFAULT '0' COMMENT '', - `origin` boolean NOT NULL DEFAULT '0' COMMENT '', + `starred` boolean NOT NULL DEFAULT '0' COMMENT 'item has been favourited', + `bookmark` boolean NOT NULL DEFAULT '0' COMMENT 'item has been bookmarked', + `unseen` boolean NOT NULL DEFAULT '1' COMMENT 'item has not been seen', + `deleted` boolean NOT NULL DEFAULT '0' COMMENT 'item has been deleted', + `origin` boolean NOT NULL DEFAULT '0' COMMENT 'item originated at this site', `forum_mode` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '', - `mention` boolean NOT NULL DEFAULT '0' COMMENT '', - `network` char(4) NOT NULL DEFAULT '' COMMENT '', + `mention` boolean NOT NULL DEFAULT '0' COMMENT 'The owner of this item was mentioned in it', + `network` char(4) NOT NULL DEFAULT '' COMMENT 'Network from where the item comes from', `rendered-hash` varchar(32) NOT NULL DEFAULT '' COMMENT '', - `rendered-html` mediumtext COMMENT '', + `rendered-html` mediumtext COMMENT 'item.body converted to html', `global` boolean NOT NULL DEFAULT '0' COMMENT '', PRIMARY KEY(`id`), INDEX `guid` (`guid`(191)), @@ -544,53 +543,53 @@ CREATE TABLE IF NOT EXISTS `item` ( INDEX `uid_eventid` (`uid`,`event-id`), INDEX `uid_authorlink` (`uid`,`author-link`(190)), INDEX `uid_ownerlink` (`uid`,`owner-link`(190)) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='All posts'; -- -- TABLE locks -- CREATE TABLE IF NOT EXISTS `locks` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', + `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', `name` varchar(128) NOT NULL DEFAULT '' COMMENT '', `locked` boolean NOT NULL DEFAULT '0' COMMENT '', - `pid` int unsigned NOT NULL DEFAULT 0 COMMENT '', + `pid` int unsigned NOT NULL DEFAULT 0 COMMENT 'Process ID', PRIMARY KEY(`id`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT=''; -- -- TABLE mail -- CREATE TABLE IF NOT EXISTS `mail` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', - `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id', - `guid` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `from-name` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `from-photo` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `from-url` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `contact-id` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `convid` int unsigned NOT NULL DEFAULT 0 COMMENT '', + `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', + `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'Owner User id', + `guid` varchar(255) NOT NULL DEFAULT '' COMMENT 'A unique identifier for this private message', + `from-name` varchar(255) NOT NULL DEFAULT '' COMMENT 'name of the sender', + `from-photo` varchar(255) NOT NULL DEFAULT '' COMMENT 'contact photo link of the sender', + `from-url` varchar(255) NOT NULL DEFAULT '' COMMENT 'profile linke of the sender', + `contact-id` varchar(255) NOT NULL DEFAULT '' COMMENT 'contact.id', + `convid` int unsigned NOT NULL DEFAULT 0 COMMENT 'conv.id', `title` varchar(255) NOT NULL DEFAULT '' COMMENT '', `body` mediumtext COMMENT '', - `seen` boolean NOT NULL DEFAULT '0' COMMENT '', + `seen` boolean NOT NULL DEFAULT '0' COMMENT 'if message visited it is 1', `reply` boolean NOT NULL DEFAULT '0' COMMENT '', `replied` boolean NOT NULL DEFAULT '0' COMMENT '', - `unknown` boolean NOT NULL DEFAULT '0' COMMENT '', + `unknown` boolean NOT NULL DEFAULT '0' COMMENT 'if sender not in the contact table this is 1', `uri` varchar(255) NOT NULL DEFAULT '' COMMENT '', `parent-uri` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', + `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'creation time of the private message', PRIMARY KEY(`id`), INDEX `uid_seen` (`uid`,`seen`), INDEX `convid` (`convid`), INDEX `uri` (`uri`(64)), INDEX `parent-uri` (`parent-uri`(64)), INDEX `contactid` (`contact-id`(32)) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='private messages'; -- -- TABLE mailacct -- CREATE TABLE IF NOT EXISTS `mailacct` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', + `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id', `server` varchar(255) NOT NULL DEFAULT '' COMMENT '', `port` smallint unsigned NOT NULL DEFAULT 0 COMMENT '', @@ -604,24 +603,24 @@ CREATE TABLE IF NOT EXISTS `mailacct` ( `pubmail` boolean NOT NULL DEFAULT '0' COMMENT '', `last_check` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', PRIMARY KEY(`id`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Mail account data for fetching mails'; -- -- TABLE manage -- CREATE TABLE IF NOT EXISTS `manage` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', + `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id', `mid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id', PRIMARY KEY(`id`), UNIQUE INDEX `uid_mid` (`uid`,`mid`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='table of accounts that can manage each other'; -- -- TABLE notify -- CREATE TABLE IF NOT EXISTS `notify` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', + `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', `hash` varchar(64) NOT NULL DEFAULT '' COMMENT '', `type` smallint unsigned NOT NULL DEFAULT 0 COMMENT '', `name` varchar(255) NOT NULL DEFAULT '' COMMENT '', @@ -629,58 +628,58 @@ CREATE TABLE IF NOT EXISTS `notify` ( `photo` varchar(255) NOT NULL DEFAULT '' COMMENT '', `date` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', `msg` mediumtext COMMENT '', - `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id', + `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'Owner User id', `link` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `iid` int unsigned NOT NULL DEFAULT 0 COMMENT '', + `iid` int unsigned NOT NULL DEFAULT 0 COMMENT 'item.id', `parent` int unsigned NOT NULL DEFAULT 0 COMMENT '', `seen` boolean NOT NULL DEFAULT '0' COMMENT '', `verb` varchar(100) NOT NULL DEFAULT '' COMMENT '', `otype` varchar(10) NOT NULL DEFAULT '' COMMENT '', - `name_cache` tinytext COMMENT '', - `msg_cache` mediumtext COMMENT '', + `name_cache` tinytext COMMENT 'Cached bbcode parsing of name', + `msg_cache` mediumtext COMMENT 'Cached bbcode parsing of msg', PRIMARY KEY(`id`), INDEX `hash_uid` (`hash`,`uid`), INDEX `seen_uid_date` (`seen`,`uid`,`date`), INDEX `uid_date` (`uid`,`date`), INDEX `uid_type_link` (`uid`,`type`,`link`(190)) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='notifications'; -- -- TABLE notify-threads -- CREATE TABLE IF NOT EXISTS `notify-threads` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', + `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', `notify-id` int unsigned NOT NULL DEFAULT 0 COMMENT '', `master-parent-item` int unsigned NOT NULL DEFAULT 0 COMMENT '', `parent-item` int unsigned NOT NULL DEFAULT 0 COMMENT '', `receiver-uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id', PRIMARY KEY(`id`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT=''; -- -- TABLE oembed -- CREATE TABLE IF NOT EXISTS `oembed` ( - `url` varbinary(255) NOT NULL COMMENT '', - `maxwidth` mediumint unsigned NOT NULL COMMENT '', - `content` mediumtext COMMENT '', - `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', + `url` varbinary(255) NOT NULL COMMENT 'page url', + `maxwidth` mediumint unsigned NOT NULL COMMENT 'Maximum width passed to Oembed', + `content` mediumtext COMMENT 'OEmbed data of the page', + `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'datetime of creation', PRIMARY KEY(`url`,`maxwidth`), INDEX `created` (`created`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='cache for OEmbed queries'; -- -- TABLE parsed_url -- CREATE TABLE IF NOT EXISTS `parsed_url` ( - `url` varbinary(255) NOT NULL COMMENT '', - `guessing` boolean NOT NULL DEFAULT '0' COMMENT '', - `oembed` boolean NOT NULL DEFAULT '0' COMMENT '', - `content` mediumtext COMMENT '', - `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', + `url` varbinary(255) NOT NULL COMMENT 'page url', + `guessing` boolean NOT NULL DEFAULT '0' COMMENT 'is the \'guessing\' mode active?', + `oembed` boolean NOT NULL DEFAULT '0' COMMENT 'is the data the result of oembed?', + `content` mediumtext COMMENT 'page data', + `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'datetime of creation', PRIMARY KEY(`url`,`guessing`,`oembed`), INDEX `created` (`created`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='cache for \'parse_url\' queries'; -- -- TABLE participation @@ -691,7 +690,7 @@ CREATE TABLE IF NOT EXISTS `participation` ( `cid` int unsigned NOT NULL COMMENT '', `fid` int unsigned NOT NULL COMMENT '', PRIMARY KEY(`iid`,`server`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Storage for participation messages from Diaspora'; -- -- TABLE pconfig @@ -704,22 +703,22 @@ CREATE TABLE IF NOT EXISTS `pconfig` ( `v` mediumtext COMMENT '', PRIMARY KEY(`id`), UNIQUE INDEX `uid_cat_k` (`uid`,`cat`,`k`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='personal (per user) configuration storage'; -- -- TABLE photo -- CREATE TABLE IF NOT EXISTS `photo` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', - `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id', - `contact-id` int unsigned NOT NULL DEFAULT 0 COMMENT '', - `guid` char(16) NOT NULL DEFAULT '' COMMENT '', + `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', + `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'Owner User id', + `contact-id` int unsigned NOT NULL DEFAULT 0 COMMENT 'contact.id', + `guid` char(16) NOT NULL DEFAULT '' COMMENT 'A unique identifier for this photo', `resource-id` char(32) NOT NULL DEFAULT '' COMMENT '', - `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', - `edited` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', + `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'creation date', + `edited` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'last edited date', `title` varchar(255) NOT NULL DEFAULT '' COMMENT '', `desc` text COMMENT '', - `album` varchar(255) NOT NULL DEFAULT '' COMMENT '', + `album` varchar(255) NOT NULL DEFAULT '' COMMENT 'The name of the album to which the photo belongs', `filename` varchar(255) NOT NULL DEFAULT '' COMMENT '', `type` varchar(30) NOT NULL DEFAULT 'image/jpeg', `height` smallint unsigned NOT NULL DEFAULT 0 COMMENT '', @@ -728,10 +727,10 @@ CREATE TABLE IF NOT EXISTS `photo` ( `data` mediumblob NOT NULL COMMENT '', `scale` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '', `profile` boolean NOT NULL DEFAULT '0' COMMENT '', - `allow_cid` mediumtext COMMENT '', - `allow_gid` mediumtext COMMENT '', - `deny_cid` mediumtext COMMENT '', - `deny_gid` mediumtext COMMENT '', + `allow_cid` mediumtext COMMENT 'Access Control - list of allowed contact.id \'<19><78>\'', + `allow_gid` mediumtext COMMENT 'Access Control - list of allowed groups', + `deny_cid` mediumtext COMMENT 'Access Control - list of denied contact.id', + `deny_gid` mediumtext COMMENT 'Access Control - list of denied groups', PRIMARY KEY(`id`), INDEX `contactid` (`contact-id`), INDEX `uid_contactid` (`uid`,`contact-id`), @@ -739,7 +738,7 @@ CREATE TABLE IF NOT EXISTS `photo` ( INDEX `uid_album_scale_created` (`uid`,`album`(32),`scale`,`created`), INDEX `uid_album_resource-id_created` (`uid`,`album`(32),`resource-id`,`created`), INDEX `resource-id` (`resource-id`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='photo storage'; -- -- TABLE poll @@ -759,18 +758,18 @@ CREATE TABLE IF NOT EXISTS `poll` ( `q9` text COMMENT '', PRIMARY KEY(`id`), INDEX `uid` (`uid`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Currently unused table for storing poll results'; -- -- TABLE poll_result -- CREATE TABLE IF NOT EXISTS `poll_result` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', + `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', `poll_id` int unsigned NOT NULL DEFAULT 0, `choice` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '', PRIMARY KEY(`id`), INDEX `poll_id` (`poll_id`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='data for polls - currently unused'; -- -- TABLE process @@ -781,20 +780,20 @@ CREATE TABLE IF NOT EXISTS `process` ( `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', PRIMARY KEY(`pid`), INDEX `command` (`command`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Currently running system processes'; -- -- TABLE profile -- CREATE TABLE IF NOT EXISTS `profile` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', - `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id', - `profile-name` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `is-default` boolean NOT NULL DEFAULT '0' COMMENT '', - `hide-friends` boolean NOT NULL DEFAULT '0' COMMENT '', + `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', + `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'Owner User id', + `profile-name` varchar(255) NOT NULL DEFAULT '' COMMENT 'Name of the profile', + `is-default` boolean NOT NULL DEFAULT '0' COMMENT 'Mark this profile as default profile', + `hide-friends` boolean NOT NULL DEFAULT '0' COMMENT 'Hide friend list from viewers of this profile', `name` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `pdesc` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `dob` varchar(32) NOT NULL DEFAULT '0000-00-00' COMMENT '', + `pdesc` varchar(255) NOT NULL DEFAULT '' COMMENT 'Title or description', + `dob` varchar(32) NOT NULL DEFAULT '0000-00-00' COMMENT 'Day of birth', `address` varchar(255) NOT NULL DEFAULT '' COMMENT '', `locality` varchar(255) NOT NULL DEFAULT '' COMMENT '', `region` varchar(255) NOT NULL DEFAULT '' COMMENT '', @@ -827,30 +826,30 @@ CREATE TABLE IF NOT EXISTS `profile` ( `xmpp` varchar(255) NOT NULL DEFAULT '' COMMENT '', `photo` varchar(255) NOT NULL DEFAULT '' COMMENT '', `thumb` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `publish` boolean NOT NULL DEFAULT '0' COMMENT '', - `net-publish` boolean NOT NULL DEFAULT '0' COMMENT '', + `publish` boolean NOT NULL DEFAULT '0' COMMENT 'publish default profile in local directory', + `net-publish` boolean NOT NULL DEFAULT '0' COMMENT 'publish profile in global directory', PRIMARY KEY(`id`), INDEX `uid_is-default` (`uid`,`is-default`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='user profiles data'; -- -- TABLE profile_check -- CREATE TABLE IF NOT EXISTS `profile_check` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', + `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id', - `cid` int unsigned NOT NULL DEFAULT 0 COMMENT '', + `cid` int unsigned NOT NULL DEFAULT 0 COMMENT 'contact.id', `dfrn_id` varchar(255) NOT NULL DEFAULT '' COMMENT '', `sec` varchar(255) NOT NULL DEFAULT '' COMMENT '', `expire` int unsigned NOT NULL DEFAULT 0 COMMENT '', PRIMARY KEY(`id`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='DFRN remote auth use'; -- -- TABLE push_subscriber -- CREATE TABLE IF NOT EXISTS `push_subscriber` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', + `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id', `callback_url` varchar(255) NOT NULL DEFAULT '' COMMENT '', `topic` varchar(255) NOT NULL DEFAULT '' COMMENT '', @@ -862,13 +861,13 @@ CREATE TABLE IF NOT EXISTS `push_subscriber` ( `secret` varchar(255) NOT NULL DEFAULT '' COMMENT '', PRIMARY KEY(`id`), INDEX `next_try` (`next_try`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Used for OStatus: Contains feed subscribers'; -- -- TABLE queue -- CREATE TABLE IF NOT EXISTS `queue` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', + `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', `cid` int unsigned NOT NULL DEFAULT 0 COMMENT 'Message receiver', `network` char(4) NOT NULL DEFAULT '' COMMENT 'Receiver\'s network', `guid` varchar(255) NOT NULL DEFAULT '' COMMENT 'Unique GUID of the message', @@ -881,13 +880,13 @@ CREATE TABLE IF NOT EXISTS `queue` ( PRIMARY KEY(`id`), INDEX `last` (`last`), INDEX `next` (`next`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Queue for messages that couldn\'t be delivered'; -- -- TABLE register -- CREATE TABLE IF NOT EXISTS `register` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', + `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', `hash` varchar(255) NOT NULL DEFAULT '' COMMENT '', `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id', @@ -895,44 +894,44 @@ CREATE TABLE IF NOT EXISTS `register` ( `language` varchar(16) NOT NULL DEFAULT '' COMMENT '', `note` text COMMENT '', PRIMARY KEY(`id`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='registrations requiring admin approval'; -- -- TABLE search -- CREATE TABLE IF NOT EXISTS `search` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', + `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id', `term` varchar(255) NOT NULL DEFAULT '' COMMENT '', PRIMARY KEY(`id`), INDEX `uid` (`uid`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT=''; -- -- TABLE session -- CREATE TABLE IF NOT EXISTS `session` ( - `id` bigint unsigned NOT NULL auto_increment COMMENT '', + `id` bigint unsigned NOT NULL auto_increment COMMENT 'sequential ID', `sid` varbinary(255) NOT NULL DEFAULT '' COMMENT '', `data` text COMMENT '', `expire` int unsigned NOT NULL DEFAULT 0 COMMENT '', PRIMARY KEY(`id`), INDEX `sid` (`sid`(64)), INDEX `expire` (`expire`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='web session storage'; -- -- TABLE sign -- CREATE TABLE IF NOT EXISTS `sign` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', - `iid` int unsigned NOT NULL DEFAULT 0 COMMENT '', + `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', + `iid` int unsigned NOT NULL DEFAULT 0 COMMENT 'item.id', `signed_text` mediumtext COMMENT '', `signature` text COMMENT '', `signer` varchar(255) NOT NULL DEFAULT '' COMMENT '', PRIMARY KEY(`id`), UNIQUE INDEX `iid` (`iid`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Diaspora signatures'; -- -- TABLE term @@ -955,17 +954,17 @@ CREATE TABLE IF NOT EXISTS `term` ( INDEX `uid_otype_type_term_global_created` (`uid`,`otype`,`type`,`term`(32),`global`,`created`), INDEX `uid_otype_type_url` (`uid`,`otype`,`type`,`url`(64)), INDEX `guid` (`guid`(64)) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='item taxonomy (categories, tags, etc.) table'; -- -- TABLE thread -- CREATE TABLE IF NOT EXISTS `thread` ( - `iid` int unsigned NOT NULL DEFAULT 0 COMMENT '', + `iid` int unsigned NOT NULL DEFAULT 0 COMMENT 'sequential ID', `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id', `contact-id` int unsigned NOT NULL DEFAULT 0 COMMENT '', - `owner-id` int unsigned NOT NULL DEFAULT 0 COMMENT '', - `author-id` int unsigned NOT NULL DEFAULT 0 COMMENT '', + `owner-id` int unsigned NOT NULL DEFAULT 0 COMMENT 'Item owner', + `author-id` int unsigned NOT NULL DEFAULT 0 COMMENT 'Item author', `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', `edited` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', `commented` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', @@ -976,7 +975,6 @@ CREATE TABLE IF NOT EXISTS `thread` ( `pubmail` boolean NOT NULL DEFAULT '0' COMMENT '', `moderated` boolean NOT NULL DEFAULT '0' COMMENT '', `visible` boolean NOT NULL DEFAULT '0' COMMENT '', - `spam` boolean NOT NULL DEFAULT '0' COMMENT '', `starred` boolean NOT NULL DEFAULT '0' COMMENT '', `ignored` boolean NOT NULL DEFAULT '0' COMMENT '', `bookmark` boolean NOT NULL DEFAULT '0' COMMENT '', @@ -998,7 +996,7 @@ CREATE TABLE IF NOT EXISTS `thread` ( INDEX `uid_commented` (`uid`,`commented`), INDEX `uid_wall_created` (`uid`,`wall`,`created`), INDEX `private_wall_origin_commented` (`private`,`wall`,`origin`,`commented`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Thread related data'; -- -- TABLE tokens @@ -1011,70 +1009,89 @@ CREATE TABLE IF NOT EXISTS `tokens` ( `scope` varchar(200) NOT NULL DEFAULT '' COMMENT '', `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id', PRIMARY KEY(`id`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='OAuth usage'; -- -- TABLE user -- CREATE TABLE IF NOT EXISTS `user` ( - `uid` mediumint unsigned NOT NULL auto_increment COMMENT '', + `uid` mediumint unsigned NOT NULL auto_increment COMMENT 'sequential ID', `parent-uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'The parent user that has full control about this user', - `guid` varchar(64) NOT NULL DEFAULT '' COMMENT '', - `username` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `password` varchar(255) NOT NULL DEFAULT '' COMMENT '', + `guid` varchar(64) NOT NULL DEFAULT '' COMMENT 'A unique identifier for this user', + `username` varchar(255) NOT NULL DEFAULT '' COMMENT 'Name that this user is known by', + `password` varchar(255) NOT NULL DEFAULT '' COMMENT 'encrypted password', `legacy_password` boolean NOT NULL DEFAULT '0' COMMENT 'Is the password hash double-hashed?', - `nickname` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `email` varchar(255) NOT NULL DEFAULT '' COMMENT '', + `nickname` varchar(255) NOT NULL DEFAULT '' COMMENT 'nick- and user name', + `email` varchar(255) NOT NULL DEFAULT '' COMMENT 'the users email address', `openid` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `timezone` varchar(128) NOT NULL DEFAULT '' COMMENT '', - `language` varchar(32) NOT NULL DEFAULT 'en' COMMENT '', - `register_date` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', - `login_date` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', - `default-location` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `allow_location` boolean NOT NULL DEFAULT '0' COMMENT '', - `theme` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `pubkey` text COMMENT '', - `prvkey` text COMMENT '', + `timezone` varchar(128) NOT NULL DEFAULT '' COMMENT 'PHP-legal timezone', + `language` varchar(32) NOT NULL DEFAULT 'en' COMMENT 'default language', + `register_date` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'timestamp of registration', + `login_date` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'timestamp of last login', + `default-location` varchar(255) NOT NULL DEFAULT '' COMMENT 'Default for item.location', + `allow_location` boolean NOT NULL DEFAULT '0' COMMENT '1 allows to display the location', + `theme` varchar(255) NOT NULL DEFAULT '' COMMENT 'user theme preference', + `pubkey` text COMMENT 'RSA public key 4096 bit', + `prvkey` text COMMENT 'RSA private key 4096 bit', `spubkey` text COMMENT '', `sprvkey` text COMMENT '', - `verified` boolean NOT NULL DEFAULT '0' COMMENT '', - `blocked` boolean NOT NULL DEFAULT '0' COMMENT '', - `blockwall` boolean NOT NULL DEFAULT '0' COMMENT '', - `hidewall` boolean NOT NULL DEFAULT '0' COMMENT '', - `blocktags` boolean NOT NULL DEFAULT '0' COMMENT '', - `unkmail` boolean NOT NULL DEFAULT '0' COMMENT '', + `verified` boolean NOT NULL DEFAULT '0' COMMENT 'user is verified through email', + `blocked` boolean NOT NULL DEFAULT '0' COMMENT '1 for user is blocked', + `blockwall` boolean NOT NULL DEFAULT '0' COMMENT 'Prohibit contacts to post to the profile page of the user', + `hidewall` boolean NOT NULL DEFAULT '0' COMMENT 'Hide profile details from unkown viewers', + `blocktags` boolean NOT NULL DEFAULT '0' COMMENT 'Prohibit contacts to tag the post of this user', + `unkmail` boolean NOT NULL DEFAULT '0' COMMENT 'Permit unknown people to send private mails to this user', `cntunkmail` int unsigned NOT NULL DEFAULT 10 COMMENT '', - `notify-flags` smallint unsigned NOT NULL DEFAULT 65535 COMMENT '', - `page-flags` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '', + `notify-flags` smallint unsigned NOT NULL DEFAULT 65535 COMMENT 'email notification options', + `page-flags` tinyint unsigned NOT NULL DEFAULT 0 COMMENT 'page/profile type', `account-type` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '', `prvnets` boolean NOT NULL DEFAULT '0' COMMENT '', `pwdreset` varchar(255) COMMENT 'Password reset request token', `pwdreset_time` datetime COMMENT 'Timestamp of the last password reset request', `maxreq` int unsigned NOT NULL DEFAULT 10 COMMENT '', `expire` int unsigned NOT NULL DEFAULT 0 COMMENT '', - `account_removed` boolean NOT NULL DEFAULT '0' COMMENT '', + `account_removed` boolean NOT NULL DEFAULT '0' COMMENT 'if 1 the account is removed', `account_expired` boolean NOT NULL DEFAULT '0' COMMENT '', - `account_expires_on` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', - `expire_notification_sent` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', + `account_expires_on` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'timestamp when account expires and will be deleted', + `expire_notification_sent` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'timestamp of last warning of account expiration', `def_gid` int unsigned NOT NULL DEFAULT 0 COMMENT '', - `allow_cid` mediumtext COMMENT '', - `allow_gid` mediumtext COMMENT '', - `deny_cid` mediumtext COMMENT '', - `deny_gid` mediumtext COMMENT '', + `allow_cid` mediumtext COMMENT 'default permission for this user', + `allow_gid` mediumtext COMMENT 'default permission for this user', + `deny_cid` mediumtext COMMENT 'default permission for this user', + `deny_gid` mediumtext COMMENT 'default permission for this user', `openidserver` text COMMENT '', PRIMARY KEY(`uid`), INDEX `nickname` (`nickname`(32)) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='The local users'; -- -- TABLE userd -- CREATE TABLE IF NOT EXISTS `userd` ( - `id` int unsigned NOT NULL auto_increment COMMENT '', + `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', `username` varchar(255) NOT NULL COMMENT '', PRIMARY KEY(`id`), INDEX `username` (`username`(32)) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Deleted usernames'; + +-- +-- TABLE user-item +-- +CREATE TABLE IF NOT EXISTS `user-item` ( + `iid` int unsigned NOT NULL DEFAULT 0 COMMENT 'Item id', + `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id', + `hidden` boolean NOT NULL DEFAULT '0' COMMENT 'Marker to hide an item from the user', + PRIMARY KEY(`uid`,`iid`) +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='User specific item data'; + +-- +-- TABLE worker-ipc +-- +CREATE TABLE IF NOT EXISTS `worker-ipc` ( + `key` int NOT NULL COMMENT '', + `jobs` boolean COMMENT 'Flag for outstanding jobs', + PRIMARY KEY(`key`) +) ENGINE=MEMORY DEFAULT COLLATE utf8mb4_general_ci COMMENT='Inter process communication between the frontend and the worker'; -- -- TABLE workerqueue @@ -1086,12 +1103,12 @@ CREATE TABLE IF NOT EXISTS `workerqueue` ( `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Creation date', `pid` int unsigned NOT NULL DEFAULT 0 COMMENT 'Process id of the worker', `executed` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Execution date', - `done` boolean NOT NULL DEFAULT '0' COMMENT 'Marked when the task was done, will be deleted later', + `done` boolean NOT NULL DEFAULT '0' COMMENT 'Marked 1 when the task was done - will be deleted later', PRIMARY KEY(`id`), INDEX `pid` (`pid`), INDEX `parameter` (`parameter`(64)), INDEX `priority_created` (`priority`,`created`), INDEX `done_executed` (`done`,`executed`) -) DEFAULT COLLATE utf8mb4_general_ci; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Background tasks queue entries'; diff --git a/doc/Home.md b/doc/Home.md index 1d72a2600f..0a41a46146 100644 --- a/doc/Home.md +++ b/doc/Home.md @@ -51,6 +51,7 @@ Friendica Documentation and Resources * [Translate Friendica](help/translations) * [Use Composer](help/Composer) * [Move classes to `src`](help/Developer-How-To-Move-Classes-to-src) + * [Run tests](help/Tests) * Reference * [Twitter/GNU Social API Functions](help/api) * [Code (Doxygen generated - sets cookies)](doc/html/) @@ -72,4 +73,3 @@ Friendica Documentation and Resources * [Site/Version Info](friendica) * [Friendica Credits](credits) - diff --git a/doc/Tests.md b/doc/Tests.md new file mode 100644 index 0000000000..6acb4e783a --- /dev/null +++ b/doc/Tests.md @@ -0,0 +1,18 @@ +# Themes + +* [Home](help) + +You can run unit tests with [PHPUnit](https://phpunit.de/): + +```bash +phpunit +``` + +Some tests require access to a MySQL database. +You can specify the database credentials in environment variables: + +```bash +USER=database_user PASS=database_password DB=database_name phpunit +``` + +**Warning**: This will empty all the tables! Never use this on a production database. diff --git a/doc/de/Home.md b/doc/de/Home.md index 8e4be6bfc8..31cce7aea4 100644 --- a/doc/de/Home.md +++ b/doc/de/Home.md @@ -56,6 +56,7 @@ Friendica - Dokumentation und Ressourcen * [Code-Referenz (mit doxygen generiert - setzt Cookies)](doc/html/) * [Twitter/GNU Social API Functions](help/api) (EN) * [Translation of Friendica](help/translations) (EN) +* [Run tests](help/Tests) (EN) **Externe Ressourcen** @@ -72,4 +73,3 @@ Friendica - Dokumentation und Ressourcen * [Seite/Friendica-Version](friendica) * [Mitwirkenden bei Friendica](credits) - diff --git a/doc/de/Settings.md b/doc/de/Settings.md index 8a654e32c8..b7b696ea65 100644 --- a/doc/de/Settings.md +++ b/doc/de/Settings.md @@ -344,6 +344,14 @@ Mit den folgenden Einstellungen kannst du die Zugriffsdaten für den Datenbank S $db_pass = 'db_password'; $db_data = 'database_name'; +Sollten alle der folgenden Environment-Variablen gesetzt sein, wird Friendica diese anstatt der vorher konfigurierten Werte nutzen. + + MYSQL_HOST + MYSQL_PORT + MYSQL_USERNAME + MYSQL_PASSWORD + MYSQL_DATABASE + ## Administratoren Du kannst einen, oder mehrere Accounts, zu Administratoren machen. diff --git a/doc/htconfig.md b/doc/htconfig.md index 6598fa142a..4743da444c 100644 --- a/doc/htconfig.md +++ b/doc/htconfig.md @@ -124,3 +124,11 @@ The configuration variables db_host, db_user, db_pass and db_data are holding yo If you need to specify a port to access the database, you can do so by appending ":portnumber" to the db_host variable. $db_host = 'your.mysqlhost.com:123456'; + +If all of the following environment variables are set, Friendica will use them instead of the previously configured variables for the db: + + MYSQL_HOST + MYSQL_PORT + MYSQL_USERNAME + MYSQL_PASSWORD + MYSQL_DATABASE diff --git a/htconfig.php b/htconfig.php index 2cbbf6335d..0e838bd90d 100644 --- a/htconfig.php +++ b/htconfig.php @@ -24,11 +24,15 @@ $db_data = 'mysqldatabasename'; // Use environment variables for mysql if they are set beforehand if (!empty(getenv('MYSQL_HOST')) && !empty(getenv('MYSQL_PORT')) - && !empty(getenv('MYSQL_USERNAME')) + && (!empty(getenv('MYSQL_USERNAME')) || !empty(getenv('MYSQL_USER'))) && !empty(getenv('MYSQL_PASSWORD')) && !empty(getenv('MYSQL_DATABASE'))) { $db_host = getenv('MYSQL_HOST') . ':' . getenv('MYSQL_PORT'); - $db_user = getenv('MYSQL_USERNAME'); + if (!empty(getenv('MYSQL_USERNAME'))) { + $db_user = getenv('MYSQL_USERNAME'); + } elseif (!empty(getenv('MYSQL_USER'))) { + $db_user = getenv('MYSQL_USER'); + } $db_pass = getenv('MYSQL_PASSWORD'); $db_data = getenv('MYSQL_DATABASE'); } diff --git a/include/api.php b/include/api.php index 628b86c649..00c2173c38 100644 --- a/include/api.php +++ b/include/api.php @@ -54,7 +54,7 @@ define('API_METHOD_POST', 'POST,PUT'); define('API_METHOD_DELETE', 'POST,DELETE'); $API = []; -$called_api = null; +$called_api = []; /** * It is not sufficient to use local_user() to check whether someone is allowed to use the API, @@ -492,7 +492,7 @@ function api_rss_extra(App $a, $arr, $user_info) */ function api_unique_id_to_nurl($id) { - $r = dba::selectFirst('contact', ['nurl'], ['uid' => 0, 'id' => $id]); + $r = dba::selectFirst('contact', ['nurl'], ['id' => $id]); if (DBM::is_result($r)) { return $r["nurl"]; @@ -532,7 +532,7 @@ function api_get_user(App $a, $contact_id = null) $user = dbesc(api_unique_id_to_nurl(intval($contact_id))); if ($user == "") { - throw new BadRequestException("User not found."); + throw new BadRequestException("User ID ".$contact_id." not found."); } $url = $user; @@ -546,7 +546,7 @@ function api_get_user(App $a, $contact_id = null) $user = dbesc(api_unique_id_to_nurl($_GET['user_id'])); if ($user == "") { - throw new BadRequestException("User not found."); + throw new BadRequestException("User ID ".$_GET['user_id']." not found."); } $url = $user; @@ -670,13 +670,14 @@ function api_get_user(App $a, $contact_id = null) 'statusnet_profile_url' => $r[0]["url"], 'uid' => 0, 'cid' => Contact::getIdForURL($r[0]["url"], api_user(), true), + 'pid' => Contact::getIdForURL($r[0]["url"], 0, true), 'self' => 0, 'network' => $r[0]["network"], ]; return $ret; } else { - throw new BadRequestException("User not found."); + throw new BadRequestException("User ".$url." not found."); } } @@ -685,14 +686,8 @@ function api_get_user(App $a, $contact_id = null) $uinfo[0]['network'] = NETWORK_DFRN; } - $usr = q( - "SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", - intval(api_user()) - ); - $profile = q( - "SELECT * FROM `profile` WHERE `uid` = %d AND `is-default` = 1 LIMIT 1", - intval(api_user()) - ); + $usr = dba::selectFirst('user', ['default-location'], ['uid' => api_user()]); + $profile = dba::selectFirst('profile', ['about'], ['uid' => api_user(), 'is-default' => true]); /// @TODO old-lost code? (twice) // Counting is deactivated by now, due to performance issues @@ -759,14 +754,14 @@ function api_get_user(App $a, $contact_id = null) $pcontact_id = Contact::getIdForURL($uinfo[0]['url'], 0, true); - if (!empty($profile[0]['about'])) { - $description = $profile[0]['about']; + if (!empty($profile['about'])) { + $description = $profile['about']; } else { $description = $uinfo[0]["about"]; } - if (!empty($usr[0]['default-location'])) { - $location = $usr[0]['default-location']; + if (!empty($usr['default-location'])) { + $location = $usr['default-location']; } elseif (!empty($uinfo[0]["location"])) { $location = $uinfo[0]["location"]; } else { @@ -809,6 +804,7 @@ function api_get_user(App $a, $contact_id = null) 'statusnet_profile_url' => $uinfo[0]['url'], 'uid' => intval($uinfo[0]['uid']), 'cid' => intval($uinfo[0]['cid']), + 'pid' => Contact::getIdForURL($uinfo[0]["url"], 0, true), 'self' => $uinfo[0]['self'], 'network' => $uinfo[0]['network'], ]; @@ -856,16 +852,12 @@ function api_get_user(App $a, $contact_id = null) */ function api_item_get_user(App $a, $item) { - $status_user = api_get_user($a, $item["author-link"]); + $status_user = api_get_user($a, $item["author-id"]); - $status_user["protected"] = (($item["allow_cid"] != "") || - ($item["allow_gid"] != "") || - ($item["deny_cid"] != "") || - ($item["deny_gid"] != "") || - $item["private"]); + $status_user["protected"] = $item["private"]; if ($item['thr-parent'] == $item['uri']) { - $owner_user = api_get_user($a, $item["owner-link"]); + $owner_user = api_get_user($a, $item["owner-id"]); } else { $owner_user = $status_user; } @@ -935,7 +927,7 @@ function api_reformat_xml(&$item, &$key) * * @return string The XML data */ -function api_create_xml($data, $root_element) +function api_create_xml(array $data, $root_element) { $childname = key($data); $data2 = array_pop($data); @@ -960,7 +952,7 @@ function api_create_xml($data, $root_element) $i = 1; foreach ($data2 as $item) { - $data4[$i++.":".$childname] = $item; + $data4[$i++ . ":" . $childname] = $item; } $data2 = $data4; @@ -1068,7 +1060,7 @@ function requestdata($k) } /** - * Waitman Gobble Mod + * Deprecated function to upload media. * * @param string $type Return type (atom, rss, xml, json) * @@ -1100,14 +1092,12 @@ function api_statuses_mediap($type) } $txt = HTML::toBBCode($txt); - $a->argv[1]=$user_info['screen_name']; //should be set to username? + $a->argv[1] = $user_info['screen_name']; //should be set to username? - // tell wall_upload function to return img info instead of echo - $_REQUEST['hush'] = 'yeah'; - $bebop = wall_upload_post($a); + $picture = wall_upload_post($a, false); // now that we have the img url in bbcode we can add it to the status and insert the wall item. - $_REQUEST['body'] = $txt . "\n\n" . $bebop; + $_REQUEST['body'] = $txt . "\n\n" . '[url=' . $picture["albumpage"] . '][img]' . $picture["preview"] . "[/img][/url]"; item_post($a); // this should output the last post (the one we just posted). @@ -1256,10 +1246,9 @@ function api_statuses_update($type) if (x($_FILES, 'media')) { // upload the image if we have one - $_REQUEST['hush'] = 'yeah'; //tell wall_upload function to return img info instead of echo - $media = wall_upload_post($a); - if (strlen($media) > 0) { - $_REQUEST['body'] .= "\n\n" . $media; + $picture = wall_upload_post($a, false); + if (is_array($picture)) { + $_REQUEST['body'] .= "\n\n" . '[url=' . $picture["albumpage"] . '][img]' . $picture["preview"] . "[/img][/url]"; } } @@ -1356,31 +1345,17 @@ function api_status_show($type) logger('api_status_show: user_info: '.print_r($user_info, true), LOGGER_DEBUG); if ($type == "raw") { - $privacy_sql = "AND `item`.`allow_cid`='' AND `item`.`allow_gid`='' AND `item`.`deny_cid`='' AND `item`.`deny_gid`=''"; + $privacy_sql = "AND NOT `private`"; } else { $privacy_sql = ""; } // get last public wall message - $lastwall = q( - "SELECT `item`.* - FROM `item` - WHERE `item`.`contact-id` = %d AND `item`.`uid` = %d - AND ((`item`.`author-link` IN ('%s', '%s')) OR (`item`.`owner-link` IN ('%s', '%s'))) - AND `item`.`type` != 'activity' $privacy_sql - ORDER BY `item`.`id` DESC - LIMIT 1", - intval($user_info['cid']), - intval(api_user()), - dbesc($user_info['url']), - dbesc(normalise_link($user_info['url'])), - dbesc($user_info['url']), - dbesc(normalise_link($user_info['url'])) - ); + $condition = ["`owner-id` = ? AND `uid` = ? AND `type` != 'activity' ".$privacy_sql, + $user_info['pid'], api_user()]; + $lastwall = dba::selectFirst('item', [], $condition, ['order' => ['id' => true]]); if (DBM::is_result($lastwall)) { - $lastwall = $lastwall[0]; - $in_reply_to = api_in_reply_to($lastwall); $converted = api_convert_item($lastwall); @@ -1428,10 +1403,10 @@ function api_status_show($type) $status_info["entities"] = $converted["entities"]; } - if (($lastwall['item_network'] != "") && ($status_info["source"] == 'web')) { - $status_info["source"] = ContactSelector::networkToName($lastwall['item_network'], $user_info['url']); - } elseif (($lastwall['item_network'] != "") && (ContactSelector::networkToName($lastwall['item_network'], $user_info['url']) != $status_info["source"])) { - $status_info["source"] = trim($status_info["source"].' ('.ContactSelector::networkToName($lastwall['item_network'], $user_info['url']).')'); + if ($status_info["source"] == 'web') { + $status_info["source"] = ContactSelector::networkToName($lastwall['network'], $user_info['url']); + } elseif (ContactSelector::networkToName($lastwall['network'], $user_info['url']) != $status_info["source"]) { + $status_info["source"] = trim($status_info["source"].' ('.ContactSelector::networkToName($lastwall['network'], $user_info['url']).')'); } // "uid" and "self" are only needed for some internal stuff, so remove it from here @@ -1460,28 +1435,12 @@ function api_users_show($type) $a = get_app(); $user_info = api_get_user($a); - $lastwall = q( - "SELECT `item`.* - FROM `item` - INNER JOIN `contact` ON `contact`.`id`=`item`.`contact-id` AND `contact`.`uid` = `item`.`uid` - WHERE `item`.`uid` = %d AND `verb` = '%s' AND `item`.`contact-id` = %d - AND ((`item`.`author-link` IN ('%s', '%s')) OR (`item`.`owner-link` IN ('%s', '%s'))) - AND `type`!='activity' - AND `item`.`allow_cid`='' AND `item`.`allow_gid`='' AND `item`.`deny_cid`='' AND `item`.`deny_gid`='' - ORDER BY `id` DESC - LIMIT 1", - intval(api_user()), - dbesc(ACTIVITY_POST), - intval($user_info['cid']), - dbesc($user_info['url']), - dbesc(normalise_link($user_info['url'])), - dbesc($user_info['url']), - dbesc(normalise_link($user_info['url'])) - ); + + $condition = ["`owner-id` = ? AND `uid` = ? AND `verb` = ? AND `type` != 'activity' AND NOT `private`", + $user_info['pid'], api_user(), ACTIVITY_POST]; + $lastwall = dba::selectFirst('item', [], $condition, ['order' => ['id' => true]]); if (DBM::is_result($lastwall)) { - $lastwall = $lastwall[0]; - $in_reply_to = api_in_reply_to($lastwall); $converted = api_convert_item($lastwall); @@ -1519,12 +1478,12 @@ function api_users_show($type) $user_info["status"]["entities"] = $converted["entities"]; } - if (($lastwall['item_network'] != "") && ($user_info["status"]["source"] == 'web')) { - $user_info["status"]["source"] = ContactSelector::networkToName($lastwall['item_network'], $user_info['url']); + if ($user_info["status"]["source"] == 'web') { + $user_info["status"]["source"] = ContactSelector::networkToName($lastwall['network'], $user_info['url']); } - if (($lastwall['item_network'] != "") && (ContactSelector::networkToName($lastwall['item_network'], $user_info['url']) != $user_info["status"]["source"])) { - $user_info["status"]["source"] = trim($user_info["status"]["source"] . ' (' . ContactSelector::networkToName($lastwall['item_network'], $user_info['url']) . ')'); + if (ContactSelector::networkToName($lastwall['network'], $user_info['url']) != $user_info["status"]["source"]) { + $user_info["status"]["source"] = trim($user_info["status"]["source"] . ' (' . ContactSelector::networkToName($lastwall['network'], $user_info['url']) . ')'); } } @@ -1573,10 +1532,10 @@ function api_users_search($type) } $userlist = ["users" => $userlist]; } else { - throw new BadRequestException("User not found."); + throw new BadRequestException("User ".$_GET["q"]." not found."); } } else { - throw new BadRequestException("User not found."); + throw new BadRequestException("No user specified."); } return api_format_data("users", $type, $userlist); @@ -1637,7 +1596,6 @@ function api_search($type) } $data = []; - $sql_extra = ''; if (!x($_REQUEST, 'q')) { throw new BadRequestException("q parameter is required."); @@ -1657,24 +1615,20 @@ function api_search($type) $start = $page * $count; + $condition = ["`verb` = ? AND `item`.`id` > ? + AND (`item`.`uid` = 0 OR (`item`.`uid` = ? AND NOT `item`.`global`)) + AND `item`.`body` LIKE CONCAT('%',?,'%')", + ACTIVITY_POST, $since_id, api_user(), $_REQUEST['q']]; + if ($max_id > 0) { - $sql_extra .= ' AND `item`.`id` <= ' . intval($max_id); + $condition[0] .= " AND `item`.`id` <= ?"; + $condition[] = $max_id; } - $r = dba::p( - "SELECT ".item_fieldlists()." - FROM `item` ".item_joins()." - WHERE ".item_condition()." AND (`item`.`uid` = 0 OR (`item`.`uid` = ? AND NOT `item`.`global`)) - AND `item`.`body` LIKE CONCAT('%',?,'%') - $sql_extra - AND `item`.`id`>? - ORDER BY `item`.`id` DESC LIMIT ".intval($start)." ,".intval($count)." ", - api_user(), - $_REQUEST['q'], - $since_id - ); + $params = ['order' => ['id' => true], 'limit' => [$start, $count]]; + $statuses = Item::select(api_user(), [], $condition, $params); - $data['status'] = api_format_items(dba::inArray($r), $user_info); + $data['status'] = api_format_items(dba::inArray($statuses), $user_info); return api_format_data("statuses", $type, $data); } @@ -1724,42 +1678,30 @@ function api_statuses_home_timeline($type) $start = $page * $count; - $sql_extra = ''; + $condition = ["`uid` = ? AND `verb` = ? AND `item`.`id` > ?", api_user(), ACTIVITY_POST, $since_id]; + if ($max_id > 0) { - $sql_extra .= ' AND `item`.`id` <= ' . intval($max_id); + $condition[0] .= " AND `item`.`id` <= ?"; + $condition[] = $max_id; } if ($exclude_replies > 0) { - $sql_extra .= ' AND `item`.`parent` = `item`.`id`'; + $condition[0] .= ' AND `item`.`parent` = `item`.`id`'; } if ($conversation_id > 0) { - $sql_extra .= ' AND `item`.`parent` = ' . intval($conversation_id); + $condition[0] .= " AND `item`.`parent` = ?"; + $condition[] = $conversation_id; } - $r = q( - "SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`, - `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`, - `contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`, - `contact`.`id` AS `cid` - FROM `item` - STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id` AND `contact`.`uid` = `item`.`uid` - AND (NOT `contact`.`blocked` OR `contact`.`pending`) - WHERE `item`.`uid` = %d AND `verb` = '%s' - AND `item`.`visible` AND NOT `item`.`moderated` AND NOT `item`.`deleted` - $sql_extra - AND `item`.`id`>%d - ORDER BY `item`.`id` DESC LIMIT %d ,%d ", - intval(api_user()), - dbesc(ACTIVITY_POST), - intval($since_id), - intval($start), - intval($count) - ); + $params = ['order' => ['id' => true], 'limit' => [$start, $count]]; + $statuses = Item::select(api_user(), [], $condition, $params); - $ret = api_format_items($r, $user_info, false, $type); + $items = dba::inArray($statuses); + + $ret = api_format_items($items, $user_info, false, $type); // Set all posts from the query above to seen $idarray = []; - foreach ($r as $item) { + foreach ($items as $item) { $idarray[] = intval($item["id"]); } @@ -1819,61 +1761,35 @@ function api_statuses_public_timeline($type) $sql_extra = ''; if ($exclude_replies && !$conversation_id) { + $condition = ["`verb` = ? AND `iid` > ? AND NOT `private` AND `wall` AND NOT `user`.`hidewall`", + ACTIVITY_POST, $since_id]; + if ($max_id > 0) { - $sql_extra = 'AND `thread`.`iid` <= ' . intval($max_id); + $condition[0] .= " AND `thread`.`iid` <= ?"; + $condition[] = $max_id; } - $r = dba::p( - "SELECT " . item_fieldlists() . " - FROM `thread` - STRAIGHT_JOIN `item` ON `item`.`id` = `thread`.`iid` - " . item_joins() . " - STRAIGHT_JOIN `user` ON `user`.`uid` = `thread`.`uid` - AND NOT `user`.`hidewall` - AND `verb` = ? - AND NOT `thread`.`private` - AND `thread`.`wall` - AND `thread`.`visible` - AND NOT `thread`.`deleted` - AND NOT `thread`.`moderated` - AND `thread`.`iid` > ? - $sql_extra - ORDER BY `thread`.`iid` DESC - LIMIT " . intval($start) . ", " . intval($count), - ACTIVITY_POST, - $since_id - ); + $params = ['order' => ['iid' => true], 'limit' => [$start, $count]]; + $statuses = Item::selectThread(api_user(), [], $condition, $params); - $r = dba::inArray($r); + $r = dba::inArray($statuses); } else { + $condition = ["`verb` = ? AND `id` > ? AND NOT `private` AND `wall` AND NOT `user`.`hidewall` AND `item`.`origin`", + ACTIVITY_POST, $since_id]; + if ($max_id > 0) { - $sql_extra = 'AND `item`.`id` <= ' . intval($max_id); + $condition[0] .= " AND `item`.`id` <= ?"; + $condition[] = $max_id; } if ($conversation_id > 0) { - $sql_extra .= ' AND `item`.`parent` = ' . intval($conversation_id); + $condition[0] .= " AND `item`.`parent` = ?"; + $condition[] = $conversation_id; } - $r = dba::p( - "SELECT " . item_fieldlists() . " - FROM `item` - " . item_joins() . " - STRAIGHT_JOIN `user` ON `user`.`uid` = `item`.`uid` - AND NOT `user`.`hidewall` - AND `verb` = ? - AND NOT `item`.`private` - AND `item`.`wall` - AND `item`.`visible` - AND NOT `item`.`deleted` - AND NOT `item`.`moderated` - AND `item`.`id` > ? - $sql_extra - ORDER BY `item`.`id` DESC - LIMIT " . intval($start) . ", " . intval($count), - ACTIVITY_POST, - $since_id - ); + $params = ['order' => ['id' => true], 'limit' => [$start, $count]]; + $statuses = Item::select(api_user(), [], $condition, $params); - $r = dba::inArray($r); + $r = dba::inArray($statuses); } $ret = api_format_items($r, $user_info, false, $type); @@ -1921,33 +1837,18 @@ function api_statuses_networkpublic_timeline($type) } $start = ($page - 1) * $count; - $sql_extra = ''; + $condition = ["`uid` = 0 AND `verb` = ? AND `thread`.`iid` > ? AND NOT `private`", + ACTIVITY_POST, $since_id]; + if ($max_id > 0) { - $sql_extra = 'AND `thread`.`iid` <= ' . intval($max_id); + $condition[0] .= " AND `thread`.`iid` <= ?"; + $condition[] = $max_id; } - $r = dba::p( - "SELECT " . item_fieldlists() . " - FROM `thread` - STRAIGHT_JOIN `item` ON `item`.`id` = `thread`.`iid` - " . item_joins() . " - WHERE `thread`.`uid` = 0 - AND `verb` = ? - AND NOT `thread`.`private` - AND `thread`.`visible` - AND NOT `thread`.`deleted` - AND NOT `thread`.`moderated` - AND `thread`.`iid` > ? - $sql_extra - ORDER BY `thread`.`iid` DESC - LIMIT " . intval($start) . ", " . intval($count), - ACTIVITY_POST, - $since_id - ); + $params = ['order' => ['iid' => true], 'limit' => [$start, $count]]; + $statuses = Item::selectThread(api_user(), [], $condition, $params); - $r = dba::inArray($r); - - $ret = api_format_items($r, $user_info, false, $type); + $ret = api_format_items(dba::inArray($statuses), $user_info, false, $type); $data = ['status' => $ret]; switch ($type) { @@ -1995,13 +1896,6 @@ function api_statuses_show($type) $conversation = (x($_REQUEST, 'conversation') ? 1 : 0); - $sql_extra = ''; - if ($conversation) { - $sql_extra .= " AND `item`.`parent` = %d ORDER BY `id` ASC "; - } else { - $sql_extra .= " AND `item`.`id` = %d"; - } - // try to fetch the item for the local user - or the public item, if there is no local one $uri_item = dba::selectFirst('item', ['uri'], ['id' => $id]); if (!DBM::is_result($uri_item)) { @@ -2015,28 +1909,22 @@ function api_statuses_show($type) $id = $item['id']; - $r = q( - "SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`, - `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`, - `contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`, - `contact`.`id` AS `cid` - FROM `item` - INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id` AND `contact`.`uid` = `item`.`uid` - AND (NOT `contact`.`blocked` OR `contact`.`pending`) - WHERE `item`.`visible` AND NOT `item`.`moderated` AND NOT `item`.`deleted` - AND `item`.`uid` IN (0, %d) AND `item`.`verb` = '%s' - $sql_extra", - intval(api_user()), - dbesc(ACTIVITY_POST), - intval($id) - ); + if ($conversation) { + $condition = ['parent' => $id, 'verb' => ACTIVITY_POST]; + $params = ['order' => ['id' => true]]; + } else { + $condition = ['id' => $id, 'verb' => ACTIVITY_POST]; + $params = []; + } + + $statuses = Item::select(api_user(), [], $condition, $params); /// @TODO How about copying this to above methods which don't check $r ? - if (!DBM::is_result($r)) { + if (!DBM::is_result($statuses)) { throw new BadRequestException("There is no status with this id."); } - $ret = api_format_items($r, $user_info, false, $type); + $ret = api_format_items(dba::inArray($statuses), $user_info, false, $type); if ($conversation) { $data = ['status' => $ret]; @@ -2101,38 +1989,22 @@ function api_conversation_show($type) $id = $parent['id']; - $sql_extra = ''; + $condition = ["`parent` = ? AND `uid` IN (0, ?) AND `verb` = ? AND `item`.`id` > ?", + $id, api_user(), ACTIVITY_POST, $since_id]; if ($max_id > 0) { - $sql_extra = ' AND `item`.`id` <= ' . intval($max_id); + $condition[0] .= " AND `item`.`id` <= ?"; + $condition[] = $max_id; } - $r = q( - "SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`, - `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`, - `contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`, - `contact`.`id` AS `cid` - FROM `item` - STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id` AND `contact`.`uid` = `item`.`uid` - AND (NOT `contact`.`blocked` OR `contact`.`pending`) - WHERE `item`.`parent` = %d AND `item`.`visible` - AND NOT `item`.`moderated` AND NOT `item`.`deleted` - AND `item`.`uid` IN (0, %d) AND `item`.`verb` = '%s' - AND `item`.`id`>%d $sql_extra - ORDER BY `item`.`id` DESC LIMIT %d ,%d", - intval($id), - intval(api_user()), - dbesc(ACTIVITY_POST), - intval($since_id), - intval($start), - intval($count) - ); + $params = ['order' => ['id' => true], 'limit' => [$start, $count]]; + $statuses = Item::select(api_user(), [], $condition, $params); - if (!DBM::is_result($r)) { - throw new BadRequestException("There is no status with this id."); + if (!DBM::is_result($statuses)) { + throw new BadRequestException("There is no status with id $id."); } - $ret = api_format_items($r, $user_info, false, $type); + $ret = api_format_items(dba::inArray($statuses), $user_info, false, $type); $data = ['status' => $ret]; return api_format_data("statuses", $type, $data); @@ -2175,30 +2047,17 @@ function api_statuses_repeat($type) logger('API: api_statuses_repeat: '.$id); - $r = q( - "SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`, `contact`.`nick` as `reply_author`, - `contact`.`name`, `contact`.`photo` as `reply_photo`, `contact`.`url` as `reply_url`, `contact`.`rel`, - `contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`, - `contact`.`id` AS `cid` - FROM `item` - INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id` AND `contact`.`uid` = `item`.`uid` - AND (NOT `contact`.`blocked` OR `contact`.`pending`) - WHERE `item`.`visible` AND NOT `item`.`moderated` AND NOT `item`.`deleted` - AND NOT `item`.`private` AND `item`.`allow_cid` = '' AND `item`.`allow_gid` = '' - AND `item`.`deny_cid` = '' AND `item`.`deny_gid` = '' - AND `item`.`id`=%d", - intval($id) - ); + $fields = ['body', 'author-name', 'author-link', 'author-avatar', 'guid', 'created', 'plink']; + $item = Item::selectFirst(api_user(), $fields, ['id' => $id, 'private' => false]); - /// @TODO other style than above functions! - if (DBM::is_result($r) && $r[0]['body'] != "") { - if (strpos($r[0]['body'], "[/share]") !== false) { - $pos = strpos($r[0]['body'], "[share"); - $post = substr($r[0]['body'], $pos); + if (DBM::is_result($item) && $item['body'] != "") { + if (strpos($item['body'], "[/share]") !== false) { + $pos = strpos($item['body'], "[share"); + $post = substr($item['body'], $pos); } else { - $post = share_header($r[0]['author-name'], $r[0]['author-link'], $r[0]['author-avatar'], $r[0]['guid'], $r[0]['created'], $r[0]['plink']); + $post = share_header($item['author-name'], $item['author-link'], $item['author-avatar'], $item['guid'], $item['created'], $item['plink']); - $post .= $r[0]['body']; + $post .= $item['body']; $post .= "[/share]"; } $_REQUEST['body'] = $post; @@ -2216,7 +2075,7 @@ function api_statuses_repeat($type) } // this should output the last post (the one we just posted). - $called_api = null; + $called_api = []; return api_status_show($type); } @@ -2256,7 +2115,7 @@ function api_statuses_destroy($type) $ret = api_statuses_show($type); - Item::deleteById($id); + Item::deleteForUser(['id' => $id], api_user()); return $ret; } @@ -2299,43 +2158,19 @@ function api_statuses_mentions($type) $start = ($page - 1) * $count; - // Ugly code - should be changed - $myurl = System::baseUrl() . '/profile/'. $a->user['nickname']; - $myurl = substr($myurl, strpos($myurl, '://') + 3); - $myurl = str_replace('www.', '', $myurl); - - $sql_extra = ''; + $condition = ["`uid` = ? AND `verb` = ? AND `item`.`id` > ? AND `author-id` != ? + AND `item`.`parent` IN (SELECT `iid` FROM `thread` WHERE `uid` = ? AND `mention` AND NOT `ignored`)", + api_user(), ACTIVITY_POST, $since_id, $user_info['pid'], api_user()]; if ($max_id > 0) { - $sql_extra .= ' AND `item`.`id` <= ' . intval($max_id); + $condition[0] .= " AND `item`.`id` <= ?"; + $condition[] = $max_id; } - $r = q( - "SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`, - `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`, - `contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`, - `contact`.`id` AS `cid` - FROM `item` FORCE INDEX (`uid_id`) - STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id` AND `contact`.`uid` = `item`.`uid` - AND (NOT `contact`.`blocked` OR `contact`.`pending`) - WHERE `item`.`uid` = %d AND `verb` = '%s' - AND NOT (`item`.`author-link` IN ('https://%s', 'http://%s')) - AND `item`.`visible` AND NOT `item`.`moderated` AND NOT `item`.`deleted` - AND `item`.`parent` IN (SELECT `iid` FROM `thread` WHERE `uid` = %d AND `mention` AND !`ignored`) - $sql_extra - AND `item`.`id`>%d - ORDER BY `item`.`id` DESC LIMIT %d ,%d ", - intval(api_user()), - dbesc(ACTIVITY_POST), - dbesc(protect_sprintf($myurl)), - dbesc(protect_sprintf($myurl)), - intval(api_user()), - intval($since_id), - intval($start), - intval($count) - ); + $params = ['order' => ['id' => true], 'limit' => [$start, $count]]; + $statuses = Item::select(api_user(), [], $condition, $params); - $ret = api_format_items($r, $user_info, false, $type); + $ret = api_format_items(dba::inArray($statuses), $user_info, false, $type); $data = ['status' => $ret]; switch ($type) { @@ -2391,46 +2226,31 @@ function api_statuses_user_timeline($type) } $start = ($page - 1) * $count; - $sql_extra = ''; + $condition = ["`uid` = ? AND `verb` = ? AND `item`.`id` > ? AND `item`.`contact-id` = ?", + api_user(), ACTIVITY_POST, $since_id, $user_info['cid']]; + if ($user_info['self'] == 1) { - $sql_extra .= " AND `item`.`wall` = 1 "; + $condition[0] .= ' AND `item`.`wall` '; } if ($exclude_replies > 0) { - $sql_extra .= ' AND `item`.`parent` = `item`.`id`'; + $condition[0] .= ' AND `item`.`parent` = `item`.`id`'; } if ($conversation_id > 0) { - $sql_extra .= ' AND `item`.`parent` = ' . intval($conversation_id); + $condition[0] .= " AND `item`.`parent` = ?"; + $condition[] = $conversation_id; } if ($max_id > 0) { - $sql_extra .= ' AND `item`.`id` <= ' . intval($max_id); + $condition[0] .= " AND `item`.`id` <= ?"; + $condition[] = $max_id; } - $r = q( - "SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`, - `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`, - `contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`, - `contact`.`id` AS `cid` - FROM `item` FORCE INDEX (`uid_contactid_id`) - STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id` AND `contact`.`uid` = `item`.`uid` - AND (NOT `contact`.`blocked` OR `contact`.`pending`) - WHERE `item`.`uid` = %d AND `verb` = '%s' - AND `item`.`contact-id` = %d - AND `item`.`visible` AND NOT `item`.`moderated` AND NOT `item`.`deleted` - $sql_extra - AND `item`.`id` > %d - ORDER BY `item`.`id` DESC LIMIT %d ,%d ", - intval(api_user()), - dbesc(ACTIVITY_POST), - intval($user_info['cid']), - intval($since_id), - intval($start), - intval($count) - ); + $params = ['order' => ['id' => true], 'limit' => [$start, $count]]; + $statuses = Item::select(api_user(), [], $condition, $params); - $ret = api_format_items($r, $user_info, true, $type); + $ret = api_format_items(dba::inArray($statuses), $user_info, true, $type); $data = ['status' => $ret]; switch ($type) { @@ -2480,24 +2300,24 @@ function api_favorites_create_destroy($type) $itemid = intval($_REQUEST['id']); } - $item = q("SELECT * FROM `item` WHERE `id`=%d AND `uid`=%d LIMIT 1", $itemid, api_user()); + $item = Item::selectFirst(api_user(), [], ['id' => $itemid, 'uid' => api_user()]); - if (!DBM::is_result($item) || count($item) == 0) { + if (!DBM::is_result($item)) { throw new BadRequestException("Invalid item."); } switch ($action) { case "create": - $item[0]['starred'] = 1; + $item['starred'] = 1; break; case "destroy": - $item[0]['starred'] = 0; + $item['starred'] = 0; break; default: throw new BadRequestException("Invalid action ".$action); } - $r = Item::update(['starred' => $item[0]['starred']], ['id' => $itemid]); + $r = Item::update(['starred' => $item['starred']], ['id' => $itemid]); if ($r === false) { throw new InternalServerErrorException("DB error"); @@ -2505,7 +2325,7 @@ function api_favorites_create_destroy($type) $user_info = api_get_user($a); - $rets = api_format_items($item, $user_info, false, $type); + $rets = api_format_items([$item], $user_info, false, $type); $ret = $rets[0]; $data = ['status' => $ret]; @@ -2549,8 +2369,6 @@ function api_favorites($type) if ($user_info['self'] == 0) { $ret = []; } else { - $sql_extra = ""; - // params $since_id = (x($_REQUEST, 'since_id') ? $_REQUEST['since_id'] : 0); $max_id = (x($_REQUEST, 'max_id') ? $_REQUEST['max_id'] : 0); @@ -2562,31 +2380,19 @@ function api_favorites($type) $start = $page*$count; + $condition = ["`uid` = ? AND `verb` = ? AND `id` > ? AND `starred`", + api_user(), ACTIVITY_POST, $since_id]; + + $params = ['order' => ['id' => true], 'limit' => [$start, $count]]; + if ($max_id > 0) { - $sql_extra .= ' AND `item`.`id` <= ' . intval($max_id); + $condition[0] .= " AND `item`.`id` <= ?"; + $condition[] = $max_id; } - $r = q( - "SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`, - `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`, - `contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`, - `contact`.`id` AS `cid` - FROM `item`, `contact` - WHERE `item`.`uid` = %d - AND `item`.`visible` = 1 AND `item`.`moderated` = 0 AND `item`.`deleted` = 0 - AND `item`.`starred` = 1 - AND `contact`.`id` = `item`.`contact-id` - AND (NOT `contact`.`blocked` OR `contact`.`pending`) - $sql_extra - AND `item`.`id`>%d - ORDER BY `item`.`id` DESC LIMIT %d ,%d ", - intval(api_user()), - intval($since_id), - intval($start), - intval($count) - ); + $statuses = Item::select(api_user(), [], $condition, $params); - $ret = api_format_items($r, $user_info, false, $type); + $ret = api_format_items(dba::inArray($statuses), $user_info, false, $type); } $data = ['status' => $ret]; @@ -2732,7 +2538,7 @@ function api_convert_item($item) * * @param string $body * - * @return array|false + * @return array */ function api_get_attachments(&$body) { @@ -2743,7 +2549,7 @@ function api_get_attachments(&$body) $ret = preg_match_all("/\[img\]([$URLSearchString]*)\[\/img\]/ism", $text, $images); if (!$ret) { - return false; + return []; } $attachments = []; @@ -3001,8 +2807,8 @@ function api_format_items_activities(&$item, $type = "json") ]; $items = q( - 'SELECT * FROM item - WHERE uid=%d AND `thr-parent`="%s" AND visible AND NOT deleted', + 'SELECT * FROM `item` + WHERE `uid` = %d AND `thr-parent` = "%s" AND `visible` AND NOT `deleted`', intval($item['uid']), dbesc($item['uri']) ); @@ -3012,7 +2818,7 @@ function api_format_items_activities(&$item, $type = "json") //builtin_activity_puller($i, $activities); // get user data and add it to the array of the activity - $user = api_get_user($a, $i['author-link']); + $user = api_get_user($a, $i['author-id']); switch ($i['verb']) { case ACTIVITY_LIKE: $activities['like'][] = $user; @@ -3168,26 +2974,18 @@ function api_format_items($r, $user_info, $filter_user = false, $type = "json") $status["entities"] = $converted["entities"]; } - if (($item['item_network'] != "") && ($status["source"] == 'web')) { - $status["source"] = ContactSelector::networkToName($item['item_network'], $user_info['url']); - } elseif (($item['item_network'] != "") && (ContactSelector::networkToName($item['item_network'], $user_info['url']) != $status["source"])) { - $status["source"] = trim($status["source"].' ('.ContactSelector::networkToName($item['item_network'], $user_info['url']).')'); + if ($status["source"] == 'web') { + $status["source"] = ContactSelector::networkToName($item['network'], $user_info['url']); + } elseif (ContactSelector::networkToName($item['network'], $user_info['url']) != $status["source"]) { + $status["source"] = trim($status["source"].' ('.ContactSelector::networkToName($item['network'], $user_info['url']).')'); } - - // Retweets are only valid for top postings - // It doesn't work reliable with the link if its a feed - //$IsRetweet = ($item['owner-link'] != $item['author-link']); - //if ($IsRetweet) - // $IsRetweet = (($item['owner-name'] != $item['author-name']) || ($item['owner-avatar'] != $item['author-avatar'])); - - if ($item["id"] == $item["parent"]) { $retweeted_item = api_share_as_retweet($item); if ($retweeted_item !== false) { $retweeted_status = $status; try { - $retweeted_status["user"] = api_get_user($a, $retweeted_item["author-link"]); + $retweeted_status["user"] = api_get_user($a, $retweeted_item["author-id"]); } catch (BadRequestException $e) { // user not found. should be found? /// @todo check if the user should be always found @@ -3384,37 +3182,23 @@ function api_lists_statuses($type) $start = $page * $count; - $sql_extra = ''; + $condition = ["`uid` = ? AND `verb` = ? AND `id` > ? AND `group_member`.`gid` = ?", + api_user(), ACTIVITY_POST, $since_id, $_REQUEST['list_id']]; + if ($max_id > 0) { - $sql_extra .= ' AND `item`.`id` <= ' . intval($max_id); + $condition[0] .= " AND `item`.`id` <= ?"; + $condition[] = $max_id; } if ($exclude_replies > 0) { - $sql_extra .= ' AND `item`.`parent` = `item`.`id`'; + $condition[0] .= ' AND `item`.`parent` = `item`.`id`'; } if ($conversation_id > 0) { - $sql_extra .= ' AND `item`.`parent` = ' . intval($conversation_id); + $condition[0] .= " AND `item`.`parent` = ?"; + $condition[] = $conversation_id; } - $statuses = dba::p( - "SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`, - `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`, - `contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`, - `contact`.`id` AS `cid`, `group_member`.`gid` - FROM `item` - STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id` AND `contact`.`uid` = `item`.`uid` - AND (NOT `contact`.`blocked` OR `contact`.`pending`) - STRAIGHT_JOIN `group_member` ON `group_member`.`contact-id` = `item`.`contact-id` - WHERE `item`.`uid` = ? AND `verb` = ? - AND `item`.`visible` AND NOT `item`.`moderated` AND NOT `item`.`deleted` - $sql_extra - AND `item`.`id`>? - AND `group_member`.`gid` = ? - ORDER BY `item`.`id` DESC LIMIT ".intval($start)." ,".intval($count), - api_user(), - ACTIVITY_POST, - $since_id, - $_REQUEST['list_id'] - ); + $params = ['order' => ['id' => true], 'limit' => [$start, $count]]; + $statuses = Item::select(api_user(), [], $condition, $params); $items = api_format_items(dba::inArray($statuses), $user_info, false, $type); @@ -4148,7 +3932,7 @@ function api_fr_photoalbum_delete($type) if (!DBM::is_result($photo_item)) { throw new InternalServerErrorException("problem with deleting items occured"); } - Item::deleteById($photo_item[0]['id']); + Item::deleteForUser(['id' => $photo_item[0]['id']], api_user()); } // now let's delete all photos from the album @@ -4395,7 +4179,6 @@ function api_fr_photo_create_update($type) throw new InternalServerErrorException("unknown error - this error on uploading or updating a photo should never happen"); } - /** * @brief delete a single photo from the database through api * @@ -4441,7 +4224,7 @@ function api_fr_photo_delete($type) } // function for setting the items to "deleted = 1" which ensures that comments, likes etc. are not shown anymore // to the user and the contacts of the users (drop_items() do all the necessary magic to avoid orphans in database and federate deletion) - Item::deleteById($photo_item[0]['id']); + Item::deleteForUser(['id' => $photo_item[0]['id']], api_user()); $answer = ['result' => 'deleted', 'message' => 'photo with id `' . $photo_id . '` has been deleted from server.']; return api_format_data("photo_delete", $type, ['$result' => $answer]); @@ -4534,6 +4317,7 @@ function api_account_update_profile_image($type) } else { throw new InternalServerErrorException('Unsupported filetype'); } + // change specified profile or all profiles to the new resource-id if ($is_default_profile) { $condition = ["`profile` AND `resource-id` != ? AND `uid` = ?", $data['photo']['id'], api_user()]; @@ -4547,7 +4331,6 @@ function api_account_update_profile_image($type) Contact::updateSelfFromUserID(api_user(), true); // Update global directory in background - //$user = api_get_user(get_app()); $url = System::baseUrl() . '/profile/' . get_app()->user['nickname']; if ($url && strlen(Config::get('system', 'directory'))) { Worker::add(PRIORITY_LOW, "Directory", $url); @@ -4937,24 +4720,13 @@ function prepare_photo_data($type, $scale, $photo_id) $data['photo']['friendica_activities'] = api_format_items_activities($item[0], $type); // retrieve comments on photo - $r = q( - "SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`, - `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`, - `contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`, - `contact`.`id` AS `cid` - FROM `item` - STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id` AND `contact`.`uid` = `item`.`uid` - AND (NOT `contact`.`blocked` OR `contact`.`pending`) - WHERE `item`.`parent` = %d AND `item`.`visible` - AND NOT `item`.`moderated` AND NOT `item`.`deleted` - AND `item`.`uid` = %d AND (`item`.`verb`='%s' OR `type`='photo')", - intval($item[0]['parent']), - intval(api_user()), - dbesc(ACTIVITY_POST) - ); + $condition = ["`parent` = ? AND `uid` = ? AND (`verb` = ? OR `type`='photo')", + $item[0]['parent'], api_user(), ACTIVITY_POST]; + + $statuses = Item::select(api_user(), [], $condition); // prepare output of comments - $commentData = api_format_items($r, $user_info, false, $type); + $commentData = api_format_items(dba::inArray($statuses), $user_info, false, $type); $comments = []; if ($type == "xml") { $k = 0; @@ -5255,7 +5027,7 @@ function api_in_reply_to($item) $in_reply_to['status_id_str'] = (string) intval($in_reply_to['status_id']); $r = q( - "SELECT `contact`.`nick`, `contact`.`name`, `contact`.`id`, `contact`.`url` FROM item + "SELECT `contact`.`nick`, `contact`.`name`, `contact`.`id`, `contact`.`url` FROM `item` STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`author-id` WHERE `item`.`id` = %d LIMIT 1", intval($in_reply_to['status_id']) @@ -5289,27 +5061,27 @@ function api_in_reply_to($item) /** * - * @param string $Text + * @param string $text * * @return string */ -function api_clean_plain_items($Text) +function api_clean_plain_items($text) { $include_entities = strtolower(x($_REQUEST, 'include_entities') ? $_REQUEST['include_entities'] : "false"); - $Text = BBCode::cleanPictureLinks($Text); + $text = BBCode::cleanPictureLinks($text); $URLSearchString = "^\[\]"; - $Text = preg_replace("/([!#@])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '$1$3', $Text); + $text = preg_replace("/([!#@])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '$1$3', $text); if ($include_entities == "true") { - $Text = preg_replace("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '[url=$1]$1[/url]', $Text); + $text = preg_replace("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '[url=$1]$1[/url]', $text); } // Simplify "attachment" element - $Text = api_clean_attachments($Text); + $text = api_clean_attachments($text); - return($Text); + return $text; } /** @@ -5944,14 +5716,10 @@ function api_friendica_notification_seen($type) $nm->setSeen($note); if ($note['otype']=='item') { // would be really better with an ItemsManager and $im->getByID() :-P - $r = q( - "SELECT * FROM `item` WHERE `id`=%d AND `uid`=%d", - intval($note['iid']), - intval(local_user()) - ); - if ($r!==false) { + $item = Item::selectFirst(api_user(), [], ['id' => $note['iid'], 'uid' => api_user()]); + if (DBM::is_result($$item)) { // we found the item, return it to the user - $ret = api_format_items($r, $user_info, false, $type); + $ret = api_format_items([$item], $user_info, false, $type); $data = ['status' => $ret]; return api_format_data("status", $type, $data); } diff --git a/include/conversation.php b/include/conversation.php index 324b53b5a8..527f38e2aa 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -15,6 +15,7 @@ use Friendica\Core\System; use Friendica\Database\DBM; use Friendica\Model\Contact; use Friendica\Model\Profile; +use Friendica\Model\Item; use Friendica\Object\Post; use Friendica\Object\Thread; use Friendica\Util\DateTimeFormat; @@ -116,7 +117,7 @@ function localize_item(&$item) { $item['body'] = item_redir_and_replace_images($extracted['body'], $extracted['images'], $item['contact-id']); } - /// @Separted ??? + /// @TODO Separted ??? $xmlhead = "<" . "?xml version='1.0' encoding='UTF-8' ?" . ">"; if (activity_match($item['verb'], ACTIVITY_LIKE) || activity_match($item['verb'], ACTIVITY_DISLIKE) @@ -162,22 +163,19 @@ function localize_item(&$item) { if (activity_match($item['verb'], ACTIVITY_LIKE)) { $bodyverb = L10n::t('%1$s likes %2$s\'s %3$s'); - } - elseif (activity_match($item['verb'], ACTIVITY_DISLIKE)) { + } elseif (activity_match($item['verb'], ACTIVITY_DISLIKE)) { $bodyverb = L10n::t('%1$s doesn\'t like %2$s\'s %3$s'); - } - elseif (activity_match($item['verb'], ACTIVITY_ATTEND)) { + } elseif (activity_match($item['verb'], ACTIVITY_ATTEND)) { $bodyverb = L10n::t('%1$s attends %2$s\'s %3$s'); - } - elseif (activity_match($item['verb'], ACTIVITY_ATTENDNO)) { + } elseif (activity_match($item['verb'], ACTIVITY_ATTENDNO)) { $bodyverb = L10n::t('%1$s doesn\'t attend %2$s\'s %3$s'); - } - elseif (activity_match($item['verb'], ACTIVITY_ATTENDMAYBE)) { + } elseif (activity_match($item['verb'], ACTIVITY_ATTENDMAYBE)) { $bodyverb = L10n::t('%1$s attends maybe %2$s\'s %3$s'); } - $item['body'] = sprintf($bodyverb, $author, $objauthor, $plink); + $item['body'] = sprintf($bodyverb, $author, $objauthor, $plink); } + if (activity_match($item['verb'], ACTIVITY_FRIEND)) { if ($item['object-type']=="" || $item['object-type']!== ACTIVITY_OBJ_PERSON) return; @@ -200,10 +198,10 @@ function localize_item(&$item) { } } - $A = '[url=' . Profile::zrl($Alink) . ']' . $Aname . '[/url]'; - $B = '[url=' . Profile::zrl($Blink) . ']' . $Bname . '[/url]'; + $A = '[url=' . Contact::magicLink($Alink) . ']' . $Aname . '[/url]'; + $B = '[url=' . Contact::magicLink($Blink) . ']' . $Bname . '[/url]'; if ($Bphoto != "") { - $Bphoto = '[url=' . Profile::zrl($Blink) . '][img]' . $Bphoto . '[/img][/url]'; + $Bphoto = '[url=' . Contact::magicLink($Blink) . '][img]' . $Bphoto . '[/img][/url]'; } $item['body'] = L10n::t('%1$s is now friends with %2$s', $A, $B)."\n\n\n".$Bphoto; @@ -237,10 +235,10 @@ function localize_item(&$item) { } } - $A = '[url=' . Profile::zrl($Alink) . ']' . $Aname . '[/url]'; - $B = '[url=' . Profile::zrl($Blink) . ']' . $Bname . '[/url]'; + $A = '[url=' . Contact::magicLink($Alink) . ']' . $Aname . '[/url]'; + $B = '[url=' . Contact::magicLink($Blink) . ']' . $Bname . '[/url]'; if ($Bphoto != "") { - $Bphoto = '[url=' . Profile::zrl($Blink) . '][img=80x80]' . $Bphoto . '[/img][/url]'; + $Bphoto = '[url=' . Contact::magicLink($Blink) . '][img=80x80]' . $Bphoto . '[/img][/url]'; } /* @@ -272,8 +270,8 @@ function localize_item(&$item) { $obj = $r[0]; - $author = '[url=' . Profile::zrl($item['author-link']) . ']' . $item['author-name'] . '[/url]'; - $objauthor = '[url=' . Profile::zrl($obj['author-link']) . ']' . $obj['author-name'] . '[/url]'; + $author = '[url=' . Contact::magicLinkById($item['author-id']) . ']' . $item['author-name'] . '[/url]'; + $objauthor = '[url=' . Contact::magicLinkById($obj['author-id']) . ']' . $obj['author-name'] . '[/url]'; switch ($obj['verb']) { case ACTIVITY_POST: @@ -304,8 +302,8 @@ function localize_item(&$item) { $item['body'] = L10n::t('%1$s tagged %2$s\'s %3$s with %4$s', $author, $objauthor, $plink, $tag ); } - if (activity_match($item['verb'], ACTIVITY_FAVORITE)) { + if (activity_match($item['verb'], ACTIVITY_FAVORITE)) { if ($item['object-type'] == "") { return; } @@ -326,8 +324,8 @@ function localize_item(&$item) { $target = $r[0]; $Bname = $target['author-name']; $Blink = $target['author-link']; - $A = '[url=' . Profile::zrl($Alink) . ']' . $Aname . '[/url]'; - $B = '[url=' . Profile::zrl($Blink) . ']' . $Bname . '[/url]'; + $A = '[url=' . Contact::magicLink($Alink) . ']' . $Aname . '[/url]'; + $B = '[url=' . Contact::magicLink($Blink) . ']' . $Bname . '[/url]'; $P = '[url=' . $target['plink'] . ']' . L10n::t('post/item') . '[/url]'; $item['body'] = L10n::t('%1$s marked %2$s\'s %3$s as favorite', $A, $B, $P)."\n"; } @@ -337,7 +335,7 @@ function localize_item(&$item) { if (preg_match_all('/@\[url=(.*?)\]/is', $item['body'], $matches, PREG_SET_ORDER)) { foreach ($matches as $mtch) { if (!strpos($mtch[1], 'zrl=')) { - $item['body'] = str_replace($mtch[0], '@[url=' . Profile::zrl($mtch[1]) . ']', $item['body']); + $item['body'] = str_replace($mtch[0], '@[url=' . Contact::magicLink($mtch[1]) . ']', $item['body']); } } } @@ -350,16 +348,7 @@ function localize_item(&$item) { } // add sparkle links to appropriate permalinks - - $x = stristr($item['plink'],'/display/'); - if ($x) { - $sparkle = false; - $y = best_link_url($item, $sparkle); - - if (strstr($y, '/redir/')) { - $item['plink'] = $y . '?f=&url=' . $item['plink']; - } - } + $item['plink'] = Contact::magicLinkById($item['author-id'], $item['plink']); } /** @@ -394,10 +383,9 @@ function visible_activity($item) { } } - if (activity_match($item['verb'], ACTIVITY_FOLLOW) && $item['object-type'] === ACTIVITY_OBJ_NOTE) { - if (!($item['self'] && ($item['uid'] == local_user()))) { - return false; - } + // @TODO below if() block can be rewritten to a single line: $isVisible = allConditionsHere; + if (activity_match($item['verb'], ACTIVITY_FOLLOW) && $item['object-type'] === ACTIVITY_OBJ_NOTE && empty($item['self']) && $item['uid'] == local_user()) { + return false; } return true; @@ -405,10 +393,12 @@ function visible_activity($item) { /** * @brief SQL query for items + * + * @param int $uid user id */ -function item_query() { +function item_query($uid = 0) { return "SELECT " . item_fieldlists() . " FROM `item` " . - item_joins() . " WHERE " . item_condition(); + item_joins($uid) . " WHERE " . item_condition(); } /** @@ -429,7 +419,6 @@ These Fields are not added below (yet). They are here to for bug search. `item`.`inform`, `item`.`pubmail`, `item`.`visible`, -`item`.`spam`, `item`.`bookmark`, `item`.`unseen`, `item`.`deleted`, @@ -437,10 +426,12 @@ These Fields are not added below (yet). They are here to for bug search. `item`.`mention`, `item`.`global`, `item`.`shadow`, + `item`.`author-link`, `item`.`author-name`, `item`.`author-avatar`, + `item`.`owner-link`, `item`.`owner-name`, `item`.`owner-avatar`, */ - return "`item`.`author-id`, `item`.`author-link`, `item`.`author-name`, `item`.`author-avatar`, - `item`.`owner-id`, `item`.`owner-link`, `item`.`owner-name`, `item`.`owner-avatar`, + return "`item`.`author-id`, + `item`.`owner-id`, `item`.`contact-id`, `item`.`uid`, `item`.`id`, `item`.`parent`, `item`.`uri`, `item`.`thr-parent`, `item`.`parent-uri`, `item`.`content-warning`, `item`.`commented`, `item`.`created`, `item`.`edited`, `item`.`received`, @@ -452,7 +443,9 @@ These Fields are not added below (yet). They are here to for bug search. `item`.`allow_cid`, `item`.`allow_gid`, `item`.`deny_cid`, `item`.`deny_gid`, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`, - `author`.`thumb` AS `author-thumb`, `owner`.`thumb` AS `owner-thumb`, + `author`.`url` AS `author-link`, `author`.`name` AS `author-name`, `author`.`thumb` AS `author-avatar`, + `owner`.`url` AS `owner-link`, `owner`.`name` AS `owner-name`, `owner`.`thumb` AS `owner-avatar`, + `contact`.`url` AS `contact-link`, `contact`.`name` AS `contact-name`, `contact`.`thumb` AS `contact-avatar`, `contact`.`network`, `contact`.`url`, `contact`.`name`, `contact`.`writable`, `contact`.`self`, `contact`.`id` AS `cid`, `contact`.`alias`, @@ -467,16 +460,19 @@ These Fields are not added below (yet). They are here to for bug search. /** * @brief SQL join for contacts that are needed for displaying items + * + * @param int $uid user id */ -function item_joins() { +function item_joins($uid = 0) { return sprintf("STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id` AND NOT `contact`.`blocked` AND ((NOT `contact`.`readonly` AND NOT `contact`.`pending` AND (`contact`.`rel` IN (%s, %s))) OR `contact`.`self` OR (`item`.`id` != `item`.`parent`) OR `contact`.`uid` = 0) - INNER JOIN `contact` AS `author` ON `author`.`id`=`item`.`author-id` AND NOT `author`.`blocked` - INNER JOIN `contact` AS `owner` ON `owner`.`id`=`item`.`owner-id` AND NOT `owner`.`blocked` + STRAIGHT_JOIN `contact` AS `author` ON `author`.`id`=`item`.`author-id` AND NOT `author`.`blocked` + STRAIGHT_JOIN `contact` AS `owner` ON `owner`.`id`=`item`.`owner-id` AND NOT `owner`.`blocked` + LEFT JOIN `user-item` ON `user-item`.`iid` = `item`.`id` AND `user-item`.`uid` = %d LEFT JOIN `event` ON `event-id` = `event`.`id`", - CONTACT_IS_SHARING, CONTACT_IS_FRIEND + CONTACT_IS_SHARING, CONTACT_IS_FRIEND, intval($uid) ); } @@ -484,7 +480,7 @@ function item_joins() { * @brief SQL condition for items that are needed for displaying items */ function item_condition() { - return "`item`.`visible` AND NOT `item`.`deleted` AND NOT `item`.`moderated`"; + return "`item`.`visible` AND NOT `item`.`deleted` AND NOT `item`.`moderated` AND (`user-item`.`hidden` IS NULL OR NOT `user-item`.`hidden`) "; } /** @@ -497,7 +493,7 @@ function item_condition() { * that are based on unique features of the calling module. * */ -function conversation(App $a, $items, $mode, $update, $preview = false, $order = 'commented') { +function conversation(App $a, $items, $mode, $update, $preview = false, $order = 'commented', $uid = 0) { require_once 'mod/proxy.php'; $ssl_state = ((local_user()) ? true : false); @@ -521,7 +517,7 @@ function conversation(App $a, $items, $mode, $update, $preview = false, $order = $previewing = (($preview) ? ' preview ' : ''); if ($mode === 'network') { - $items = conversation_add_children($items, false, $order); + $items = conversation_add_children($items, false, $order, $uid); $profile_owner = local_user(); if (!$update) { /* @@ -540,7 +536,6 @@ function conversation(App $a, $items, $mode, $update, $preview = false, $order = . ((x($_GET, 'bmark')) ? '&bmark=' . $_GET['bmark'] : '') . ((x($_GET, 'liked')) ? '&liked=' . $_GET['liked'] : '') . ((x($_GET, 'conv')) ? '&conv=' . $_GET['conv'] : '') - . ((x($_GET, 'spam')) ? '&spam=' . $_GET['spam'] : '') . ((x($_GET, 'nets')) ? '&nets=' . $_GET['nets'] : '') . ((x($_GET, 'cmin')) ? '&cmin=' . $_GET['cmin'] : '') . ((x($_GET, 'cmax')) ? '&cmax=' . $_GET['cmax'] : '') @@ -582,7 +577,7 @@ function conversation(App $a, $items, $mode, $update, $preview = false, $order = . " var profile_page = 1; "; } } elseif ($mode === 'community') { - $items = conversation_add_children($items, true, $order); + $items = conversation_add_children($items, true, $order, $uid); $profile_owner = 0; if (!$update) { $live_update_div = '
' . "\r\n" @@ -666,6 +661,13 @@ function conversation(App $a, $items, $mode, $update, $preview = false, $order = continue; } + if ($item['network'] == NETWORK_FEED) { + $item['author-avatar'] = $item['contact-avatar']; + $item['author-name'] = $item['contact-name']; + $item['owner-avatar'] = $item['contact-avatar']; + $item['owner-name'] = $item['contact-name']; + } + $profile_name = (strlen($item['author-name']) ? $item['author-name'] : $item['name']); if ($item['author-link'] && !$item['author-name']) { $profile_name = $item['author-link']; @@ -673,34 +675,10 @@ function conversation(App $a, $items, $mode, $update, $preview = false, $order = $tags = \Friendica\Model\Term::populateTagsFromItem($item); - $sp = false; - $profile_link = best_link_url($item, $sp); - if ($profile_link === 'mailbox') { - $profile_link = ''; - } + $profile_link = Contact::magicLinkbyId($item['author-id']); - if ($sp) { + if (strpos($profile_link, 'redir/') === 0) { $sparkle = ' sparkle'; - } else { - $profile_link = Profile::zrl($profile_link); - } - - if (!x($item, 'author-thumb') || ($item['author-thumb'] == "")) { - $author_contact = Contact::getDetailsByURL($item['author-link'], $profile_owner); - if ($author_contact["thumb"]) { - $item['author-thumb'] = $author_contact["thumb"]; - } else { - $item['author-thumb'] = $item['author-avatar']; - } - } - - if (!isset($item['owner-thumb']) || ($item['owner-thumb'] == "")) { - $owner_contact = Contact::getDetailsByURL($item['owner-link'], $profile_owner); - if ($owner_contact["thumb"]) { - $item['owner-thumb'] = $owner_contact["thumb"]; - } else { - $item['owner-thumb'] = $item['owner-avatar']; - } } $locate = ['location' => $item['location'], 'coord' => $item['coord'], 'html' => '']; @@ -757,13 +735,13 @@ function conversation(App $a, $items, $mode, $update, $preview = false, $order = 'guid' => (($preview) ? 'Q0' : $item['guid']), 'network' => $item['item_network'], 'network_name' => ContactSelector::networkToName($item['item_network'], $profile_link), - 'linktitle' => L10n::t('View %s\'s profile @ %s', $profile_name, ((strlen($item['author-link'])) ? $item['author-link'] : $item['url'])), + '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, 'sparkle' => $sparkle, 'lock' => $lock, - 'thumb' => System::removedBaseUrl(proxy_url($item['author-thumb'], false, PROXY_SIZE_THUMB)), + 'thumb' => System::removedBaseUrl(proxy_url($item['author-avatar'], false, PROXY_SIZE_THUMB)), 'title' => $title_e, 'body' => $body_e, 'tags' => $tags_e, @@ -782,7 +760,7 @@ function conversation(App $a, $items, $mode, $update, $preview = false, $order = 'indent' => '', 'owner_name' => $owner_name_e, 'owner_url' => $owner_url, - 'owner_photo' => System::removedBaseUrl(proxy_url($item['owner-thumb'], false, PROXY_SIZE_THUMB)), + 'owner_photo' => System::removedBaseUrl(proxy_url($item['owner-avatar'], false, PROXY_SIZE_THUMB)), 'plink' => get_plink($item), 'edpost' => false, 'isstarred' => $isstarred, @@ -885,24 +863,24 @@ function conversation(App $a, $items, $mode, $update, $preview = false, $order = * * @return array items with parents and comments */ -function conversation_add_children($parents, $block_authors, $order) { +function conversation_add_children($parents, $block_authors, $order, $uid) { $max_comments = Config::get('system', 'max_comments', 100); + $params = ['order' => ['uid', 'commented' => true]]; + if ($max_comments > 0) { - $limit = ' LIMIT '.intval($max_comments + 1); - } else { - $limit = ''; + $params['limit'] = $max_comments; } $items = []; - $block_sql = $block_authors ? "AND NOT `author`.`hidden` AND NOT `author`.`blocked`" : ""; - foreach ($parents AS $parent) { - $thread_items = dba::p(item_query()."AND `item`.`parent-uri` = ? - AND `item`.`uid` IN (0, ?) $block_sql - ORDER BY `item`.`uid` ASC, `item`.`commented` DESC" . $limit, - $parent['uri'], local_user()); + $condition = ["`item`.`parent-uri` = ? AND `item`.`uid` IN (0, ?) ", + $parent['uri'], local_user()]; + if ($block_authors) { + $condition[0] .= "AND NOT `author`.`hidden`"; + } + $thread_items = Item::select(local_user(), [], $condition, $params); $comments = dba::inArray($thread_items); @@ -922,48 +900,6 @@ function conversation_add_children($parents, $block_authors, $order) { return $items; } -function best_link_url($item, &$sparkle, $url = '') { - - $best_url = ''; - $sparkle = false; - - $clean_url = normalise_link($item['author-link']); - - if (local_user()) { - $condition = [ - 'network' => NETWORK_DFRN, - 'uid' => local_user(), - 'nurl' => normalise_link($clean_url), - 'pending' => false - ]; - $contact = dba::selectFirst('contact', ['id'], $condition); - if (DBM::is_result($contact)) { - $best_url = 'redir/' . $contact['id']; - $sparkle = true; - if ($url != '') { - $hostname = get_app()->get_hostname(); - if (!strstr($url, $hostname)) { - $best_url .= "?url=".$url; - } else { - $best_url = $url; - } - } - } - } - if (!$best_url) { - if ($url != '') { - $best_url = $url; - } elseif (strlen($item['author-link'])) { - $best_url = $item['author-link']; - } else { - $best_url = $item['url']; - } - } - - return $best_url; -} - - function item_photo_menu($item) { $sub_link = ''; $poke_link = ''; @@ -977,11 +913,8 @@ function item_photo_menu($item) { $sub_link = 'javascript:dosubthread(' . $item['id'] . '); return false;'; } - $sparkle = false; - $profile_link = best_link_url($item, $sparkle); - if ($profile_link === 'mailbox') { - $profile_link = ''; - } + $profile_link = Contact::magicLinkById($item['author-id']); + $sparkle = (strpos($profile_link, 'redir/') === 0); $cid = 0; $network = ''; @@ -999,7 +932,7 @@ function item_photo_menu($item) { $photos_link = $profile_link . '?url=photos'; $profile_link = $profile_link . '?url=profile'; } else { - $profile_link = Profile::zrl($profile_link); + $profile_link = Contact::magicLink($profile_link); } if ($cid && !$item['self']) { @@ -1087,17 +1020,14 @@ function builtin_activity_puller($item, &$conv_responses) { } if (activity_match($item['verb'], $verb) && ($item['id'] != $item['parent'])) { - $url = $item['author-link']; - if (local_user() && (local_user() == $item['uid']) && ($item['network'] === NETWORK_DFRN) && !$item['self'] && link_compare($item['author-link'], $item['url'])) { - $url = 'redir/' . $item['contact-id']; + $url = Contact::MagicLinkbyId($item['author-id']); + if (strpos($url, 'redir/') === 0) { $sparkle = ' class="sparkle" '; - } else { - $url = Profile::zrl($url); } $url = '' . htmlentities($item['author-name']) . ''; - if (!$item['thr-parent']) { + if (!x($item, 'thr-parent')) { $item['thr-parent'] = $item['parent-uri']; } @@ -1585,19 +1515,17 @@ function sort_thr_commented(array $a, array $b) return strcmp($b['commented'], $a['commented']); } -/// @TODO Add type-hint -function render_location_dummy($item) { - if ($item['location'] != "") { +function render_location_dummy(array $item) { + if (x($item, 'location') && !empty($item['location'])) { return $item['location']; } - if ($item['coord'] != "") { + if (x($item, 'coord') && !empty($item['coord'])) { return $item['coord']; } } -/// @TODO Add type-hint -function get_responses($conv_responses, $response_verbs, $ob, $item) { +function get_responses(array $conv_responses, array $response_verbs, $ob, array $item) { $ret = []; foreach ($response_verbs as $v) { $ret[$v] = []; diff --git a/include/dba.php b/include/dba.php index f915d78373..550fbe2557 100644 --- a/include/dba.php +++ b/include/dba.php @@ -27,7 +27,7 @@ class dba { private static $relation = []; public static function connect($serveraddr, $user, $pass, $db) { - if (!is_null(self::$db)) { + if (!is_null(self::$db) && self::connected()) { return true; } @@ -54,16 +54,6 @@ echo "1"; return false; } - if ($a->mode == App::MODE_INSTALL) { - // server has to be a non-empty string that is not 'localhost' and not an IP - if (strlen($server) && ($server !== 'localhost') && filter_var($server, FILTER_VALIDATE_IP) === false) { - if (! dns_get_record($server, DNS_A + DNS_CNAME)) { - self::$error = L10n::t('Cannot locate DNS info for database server \'%s\'', $server); - return false; - } - } - } - if (class_exists('\PDO') && in_array('mysql', PDO::getAvailableDrivers())) { self::$driver = 'pdo'; $connect = "mysql:host=".$server.";dbname=".$db; @@ -119,6 +109,35 @@ echo "1"; return $ret; } + /** + * Disconnects the current database connection + */ + public static function disconnect() + { + if (is_null(self::$db)) { + return; + } + + switch (self::$driver) { + case 'pdo': + self::$db = null; + break; + case 'mysqli': + self::$db->close(); + self::$db = null; + break; + } + } + + /** + * Return the database object. + * @return PDO|mysqli + */ + public static function get_db() + { + return self::$db; + } + /** * @brief Returns the MySQL server version string * @@ -1184,29 +1203,9 @@ echo "1"; $condition_string = self::buildCondition($condition); - $order_string = ''; - if (isset($params['order'])) { - $order_string = " ORDER BY "; - foreach ($params['order'] AS $fields => $order) { - if (!is_int($fields)) { - $order_string .= "`" . $fields . "` " . ($order ? "DESC" : "ASC") . ", "; - } else { - $order_string .= "`" . $order . "`, "; - } - } - $order_string = substr($order_string, 0, -2); - } + $param_string = self::buildParameter($params); - $limit_string = ''; - if (isset($params['limit']) && is_int($params['limit'])) { - $limit_string = " LIMIT " . $params['limit']; - } - - if (isset($params['limit']) && is_array($params['limit'])) { - $limit_string = " LIMIT " . intval($params['limit'][0]) . ", " . intval($params['limit'][1]); - } - - $sql = "SELECT " . $select_fields . " FROM `" . $table . "`" . $condition_string . $order_string . $limit_string; + $sql = "SELECT " . $select_fields . " FROM `" . $table . "`" . $condition_string . $param_string; $result = self::p($sql, $condition); @@ -1263,14 +1262,14 @@ echo "1"; * @param array $condition * @return string */ - private static function buildCondition(array &$condition = []) + public static function buildCondition(array &$condition = []) { $condition_string = ''; if (count($condition) > 0) { reset($condition); $first_key = key($condition); if (is_int($first_key)) { - $condition_string = " WHERE ".array_shift($condition); + $condition_string = " WHERE (" . array_shift($condition) . ")"; } else { $new_values = []; $condition_string = ""; @@ -1287,7 +1286,7 @@ echo "1"; $condition_string .= "`" . $field . "` = ?"; } } - $condition_string = " WHERE " . $condition_string; + $condition_string = " WHERE (" . $condition_string . ")"; $condition = $new_values; } } @@ -1295,6 +1294,39 @@ echo "1"; return $condition_string; } + /** + * @brief Returns the SQL parameter string built from the provided parameter array + * + * @param array $params + * @return string + */ + public static function buildParameter(array $params = []) + { + $order_string = ''; + if (isset($params['order'])) { + $order_string = " ORDER BY "; + foreach ($params['order'] AS $fields => $order) { + if (!is_int($fields)) { + $order_string .= "`" . $fields . "` " . ($order ? "DESC" : "ASC") . ", "; + } else { + $order_string .= "`" . $order . "`, "; + } + } + $order_string = substr($order_string, 0, -2); + } + + $limit_string = ''; + if (isset($params['limit']) && is_int($params['limit'])) { + $limit_string = " LIMIT " . $params['limit']; + } + + if (isset($params['limit']) && is_array($params['limit'])) { + $limit_string = " LIMIT " . intval($params['limit'][0]) . ", " . intval($params['limit'][1]); + } + + return $order_string.$limit_string; + } + /** * @brief Fills an array with data from a query * diff --git a/include/enotify.php b/include/enotify.php index 39c74fdc64..7eb2c80ebc 100644 --- a/include/enotify.php +++ b/include/enotify.php @@ -11,6 +11,7 @@ use Friendica\Core\System; use Friendica\Database\DBM; use Friendica\Util\DateTimeFormat; use Friendica\Util\Emailer; +use Friendica\Model\Item; /** * @brief Creates a notification entry and possibly sends a mail @@ -129,7 +130,7 @@ function notification($params) $item = null; if ($params['otype'] === 'item' && $parent_id) { - $item = dba::selectFirst('item', [], ['id' => $parent_id]); + $item = Item::selectFirst($params['uid'], [], ['id' => $parent_id]); } $item_post_type = item_post_type($item); @@ -152,7 +153,7 @@ function notification($params) } // "your post" - if (DBM::is_result($item) && $item['owner-name'] == $item['author-name'] && $item['wall']) { + if (DBM::is_result($item) && $item['owner-id'] == $item['author-id'] && $item['wall']) { $dest_str = L10n::t('%1$s commented on [url=%2$s]your %3$s[/url]', '[url='.$params['source_link'].']'.$params['source_name'].'[/url]', $itemlink, @@ -739,7 +740,7 @@ function check_item_notification($itemid, $uid, $defaulttype = "") { // Only act if it is a "real" post // We need the additional check for the "local_profile" because of mixed situations on connector networks - $item = q("SELECT `id`, `mention`, `tag`,`parent`, `title`, `body`, `author-name`, `author-link`, `author-avatar`, `guid`, + $item = q("SELECT `id`, `mention`, `tag`,`parent`, `title`, `body`, `author-id`, `guid`, `parent-uri`, `uri`, `contact-id` FROM `item` WHERE `id` = %d AND `verb` IN ('%s', '') AND `type` != 'activity' AND NOT (`author-link` IN ($profile_list)) LIMIT 1", @@ -747,6 +748,8 @@ function check_item_notification($itemid, $uid, $defaulttype = "") { if (!$item) return false; + $author = dba::selectFirst('contact', ['name', 'thumb', 'url'], ['id' => $item[0]['author-id']]); + // Generate the notification array $params = []; $params["uid"] = $uid; @@ -758,9 +761,9 @@ function check_item_notification($itemid, $uid, $defaulttype = "") { $params["parent"] = $item[0]["parent"]; $params["link"] = System::baseUrl().'/display/'.urlencode($item[0]["guid"]); $params["otype"] = 'item'; - $params["source_name"] = $item[0]["author-name"]; - $params["source_link"] = $item[0]["author-link"]; - $params["source_photo"] = $item[0]["author-avatar"]; + $params["source_name"] = $author["name"]; + $params["source_link"] = $author["url"]; + $params["source_photo"] = $author["thumb"]; if ($item[0]["parent-uri"] === $item[0]["uri"]) { // Send a notification for every new post? diff --git a/include/items.php b/include/items.php index c04bef01c3..c54869c3e5 100644 --- a/include/items.php +++ b/include/items.php @@ -274,6 +274,7 @@ function consume_feed($xml, $importer, $contact, &$hub, $datedir = 0, $pass = 0) function subscribe_to_hub($url, $importer, $contact, $hubmode = 'subscribe') { $a = get_app(); + $r = null; if (is_array($importer)) { $r = q("SELECT `nickname` FROM `user` WHERE `uid` = %d LIMIT 1", @@ -321,7 +322,7 @@ function drop_items($items) { if (count($items)) { foreach ($items as $item) { - $owner = Item::deleteById($item); + $owner = Item::deleteForUser(['id' => $item], local_user()); if ($owner && !$uid) $uid = $owner; } @@ -393,7 +394,7 @@ function drop_item($id) { } // delete the item - Item::deleteById($item['id']); + Item::deleteForUser(['id' => $item['id']], local_user()); goaway(System::baseUrl() . '/' . $_SESSION['return_url']); //NOTREACHED diff --git a/include/security.php b/include/security.php index b13a507cf4..bcfddf8872 100644 --- a/include/security.php +++ b/include/security.php @@ -254,6 +254,7 @@ function can_write_wall($owner) return false; } +/// @TODO $groups should be array function permissions_sql($owner_id, $remote_verified = false, $groups = null) { $local_user = local_user(); @@ -275,6 +276,13 @@ function permissions_sql($owner_id, $remote_verified = false, $groups = null) */ if ($local_user && $local_user == $owner_id) { $sql = ''; + /** + * Authenticated visitor. Unless pre-verified, + * check that the contact belongs to this $owner_id + * and load the groups the visitor belongs to. + * If pre-verified, the caller is expected to have already + * done this and passed the groups into this function. + */ } elseif ($remote_user) { /* * Authenticated visitor. Unless pre-verified, @@ -298,9 +306,10 @@ function permissions_sql($owner_id, $remote_verified = false, $groups = null) if ($remote_verified) { $gs = '<<>>'; // should be impossible to match - if (is_array($groups) && count($groups)) { - foreach ($groups as $g) + if (is_array($groups)) { + foreach ($groups as $g) { $gs .= '|<' . intval($g) . '>'; + } } $sql = sprintf( diff --git a/include/text.php b/include/text.php index 6830f91e0f..f145c03e53 100644 --- a/include/text.php +++ b/include/text.php @@ -152,7 +152,7 @@ function autoname($len) { 'nd','ng','nk','nt','rn','rp','rt']; $noend = ['bl', 'br', 'cl','cr','dr','fl','fr','gl','gr', - 'kh', 'kl','kr','mn','pl','pr','rh','tr','qu','wh']; + 'kh', 'kl','kr','mn','pl','pr','rh','tr','qu','wh','q']; $start = mt_rand(0,2); if ($start == 0) { @@ -178,14 +178,13 @@ function autoname($len) { $word = substr($word,0,$len); foreach ($noend as $noe) { - if ((strlen($word) > 2) && (substr($word, -2) == $noe)) { - $word = substr($word, 0, -1); + $noelen = strlen($noe); + if ((strlen($word) > $noelen) && (substr($word, -$noelen) == $noe)) { + $word = autoname($len); break; } } - if (substr($word, -1) == 'q') { - $word = substr($word, 0, -1); - } + return $word; } @@ -453,7 +452,7 @@ function perms2str($p) { if (is_array($p)) { $tmp = $p; } else { - $tmp = explode(',',$p); + $tmp = explode(',', $p); } if (is_array($tmp)) { @@ -962,13 +961,9 @@ function micropro($contact, $redirect = false, $class = '', $textmode = false) { $redir = false; if ($redirect) { - $redirect_url = 'redir/' . $contact['id']; - if (local_user() && ($contact['uid'] == local_user()) && ($contact['network'] === NETWORK_DFRN)) { - $redir = true; - $url = $redirect_url; + $url = Contact::magicLink($contact['url']); + if (strpos($url, 'redir/') === 0) { $sparkle = ' sparkle'; - } else { - $url = Profile::zrl($url); } } @@ -1301,11 +1296,7 @@ function prepare_body(array &$item, $attach = false, $is_preview = false) foreach ($matches as $mtch) { $mime = $mtch[3]; - if ((local_user() == $item['uid']) && ($item['contact-id'] != $a->contact['id']) && ($item['network'] == NETWORK_DFRN)) { - $the_url = 'redir/' . $item['contact-id'] . '?f=1&url=' . $mtch[1]; - } else { - $the_url = $mtch[1]; - } + $the_url = Contact::magicLinkById($item['author-id'], $mtch[1]); if (strpos($mime, 'video') !== false) { if (!$vhead) { @@ -1661,10 +1652,11 @@ function bb_translate_video($s) { $r = preg_match_all("/\[video\](.*?)\[\/video\]/ism",$s,$matches,PREG_SET_ORDER); if ($r) { foreach ($matches as $mtch) { - if ((stristr($mtch[1],'youtube')) || (stristr($mtch[1],'youtu.be'))) - $s = str_replace($mtch[0],'[youtube]' . $mtch[1] . '[/youtube]',$s); - elseif (stristr($mtch[1],'vimeo')) - $s = str_replace($mtch[0],'[vimeo]' . $mtch[1] . '[/vimeo]',$s); + if ((stristr($mtch[1], 'youtube')) || (stristr($mtch[1], 'youtu.be'))) { + $s = str_replace($mtch[0], '[youtube]' . $mtch[1] . '[/youtube]', $s); + } elseif (stristr($mtch[1], 'vimeo')) { + $s = str_replace($mtch[0], '[vimeo]' . $mtch[1] . '[/vimeo]', $s); + } } } return $s; @@ -1782,7 +1774,7 @@ function file_tag_file_query($table,$s,$type = 'file') { } // ex. given music,video return