]> git.mxchange.org Git - friendica.git/commitdiff
Merge branch 'master' into develop
authorHypolite Petovan <mrpetovan@gmail.com>
Fri, 1 Jun 2018 11:30:04 +0000 (07:30 -0400)
committerHypolite Petovan <mrpetovan@gmail.com>
Fri, 1 Jun 2018 11:30:04 +0000 (07:30 -0400)
- Updated new develop version label
- Incremented database build number

47 files changed:
.gitattributes
.gitignore
.htaccess
.travis.yml
VERSION
bin/daemon.php
boot.php
composer.json
composer.lock
database.sql
doc/Home.md
doc/Tests.md [new file with mode: 0644]
doc/de/Home.md
doc/de/Settings.md
doc/htconfig.md
include/api.php
include/conversation.php
include/dba.php
include/items.php
include/security.php
include/text.php
mod/admin.php
mod/events.php
mod/photos.php
mod/poco.php
mod/share.php
mod/subthread.php
mod/tagger.php
mods/readme.txt [deleted file]
mods/redme.txt [new file with mode: 0644]
phpunit.xml
src/Core/Cache.php
src/Core/Cache/RedisCacheDriver.php [new file with mode: 0644]
src/Core/PConfig.php
src/Core/Worker.php
src/Database/DBStructure.php
src/Model/Event.php
src/Model/Item.php
src/Protocol/DFRN.php
src/Protocol/OStatus.php
src/Protocol/PortableContact.php
tests/ApiTest.php [new file with mode: 0644]
tests/BaseObjectTest.php
tests/DatabaseTest.php [new file with mode: 0644]
tests/TextTest.php
tests/bootstrap.php [new file with mode: 0644]
tests/datasets/api.yml [new file with mode: 0644]

index 4be1c918527cb1766cac23f98c6f14867a8c589c..18ba9e0758c7b4ebe701e521b1258f3ef8ff6706 100644 (file)
@@ -1,2 +1,2 @@
-# Disable LF normalization for all files\r
-* -text
\ No newline at end of file
+# Disable LF normalization for all files
+* -text
index 9e6504184c03c4347f630441b34c0fc8e133c13c..9de700d148d8960ee1b9a52f5f00ba4dc8b31300 100644 (file)
@@ -1,61 +1,64 @@
-favicon.*\r
-.htconfig.php\r
-.htpreconfig.php\r
-\#*\r
-include/jquery-1.4.2.min.js\r
-*.log\r
-*.out\r
-*.version*\r
-favicon.*\r
-home.html\r
-addon\r
-*.orig\r
-*~\r
-robots.txt\r
-\r
-#ignore documentation, it should be newly built\r
-doc/html\r
-\r
-#ignore reports, should be generted with every build\r
-report/\r
-\r
-#ignore config files from eclipse, we don't want IDE files in our repository\r
-.project\r
-.buildpath\r
-.externalToolBuilders\r
-.settings\r
-#ignore OSX .DS_Store files\r
-.DS_Store\r
-\r
-/nbproject/private/\r
-\r
-#ignore smarty cache\r
-/view/smarty3/compiled/\r
-\r
-#ignore cache folders\r
-/privacy_image_cache/\r
-/photo/\r
-/proxy/\r
-nbproject\r
-\r
-#ignore vagrant dir\r
-.vagrant/\r
-\r
-#ignore local folder\r
-/local/\r
-\r
-#ignore config files from Visual Studio\r
-/.vs/\r
-/php_friendica.phpproj\r
-/php_friendica.sln\r
-/php_friendica.phpproj.user\r
-\r
-#ignore things from transifex-client\r
-venv/\r
-\r
-#ignore Composer dependencies\r
-/vendor\r
-/view/asset\r
-\r
-#ignore config files from JetBrains\r
-/.idea\r
+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 all in 'vendor' as `utils/composer.phar install` will bring it back
+vendor/*
+
+#ignore config files from JetBrains
+/.idea
+
+#ignore addons/ directory
+addons/
index 2348cdc38b36ca4eed776ae762eee7d2c8edf660..a671cc680aff06f63aa301add63c8cc59c34ad33 100644 (file)
--- a/.htaccess
+++ b/.htaccess
@@ -4,7 +4,7 @@ AddType audio/ogg .oga
 #AddHandler php53-cgi .php
 
 <FilesMatch "\.(out|log)$">
-  <IfModule authz_host_module> 
+  <IfModule authz_host_module>
     #Apache 2.4
     Require all denied
   </IfModule>
@@ -38,4 +38,3 @@ AddType audio/ogg .oga
   RewriteRule ^(.*)$ index.php?pagename=$1 [E=REMOTE_USER:%{HTTP:Authorization},L,QSA]
 
 </IfModule>
-
index d68b7727e893648344978d94f4ff378589a62e15..82b5a5d218bd3de32b17a142b8e22026263b1e5b 100644 (file)
@@ -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/VERSION b/VERSION
index 41df8e6ae67dfcfd8fbc0ffb4f8bbaf60b8f9bd3..607ef5eb6ac67ed654ae7253ffdaa265496e986d 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2018.05
+2018.08-dev
index 6b0e377a3a1bfa0126c8a4bfe9b5d25efebd603c..b51dd392ef7fdd1e7c831871ab15a55f38df4575 100755 (executable)
@@ -38,7 +38,7 @@ if (substr($directory, 0, 1) != "/") {
 }
 $directory = realpath($directory."/..");
 
-@include($directory."/.htconfig.php");
+include $directory."/.htconfig.php";
 
 if (!isset($pidfile)) {
        die('Please specify a pid file in the variable $pidfile in the .htconfig.php. For example:'."\n".
index 8f077b440db967a0f9e55036b83a0ac451f81841..57176296e450b0c92af1a58e10d24f0227141497 100644 (file)
--- 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');
+define('FRIENDICA_VERSION',      '2018.08-dev');
 define('DFRN_PROTOCOL_VERSION',  '2.23');
-define('DB_UPDATE_VERSION',      1266);
+define('DB_UPDATE_VERSION',      1267);
 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()
index b7cd645bdb43d72580af2d8e0e31c2a98c3a344a..9668b9341c14e819a1f267fd4cd7d314d3742261 100644 (file)
@@ -47,7 +47,8 @@
        ],
        "autoload": {
                "psr-4": {
-                       "Friendica\\": "src/"
+                       "Friendica\\": "src/",
+                       "Friendica\\Test\\": "tests/"
                },
                "psr-0": {
                        "": "library/"
                "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"
        }
 }
index f294c16ef5f59a6274ea9c75e0f867fbaf61b4dd..dd2665ebbe251b4dffa61f87ea267c1d2c1eaa2a 100644 (file)
@@ -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",
             "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": {
index ce5befc863557eec40b88d40c44342b87fb8ce67..cc6ab16e1dc8d25f200d9b8b83df18cdb2b36551 100644 (file)
@@ -1,6 +1,6 @@
 -- ------------------------------------------
--- Friendica 2018.05 (The Tazmans Flax-lily)
--- DB_UPDATE_VERSION 1266
+-- Friendica 2018.08-dev (The Tazmans Flax-lily)
+-- DB_UPDATE_VERSION 1267
 -- ------------------------------------------
 
 
@@ -9,12 +9,12 @@
 --
 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;
@@ -23,19 +23,19 @@ CREATE TABLE IF NOT EXISTS `addon` (
 -- 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;
 
@@ -67,7 +67,7 @@ CREATE TABLE IF NOT EXISTS `cache` (
 -- 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 '',
@@ -105,26 +105,26 @@ CREATE TABLE IF NOT EXISTS `config` (
 -- 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 '',
@@ -192,14 +192,14 @@ CREATE TABLE IF NOT EXISTS `contact` (
 -- 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;
@@ -208,13 +208,13 @@ CREATE TABLE IF NOT EXISTS `conv` (
 -- 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`)
@@ -224,26 +224,26 @@ CREATE TABLE IF NOT EXISTS `conversation` (
 -- 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;
@@ -252,8 +252,8 @@ CREATE TABLE IF NOT EXISTS `event` (
 -- 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 '',
@@ -294,9 +294,9 @@ CREATE TABLE IF NOT EXISTS `fsuggest` (
 -- 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`)
@@ -306,12 +306,12 @@ CREATE TABLE IF NOT EXISTS `gcign` (
 -- 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)),
@@ -345,7 +345,7 @@ CREATE TABLE IF NOT EXISTS `gcontact` (
 -- 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 '',
@@ -360,11 +360,11 @@ CREATE TABLE IF NOT EXISTS `glink` (
 -- 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;
@@ -373,9 +373,9 @@ CREATE TABLE IF NOT EXISTS `group` (
 -- 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`)
@@ -385,14 +385,14 @@ CREATE TABLE IF NOT EXISTS `group_member` (
 -- 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 '',
@@ -421,11 +421,11 @@ CREATE TABLE IF NOT EXISTS `gserver-tag` (
 -- 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;
@@ -434,7 +434,7 @@ CREATE TABLE IF NOT EXISTS `hook` (
 -- 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 '',
@@ -453,68 +453,68 @@ CREATE TABLE IF NOT EXISTS `intro` (
 --
 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 toa 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)),
@@ -550,10 +550,10 @@ CREATE TABLE IF NOT EXISTS `item` (
 -- 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;
 
@@ -561,23 +561,23 @@ CREATE TABLE IF NOT EXISTS `locks` (
 -- 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`),
@@ -590,7 +590,7 @@ CREATE TABLE IF NOT EXISTS `mail` (
 -- 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 '',
@@ -610,7 +610,7 @@ CREATE TABLE IF NOT EXISTS `mailacct` (
 -- 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`),
@@ -621,7 +621,7 @@ CREATE TABLE IF NOT EXISTS `manage` (
 -- 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,15 +629,15 @@ 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`),
@@ -649,7 +649,7 @@ CREATE TABLE IF NOT EXISTS `notify` (
 -- 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 '',
@@ -661,10 +661,10 @@ CREATE TABLE IF NOT EXISTS `notify-threads` (
 -- 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;
@@ -673,11 +673,11 @@ CREATE TABLE IF NOT EXISTS `oembed` (
 -- 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;
@@ -710,16 +710,16 @@ CREATE TABLE IF NOT EXISTS `pconfig` (
 -- 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 +728,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`),
@@ -765,7 +765,7 @@ CREATE TABLE IF NOT EXISTS `poll` (
 -- 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`),
@@ -787,14 +787,14 @@ CREATE TABLE IF NOT EXISTS `process` (
 -- 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,8 +827,8 @@ 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;
@@ -837,9 +837,9 @@ CREATE TABLE IF NOT EXISTS `profile` (
 -- 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 '',
@@ -850,7 +850,7 @@ CREATE TABLE IF NOT EXISTS `profile_check` (
 -- 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 '',
@@ -868,7 +868,7 @@ CREATE TABLE IF NOT EXISTS `push_subscriber` (
 -- 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',
@@ -887,7 +887,7 @@ CREATE TABLE IF NOT EXISTS `queue` (
 -- 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',
@@ -901,7 +901,7 @@ CREATE TABLE IF NOT EXISTS `register` (
 -- 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`),
@@ -912,7 +912,7 @@ CREATE TABLE IF NOT EXISTS `search` (
 -- 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 '',
@@ -925,8 +925,8 @@ CREATE TABLE IF NOT EXISTS `session` (
 -- 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 '',
@@ -961,11 +961,11 @@ CREATE TABLE IF NOT EXISTS `term` (
 -- 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 '',
@@ -1017,50 +1017,50 @@ CREATE TABLE IF NOT EXISTS `tokens` (
 -- 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))
@@ -1070,7 +1070,7 @@ CREATE TABLE IF NOT EXISTS `user` (
 -- 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))
@@ -1096,7 +1096,7 @@ 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 1d72a2600ff14ce2bc1e386cfe9c1ea578ed837e..0a41a461463d085287be128358dde9a7f7f180fd 100644 (file)
@@ -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 (file)
index 0000000..6acb4e7
--- /dev/null
@@ -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.
index 8e4be6bfc8bd0a02628013c62e953695462304a7..31cce7aea437865586fde3ee2d1d44e949f8a317 100644 (file)
@@ -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)
-
index 8a654e32c8518f8311c5f37dd45ed7a6e20614f6..b7b696ea652eddfb3ef92fa64818453738b08ce2 100644 (file)
@@ -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.
index 6598fa142affa227a95a1b4fa3859de18520401d..4743da444cb95aaabc705c7ed8f3eb0f6a667af3 100644 (file)
@@ -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
index a70c18f3ca6a149417d50ea813c5d3eb2e2b12e2..8ffe27e74921cb7426e020550b7bc66b6894d474 100644 (file)
@@ -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,
@@ -935,7 +935,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 +960,7 @@ function api_create_xml($data, $root_element)
                $i = 1;
 
                foreach ($data2 as $item) {
-                       $data4[$i++.":".$childname] = $item;
+                       $data4[$i++ . ":" . $childname] = $item;
                }
 
                $data2 = $data4;
@@ -2216,7 +2216,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);
 }
 
@@ -2732,7 +2732,7 @@ function api_convert_item($item)
  *
  * @param string $body
  *
- * @return array|false
+ * @return array
  */
 function api_get_attachments(&$body)
 {
@@ -2743,7 +2743,7 @@ function api_get_attachments(&$body)
        $ret = preg_match_all("/\[img\]([$URLSearchString]*)\[\/img\]/ism", $text, $images);
 
        if (!$ret) {
-               return false;
+               return [];
        }
 
        $attachments = [];
@@ -4395,7 +4395,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
  *
@@ -4534,6 +4533,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 +4547,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);
@@ -5289,27 +5288,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;
 }
 
 /**
index 290d68bf3da80c1910528eb35839cb878b7f50c6..60fa0e4ecd71cb7dee293f320fe14de2ab51d238 100644 (file)
@@ -116,7 +116,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 +162,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;
@@ -304,8 +301,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;
                }
@@ -394,10 +391,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;
@@ -1102,7 +1098,7 @@ function builtin_activity_puller($item, &$conv_responses) {
 
                        $url = '<a href="'. $url . '"'. $sparkle .'>' . htmlentities($item['author-name']) . '</a>';
 
-                       if (!$item['thr-parent']) {
+                       if (!x($item, 'thr-parent')) {
                                $item['thr-parent'] = $item['parent-uri'];
                        }
 
@@ -1590,19 +1586,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] = [];
index e645755386a830aebd77d90bf2dd3d733ad2ec53..aa63a5b36145d06da05b0faaab8db10aedf4e424 100644 (file)
@@ -92,6 +92,15 @@ class dba {
                return self::$connected;
        }
 
+       /**
+        * Return the database object.
+        * @return PDO|mysqli
+        */
+       public static function get_db()
+       {
+               return self::$db;
+       }
+
        /**
         * @brief Returns the MySQL server version string
         *
index 4533b6077e1b0d68574a944a35dbb4668635e93b..c54869c3e51c310143f86d908969bef2bc15bb08 100644 (file)
@@ -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",
index b13a507cf483c124e5e1de3ed3817b205784d3aa..bcfddf8872cab6c909f0e8999dfc3800a25543d0 100644 (file)
@@ -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(
index 6830f91e0f8ae15b4edc683bdad09b968bf47ca2..53eae1ff33924f7118df4c5f8beb3714743628c0 100644 (file)
@@ -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)) {
@@ -1661,10 +1660,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 +1782,7 @@ function file_tag_file_query($table,$s,$type = 'file') {
 }
 
 // ex. given music,video return <music><video> or [music][video]
-function file_tag_list_to_file($list,$type = 'file') {
+function file_tag_list_to_file($list, $type = 'file') {
        $tag_list = '';
        if (strlen($list)) {
                $list_array = explode(",",$list);
@@ -1804,7 +1804,7 @@ function file_tag_list_to_file($list,$type = 'file') {
 }
 
 // ex. given <music><video>[friends], return music,video or friends
-function file_tag_file_to_list($file,$type = 'file') {
+function file_tag_file_to_list($file, $type = 'file') {
        $matches = false;
        $list = '';
        if ($type == 'file') {
@@ -1830,8 +1830,7 @@ function file_tag_update_pconfig($uid, $file_old, $file_new, $type = 'file') {
 
        if (!intval($uid)) {
                return false;
-       }
-       if ($file_old == $file_new) {
+       } elseif ($file_old == $file_new) {
                return true;
        }
 
@@ -1854,8 +1853,9 @@ function file_tag_update_pconfig($uid, $file_old, $file_new, $type = 'file') {
                $check_new_tags = explode(",",file_tag_file_to_list($file_new,$type));
 
                foreach ($check_new_tags as $tag) {
-                       if (! stristr($saved,$lbracket . file_tag_encode($tag) . $rbracket))
+                       if (! stristr($saved,$lbracket . file_tag_encode($tag) . $rbracket)) {
                                $new_tags[] = $tag;
+                       }
                }
 
                $filetags_updated .= file_tag_list_to_file(implode(",",$new_tags),$type);
@@ -1865,8 +1865,9 @@ function file_tag_update_pconfig($uid, $file_old, $file_new, $type = 'file') {
                $check_deleted_tags = explode(",",file_tag_file_to_list($file_old,$type));
 
                foreach ($check_deleted_tags as $tag) {
-                       if (! stristr($file_new,$lbracket . file_tag_encode($tag) . $rbracket))
+                       if (! stristr($file_new,$lbracket . file_tag_encode($tag) . $rbracket)) {
                                $deleted_tags[] = $tag;
+                       }
                }
 
                foreach ($deleted_tags as $key => $tag) {
@@ -1980,17 +1981,22 @@ function protect_sprintf($s) {
        return str_replace('%', '%%', $s);
 }
 
-
+/// @TODO Rewrite this
 function is_a_date_arg($s) {
        $i = intval($s);
+
        if ($i > 1900) {
                $y = date('Y');
+
                if ($i <= $y + 1 && strpos($s, '-') == 4) {
-                       $m = intval(substr($s,5));
-                       if ($m > 0 && $m <= 12)
+                       $m = intval(substr($s, 5));
+
+                       if ($m > 0 && $m <= 12) {
                                return true;
+                       }
                }
        }
+
        return false;
 }
 
@@ -2008,6 +2014,7 @@ function deindent($text, $chr = "[\t ]", $count = NULL) {
                preg_match("|^" . $chr . "*|", $lines[$k], $m);
                $count = strlen($m[0]);
        }
+
        for ($k = 0; $k < count($lines); $k++) {
                $lines[$k] = preg_replace("|^" . $chr . "{" . $count . "}|", "", $lines[$k]);
        }
index 3d7c553ff45494e55adebdbcfd1afaf7051bd4ea..81c65859c31124c4158320a5a309aa8a1b641761 100644 (file)
@@ -65,7 +65,7 @@ function admin_post(App $a)
                        case 'addons':
                                if ($a->argc > 2 &&
                                        is_file("addon/" . $a->argv[2] . "/" . $a->argv[2] . ".php")) {
-                                       @include_once("addon/" . $a->argv[2] . "/" . $a->argv[2] . ".php");
+                                       include_once "addon/" . $a->argv[2] . "/" . $a->argv[2] . ".php";
                                        if (function_exists($a->argv[2] . '_addon_admin_post')) {
                                                $func = $a->argv[2] . '_addon_admin_post';
                                                $func($a);
@@ -916,6 +916,7 @@ function admin_page_site_post(App $a)
                        $upds = implode(", ", $upd);
 
                        $r = q("UPDATE %s SET %s;", $table_name, $upds);
+
                        if (!DBM::is_result($r)) {
                                notice("Failed updating '$table_name': " . dba::errorMessage());
                                goaway('admin/site');
@@ -1297,15 +1298,18 @@ function admin_page_site(App $a)
        $user_names = [];
        $user_names['---'] = L10n::t('Multi user instance');
        $users = q("SELECT `username`, `nickname` FROM `user`");
+
        foreach ($users as $user) {
                $user_names[$user['nickname']] = $user['username'];
        }
 
        /* Banner */
        $banner = Config::get('system', 'banner');
+
        if ($banner == false) {
                $banner = '<a href="https://friendi.ca"><img id="logo-img" src="images/friendica-32.png" alt="logo" /></a><span id="logo-text"><a href="https://friendi.ca">Friendica</a></span>';
        }
+
        $banner = htmlspecialchars($banner);
        $info = Config::get('config', 'info');
        $info = htmlspecialchars($info);
@@ -1501,9 +1505,12 @@ function admin_page_dbsync(App $a)
 
        if ($a->argc > 2 && intval($a->argv[2])) {
                require_once 'update.php';
+
                $func = 'update_' . intval($a->argv[2]);
+
                if (function_exists($func)) {
                        $retval = $func();
+
                        if ($retval === UPDATE_FAILED) {
                                $o .= L10n::t("Executing %s failed with error: %s", $func, $retval);
                        } elseif ($retval === UPDATE_SUCCESS) {
@@ -1516,11 +1523,13 @@ function admin_page_dbsync(App $a)
                        $o .= L10n::t('There was no additional update function %s that needed to be called.', $func) . "<br />";
                        Config::set('database', $func, 'success');
                }
+
                return $o;
        }
 
        $failed = [];
        $r = q("SELECT `k`, `v` FROM `config` WHERE `cat` = 'database' ");
+
        if (DBM::is_result($r)) {
                foreach ($r as $rr) {
                        $upd = intval(substr($rr['k'], 7));
@@ -1530,6 +1539,7 @@ function admin_page_dbsync(App $a)
                        $failed[] = $upd;
                }
        }
+
        if (!count($failed)) {
                $o = replace_macros(get_markup_template('structure_check.tpl'), [
                        '$base' => System::baseUrl(true),
@@ -1764,8 +1774,8 @@ function admin_page_users(App $a)
                $e['page-flags-raw'] = $e['page-flags'];
                $e['page-flags'] = $page_types[$e['page-flags']];
 
-               $e['account-type-raw'] = ($e['page_flags_raw']==0) ? $e['account-type'] : -1;
-               $e['account-type'] = ($e['page_flags_raw']==0) ? $account_types[$e['account-type']] : "";
+               $e['account-type-raw'] = ($e['page_flags_raw'] == 0) ? $e['account-type'] : -1;
+               $e['account-type'] = ($e['page_flags_raw'] == 0) ? $account_types[$e['account-type']] : "";
 
                $e['register_date'] = Temporal::getRelativeDate($e['register_date']);
                $e['login_date'] = Temporal::getRelativeDate($e['login_date']);
@@ -1916,7 +1926,7 @@ function admin_page_addons(App $a)
 
                $admin_form = "";
                if (in_array($addon, $a->addons_admin)) {
-                       @require_once("addon/$addon/$addon.php");
+                       require_once "addon/$addon/$addon.php";
                        $func = $addon . '_addon_admin';
                        $func($a, $admin_form);
                }
@@ -2157,6 +2167,7 @@ function admin_page_themes(App $a)
                }
 
                $readme = null;
+
                if (is_file("view/theme/$theme/README.md")) {
                        $readme = Markdown::convert(file_get_contents("view/theme/$theme/README.md"), false);
                } elseif (is_file("view/theme/$theme/README")) {
index 87c358a99eed6c3e9559e86cf0d1cc2ed48d67bc..7914b93d09ef9f0cb5fa875586ccbe0977434416 100644 (file)
@@ -433,6 +433,7 @@ function events_content(App $a) {
                if (x($_REQUEST, 'location'))    {$orig_event['location']    = $_REQUEST['location'];}
                if (x($_REQUEST, 'start'))       {$orig_event['start']       = $_REQUEST['start'];}
                if (x($_REQUEST, 'finish'))      {$orig_event['finish']      = $_REQUEST['finish'];}
+               if (x($_REQUEST,'finish')) $orig_event['finish'] = $_REQUEST['finish'];
 
                $n_checked = ((x($orig_event) && $orig_event['nofinish']) ? ' checked="checked" ' : '');
                $a_checked = ((x($orig_event) && $orig_event['adjust'])   ? ' checked="checked" ' : '');
index 30d3728d36865db24d5d14441daec2752894d308..45e713677abf18cd790a2e3768218ce75fec1f1e 100644 (file)
@@ -1231,9 +1231,11 @@ function photos_content(App $a)
                $prevlink = '';
                $nextlink = '';
 
-               /// @todo This query is totally bad, the whole functionality has to be changed
-               // The query leads to a really intense used index.
-               // By now we hide it if someone wants to.
+               /*
+                * @todo This query is totally bad, the whole functionality has to be changed
+                * The query leads to a really intense used index.
+                * By now we hide it if someone wants to.
+                */
                if (!Config::get('system', 'no_count', false)) {
                        $order_field = defaults($_GET, 'order', '');
                        if ($order_field === 'posted') {
@@ -1268,8 +1270,10 @@ function photos_content(App $a)
                        }
                }
 
-               if (count($ph) == 1)
+               if (count($ph) == 1) {
                        $hires = $lores = $ph[0];
+               }
+
                if (count($ph) > 1) {
                        if ($ph[1]['scale'] == 2) {
                                // original is 640 or less, we can display it directly
@@ -1281,6 +1285,7 @@ function photos_content(App $a)
                }
 
                $album_link = 'photos/' . $a->data['user']['nickname'] . '/album/' . bin2hex($ph[0]['album']);
+
                $tools = null;
                $lock = null;
 
@@ -1307,8 +1312,9 @@ function photos_content(App $a)
                        ]);
                }
 
-               if ($prevlink)
+               if ($prevlink) {
                        $prevlink = [$prevlink, '<div class="icon prev"></div>'] ;
+               }
 
                $photo = [
                        'href' => 'photo/' . $hires['resource-id'] . '-' . $hires['scale'] . '.' . $phototypes[$hires['type']],
@@ -1669,8 +1675,9 @@ function photos_content(App $a)
                $twist = false;
                foreach ($r as $rr) {
                        //hide profile photos to others
-                       if (!$is_owner && !remote_user() && ($rr['album'] == L10n::t('Profile Photos')))
+                       if (!$is_owner && !remote_user() && ($rr['album'] == L10n::t('Profile Photos'))) {
                                continue;
+                       }
 
                        $twist = !$twist;
 
index 0728020eccab3292e6cc7428b616bc5b80bed149..671551f832589e89ab4c839e1c48ada353a79cb7 100644 (file)
@@ -43,6 +43,7 @@ function poco_init(App $a) {
                echo json_encode($ret);
                killme();
        }
+
        if ($a->argc > 1 && $a->argv[1] === '@global') {
                // List of all profiles that this server recently had data from
                $global = true;
index f67dd3d200c96aa74c37602e2a360cc439db4638..555273443c6fc668b4bca76a7ddecf0b6ff26998 100644 (file)
@@ -5,6 +5,7 @@ use Friendica\Database\DBM;
 
 function share_init(App $a) {
        $post_id = (($a->argc > 1) ? intval($a->argv[1]) : 0);
+
        if (!$post_id || !local_user()) {
                killme();
        }
@@ -14,37 +15,44 @@ function share_init(App $a) {
                WHERE `item`.`id` = %d LIMIT 1",
                intval($post_id)
        );
+
        if (!DBM::is_result($r) || ($r[0]['private'] == 1)) {
                killme();
        }
+
        if (strpos($r[0]['body'], "[/share]") !== false) {
                $pos = strpos($r[0]['body'], "[share");
                $o = substr($r[0]['body'], $pos);
        } else {
                $o = share_header($r[0]['author-name'], $r[0]['author-link'], $r[0]['author-avatar'], $r[0]['guid'], $r[0]['created'], $r[0]['plink']);
 
-               if ($r[0]['title'])
+               if ($r[0]['title']) {
                        $o .= '[b]'.$r[0]['title'].'[/b]'."\n";
+               }
+
                $o .= $r[0]['body'];
-               $o.= "[/share]";
+               $o .= "[/share]";
        }
 
        echo $o;
        killme();
 }
 
+/// @TODO Rewrite to handle over whole record array
 function share_header($author, $profile, $avatar, $guid, $posted, $link) {
-       $header = "[share author='".str_replace(["'", "[", "]"], ["&#x27;", "&#x5B;", "&#x5D;"], $author).
-               "' profile='".str_replace(["'", "[", "]"], ["&#x27;", "&#x5B;", "&#x5D;"], $profile).
-               "' avatar='".str_replace(["'", "[", "]"], ["&#x27;", "&#x5B;", "&#x5D;"], $avatar);
+       $header = "[share author='" . str_replace(["'", "[", "]"], ["&#x27;", "&#x5B;", "&#x5D;"], $author).
+               "' profile='" . str_replace(["'", "[", "]"], ["&#x27;", "&#x5B;", "&#x5D;"], $profile).
+               "' avatar='" . str_replace(["'", "[", "]"], ["&#x27;", "&#x5B;", "&#x5D;"], $avatar);
 
        if ($guid) {
-               $header .= "' guid='".str_replace(["'", "[", "]"], ["&#x27;", "&#x5B;", "&#x5D;"], $guid);
+               $header .= "' guid='" . str_replace(["'", "[", "]"], ["&#x27;", "&#x5B;", "&#x5D;"], $guid);
        }
+
        if ($posted) {
-               $header .= "' posted='".str_replace(["'", "[", "]"], ["&#x27;", "&#x5B;", "&#x5D;"], $posted);
+               $header .= "' posted='" . str_replace(["'", "[", "]"], ["&#x27;", "&#x5B;", "&#x5D;"], $posted);
        }
-       $header .= "' link='".str_replace(["'", "[", "]"], ["&#x27;", "&#x5B;", "&#x5D;"], $link)."']";
+
+       $header .= "' link='" . str_replace(["'", "[", "]"], ["&#x27;", "&#x5B;", "&#x5D;"], $link)."']";
 
        return $header;
 }
index c858f2d1fa3a3c847ea132b823605d33b31496ce..df44df6efa893331ba525d29de6ee2573a80ea95 100644 (file)
@@ -63,17 +63,19 @@ function subthread_content(App $a) {
                WHERE `contact`.`self` = 1 AND `contact`.`uid` = %d LIMIT 1",
                intval($owner_uid)
        );
-       if (DBM::is_result($r))
+
+       if (DBM::is_result($r)) {
                $owner = $r[0];
+       }
 
        if (! $owner) {
                logger('like: no owner');
                return;
        }
 
-       if (! $remote_owner)
+       if (! $remote_owner) {
                $remote_owner = $owner;
-
+       }
 
        $contact = null;
        // This represents the person posting
@@ -85,8 +87,10 @@ function subthread_content(App $a) {
                        intval($_SESSION['visitor_id']),
                        intval($owner_uid)
                );
-               if (DBM::is_result($r))
+
+               if (DBM::is_result($r)) {
                        $contact = $r[0];
+               }
        }
        if (! $contact) {
                return;
index 16195cc339d2f02f4c04eb719f7e7b04484e1e98..211e2ffa1fe6c94bb63eac0c84ebc7447ade683a 100644 (file)
@@ -159,11 +159,13 @@ EOT;
        }
 
        $term_objtype = ($item['resource-id'] ? TERM_OBJ_PHOTO : TERM_OBJ_POST);
-        $t = q("SELECT count(tid) as tcount FROM term WHERE oid=%d AND term='%s'",
-                intval($item['id']),
-                dbesc($term)
-        );
-       if((! $blocktags) && $t[0]['tcount']==0 ) {
+
+       $t = q("SELECT count(tid) as tcount FROM term WHERE oid=%d AND term='%s'",
+               intval($item['id']),
+               dbesc($term)
+       );
+
+       if ((!$blocktags) && $t[0]['tcount'] == 0 ) {
                q("INSERT INTO term (oid, otype, type, term, url, uid) VALUE (%d, %d, %d, '%s', '%s', %d)",
                   intval($item['id']),
                   $term_objtype,
@@ -176,26 +178,28 @@ EOT;
 
        // if the original post is on this site, update it.
 
-       $r = q("select `tag`,`id`,`uid` from item where `origin` = 1 AND `uri` = '%s' LIMIT 1",
+       $r = q("SELECT `tag`,`id`,`uid` FROM `item` WHERE `origin`=1 AND `uri`='%s' LIMIT 1",
                dbesc($item['uri'])
        );
+
        if (DBM::is_result($r)) {
-               $x = q("SELECT `blocktags` FROM `user` WHERE `uid` = %d limit 1",
+               $x = q("SELECT `blocktags` FROM `user` WHERE `uid`=%d LIMIT 1",
                        intval($r[0]['uid'])
                );
-               $t = q("SELECT count(tid) as tcount FROM term WHERE oid=%d AND term='%s'",
+               $t = q("SELECT COUNT(`tid`) AS `tcount` FROM `term` WHERE `oid`=%d AND `term`='%s'",
                        intval($r[0]['id']),
                        dbesc($term)
                );
-               if(count($x) && !$x[0]['blocktags'] && $t[0]['tcount']==0){
-                       q("INSERT INTO term (oid, otype, type, term, url, uid) VALUE (%d, %d, %d, '%s', '%s', %d)",
-                          intval($r[0]['id']),
-                          $term_objtype,
-                          TERM_HASHTAG,
-                          dbesc($term),
-                          dbesc(System::baseUrl() . '/search?tag=' . $term),
-                          intval($owner_uid)
-                       );
+
+               if (DBM::is_result($x) && !$x[0]['blocktags'] && $t[0]['tcount'] == 0){
+                       q("INSERT INTO term (`oid`, `otype`, `type`, `term`, `url`, `uid`) VALUE (%d, %d, %d, '%s', '%s', %d)",
+                               intval($r[0]['id']),
+                               $term_objtype,
+                               TERM_HASHTAG,
+                               dbesc($term),
+                               dbesc(System::baseUrl() . '/search?tag=' . $term),
+                               intval($owner_uid)
+                       );
                }
        }
 
diff --git a/mods/readme.txt b/mods/readme.txt
deleted file mode 100644 (file)
index 8fc1c48..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-sample-Lighttpd.config
-sample-nginx.config
-
-               Sample configuration files to use Friendica with Lighttpd
-               or Nginx. Pleas check software documentation to know how modify
-               these examples to make them work on your server.
-
-
-sample-systemd.timer
-sample-systemd.service
-
-               Sample systemd unit files to start worker.php periodically.
-               
-               Please place them in the correct location for your system,
-               typically this is /etc/systemd/system/friendicaworker.timer 
-               and /etc/systemd/system/friendicaworker.service.
-               Please report problems and improvements to 
-               !helpers@forum.friendi.ca and @utzer@social.yl.ms or open an 
-               issue in Github (https://github.com/friendica/friendica/issues).
-               This is for usage of systemd instead of cron to start the worker.php
-               periodically, the solution is work-in-progress and can surely be improved.
-
-home.css
-home.html
-
-               Example files to customize the landing page of your Friendica node.
-               The home.html file contains the text of the page, the home.css file
-               the style information. The login box will be added according to the
-               other system settings.
-               Both files have to be placed in the base directory of your Friendica
-               installation to be used for the landing page.
diff --git a/mods/redme.txt b/mods/redme.txt
new file mode 100644 (file)
index 0000000..8fc1c48
--- /dev/null
@@ -0,0 +1,31 @@
+sample-Lighttpd.config
+sample-nginx.config
+
+               Sample configuration files to use Friendica with Lighttpd
+               or Nginx. Pleas check software documentation to know how modify
+               these examples to make them work on your server.
+
+
+sample-systemd.timer
+sample-systemd.service
+
+               Sample systemd unit files to start worker.php periodically.
+               
+               Please place them in the correct location for your system,
+               typically this is /etc/systemd/system/friendicaworker.timer 
+               and /etc/systemd/system/friendicaworker.service.
+               Please report problems and improvements to 
+               !helpers@forum.friendi.ca and @utzer@social.yl.ms or open an 
+               issue in Github (https://github.com/friendica/friendica/issues).
+               This is for usage of systemd instead of cron to start the worker.php
+               periodically, the solution is work-in-progress and can surely be improved.
+
+home.css
+home.html
+
+               Example files to customize the landing page of your Friendica node.
+               The home.html file contains the text of the page, the home.css file
+               the style information. The login box will be added according to the
+               other system settings.
+               Both files have to be placed in the base directory of your Friendica
+               installation to be used for the landing page.
index 6a275ad3fcd4f0534f15a3b9dfb006f92668a034..b2d978aee6ed895fb126ca90abdec6217aa768e6 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<phpunit bootstrap="boot.php">
+<phpunit bootstrap="tests/bootstrap.php">
     <testsuites>
         <testsuite>
             <directory>tests/</directory>
index f1d1e11a542a26835b0700e25221fd36493ef044..4202db325c411c38b7852321af769bfb0f09d33c 100644 (file)
@@ -40,6 +40,12 @@ class Cache extends \Friendica\BaseObject
 
                                self::$driver = new Cache\MemcachedCacheDriver($memcached_hosts);
                                break;
+                       case 'redis':
+                               $redis_host = Config::get('system', 'redis_host', '127.0.0.1');
+                               $redis_port = Config::get('system', 'redis_port', 6379);
+
+                               self::$driver = new Cache\RedisCacheDriver($redis_host, $redis_port);
+                               break;
                        default:
                                self::$driver = new Cache\DatabaseCacheDriver();
                }
diff --git a/src/Core/Cache/RedisCacheDriver.php b/src/Core/Cache/RedisCacheDriver.php
new file mode 100644 (file)
index 0000000..fa98842
--- /dev/null
@@ -0,0 +1,77 @@
+<?php
+
+namespace Friendica\Core\Cache;
+
+use Friendica\BaseObject;
+use Friendica\Core\Cache;
+
+/**
+ * Redis Cache Driver. This driver is based on Memcache driver
+ *
+ * @author Hypolite Petovan <mrpetovan@gmail.com>
+ * @author Roland Haeder <roland@mxchange.org>
+ */
+class RedisCacheDriver extends BaseObject implements ICacheDriver
+{
+       /**
+        * @var Redis
+        */
+       private $redis;
+
+       public function __construct($redis_host, $redis_port)
+       {
+               if (!class_exists('Redis', false)) {
+                       throw new \Exception('Redis class isn\'t available');
+               }
+
+               $this->redis = new \Redis();
+
+               if (!$this->redis->connect($redis_host, $redis_port)) {
+                       throw new \Exception('Expected Redis server at ' . $redis_host . ':' . $redis_port . ' isn\'t available');
+               }
+       }
+
+       public function get($key)
+       {
+               $return = null;
+
+               // We fetch with the hostname as key to avoid problems with other applications
+               $cached = $this->redis->get(self::getApp()->get_hostname() . ':' . $key);
+
+               // @see http://php.net/manual/en/redis.get.php#84275
+               if (is_bool($cached) || is_double($cached) || is_long($cached)) {
+                       return $return;
+               }
+
+               $value = @unserialize($cached);
+
+               // Only return a value if the serialized value is valid.
+               // We also check if the db entry is a serialized
+               // boolean 'false' value (which we want to return).
+               if ($cached === serialize(false) || $value !== false) {
+                       $return = $value;
+               }
+
+               return $return;
+       }
+
+       public function set($key, $value, $duration = Cache::MONTH)
+       {
+               // We store with the hostname as key to avoid problems with other applications
+               return $this->redis->set(
+                       self::getApp()->get_hostname() . ":" . $key,
+                       serialize($value),
+                       time() + $duration
+               );
+       }
+
+       public function delete($key)
+       {
+               return $this->redis->delete($key);
+       }
+
+       public function clear()
+       {
+               return true;
+       }
+}
index bfa52f5a36ebd7e480d97d2c638ccf8a77b2958e..274122deda4513dd63acaeded4414989b0d7fd21 100644 (file)
@@ -29,9 +29,7 @@ class PConfig extends BaseObject
 
        public static function init($uid)
        {
-               $a = self::getApp();
-
-               if (isset($a->config['system']['config_adapter']) && $a->config['system']['config_adapter'] == 'preload') {
+               if (Config::get('system', 'config_adapter') == 'preload') {
                        self::$adapter = new Config\PreloadPConfigAdapter($uid);
                } else {
                        self::$adapter = new Config\JITPConfigAdapter($uid);
index 2936480de49c8cb8373123bf7d1f44885e8fbd12..81cdf1bbd28a8985a5db29800dd18790343529a2 100644 (file)
@@ -688,7 +688,7 @@ class Worker
                        logger("Load: ".$load."/".$maxsysload." - processes: ".$active."/".$entries.$processlist." - maximum: ".$queues."/".$maxqueues, LOGGER_DEBUG);
 
                        // Are there fewer workers running as possible? Then fork a new one.
-                       if (!Config::get("system", "worker_dont_fork") && ($queues > ($active + 1)) && ($entries > 1)) {
+                       if (!Config::get("system", "worker_dont_fork", false) && ($queues > ($active + 1)) && ($entries > 1)) {
                                logger("Active workers: ".$active."/".$queues." Fork a new worker.", LOGGER_DEBUG);
                                self::spawnWorker();
                        }
@@ -1040,7 +1040,7 @@ class Worker
                }
 
                $priority = PRIORITY_MEDIUM;
-               $dont_fork = Config::get("system", "worker_dont_fork");
+               $dont_fork = Config::get("system", "worker_dont_fork", false);
                $created = DateTimeFormat::utcNow();
 
                $run_parameter = array_shift($args);
index 847449b75419c8ab3fe6aad072c8ebb1c32d8e30..c285528e00e1ef43ecc18ba9848c4f632e764b1f 100644 (file)
@@ -668,12 +668,12 @@ class DBStructure
                                "comment" => "registered addons",
                                "fields" => [
                                                "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
-                                               "name" => ["type" => "varchar(50)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "version" => ["type" => "varchar(50)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "installed" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "hidden" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "timestamp" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "plugin_admin" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
+                                               "name" => ["type" => "varchar(50)", "not null" => "1", "default" => "", "comment" => "addon base (file)name"],
+                                               "version" => ["type" => "varchar(50)", "not null" => "1", "default" => "", "comment" => "currently unused"],
+                                               "installed" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "currently always 1"],
+                                               "hidden" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "currently unused"],
+                                               "timestamp" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "comment" => "file timestamp to check for reloads"],
+                                               "plugin_admin" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "1 = has admin config, 0 = has no admin config"],
                                                ],
                                "indexes" => [
                                                "PRIMARY" => ["id"],
@@ -683,19 +683,19 @@ class DBStructure
                $database["attach"] = [
                                "comment" => "file attachments",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
-                                               "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "User id"],
-                                               "hash" => ["type" => "varchar(64)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "filename" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "filetype" => ["type" => "varchar(64)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "filesize" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "data" => ["type" => "longblob", "not null" => "1", "comment" => ""],
-                                               "created" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
-                                               "edited" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
-                                               "allow_cid" => ["type" => "mediumtext", "comment" => ""],
-                                               "allow_gid" => ["type" => "mediumtext", "comment" => ""],
-                                               "deny_cid" => ["type" => "mediumtext", "comment" => ""],
-                                               "deny_gid" => ["type" => "mediumtext", "comment" => ""],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "generated index"],
+                                               "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "Owner User id"],
+                                               "hash" => ["type" => "varchar(64)", "not null" => "1", "default" => "", "comment" => "hash"],
+                                               "filename" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "filename of original"],
+                                               "filetype" => ["type" => "varchar(64)", "not null" => "1", "default" => "", "comment" => "mimetype"],
+                                               "filesize" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "comment" => "size in bytes"],
+                                               "data" => ["type" => "longblob", "not null" => "1", "comment" => "file data"],
+                                               "created" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "creation time"],
+                                               "edited" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "last edit time"],
+                                               "allow_cid" => ["type" => "mediumtext", "comment" => "Access Control - list of allowed contact.id '<19><78>"],
+                                               "allow_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of allowed groups"],
+                                               "deny_cid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied contact.id"],
+                                               "deny_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied groups"],
                                                ],
                                "indexes" => [
                                                "PRIMARY" => ["id"],
@@ -730,7 +730,7 @@ class DBStructure
                $database["challenge"] = [
                                "comment" => "",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
                                                "challenge" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "dfrn-id" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "expire" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "comment" => ""],
@@ -771,26 +771,26 @@ class DBStructure
                $database["contact"] = [
                                "comment" => "contact table",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
-                                               "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "User id"],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
+                                               "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "Owner User id"],
                                                "created" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
-                                               "self" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
+                                               "self" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "1 if the contact is the user him/her self"],
                                                "remote_self" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "rel" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""],
+                                               "rel" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => "The kind of the relation between the user and the contact"],
                                                "duplex" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "network" => ["type" => "char(4)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "nick" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
+                                               "network" => ["type" => "char(4)", "not null" => "1", "default" => "", "comment" => "Network protocol of the contact"],
+                                               "name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Name that this contact is known by"],
+                                               "nick" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Nick- and user name of the contact"],
                                                "location" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "about" => ["type" => "text", "comment" => ""],
-                                               "keywords" => ["type" => "text", "comment" => ""],
+                                               "keywords" => ["type" => "text", "comment" => "public keywords (interests) of the contact"],
                                                "gender" => ["type" => "varchar(32)", "not null" => "1", "default" => "", "comment" => ""],
                                                "xmpp" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "attag" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "avatar" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "photo" => ["type" => "varchar(255)", "default" => "", "comment" => ""],
-                                               "thumb" => ["type" => "varchar(255)", "default" => "", "comment" => ""],
-                                               "micro" => ["type" => "varchar(255)", "default" => "", "comment" => ""],
+                                               "photo" => ["type" => "varchar(255)", "default" => "", "comment" => "Link to the profile photo of the contact"],
+                                               "thumb" => ["type" => "varchar(255)", "default" => "", "comment" => "Link to the profile photo (thumb size)"],
+                                               "micro" => ["type" => "varchar(255)", "default" => "", "comment" => "Link to the profile photo (micro size)"],
                                                "site-pubkey" => ["type" => "text", "comment" => ""],
                                                "issued-id" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "dfrn-id" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
@@ -798,8 +798,8 @@ class DBStructure
                                                "nurl" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "addr" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "alias" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "pubkey" => ["type" => "text", "comment" => ""],
-                                               "prvkey" => ["type" => "text", "comment" => ""],
+                                               "pubkey" => ["type" => "text", "comment" => "RSA public key 4096 bit"],
+                                               "prvkey" => ["type" => "text", "comment" => "RSA private key 4096 bit"],
                                                "batch" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "request" => ["type" => "varchar(255)", "comment" => ""],
                                                "notify" => ["type" => "varchar(255)", "comment" => ""],
@@ -811,20 +811,20 @@ class DBStructure
                                                "usehub" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
                                                "subhub" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
                                                "hub-verify" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "last-update" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
-                                               "success_update" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
-                                               "failure_update" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
+                                               "last-update" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "Date of the last try to update the contact info"],
+                                               "success_update" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "Date of the last successful contact update"],
+                                               "failure_update" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "Date of the last failed update"],
                                                "name-date" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
                                                "uri-date" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
                                                "avatar-date" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
                                                "term-date" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
-                                               "last-item" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
+                                               "last-item" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "date of the last post"],
                                                "priority" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""],
                                                "blocked" => ["type" => "boolean", "not null" => "1", "default" => "1", "comment" => ""],
-                                               "readonly" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
+                                               "readonly" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "posts of the contact are readonly"],
                                                "writable" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "forum" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "prv" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
+                                               "forum" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "contact is a forum"],
+                                               "prv" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "contact is a private group"],
                                                "contact-type" => ["type" => "tinyint", "not null" => "1", "default" => "0", "comment" => ""],
                                                "hidden" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
                                                "archive" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
@@ -859,14 +859,14 @@ class DBStructure
                $database["conv"] = [
                                "comment" => "private messages",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
-                                               "guid" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "recips" => ["type" => "text", "comment" => ""],
-                                               "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "User id"],
-                                               "creator" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "created" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
-                                               "updated" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
-                                               "subject" => ["type" => "text", "comment" => ""],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
+                                               "guid" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "A unique identifier for this conversation"],
+                                               "recips" => ["type" => "text", "comment" => "sender_handle;recipient_handle"],
+                                               "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "Owner User id"],
+                                               "creator" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "handle of creator"],
+                                               "created" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "creation timestamp"],
+                                               "updated" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "edited timestamp"],
+                                               "subject" => ["type" => "text", "comment" => "subject of initial message"],
                                                ],
                                "indexes" => [
                                                "PRIMARY" => ["id"],
@@ -876,13 +876,13 @@ class DBStructure
                $database["conversation"] = [
                                "comment" => "Raw data and structure information for messages",
                                "fields" => [
-                                               "item-uri" => ["type" => "varbinary(255)", "not null" => "1", "primary" => "1", "comment" => ""],
-                                               "reply-to-uri" => ["type" => "varbinary(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "conversation-uri" => ["type" => "varbinary(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "conversation-href" => ["type" => "varbinary(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "protocol" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "source" => ["type" => "mediumtext", "comment" => ""],
-                                               "received" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
+                                               "item-uri" => ["type" => "varbinary(255)", "not null" => "1", "primary" => "1", "comment" => "URI of the item"],
+                                               "reply-to-uri" => ["type" => "varbinary(255)", "not null" => "1", "default" => "", "comment" => "URI to which this item is a reply"],
+                                               "conversation-uri" => ["type" => "varbinary(255)", "not null" => "1", "default" => "", "comment" => "GNU Social conversation URI"],
+                                               "conversation-href" => ["type" => "varbinary(255)", "not null" => "1", "default" => "", "comment" => "GNU Social conversation link"],
+                                               "protocol" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => "The protocol of the item"],
+                                               "source" => ["type" => "mediumtext", "comment" => "Original source"],
+                                               "received" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "Receiving date"],
                                                ],
                                "indexes" => [
                                                "PRIMARY" => ["item-uri"],
@@ -893,26 +893,26 @@ class DBStructure
                $database["event"] = [
                                "comment" => "Events",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
                                                "guid" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "User id"],
-                                               "cid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["contact" => "id"], "comment" => ""],
+                                               "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "Owner User id"],
+                                               "cid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["contact" => "id"], "comment" => "contact_id (ID of the contact in contact table)"],
                                                "uri" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "created" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
-                                               "edited" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
-                                               "start" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
-                                               "finish" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
-                                               "summary" => ["type" => "text", "comment" => ""],
-                                               "desc" => ["type" => "text", "comment" => ""],
-                                               "location" => ["type" => "text", "comment" => ""],
-                                               "type" => ["type" => "varchar(20)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "nofinish" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "adjust" => ["type" => "boolean", "not null" => "1", "default" => "1", "comment" => ""],
-                                               "ignore" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "allow_cid" => ["type" => "mediumtext", "comment" => ""],
-                                               "allow_gid" => ["type" => "mediumtext", "comment" => ""],
-                                               "deny_cid" => ["type" => "mediumtext", "comment" => ""],
-                                               "deny_gid" => ["type" => "mediumtext", "comment" => ""],
+                                               "created" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "creation time"],
+                                               "edited" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "last edit time"],
+                                               "start" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "event start time"],
+                                               "finish" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "event end time"],
+                                               "summary" => ["type" => "text", "comment" => "short description or title of the event"],
+                                               "desc" => ["type" => "text", "comment" => "event description"],
+                                               "location" => ["type" => "text", "comment" => "event location"],
+                                               "type" => ["type" => "varchar(20)", "not null" => "1", "default" => "", "comment" => "event or birthday"],
+                                               "nofinish" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "if event does have no end this is 1"],
+                                               "adjust" => ["type" => "boolean", "not null" => "1", "default" => "1", "comment" => "adjust to timezone of the recipient (0 or 1)"],
+                                               "ignore" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "0 or 1"],
+                                               "allow_cid" => ["type" => "mediumtext", "comment" => "Access Control - list of allowed contact.id '<19><78>'"],
+                                               "allow_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of allowed groups"],
+                                               "deny_cid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied contact.id"],
+                                               "deny_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied groups"],
                                                ],
                                "indexes" => [
                                                "PRIMARY" => ["id"],
@@ -922,8 +922,8 @@ class DBStructure
                $database["fcontact"] = [
                                "comment" => "Diaspora compatible contacts - used in the Diaspora implementation",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
-                                               "guid" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
+                                               "guid" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "unique id"],
                                                "url" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "photo" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
@@ -966,9 +966,9 @@ class DBStructure
                $database["gcign"] = [
                                "comment" => "contacts ignored by friend suggestions",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
-                                               "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "User id"],
-                                               "gcid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["gcontact" => "id"], "comment" => ""],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
+                                               "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "Local User id"],
+                                               "gcid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["gcontact" => "id"], "comment" => "gcontact.id of ignored contact"],
                                                ],
                                "indexes" => [
                                                "PRIMARY" => ["id"],
@@ -979,12 +979,12 @@ class DBStructure
                $database["gcontact"] = [
                                "comment" => "global contacts",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
-                                               "name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "nick" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "url" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
+                                               "name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Name that this contact is known by"],
+                                               "nick" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Nick- and user name of the contact"],
+                                               "url" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Link to the contacts profile page"],
                                                "nurl" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "photo" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
+                                               "photo" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Link to the profile photo"],
                                                "connect" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "created" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
                                                "updated" => ["type" => "datetime", "default" => NULL_DATE, "comment" => ""],
@@ -992,19 +992,19 @@ class DBStructure
                                                "last_failure" => ["type" => "datetime", "default" => NULL_DATE, "comment" => ""],
                                                "location" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "about" => ["type" => "text", "comment" => ""],
-                                               "keywords" => ["type" => "text", "comment" => ""],
+                                               "keywords" => ["type" => "text", "comment" => "puplic keywords (interests)"],
                                                "gender" => ["type" => "varchar(32)", "not null" => "1", "default" => "", "comment" => ""],
                                                "birthday" => ["type" => "varchar(32)", "not null" => "1", "default" => "0001-01-01", "comment" => ""],
-                                               "community" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
+                                               "community" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "1 if contact is forum account"],
                                                "contact-type" => ["type" => "tinyint", "not null" => "1", "default" => "-1", "comment" => ""],
-                                               "hide" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "nsfw" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "network" => ["type" => "char(4)", "not null" => "1", "default" => "", "comment" => ""],
+                                               "hide" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "1 = should be hidden from search"],
+                                               "nsfw" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "1 = contact posts nsfw content"],
+                                               "network" => ["type" => "char(4)", "not null" => "1", "default" => "", "comment" => "social network protocol"],
                                                "addr" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "notify" => ["type" => "varchar(255)", "comment" => ""],
                                                "alias" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "generation" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "server_url" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
+                                               "server_url" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "baseurl of the contacts server"],
                                                ],
                                "indexes" => [
                                                "PRIMARY" => ["id"],
@@ -1019,7 +1019,7 @@ class DBStructure
                $database["glink"] = [
                                "comment" => "'friends of friends' linkages derived from poco",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
                                                "cid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["contact" => "id"], "comment" => ""],
                                                "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "User id"],
                                                "gcid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["gcontact" => "id"], "comment" => ""],
@@ -1035,11 +1035,11 @@ class DBStructure
                $database["group"] = [
                                "comment" => "privacy groups, group info",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
-                                               "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "User id"],
-                                               "visible" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "deleted" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
+                                               "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "Owner User id"],
+                                               "visible" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "1 indicates the member list is not private"],
+                                               "deleted" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "1 indicates the group has been deleted"],
+                                               "name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "human readable name of group"],
                                                ],
                                "indexes" => [
                                                "PRIMARY" => ["id"],
@@ -1049,9 +1049,9 @@ class DBStructure
                $database["group_member"] = [
                                "comment" => "privacy groups, member info",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
-                                               "gid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["group" => "id"], "comment" => ""],
-                                               "contact-id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["contact" => "id"], "comment" => ""],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
+                                               "gid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["group" => "id"], "comment" => "groups.id of the associated group"],
+                                               "contact-id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["contact" => "id"], "comment" => "contact.id  of the member assigned to the associated group"],
                                                ],
                                "indexes" => [
                                                "PRIMARY" => ["id"],
@@ -1062,14 +1062,14 @@ class DBStructure
                $database["gserver"] = [
                                "comment" => "Global servers",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
                                                "url" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "nurl" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "version" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "site_name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "info" => ["type" => "text", "comment" => ""],
                                                "register_policy" => ["type" => "tinyint", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "registered-users" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "comment" => ""],
+                                               "registered-users" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "comment" => "Number of registered users"],
                                                "poco" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "noscrape" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "network" => ["type" => "char(4)", "not null" => "1", "default" => "", "comment" => ""],
@@ -1100,11 +1100,11 @@ class DBStructure
                $database["hook"] = [
                                "comment" => "addon hook registry",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
-                                               "hook" => ["type" => "varbinary(100)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "file" => ["type" => "varbinary(200)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "function" => ["type" => "varbinary(200)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "priority" => ["type" => "smallint unsigned", "not null" => "1", "default" => "0", "comment" => ""],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
+                                               "hook" => ["type" => "varbinary(100)", "not null" => "1", "default" => "", "comment" => "name of hook"],
+                                               "file" => ["type" => "varbinary(200)", "not null" => "1", "default" => "", "comment" => "relative filename of hook handler"],
+                                               "function" => ["type" => "varbinary(200)", "not null" => "1", "default" => "", "comment" => "function name of hook handler"],
+                                               "priority" => ["type" => "smallint unsigned", "not null" => "1", "default" => "0", "comment" => "not yet implemented - can be used to sort conflicts in hook handling by calling handlers in priority order"],
                                                ],
                                "indexes" => [
                                                "PRIMARY" => ["id"],
@@ -1114,7 +1114,7 @@ class DBStructure
                $database["intro"] = [
                                "comment" => "",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
                                                "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "User id"],
                                                "fid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["fcontact" => "id"], "comment" => ""],
                                                "contact-id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["contact" => "id"], "comment" => ""],
@@ -1134,68 +1134,68 @@ class DBStructure
                                "comment" => "All posts",
                                "fields" => [
                                                "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "relation" => ["thread" => "iid"]],
-                                               "guid" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
+                                               "guid" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "A unique identifier for this item"],
                                                "uri" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "User id"],
-                                               "contact-id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["contact" => "id"], "comment" => ""],
+                                               "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "Owner id which owns this copy of the item"],
+                                               "contact-id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["contact" => "id"], "comment" => "contact.id"],
                                                "type" => ["type" => "varchar(20)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "wall" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
+                                               "wall" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "This item was posted to the wall of uid"],
                                                "gravity" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "parent" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["item" => "id"], "comment" => ""],
-                                               "parent-uri" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
+                                               "parent" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["item" => "id"], "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" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "uri of the parent to this item"],
                                                "extid" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "thr-parent" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "created" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
-                                               "edited" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
-                                               "commented" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
-                                               "received" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
-                                               "changed" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
-                                               "owner-id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["contact" => "id"], "comment" => ""],
-                                               "owner-name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "owner-link" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "owner-avatar" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "author-id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["contact" => "id"], "comment" => ""],
-                                               "author-name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "author-link" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "author-avatar" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "title" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
+                                               "thr-parent" => ["type" => "varchar(255)", "not null" => "1", "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" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "Creation timestamp."],
+                                               "edited" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "Date of  last edit (default is created)"],
+                                               "commented" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "Date of last comment/reply to this item"],
+                                               "received" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "datetime"],
+                                               "changed" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "Date that something in the conversation changed, indicating clients should fetch the conversation again"],
+                                               "owner-id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["contact" => "id"], "comment" => "Link to the contact table with uid=0 of the owner of this item"],
+                                               "owner-name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Name of the owner of this item"],
+                                               "owner-link" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Link to the profile page of the owner of this item"],
+                                               "owner-avatar" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Link to the avatar picture of the owner of this item"],
+                                               "author-id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["contact" => "id"], "comment" => "Link to the contact table with uid=0 of the author of this item"],
+                                               "author-name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Name of the author of this item"],
+                                               "author-link" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Link to the profile page of the author of this item"],
+                                               "author-avatar" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Link to the avatar picture of the author of this item"],
+                                               "title" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "item title"],
                                                "content-warning" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "body" => ["type" => "mediumtext", "comment" => ""],
-                                               "app" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "verb" => ["type" => "varchar(100)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "object-type" => ["type" => "varchar(100)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "object" => ["type" => "text", "comment" => ""],
-                                               "target-type" => ["type" => "varchar(100)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "target" => ["type" => "text", "comment" => ""],
-                                               "postopts" => ["type" => "text", "comment" => ""],
-                                               "plink" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "resource-id" => ["type" => "varchar(32)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "event-id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["event" => "id"], "comment" => ""],
+                                               "body" => ["type" => "mediumtext", "comment" => "item body content"],
+                                               "app" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "application which generated this item"],
+                                               "verb" => ["type" => "varchar(100)", "not null" => "1", "default" => "", "comment" => "ActivityStreams verb"],
+                                               "object-type" => ["type" => "varchar(100)", "not null" => "1", "default" => "", "comment" => "ActivityStreams object type"],
+                                               "object" => ["type" => "text", "comment" => "JSON encoded object structure unless it is an implied object (normal post)"],
+                                               "target-type" => ["type" => "varchar(100)", "not null" => "1", "default" => "", "comment" => "ActivityStreams target type if applicable (URI)"],
+                                               "target" => ["type" => "text", "comment" => "JSON encoded target structure if used"],
+                                               "postopts" => ["type" => "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" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "permalink or URL toa displayable copy  of the message at its source"],
+                                               "resource-id" => ["type" => "varchar(32)", "not null" => "1", "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" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["event" => "id"], "comment" => "Used to link to the event.id"],
                                                "tag" => ["type" => "mediumtext", "comment" => ""],
-                                               "attach" => ["type" => "mediumtext", "comment" => ""],
+                                               "attach" => ["type" => "mediumtext", "comment" => "JSON structure representing attachments to this item"],
                                                "inform" => ["type" => "mediumtext", "comment" => ""],
                                                "file" => ["type" => "mediumtext", "comment" => ""],
-                                               "location" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "coord" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "allow_cid" => ["type" => "mediumtext", "comment" => ""],
-                                               "allow_gid" => ["type" => "mediumtext", "comment" => ""],
-                                               "deny_cid" => ["type" => "mediumtext", "comment" => ""],
-                                               "deny_gid" => ["type" => "mediumtext", "comment" => ""],
-                                               "private" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
+                                               "location" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "text location where this item originated"],
+                                               "coord" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "longitude/latitude pair representing location where this item originated"],
+                                               "allow_cid" => ["type" => "mediumtext", "comment" => "Access Control - list of allowed contact.id '<19><78>'"],
+                                               "allow_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of allowed groups"],
+                                               "deny_cid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied contact.id"],
+                                               "deny_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied groups"],
+                                               "private" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "distribution is restricted"],
                                                "pubmail" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
                                                "moderated" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
                                                "visible" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
                                                "spam" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "starred" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "bookmark" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "unseen" => ["type" => "boolean", "not null" => "1", "default" => "1", "comment" => ""],
-                                               "deleted" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "origin" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
+                                               "starred" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "item has been favourited"],
+                                               "bookmark" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "item has been bookmarked"],
+                                               "unseen" => ["type" => "boolean", "not null" => "1", "default" => "1", "comment" => "item has not been seen"],
+                                               "deleted" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "item has been deleted"],
+                                               "origin" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "item originated at this site"],
                                                "forum_mode" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "mention" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "network" => ["type" => "char(4)", "not null" => "1", "default" => "", "comment" => ""],
+                                               "mention" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "The owner of this item was mentioned in it"],
+                                               "network" => ["type" => "char(4)", "not null" => "1", "default" => "", "comment" => "Network from where the item comes from"],
                                                "rendered-hash" => ["type" => "varchar(32)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "rendered-html" => ["type" => "mediumtext", "comment" => ""],
+                                               "rendered-html" => ["type" => "mediumtext", "comment" => "item.body converted to html"],
                                                "global" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
                                                ],
                                "indexes" => [
@@ -1232,10 +1232,10 @@ class DBStructure
                $database["locks"] = [
                                "comment" => "",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
                                                "name" => ["type" => "varchar(128)", "not null" => "1", "default" => "", "comment" => ""],
                                                "locked" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "pid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "comment" => ""],
+                                               "pid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "comment" => "Process ID"],
                                                ],
                                "indexes" => [
                                                "PRIMARY" => ["id"],
@@ -1244,23 +1244,23 @@ class DBStructure
                $database["mail"] = [
                                "comment" => "private messages",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
-                                               "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "User id"],
-                                               "guid" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "from-name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "from-photo" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "from-url" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "contact-id" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "relation" => ["contact" => "id"], "comment" => ""],
-                                               "convid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["conv" => "id"], "comment" => ""],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
+                                               "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "Owner User id"],
+                                               "guid" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "A unique identifier for this private message"],
+                                               "from-name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "name of the sender"],
+                                               "from-photo" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "contact photo link of the sender"],
+                                               "from-url" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "profile linke of the sender"],
+                                               "contact-id" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "relation" => ["contact" => "id"], "comment" => "contact.id"],
+                                               "convid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["conv" => "id"], "comment" => "conv.id"],
                                                "title" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "body" => ["type" => "mediumtext", "comment" => ""],
-                                               "seen" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
+                                               "seen" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "if message visited it is 1"],
                                                "reply" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
                                                "replied" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "unknown" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
+                                               "unknown" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "if sender not in the contact table this is 1"],
                                                "uri" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "parent-uri" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "created" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
+                                               "created" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "creation time of the private message"],
                                                ],
                                "indexes" => [
                                                "PRIMARY" => ["id"],
@@ -1274,7 +1274,7 @@ class DBStructure
                $database["mailacct"] = [
                                "comment" => "Mail account data for fetching mails",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
                                                "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "User id"],
                                                "server" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "port" => ["type" => "smallint unsigned", "not null" => "1", "default" => "0", "comment" => ""],
@@ -1295,7 +1295,7 @@ class DBStructure
                $database["manage"] = [
                                "comment" => "table of accounts that can manage each other",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
                                                "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "User id"],
                                                "mid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "User id"],
                                                ],
@@ -1307,7 +1307,7 @@ class DBStructure
                $database["notify"] = [
                                "comment" => "notifications",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
                                                "hash" => ["type" => "varchar(64)", "not null" => "1", "default" => "", "comment" => ""],
                                                "type" => ["type" => "smallint unsigned", "not null" => "1", "default" => "0", "comment" => ""],
                                                "name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
@@ -1315,15 +1315,15 @@ class DBStructure
                                                "photo" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "date" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
                                                "msg" => ["type" => "mediumtext", "comment" => ""],
-                                               "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "User id"],
+                                               "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "Owner User id"],
                                                "link" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "iid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["item" => "id"], "comment" => ""],
+                                               "iid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["item" => "id"], "comment" => "item.id"],
                                                "parent" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["item" => "id"], "comment" => ""],
                                                "seen" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
                                                "verb" => ["type" => "varchar(100)", "not null" => "1", "default" => "", "comment" => ""],
                                                "otype" => ["type" => "varchar(10)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "name_cache" => ["type" => "tinytext", "comment" => ""],
-                                               "msg_cache" => ["type" => "mediumtext", "comment" => ""]
+                                               "name_cache" => ["type" => "tinytext", "comment" => "Cached bbcode parsing of name"],
+                                               "msg_cache" => ["type" => "mediumtext", "comment" => "Cached bbcode parsing of msg"]
                                                ],
                                "indexes" => [
                                                "PRIMARY" => ["id"],
@@ -1336,7 +1336,7 @@ class DBStructure
                $database["notify-threads"] = [
                                "comment" => "",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
                                                "notify-id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["notify" => "id"], "comment" => ""],
                                                "master-parent-item" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["item" => "id"], "comment" => ""],
                                                "parent-item" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "comment" => ""],
@@ -1349,10 +1349,10 @@ class DBStructure
                $database["oembed"] = [
                                "comment" => "cache for OEmbed queries",
                                "fields" => [
-                                               "url" => ["type" => "varbinary(255)", "not null" => "1", "primary" => "1", "comment" => ""],
-                                               "maxwidth" => ["type" => "mediumint unsigned", "not null" => "1", "primary" => "1", "comment" => ""],
-                                               "content" => ["type" => "mediumtext", "comment" => ""],
-                                               "created" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
+                                               "url" => ["type" => "varbinary(255)", "not null" => "1", "primary" => "1", "comment" => "page url"],
+                                               "maxwidth" => ["type" => "mediumint unsigned", "not null" => "1", "primary" => "1", "comment" => "Maximum width passed to Oembed"],
+                                               "content" => ["type" => "mediumtext", "comment" => "OEmbed data of the page"],
+                                               "created" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "datetime of creation"],
                                                ],
                                "indexes" => [
                                                "PRIMARY" => ["url", "maxwidth"],
@@ -1362,11 +1362,11 @@ class DBStructure
                $database["parsed_url"] = [
                                "comment" => "cache for 'parse_url' queries",
                                "fields" => [
-                                               "url" => ["type" => "varbinary(255)", "not null" => "1", "primary" => "1", "comment" => ""],
-                                               "guessing" => ["type" => "boolean", "not null" => "1", "default" => "0", "primary" => "1", "comment" => ""],
-                                               "oembed" => ["type" => "boolean", "not null" => "1", "default" => "0", "primary" => "1", "comment" => ""],
-                                               "content" => ["type" => "mediumtext", "comment" => ""],
-                                               "created" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
+                                               "url" => ["type" => "varbinary(255)", "not null" => "1", "primary" => "1", "comment" => "page url"],
+                                               "guessing" => ["type" => "boolean", "not null" => "1", "default" => "0", "primary" => "1", "comment" => "is the 'guessing' mode active?"],
+                                               "oembed" => ["type" => "boolean", "not null" => "1", "default" => "0", "primary" => "1", "comment" => "is the data the result of oembed?"],
+                                               "content" => ["type" => "mediumtext", "comment" => "page data"],
+                                               "created" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "datetime of creation"],
                                                ],
                                "indexes" => [
                                                "PRIMARY" => ["url", "guessing", "oembed"],
@@ -1402,16 +1402,16 @@ class DBStructure
                $database["photo"] = [
                                "comment" => "photo storage",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
-                                               "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "User id"],
-                                               "contact-id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["contact" => "id"], "comment" => ""],
-                                               "guid" => ["type" => "char(16)", "not null" => "1", "default" => "", "comment" => ""],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
+                                               "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "Owner User id"],
+                                               "contact-id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["contact" => "id"], "comment" => "contact.id"],
+                                               "guid" => ["type" => "char(16)", "not null" => "1", "default" => "", "comment" => "A unique identifier for this photo"],
                                                "resource-id" => ["type" => "char(32)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "created" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
-                                               "edited" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
+                                               "created" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "creation date"],
+                                               "edited" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "last edited date"],
                                                "title" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "desc" => ["type" => "text", "comment" => ""],
-                                               "album" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
+                                               "album" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "The name of the album to which the photo belongs"],
                                                "filename" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "type" => ["type" => "varchar(30)", "not null" => "1", "default" => "image/jpeg"],
                                                "height" => ["type" => "smallint unsigned", "not null" => "1", "default" => "0", "comment" => ""],
@@ -1420,10 +1420,10 @@ class DBStructure
                                                "data" => ["type" => "mediumblob", "not null" => "1", "comment" => ""],
                                                "scale" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""],
                                                "profile" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "allow_cid" => ["type" => "mediumtext", "comment" => ""],
-                                               "allow_gid" => ["type" => "mediumtext", "comment" => ""],
-                                               "deny_cid" => ["type" => "mediumtext", "comment" => ""],
-                                               "deny_gid" => ["type" => "mediumtext", "comment" => ""],
+                                               "allow_cid" => ["type" => "mediumtext", "comment" => "Access Control - list of allowed contact.id '<19><78>'"],
+                                               "allow_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of allowed groups"],
+                                               "deny_cid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied contact.id"],
+                                               "deny_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied groups"],
                                                ],
                                "indexes" => [
                                                "PRIMARY" => ["id"],
@@ -1459,7 +1459,7 @@ class DBStructure
                $database["poll_result"] = [
                                "comment" => "data for polls - currently unused",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
                                                "poll_id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["poll" => "id"]],
                                                "choice" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""],
                                                ],
@@ -1483,14 +1483,14 @@ class DBStructure
                $database["profile"] = [
                                "comment" => "user profiles data",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
-                                               "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "User id"],
-                                               "profile-name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "is-default" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "hide-friends" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
+                                               "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "Owner User id"],
+                                               "profile-name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Name of the profile"],
+                                               "is-default" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Mark this profile as default profile"],
+                                               "hide-friends" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Hide friend list from viewers of this profile"],
                                                "name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "pdesc" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "dob" => ["type" => "varchar(32)", "not null" => "1", "default" => "0000-00-00", "comment" => ""],
+                                               "pdesc" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Title or description"],
+                                               "dob" => ["type" => "varchar(32)", "not null" => "1", "default" => "0000-00-00", "comment" => "Day of birth"],
                                                "address" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "locality" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "region" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
@@ -1523,8 +1523,8 @@ class DBStructure
                                                "xmpp" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "photo" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "thumb" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "publish" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "net-publish" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
+                                               "publish" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "publish default profile in local directory"],
+                                               "net-publish" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "publish profile in global directory"],
                                                ],
                                "indexes" => [
                                                "PRIMARY" => ["id"],
@@ -1534,9 +1534,9 @@ class DBStructure
                $database["profile_check"] = [
                                "comment" => "DFRN remote auth use",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
                                                "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "User id"],
-                                               "cid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["contact" => "id"], "comment" => ""],
+                                               "cid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["contact" => "id"], "comment" => "contact.id"],
                                                "dfrn_id" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "sec" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "expire" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "comment" => ""],
@@ -1548,7 +1548,7 @@ class DBStructure
                $database["push_subscriber"] = [
                                "comment" => "Used for OStatus: Contains feed subscribers",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
                                                "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "User id"],
                                                "callback_url" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "topic" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
@@ -1567,7 +1567,7 @@ class DBStructure
                $database["queue"] = [
                                "comment" => "Queue for messages that couldn't be delivered",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
                                                "cid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["contact" => "id"], "comment" => "Message receiver"],
                                                "network" => ["type" => "char(4)", "not null" => "1", "default" => "", "comment" => "Receiver's network"],
                                                "guid" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Unique GUID of the message"],
@@ -1587,7 +1587,7 @@ class DBStructure
                $database["register"] = [
                                "comment" => "registrations requiring admin approval",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
                                                "hash" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "created" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
                                                "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "User id"],
@@ -1602,7 +1602,7 @@ class DBStructure
                $database["search"] = [
                                "comment" => "",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
                                                "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "User id"],
                                                "term" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                ],
@@ -1614,7 +1614,7 @@ class DBStructure
                $database["session"] = [
                                "comment" => "web session storage",
                                "fields" => [
-                                               "id" => ["type" => "bigint unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
+                                               "id" => ["type" => "bigint unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
                                                "sid" => ["type" => "varbinary(255)", "not null" => "1", "default" => "", "comment" => ""],
                                                "data" => ["type" => "text", "comment" => ""],
                                                "expire" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "comment" => ""],
@@ -1628,8 +1628,8 @@ class DBStructure
                $database["sign"] = [
                                "comment" => "Diaspora signatures",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
-                                               "iid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["item" => "id"], "comment" => ""],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
+                                               "iid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["item" => "id"], "comment" => "item.id"],
                                                "signed_text" => ["type" => "mediumtext", "comment" => ""],
                                                "signature" => ["type" => "text", "comment" => ""],
                                                "signer" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
@@ -1666,11 +1666,11 @@ class DBStructure
                $database["thread"] = [
                                "comment" => "Thread related data",
                                "fields" => [
-                                               "iid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "primary" => "1", "relation" => ["item" => "id"], "comment" => ""],
+                                               "iid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "primary" => "1", "relation" => ["item" => "id"], "comment" => "sequential ID"],
                                                "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "User id"],
                                                "contact-id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["contact" => "id"], "comment" => ""],
-                                               "owner-id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["contact" => "id"], "comment" => ""],
-                                               "author-id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["contact" => "id"], "comment" => ""],
+                                               "owner-id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["contact" => "id"], "comment" => "Item owner"],
+                                               "author-id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["contact" => "id"], "comment" => "Item author"],
                                                "created" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
                                                "edited" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
                                                "commented" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
@@ -1724,50 +1724,50 @@ class DBStructure
                $database["user"] = [
                                "comment" => "The local users",
                                "fields" => [
-                                               "uid" => ["type" => "mediumint unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
+                                               "uid" => ["type" => "mediumint unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
                                                "parent-uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "The parent user that has full control about this user"],
-                                               "guid" => ["type" => "varchar(64)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "username" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "password" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
+                                               "guid" => ["type" => "varchar(64)", "not null" => "1", "default" => "", "comment" => "A unique identifier for this user"],
+                                               "username" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Name that this user is known by"],
+                                               "password" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "encrypted password"],
                                                "legacy_password" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Is the password hash double-hashed?"],
-                                               "nickname" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "email" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
+                                               "nickname" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "nick- and user name"],
+                                               "email" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "the users email address"],
                                                "openid" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "timezone" => ["type" => "varchar(128)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "language" => ["type" => "varchar(32)", "not null" => "1", "default" => "en", "comment" => ""],
-                                               "register_date" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
-                                               "login_date" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
-                                               "default-location" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "allow_location" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "theme" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
-                                               "pubkey" => ["type" => "text", "comment" => ""],
-                                               "prvkey" => ["type" => "text", "comment" => ""],
+                                               "timezone" => ["type" => "varchar(128)", "not null" => "1", "default" => "", "comment" => "PHP-legal timezone"],
+                                               "language" => ["type" => "varchar(32)", "not null" => "1", "default" => "en", "comment" => "default language"],
+                                               "register_date" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "timestamp of registration"],
+                                               "login_date" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "timestamp of last login"],
+                                               "default-location" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Default for item.location"],
+                                               "allow_location" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "1 allows to display the location"],
+                                               "theme" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "user theme preference"],
+                                               "pubkey" => ["type" => "text", "comment" => "RSA public key 4096 bit"],
+                                               "prvkey" => ["type" => "text", "comment" => "RSA private key 4096 bit"],
                                                "spubkey" => ["type" => "text", "comment" => ""],
                                                "sprvkey" => ["type" => "text", "comment" => ""],
-                                               "verified" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "blocked" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "blockwall" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "hidewall" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "blocktags" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "unkmail" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
+                                               "verified" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "user is verified through email"],
+                                               "blocked" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "1 for user is blocked"],
+                                               "blockwall" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Prohibit contacts to post to the profile page of the user"],
+                                               "hidewall" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Hide profile details from unkown viewers"],
+                                               "blocktags" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Prohibit contacts to tag the post of this user"],
+                                               "unkmail" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Permit unknown people to send private mails to this user"],
                                                "cntunkmail" => ["type" => "int unsigned", "not null" => "1", "default" => "10", "comment" => ""],
-                                               "notify-flags" => ["type" => "smallint unsigned", "not null" => "1", "default" => "65535", "comment" => ""],
-                                               "page-flags" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""],
+                                               "notify-flags" => ["type" => "smallint unsigned", "not null" => "1", "default" => "65535", "comment" => "email notification options"],
+                                               "page-flags" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => "page/profile type"],
                                                "account-type" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""],
                                                "prvnets" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
                                                "pwdreset" => ["type" => "varchar(255)", "comment" => "Password reset request token"],
                                                "pwdreset_time" => ["type" => "datetime", "comment" => "Timestamp of the last password reset request"],
                                                "maxreq" => ["type" => "int unsigned", "not null" => "1", "default" => "10", "comment" => ""],
                                                "expire" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "account_removed" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
+                                               "account_removed" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "if 1 the account is removed"],
                                                "account_expired" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "account_expires_on" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
-                                               "expire_notification_sent" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => ""],
+                                               "account_expires_on" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "timestamp when account expires and will be deleted"],
+                                               "expire_notification_sent" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "timestamp of last warning of account expiration"],
                                                "def_gid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "comment" => ""],
-                                               "allow_cid" => ["type" => "mediumtext", "comment" => ""],
-                                               "allow_gid" => ["type" => "mediumtext", "comment" => ""],
-                                               "deny_cid" => ["type" => "mediumtext", "comment" => ""],
-                                               "deny_gid" => ["type" => "mediumtext", "comment" => ""],
+                                               "allow_cid" => ["type" => "mediumtext", "comment" => "default permission for this user"],
+                                               "allow_gid" => ["type" => "mediumtext", "comment" => "default permission for this user"],
+                                               "deny_cid" => ["type" => "mediumtext", "comment" => "default permission for this user"],
+                                               "deny_gid" => ["type" => "mediumtext", "comment" => "default permission for this user"],
                                                "openidserver" => ["type" => "text", "comment" => ""],
                                                ],
                                "indexes" => [
@@ -1778,7 +1778,7 @@ class DBStructure
                $database["userd"] = [
                                "comment" => "Deleted usernames",
                                "fields" => [
-                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""],
+                                               "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
                                                "username" => ["type" => "varchar(255)", "not null" => "1", "comment" => ""],
                                                ],
                                "indexes" => [
@@ -1806,7 +1806,7 @@ class DBStructure
                                                "created" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "Creation date"],
                                                "pid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "comment" => "Process id of the worker"],
                                                "executed" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "Execution date"],
-                                               "done" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Marked when the task was done, will be deleted later"],
+                                               "done" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Marked 1 when the task was done - will be deleted later"],
                                                ],
                                "indexes" => [
                                                "PRIMARY" => ["id"],
index e65e61ee58367a4e3e6005217a36a5a29af1b860..db9e2b93034127cc85e1036571a8a3caea20899a 100644 (file)
@@ -803,10 +803,10 @@ class Event extends BaseObject
        /**
         * @brief Format an item array with event data to HTML.
         *
-        * @param arr $item Array with item and event data.
+        * @param array $item Array with item and event data.
         * @return string HTML output.
         */
-       public static function getItemHTML($item) {
+       public static function getItemHTML(array $item) {
                $same_date = false;
                $finish    = false;
 
index 0bac3210d716beea256833cae90b616a614134f1..e6ce67590e91a50d71c053254a2817d86fc1f4ff 100644 (file)
@@ -1122,8 +1122,9 @@ class Item extends BaseObject
                }
 
                // Is this a shadow entry?
-               if ($item['uid'] == 0)
+               if ($item['uid'] == 0) {
                        return;
+               }
 
                // Is there a shadow parent?
                if (!dba::exists('item', ['uri' => $item['parent-uri'], 'uid' => 0])) {
@@ -1163,10 +1164,8 @@ class Item extends BaseObject
 
                // If this was a comment to a Diaspora post we don't get our comment back.
                // This means that we have to distribute the comment by ourselves.
-               if ($origin) {
-                       if (dba::exists('item', ['id' => $parent, 'network' => NETWORK_DIASPORA])) {
-                               self::distribute($public_shadow);
-                       }
+               if ($origin && dba::exists('item', ['id' => $parent, 'network' => NETWORK_DIASPORA])) {
+                       self::distribute($public_shadow);
                }
        }
 
@@ -1177,14 +1176,14 @@ class Item extends BaseObject
         */
        private static function addLanguageInPostopts(&$item)
        {
+               $postopts = "";
+
                if (!empty($item['postopts'])) {
                        if (strstr($item['postopts'], 'lang=')) {
                                // do not override
                                return;
                        }
                        $postopts = $item['postopts'];
-               } else {
-                       $postopts = "";
                }
 
                $naked_body = Text\BBCode::toPlaintext($item['body'], false);
index ac147a7626c70ca5e9cf901eb333113658bd6fb6..6b9ff3de50e886fda0a672d2647f5fef4406adf9 100644 (file)
@@ -63,7 +63,7 @@ class DFRN
         * @param array $owner Owner record
         *
         * @return string DFRN entries
-        * @todo Add type-hints
+        * @todo Find proper type-hints
         */
        public static function entries($items, $owner)
        {
@@ -81,7 +81,7 @@ class DFRN
                        $root->appendChild($entry);
                }
 
-               return(trim($doc->saveXML()));
+               return trim($doc->saveXML());
        }
 
        /**
@@ -120,8 +120,6 @@ class DFRN
                        }
                }
 
-
-
                // default permissions - anonymous user
 
                $sql_extra = " AND `item`.`allow_cid` = '' AND `item`.`allow_gid` = '' AND `item`.`deny_cid`  = '' AND `item`.`deny_gid`  = '' ";
@@ -134,6 +132,7 @@ class DFRN
                );
 
                if (! DBM::is_result($r)) {
+                       logger(sprintf('No contact found for nickname=%d', $owner_nick), LOGGER_WARNING);
                        killme();
                }
 
@@ -169,6 +168,7 @@ class DFRN
                        );
 
                        if (! DBM::is_result($r)) {
+                               logger(sprintf('No contact found for uid=%d', $owner_id), LOGGER_WARNING);
                                killme();
                        }
 
@@ -177,8 +177,10 @@ class DFRN
                        $groups = Group::getIdsByContactId($contact['id']);
 
                        if (count($groups)) {
-                               for ($x = 0; $x < count($groups); $x ++)
+                               for ($x = 0; $x < count($groups); $x ++) {
                                        $groups[$x] = '<' . intval($groups[$x]) . '>' ;
+                               }
+
                                $gs = implode('|', $groups);
                        } else {
                                $gs = '<<>>' ; // Impossible to match
@@ -219,10 +221,8 @@ class DFRN
                        //$sql_extra .= file_tag_file_query('item',$category,'category');
                }
 
-               if ($public_feed) {
-                       if (! $converse) {
-                               $sql_extra .= " AND `contact`.`self` = 1 ";
-                       }
+               if ($public_feed && ! $converse) {
+                       $sql_extra .= " AND `contact`.`self` = 1 ";
                }
 
                $check_date = DateTimeFormat::utc($last_update);
@@ -397,7 +397,7 @@ class DFRN
         * @param array $owner Owner record
         *
         * @return string DFRN mail
-        * @todo Add type-hints
+        * @todo Find proper type-hints
         */
        public static function mail($item, $owner)
        {
@@ -423,7 +423,7 @@ class DFRN
 
                $root->appendChild($mail);
 
-               return(trim($doc->saveXML()));
+               return trim($doc->saveXML());
        }
 
        /**
@@ -433,7 +433,7 @@ class DFRN
         * @param array $owner Owner record
         *
         * @return string DFRN suggestions
-        * @todo Add type-hints
+        * @todo Find proper type-hints
         */
        public static function fsuggest($item, $owner)
        {
@@ -452,7 +452,7 @@ class DFRN
 
                $root->appendChild($suggest);
 
-               return(trim($doc->saveXML()));
+               return trim($doc->saveXML());
        }
 
        /**
@@ -462,7 +462,7 @@ class DFRN
         * @param int   $uid   User ID
         *
         * @return string DFRN relocations
-        * @todo Add type-hints
+        * @todo Find proper type-hints
         */
        public static function relocate($owner, $uid)
        {
@@ -487,7 +487,6 @@ class DFRN
                        $photos[$p['scale']] = System::baseUrl().'/photo/'.$p['resource-id'].'-'.$p['scale'].'.'.$ext[$p['type']];
                }
 
-               unset($rp, $ext);
 
                $doc = new DOMDocument('1.0', 'utf-8');
                $doc->formatOutput = true;
@@ -511,7 +510,7 @@ class DFRN
 
                $root->appendChild($relocate);
 
-               return(trim($doc->saveXML()));
+               return trim($doc->saveXML());
        }
 
        /**
@@ -524,7 +523,7 @@ class DFRN
         * @param bool   $public        Is it a header for public posts?
         *
         * @return object XML root object
-        * @todo Add type-hints
+        * @todo Find proper type-hints
         */
        private static function addHeader($doc, $owner, $authorelement, $alternatelink = "", $public = false)
        {
@@ -600,7 +599,7 @@ class DFRN
         * @param boolean $public        boolean
         *
         * @return object XML author object
-        * @todo Add type-hints
+        * @todo Find proper type-hints
         */
        private static function addAuthor($doc, $owner, $authorelement, $public)
        {
@@ -744,7 +743,7 @@ class DFRN
         * @param array  $item        Item elements
         *
         * @return object XML author object
-        * @todo Add type-hints
+        * @todo Find proper type-hints
         */
        private static function addEntryAuthor($doc, $element, $contact_url, $item)
        {
@@ -785,7 +784,7 @@ class DFRN
         * @param string $activity activity value
         *
         * @return object XML activity object
-        * @todo Add type-hints
+        * @todo Find proper type-hints
         */
        private static function createActivity($doc, $element, $activity)
        {
@@ -796,12 +795,15 @@ class DFRN
                        if (!$r) {
                                return false;
                        }
+
                        if ($r->type) {
                                XML::addElement($doc, $entry, "activity:object-type", $r->type);
                        }
+
                        if ($r->id) {
                                XML::addElement($doc, $entry, "id", $r->id);
                        }
+
                        if ($r->title) {
                                XML::addElement($doc, $entry, "title", $r->title);
                        }
@@ -848,7 +850,7 @@ class DFRN
         * @param array  $item Item element
         *
         * @return object XML attachment object
-        * @todo Add type-hints
+        * @todo Find proper type-hints
         */
        private static function getAttachment($doc, $root, $item)
        {
@@ -888,9 +890,9 @@ class DFRN
         * @param bool   $single  If set, the entry is created as an XML document with a single "entry" element
         *
         * @return object XML entry object
-        * @todo Add type-hints
+        * @todo Find proper type-hints
         */
-       private static function entry($doc, $type, $item, $owner, $comment = false, $cid = 0, $single = false)
+       private static function entry($doc, $type, array $item, array $owner, $comment = false, $cid = 0, $single = false)
        {
                $mentioned = [];
 
@@ -934,7 +936,7 @@ class DFRN
                        $htmlbody = $body;
 
                        if ($item['title'] != "") {
-                               $htmlbody = "[b]".$item['title']."[/b]\n\n".$htmlbody;
+                               $htmlbody = "[b]" . $item['title'] . "[/b]\n\n" . $htmlbody;
                        }
 
                        $htmlbody = BBCode::convert($htmlbody, false, 7);
@@ -1061,6 +1063,7 @@ class DFRN
 
                $tags = Item::getFeedTags($item);
 
+               /// @TODO Combine this with similar below if() block?
                if (count($tags)) {
                        foreach ($tags as $t) {
                                if (($type != 'html') || ($t[0] != "@")) {
@@ -1289,7 +1292,6 @@ class DFRN
                        $postvars['dissolve'] = '1';
                }
 
-
                if ((($contact['rel']) && ($contact['rel'] != CONTACT_IS_SHARING) && (! $contact['blocked'])) || ($owner['page-flags'] == PAGE_COMMUNITY)) {
                        $postvars['data'] = $atom;
                        $postvars['perm'] = 'rw';
@@ -1571,12 +1573,12 @@ class DFRN
                // Until now we aren't serving different sizes - but maybe later
                $avatarlist = [];
                /// @todo check if "avatar" or "photo" would be the best field in the specification
-               $avatars = $xpath->query($element."/atom:link[@rel='avatar']", $context);
+               $avatars = $xpath->query($element . "/atom:link[@rel='avatar']", $context);
                foreach ($avatars as $avatar) {
                        $href = "";
                        $width = 0;
                        foreach ($avatar->attributes as $attributes) {
-                               /// @TODO Rewrite these similar if () to one switch
+                               /// @TODO Rewrite these similar if() to one switch
                                if ($attributes->name == "href") {
                                        $href = $attributes->textContent;
                                }
@@ -1591,6 +1593,7 @@ class DFRN
                                $avatarlist[$width] = $href;
                        }
                }
+
                if (count($avatarlist) > 0) {
                        krsort($avatarlist);
                        $author["avatar"] = current($avatarlist);
@@ -2093,6 +2096,9 @@ class DFRN
                $condition = ["(`id` = ?) OR (`nurl` = ?)", $importer["id"], normalise_link($old["url"])];
                dba::update('contact', $fields, $condition);
 
+               // @TODO No dba:update here?
+               dba::update('contact', $fields, $condition);
+
                Contact::updateAvatar($relocate["avatar"], $importer["importer_uid"], $importer["id"], true);
 
                logger('Contacts are updated.');
@@ -2699,7 +2705,7 @@ class DFRN
                        if (self::updateContent($current, $item, $importer, $entrytype)) {
                                logger("Item ".$item["uri"]." was updated.", LOGGER_DEBUG);
                        } else {
-                               logger("Item ".$item["uri"]." already existed.", LOGGER_DEBUG);
+                               logger("Item " . $item["uri"] . " already existed.", LOGGER_DEBUG);
                        }
                        return;
                }
@@ -2775,6 +2781,7 @@ class DFRN
        {
                logger("Processing deletions");
                $uri = null;
+
                foreach ($deletion->attributes as $attributes) {
                        if ($attributes->name == "ref") {
                                $uri = $attributes->textContent;
index e91d81f58e212d7453ae9160dc80410a355e8db1..ce9e6642edec4edab337907fdc57bbbbd3bcda6c 100644 (file)
@@ -1947,7 +1947,7 @@ class OStatus
         * @param bool   $complete default true
         * @return void
         */
-       private static function entryFooter($doc, $entry, $item, $owner, $complete = true)
+       private static function entryFooter($doc, $entry, array $item, array $owner, $complete = true)
        {
                $mentioned = [];
 
@@ -1987,6 +1987,7 @@ class OStatus
 
                        if (isset($parent_item)) {
                                $r = dba::fetch_first("SELECT `conversation-uri`, `conversation-href` FROM `conversation` WHERE `item-uri` = ?", $parent_item);
+
                                if (DBM::is_result($r)) {
                                        if ($r['conversation-uri'] != '') {
                                                $conversation_uri = $r['conversation-uri'];
@@ -2047,9 +2048,11 @@ class OStatus
                }
 
                if ($owner['account-type'] == ACCOUNT_TYPE_COMMUNITY) {
-                       XML::addElement($doc, $entry, "link", "", ["rel" => "mentioned",
-                                                                       "ostatus:object-type" => "http://activitystrea.ms/schema/1.0/group",
-                                                                       "href" => $owner['url']]);
+                       XML::addElement($doc, $entry, "link", "", [
+                               "rel" => "mentioned",
+                               "ostatus:object-type" => "http://activitystrea.ms/schema/1.0/group",
+                               "href" => $owner['url']
+                       ]);
                }
 
                if (!$item["private"]) {
index 35052fe67967a021a54a5d9b6ed32910d0af7033..4eaf5bbb6c74c76e4eda74763a6478f42f16831f 100644 (file)
@@ -1321,20 +1321,8 @@ class PortableContact
                                        $version = $data->version;
                                        $site_name = $data->site_name;
                                        $info = $data->info;
-                                       $register_policy_str = $data->register_policy;
+                                       $register_policy = constant($data->register_policy);
                                        $platform = $data->platform;
-
-                                       switch ($register_policy_str) {
-                                               case "REGISTER_CLOSED":
-                                                       $register_policy = REGISTER_CLOSED;
-                                                       break;
-                                               case "REGISTER_APPROVE":
-                                                       $register_policy = REGISTER_APPROVE;
-                                                       break;
-                                               case "REGISTER_OPEN":
-                                                       $register_policy = REGISTER_OPEN;
-                                                       break;
-                                       }
                                }
                        }
                }
diff --git a/tests/ApiTest.php b/tests/ApiTest.php
new file mode 100644 (file)
index 0000000..f0e27b4
--- /dev/null
@@ -0,0 +1,3669 @@
+<?php
+/**
+ * ApiTest class.
+ */
+
+namespace Friendica\Test;
+
+use Friendica\App;
+use Friendica\Core\Config;
+use Friendica\Core\PConfig;
+use Friendica\Network\BadRequestException;
+use Friendica\Network\HTTPException;
+use Friendica\Render\FriendicaSmarty;
+
+/**
+ * Tests for the API functions.
+ *
+ * Functions that use header() need to be tested in a separate process.
+ * @see https://phpunit.de/manual/5.7/en/appendixes.annotations.html#appendixes.annotations.runTestsInSeparateProcesses
+ */
+class ApiTest extends DatabaseTest
+{
+
+       /**
+        * Create variables used by tests.
+        */
+       protected function setUp()
+       {
+               global $a;
+               parent::setUp();
+
+               // User data that the test database is populated with
+               $this->selfUser = [
+                       'id' => 42,
+                       'name' => 'Self contact',
+                       'nick' => 'selfcontact',
+                       'nurl' => 'http://localhost/profile/selfcontact'
+               ];
+               $this->otherUser = [
+                       'id' => 43,
+                       'name' => 'othercontact',
+                       'nick' => 'othercontact',
+                       'nurl' => 'http://localhost/profile/othercontact'
+               ];
+
+               // User ID that we know is not in the database
+               $this->wrongUserId = 666;
+
+               // Most API require login so we force the session
+               $_SESSION = [
+                       'allow_api' => true,
+                       'authenticated' => true,
+                       'uid' => $this->selfUser['id']
+               ];
+
+               // Reusable App object
+               $this->app = new App(__DIR__.'/../');
+               $a = $this->app;
+
+               // Default config
+               Config::set('config', 'hostname', 'localhost');
+               Config::set('system', 'throttle_limit_day', 100);
+               Config::set('system', 'throttle_limit_week', 100);
+               Config::set('system', 'throttle_limit_month', 100);
+               Config::set('system', 'theme', 'system_theme');
+       }
+
+       /**
+        * Assert that an user array contains expected keys.
+        * @param array $user User array
+        * @return void
+        */
+       private function assertSelfUser(array $user)
+       {
+               $this->assertEquals($this->selfUser['id'], $user['uid']);
+               $this->assertEquals($this->selfUser['id'], $user['cid']);
+               $this->assertEquals(1, $user['self']);
+               $this->assertEquals('Friendica', $user['location']);
+               $this->assertEquals($this->selfUser['name'], $user['name']);
+               $this->assertEquals($this->selfUser['nick'], $user['screen_name']);
+               $this->assertEquals('dfrn', $user['network']);
+               $this->assertTrue($user['verified']);
+       }
+
+       /**
+        * Assert that an user array contains expected keys.
+        * @param array $user User array
+        * @return void
+        */
+       private function assertOtherUser(array $user)
+       {
+               $this->assertEquals($this->otherUser['id'], $user['id']);
+               $this->assertEquals($this->otherUser['id'], $user['id_str']);
+               $this->assertEquals(0, $user['self']);
+               $this->assertEquals($this->otherUser['name'], $user['name']);
+               $this->assertEquals($this->otherUser['nick'], $user['screen_name']);
+               $this->assertFalse($user['verified']);
+       }
+
+       /**
+        * Assert that a status array contains expected keys.
+        * @param array $status Status array
+        * @return void
+        */
+       private function assertStatus(array $status)
+       {
+               $this->assertInternalType('string', $status['text']);
+               $this->assertInternalType('int', $status['id']);
+               // We could probably do more checks here.
+       }
+
+       /**
+        * Assert that a list array contains expected keys.
+        * @param array $list List array
+        * @return void
+        */
+       private function assertList(array $list)
+       {
+               $this->assertInternalType('string', $list['name']);
+               $this->assertInternalType('int', $list['id']);
+               $this->assertInternalType('string', $list['id_str']);
+               $this->assertContains($list['mode'], ['public', 'private']);
+               // We could probably do more checks here.
+       }
+
+       /**
+        * Assert that the string is XML and contain the root element.
+        * @param string $result       XML string
+        * @param string $root_element Root element name
+        * @return void
+        */
+       private function assertXml($result, $root_element)
+       {
+               $this->assertStringStartsWith('<?xml version="1.0"?>', $result);
+               $this->assertContains('<'.$root_element, $result);
+               // We could probably do more checks here.
+       }
+
+       /**
+        * Get the path to a temporary empty PNG image.
+        * @return string Path
+        */
+       private function getTempImage()
+       {
+               $tmpFile = tempnam(sys_get_temp_dir(), 'tmp_file');
+               file_put_contents(
+                       $tmpFile,
+                       base64_decode(
+                               // Empty 1x1 px PNG image
+                               'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg=='
+                       )
+               );
+
+               return $tmpFile;
+       }
+
+       /**
+        * Test the api_user() function.
+        * @return void
+        */
+       public function testApiUser()
+       {
+               $this->assertEquals($this->selfUser['id'], api_user());
+       }
+
+       /**
+        * Test the api_user() function with an unallowed user.
+        * @return void
+        */
+       public function testApiUserWithUnallowedUser()
+       {
+               $_SESSION = ['allow_api' => false];
+               $this->assertEquals(false, api_user());
+       }
+
+       /**
+        * Test the api_source() function.
+        * @return void
+        */
+       public function testApiSource()
+       {
+               $this->assertEquals('api', api_source());
+       }
+
+       /**
+        * Test the api_source() function with a Twidere user agent.
+        * @return void
+        */
+       public function testApiSourceWithTwidere()
+       {
+               $_SERVER['HTTP_USER_AGENT'] = 'Twidere';
+               $this->assertEquals('Twidere', api_source());
+       }
+
+       /**
+        * Test the api_source() function with a GET parameter.
+        * @return void
+        */
+       public function testApiSourceWithGet()
+       {
+               $_GET['source'] = 'source_name';
+               $this->assertEquals('source_name', api_source());
+       }
+
+       /**
+        * Test the api_date() function.
+        * @return void
+        */
+       public function testApiDate()
+       {
+               $this->assertEquals('Wed Oct 10 00:00:00 +0000 1990', api_date('1990-10-10'));
+       }
+
+       /**
+        * Test the api_register_func() function.
+        * @return void
+        */
+       public function testApiRegisterFunc()
+       {
+               global $API;
+               $this->assertNull(
+                       api_register_func(
+                               'api_path',
+                               function () {
+                               },
+                               true,
+                               'method'
+                       )
+               );
+               $this->assertTrue($API['api_path']['auth']);
+               $this->assertEquals('method', $API['api_path']['method']);
+               $this->assertTrue(is_callable($API['api_path']['func']));
+       }
+
+       /**
+        * Test the api_login() function without any login.
+        * @return void
+        * @runInSeparateProcess
+        * @expectedException Friendica\Network\HTTPException\UnauthorizedException
+        */
+       public function testApiLoginWithoutLogin()
+       {
+               api_login($this->app);
+       }
+
+       /**
+        * Test the api_login() function with a bad login.
+        * @return void
+        * @runInSeparateProcess
+        * @expectedException Friendica\Network\HTTPException\UnauthorizedException
+        */
+       public function testApiLoginWithBadLogin()
+       {
+               $_SERVER['PHP_AUTH_USER'] = 'user@server';
+               api_login($this->app);
+       }
+
+       /**
+        * Test the api_login() function with oAuth.
+        * @return void
+        */
+       public function testApiLoginWithOauth()
+       {
+               $this->markTestIncomplete('Can we test this easily?');
+       }
+
+       /**
+        * Test the api_login() function with authentication provided by an addon.
+        * @return void
+        */
+       public function testApiLoginWithAddonAuth()
+       {
+               $this->markTestIncomplete('Can we test this easily?');
+       }
+
+       /**
+        * Test the api_login() function with a correct login.
+        * @return void
+        * @runInSeparateProcess
+        */
+       public function testApiLoginWithCorrectLogin()
+       {
+               $_SERVER['PHP_AUTH_USER'] = 'Test user';
+               $_SERVER['PHP_AUTH_PW'] = 'password';
+               api_login($this->app);
+       }
+
+       /**
+        * Test the api_login() function with a remote user.
+        * @return void
+        * @runInSeparateProcess
+        * @expectedException Friendica\Network\HTTPException\UnauthorizedException
+        */
+       public function testApiLoginWithRemoteUser()
+       {
+               $_SERVER['REDIRECT_REMOTE_USER'] = '123456dXNlcjpwYXNzd29yZA==';
+               api_login($this->app);
+       }
+
+       /**
+        * Test the api_check_method() function.
+        * @return void
+        */
+       public function testApiCheckMethod()
+       {
+               $this->assertFalse(api_check_method('method'));
+       }
+
+       /**
+        * Test the api_check_method() function with a correct method.
+        * @return void
+        */
+       public function testApiCheckMethodWithCorrectMethod()
+       {
+               $_SERVER['REQUEST_METHOD'] = 'method';
+               $this->assertTrue(api_check_method('method'));
+       }
+
+       /**
+        * Test the api_check_method() function with a wildcard.
+        * @return void
+        */
+       public function testApiCheckMethodWithWildcard()
+       {
+               $this->assertTrue(api_check_method('*'));
+       }
+
+       /**
+        * Test the api_call() function.
+        * @return void
+        * @runInSeparateProcess
+        */
+       public function testApiCall()
+       {
+               global $API;
+               $API['api_path'] = [
+                       'method' => 'method',
+                       'func' => function () {
+                               return ['data' => ['some_data']];
+                       }
+               ];
+               $_SERVER['REQUEST_METHOD'] = 'method';
+               $_GET['callback'] = 'callback_name';
+
+               $this->app->query_string = 'api_path';
+               $this->assertEquals(
+                       'callback_name(["some_data"])',
+                       api_call($this->app)
+               );
+       }
+
+       /**
+        * Test the api_call() function with the profiled enabled.
+        * @return void
+        * @runInSeparateProcess
+        */
+       public function testApiCallWithProfiler()
+       {
+               global $API;
+               $API['api_path'] = [
+                       'method' => 'method',
+                       'func' => function () {
+                               return ['data' => ['some_data']];
+                       }
+               ];
+               $_SERVER['REQUEST_METHOD'] = 'method';
+               Config::set('system', 'profiler', true);
+               Config::set('rendertime', 'callstack', true);
+               $this->app->callstack = [
+                       'database' => ['some_function' => 200],
+                       'database_write' => ['some_function' => 200],
+                       'cache' => ['some_function' => 200],
+                       'cache_write' => ['some_function' => 200],
+                       'network' => ['some_function' => 200]
+               ];
+
+               $this->app->query_string = 'api_path';
+               $this->assertEquals(
+                       '["some_data"]',
+                       api_call($this->app)
+               );
+       }
+
+       /**
+        * Test the api_call() function without any result.
+        * @return void
+        * @runInSeparateProcess
+        */
+       public function testApiCallWithNoResult()
+       {
+               global $API;
+               $API['api_path'] = [
+                       'method' => 'method',
+                       'func' => function () {
+                               return false;
+                       }
+               ];
+               $_SERVER['REQUEST_METHOD'] = 'method';
+
+               $this->app->query_string = 'api_path';
+               $this->assertEquals(
+                       '{"status":{"error":"Internal Server Error","code":"500 Internal Server Error","request":"api_path"}}',
+                       api_call($this->app)
+               );
+       }
+
+       /**
+        * Test the api_call() function with an unimplemented API.
+        * @return void
+        * @runInSeparateProcess
+        */
+       public function testApiCallWithUninplementedApi()
+       {
+               $this->assertEquals(
+                       '{"status":{"error":"Not Implemented","code":"501 Not Implemented","request":""}}',
+                       api_call($this->app)
+               );
+       }
+
+       /**
+        * Test the api_call() function with a JSON result.
+        * @return void
+        * @runInSeparateProcess
+        */
+       public function testApiCallWithJson()
+       {
+               global $API;
+               $API['api_path'] = [
+                       'method' => 'method',
+                       'func' => function () {
+                               return ['data' => ['some_data']];
+                       }
+               ];
+               $_SERVER['REQUEST_METHOD'] = 'method';
+
+               $this->app->query_string = 'api_path.json';
+               $this->assertEquals(
+                       '["some_data"]',
+                       api_call($this->app)
+               );
+       }
+
+       /**
+        * Test the api_call() function with an XML result.
+        * @return void
+        * @runInSeparateProcess
+        */
+       public function testApiCallWithXml()
+       {
+               global $API;
+               $API['api_path'] = [
+                       'method' => 'method',
+                       'func' => function () {
+                               return 'some_data';
+                       }
+               ];
+               $_SERVER['REQUEST_METHOD'] = 'method';
+
+               $this->app->query_string = 'api_path.xml';
+               $this->assertEquals(
+                       'some_data',
+                       api_call($this->app)
+               );
+       }
+
+       /**
+        * Test the api_call() function with an RSS result.
+        * @return void
+        * @runInSeparateProcess
+        */
+       public function testApiCallWithRss()
+       {
+               global $API;
+               $API['api_path'] = [
+                       'method' => 'method',
+                       'func' => function () {
+                               return 'some_data';
+                       }
+               ];
+               $_SERVER['REQUEST_METHOD'] = 'method';
+
+               $this->app->query_string = 'api_path.rss';
+               $this->assertEquals(
+                       '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL.
+                               'some_data',
+                       api_call($this->app)
+               );
+       }
+
+       /**
+        * Test the api_call() function with an Atom result.
+        * @return void
+        * @runInSeparateProcess
+        */
+       public function testApiCallWithAtom()
+       {
+               global $API;
+               $API['api_path'] = [
+                       'method' => 'method',
+                       'func' => function () {
+                               return 'some_data';
+                       }
+               ];
+               $_SERVER['REQUEST_METHOD'] = 'method';
+
+               $this->app->query_string = 'api_path.atom';
+               $this->assertEquals(
+                       '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL.
+                               'some_data',
+                       api_call($this->app)
+               );
+       }
+
+       /**
+        * Test the api_call() function with an unallowed method.
+        * @return void
+        * @runInSeparateProcess
+        */
+       public function testApiCallWithWrongMethod()
+       {
+               global $API;
+               $API['api_path'] = ['method' => 'method'];
+
+               $this->app->query_string = 'api_path';
+               $this->assertEquals(
+                       '{"status":{"error":"Method Not Allowed","code":"405 Method Not Allowed","request":"api_path"}}',
+                       api_call($this->app)
+               );
+       }
+
+       /**
+        * Test the api_call() function with an unauthorized user.
+        * @return void
+        * @runInSeparateProcess
+        */
+       public function testApiCallWithWrongAuth()
+       {
+               global $API;
+               $API['api_path'] = [
+                       'method' => 'method',
+                       'auth' => true
+               ];
+               $_SERVER['REQUEST_METHOD'] = 'method';
+               $_SESSION['authenticated'] = false;
+
+               $this->app->query_string = 'api_path';
+               $this->assertEquals(
+                       '{"status":{"error":"This API requires login","code":"401 Unauthorized","request":"api_path"}}',
+                       api_call($this->app)
+               );
+       }
+
+       /**
+        * Test the api_error() function with a JSON result.
+        * @return void
+        * @runInSeparateProcess
+        */
+       public function testApiErrorWithJson()
+       {
+               $this->assertEquals(
+                       '{"status":{"error":"error_message","code":"200 Friendica\\\\Network\\\\HTTP","request":""}}',
+                       api_error('json', new HTTPException('error_message'))
+               );
+       }
+
+       /**
+        * Test the api_error() function with an XML result.
+        * @return void
+        * @runInSeparateProcess
+        */
+       public function testApiErrorWithXml()
+       {
+               $this->assertEquals(
+                       '<?xml version="1.0"?>'.PHP_EOL.
+                       '<status xmlns="http://api.twitter.com" xmlns:statusnet="http://status.net/schema/api/1/" '.
+                               'xmlns:friendica="http://friendi.ca/schema/api/1/" '.
+                               'xmlns:georss="http://www.georss.org/georss">'.PHP_EOL.
+                       '  <error>error_message</error>'.PHP_EOL.
+                       '  <code>200 Friendica\Network\HTTP</code>'.PHP_EOL.
+                       '  <request/>'.PHP_EOL.
+                       '</status>'.PHP_EOL,
+                       api_error('xml', new HTTPException('error_message'))
+               );
+       }
+
+       /**
+        * Test the api_error() function with an RSS result.
+        * @return void
+        * @runInSeparateProcess
+        */
+       public function testApiErrorWithRss()
+       {
+               $this->assertEquals(
+                       '<?xml version="1.0"?>'.PHP_EOL.
+                       '<status xmlns="http://api.twitter.com" xmlns:statusnet="http://status.net/schema/api/1/" '.
+                               'xmlns:friendica="http://friendi.ca/schema/api/1/" '.
+                               'xmlns:georss="http://www.georss.org/georss">'.PHP_EOL.
+                       '  <error>error_message</error>'.PHP_EOL.
+                       '  <code>200 Friendica\Network\HTTP</code>'.PHP_EOL.
+                       '  <request/>'.PHP_EOL.
+                       '</status>'.PHP_EOL,
+                       api_error('rss', new HTTPException('error_message'))
+               );
+       }
+
+       /**
+        * Test the api_error() function with an Atom result.
+        * @return void
+        * @runInSeparateProcess
+        */
+       public function testApiErrorWithAtom()
+       {
+               $this->assertEquals(
+                       '<?xml version="1.0"?>'.PHP_EOL.
+                       '<status xmlns="http://api.twitter.com" xmlns:statusnet="http://status.net/schema/api/1/" '.
+                               'xmlns:friendica="http://friendi.ca/schema/api/1/" '.
+                               'xmlns:georss="http://www.georss.org/georss">'.PHP_EOL.
+                       '  <error>error_message</error>'.PHP_EOL.
+                       '  <code>200 Friendica\Network\HTTP</code>'.PHP_EOL.
+                       '  <request/>'.PHP_EOL.
+                       '</status>'.PHP_EOL,
+                       api_error('atom', new HTTPException('error_message'))
+               );
+       }
+
+       /**
+        * Test the api_rss_extra() function.
+        * @return void
+        */
+       public function testApiRssExtra()
+       {
+               $user_info = ['url' => 'user_url'];
+               $result = api_rss_extra($this->app, [], $user_info);
+               $this->assertEquals($user_info, $result['$user']);
+               $this->assertEquals($user_info['url'], $result['$rss']['alternate']);
+               $this->assertArrayHasKey('self', $result['$rss']);
+               $this->assertArrayHasKey('base', $result['$rss']);
+               $this->assertArrayHasKey('updated', $result['$rss']);
+               $this->assertArrayHasKey('atom_updated', $result['$rss']);
+               $this->assertArrayHasKey('language', $result['$rss']);
+               $this->assertArrayHasKey('logo', $result['$rss']);
+       }
+
+       /**
+        * Test the api_rss_extra() function without any user info.
+        * @return void
+        * @runInSeparateProcess
+        */
+       public function testApiRssExtraWithoutUserInfo()
+       {
+               $result = api_rss_extra($this->app, [], null);
+               $this->assertInternalType('array', $result['$user']);
+               $this->assertArrayHasKey('alternate', $result['$rss']);
+               $this->assertArrayHasKey('self', $result['$rss']);
+               $this->assertArrayHasKey('base', $result['$rss']);
+               $this->assertArrayHasKey('updated', $result['$rss']);
+               $this->assertArrayHasKey('atom_updated', $result['$rss']);
+               $this->assertArrayHasKey('language', $result['$rss']);
+               $this->assertArrayHasKey('logo', $result['$rss']);
+       }
+
+       /**
+        * Test the api_unique_id_to_nurl() function.
+        * @return void
+        */
+       public function testApiUniqueIdToNurl()
+       {
+               $this->assertFalse(api_unique_id_to_nurl($this->wrongUserId));
+       }
+
+       /**
+        * Test the api_unique_id_to_nurl() function with a correct ID.
+        * @return void
+        */
+       public function testApiUniqueIdToNurlWithCorrectId()
+       {
+               $this->assertEquals($this->otherUser['nurl'], api_unique_id_to_nurl($this->otherUser['id']));
+       }
+
+       /**
+        * Test the api_get_user() function.
+        * @return void
+        * @runInSeparateProcess
+        */
+       public function testApiGetUser()
+       {
+               $user = api_get_user($this->app);
+               $this->assertSelfUser($user);
+               $this->assertEquals('708fa0', $user['profile_sidebar_fill_color']);
+               $this->assertEquals('6fdbe8', $user['profile_link_color']);
+               $this->assertEquals('ededed', $user['profile_background_color']);
+       }
+
+       /**
+        * Test the api_get_user() function with a Frio schema.
+        * @return void
+        * @runInSeparateProcess
+        */
+       public function testApiGetUserWithFrioSchema()
+       {
+               PConfig::set($this->selfUser['id'], 'frio', 'schema', 'red');
+               $user = api_get_user($this->app);
+               $this->assertSelfUser($user);
+               $this->assertEquals('708fa0', $user['profile_sidebar_fill_color']);
+               $this->assertEquals('6fdbe8', $user['profile_link_color']);
+               $this->assertEquals('ededed', $user['profile_background_color']);
+       }
+
+       /**
+        * Test the api_get_user() function with a custom Frio schema.
+        * @return void
+        * @runInSeparateProcess
+        */
+       public function testApiGetUserWithCustomFrioSchema()
+       {
+               PConfig::set($this->selfUser['id'], 'frio', 'schema', '---');
+               PConfig::set($this->selfUser['id'], 'frio', 'nav_bg', '#123456');
+               PConfig::set($this->selfUser['id'], 'frio', 'link_color', '#123456');
+               PConfig::set($this->selfUser['id'], 'frio', 'background_color', '#123456');
+               $user = api_get_user($this->app);
+               $this->assertSelfUser($user);
+               $this->assertEquals('123456', $user['profile_sidebar_fill_color']);
+               $this->assertEquals('123456', $user['profile_link_color']);
+               $this->assertEquals('123456', $user['profile_background_color']);
+       }
+
+       /**
+        * Test the api_get_user() function with an empty Frio schema.
+        * @return void
+        * @runInSeparateProcess
+        */
+       public function testApiGetUserWithEmptyFrioSchema()
+       {
+               PConfig::set($this->selfUser['id'], 'frio', 'schema', '---');
+               $user = api_get_user($this->app);
+               $this->assertSelfUser($user);
+               $this->assertEquals('708fa0', $user['profile_sidebar_fill_color']);
+               $this->assertEquals('6fdbe8', $user['profile_link_color']);
+               $this->assertEquals('ededed', $user['profile_background_color']);
+       }
+
+       /**
+        * Test the api_get_user() function with an user that is not allowed to use the API.
+        * @return void
+        * @runInSeparateProcess
+        */
+       public function testApiGetUserWithoutApiUser()
+       {
+               $_SERVER['PHP_AUTH_USER'] = 'Test user';
+               $_SERVER['PHP_AUTH_PW'] = 'password';
+               $_SESSION['allow_api'] = false;
+               $this->assertFalse(api_get_user($this->app));
+       }
+
+       /**
+        * Test the api_get_user() function with an user ID in a GET parameter.
+        * @return void
+        * @runInSeparateProcess
+        */
+       public function testApiGetUserWithGetId()
+       {
+               $_GET['user_id'] = $this->otherUser['id'];
+               $this->assertOtherUser(api_get_user($this->app));
+       }
+
+       /**
+        * Test the api_get_user() function with a wrong user ID in a GET parameter.
+        * @return void
+        * @runInSeparateProcess
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        */
+       public function testApiGetUserWithWrongGetId()
+       {
+               $_GET['user_id'] = $this->wrongUserId;
+               $this->assertOtherUser(api_get_user($this->app));
+       }
+
+       /**
+        * Test the api_get_user() function with an user name in a GET parameter.
+        * @return void
+        * @runInSeparateProcess
+        */
+       public function testApiGetUserWithGetName()
+       {
+               $_GET['screen_name'] = $this->selfUser['nick'];
+               $this->assertSelfUser(api_get_user($this->app));
+       }
+
+       /**
+        * Test the api_get_user() function with a profile URL in a GET parameter.
+        * @return void
+        * @runInSeparateProcess
+        */
+       public function testApiGetUserWithGetUrl()
+       {
+               $_GET['profileurl'] = $this->selfUser['nurl'];
+               $this->assertSelfUser(api_get_user($this->app));
+       }
+
+       /**
+        * Test the api_get_user() function with an user ID in the API path.
+        * @return void
+        * @runInSeparateProcess
+        */
+       public function testApiGetUserWithNumericCalledApi()
+       {
+               global $called_api;
+               $called_api = ['api_path'];
+               $this->app->argv[1] = $this->otherUser['id'].'.json';
+               $this->assertOtherUser(api_get_user($this->app));
+       }
+
+       /**
+        * Test the api_get_user() function with the $called_api global variable.
+        * @return void
+        * @runInSeparateProcess
+        */
+       public function testApiGetUserWithCalledApi()
+       {
+               global $called_api;
+               $called_api = ['api_path'];
+               $this->assertSelfUser(api_get_user($this->app));
+       }
+
+       /**
+        * Test the api_get_user() function with a valid user.
+        * @return void
+        * @runInSeparateProcess
+        */
+       public function testApiGetUserWithCorrectUser()
+       {
+               $this->assertOtherUser(api_get_user($this->app, $this->otherUser['id']));
+       }
+
+       /**
+        * Test the api_get_user() function with a wrong user ID.
+        * @return void
+        * @runInSeparateProcess
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        */
+       public function testApiGetUserWithWrongUser()
+       {
+               $this->assertOtherUser(api_get_user($this->app, $this->wrongUserId));
+       }
+
+       /**
+        * Test the api_get_user() function with a 0 user ID.
+        * @return void
+        * @runInSeparateProcess
+        */
+       public function testApiGetUserWithZeroUser()
+       {
+               $this->assertSelfUser(api_get_user($this->app, 0));
+       }
+
+
+       /**
+        * Test the api_item_get_user() function.
+        * @return void
+        * @runInSeparateProcess
+        */
+       public function testApiItemGetUser()
+       {
+               $users = api_item_get_user($this->app, []);
+               $this->assertSelfUser($users[0]);
+       }
+
+       /**
+        * Test the api_item_get_user() function with a different item parent.
+        * @return void
+        */
+       public function testApiItemGetUserWithDifferentParent()
+       {
+               $users = api_item_get_user($this->app, ['thr-parent' => 'item_parent', 'uri' => 'item_uri']);
+               $this->assertSelfUser($users[0]);
+               $this->assertEquals($users[0], $users[1]);
+       }
+
+       /**
+        * Test the api_walk_recursive() function.
+        * @return void
+        */
+       public function testApiWalkRecursive()
+       {
+               $array = ['item1'];
+               $this->assertEquals(
+                       $array,
+                       api_walk_recursive(
+                               $array,
+                               function () {
+                                       // Should we test this with a callback that actually does something?
+                                       return true;
+                               }
+                       )
+               );
+       }
+
+       /**
+        * Test the api_walk_recursive() function with an array.
+        * @return void
+        */
+       public function testApiWalkRecursiveWithArray()
+       {
+               $array = [['item1'], ['item2']];
+               $this->assertEquals(
+                       $array,
+                       api_walk_recursive(
+                               $array,
+                               function () {
+                                       // Should we test this with a callback that actually does something?
+                                       return true;
+                               }
+                       )
+               );
+       }
+
+       /**
+        * Test the api_reformat_xml() function.
+        * @return void
+        */
+       public function testApiReformatXml()
+       {
+               $item = true;
+               $key = '';
+               $this->assertTrue(api_reformat_xml($item, $key));
+               $this->assertEquals('true', $item);
+       }
+
+       /**
+        * Test the api_reformat_xml() function with a statusnet_api key.
+        * @return void
+        */
+       public function testApiReformatXmlWithStatusnetKey()
+       {
+               $item = '';
+               $key = 'statusnet_api';
+               $this->assertTrue(api_reformat_xml($item, $key));
+               $this->assertEquals('statusnet:api', $key);
+       }
+
+       /**
+        * Test the api_reformat_xml() function with a friendica_api key.
+        * @return void
+        */
+       public function testApiReformatXmlWithFriendicaKey()
+       {
+               $item = '';
+               $key = 'friendica_api';
+               $this->assertTrue(api_reformat_xml($item, $key));
+               $this->assertEquals('friendica:api', $key);
+       }
+
+       /**
+        * Test the api_create_xml() function.
+        * @return void
+        */
+       public function testApiCreateXml()
+       {
+               $this->assertEquals(
+                       '<?xml version="1.0"?>'.PHP_EOL.
+                       '<root_element xmlns="http://api.twitter.com" xmlns:statusnet="http://status.net/schema/api/1/" '.
+                               'xmlns:friendica="http://friendi.ca/schema/api/1/" '.
+                               'xmlns:georss="http://www.georss.org/georss">'.PHP_EOL.
+                               '  <data>some_data</data>'.PHP_EOL.
+                       '</root_element>'.PHP_EOL,
+                       api_create_xml(['data' => ['some_data']], 'root_element')
+               );
+       }
+
+       /**
+        * Test the api_create_xml() function without any XML namespace.
+        * @return void
+        */
+       public function testApiCreateXmlWithoutNamespaces()
+       {
+               $this->assertEquals(
+                       '<?xml version="1.0"?>'.PHP_EOL.
+                       '<ok>'.PHP_EOL.
+                               '  <data>some_data</data>'.PHP_EOL.
+                       '</ok>'.PHP_EOL,
+                       api_create_xml(['data' => ['some_data']], 'ok')
+               );
+       }
+
+       /**
+        * Test the api_format_data() function.
+        * @return void
+        */
+       public function testApiFormatData()
+       {
+               $data = ['some_data'];
+               $this->assertEquals($data, api_format_data('root_element', 'json', $data));
+       }
+
+       /**
+        * Test the api_format_data() function with an XML result.
+        * @return void
+        */
+       public function testApiFormatDataWithXml()
+       {
+               $this->assertEquals(
+                       '<?xml version="1.0"?>'.PHP_EOL.
+                       '<root_element xmlns="http://api.twitter.com" xmlns:statusnet="http://status.net/schema/api/1/" '.
+                               'xmlns:friendica="http://friendi.ca/schema/api/1/" '.
+                               'xmlns:georss="http://www.georss.org/georss">'.PHP_EOL.
+                               '  <data>some_data</data>'.PHP_EOL.
+                       '</root_element>'.PHP_EOL,
+                       api_format_data('root_element', 'xml', ['data' => ['some_data']])
+               );
+       }
+
+       /**
+        * Test the api_account_verify_credentials() function.
+        * @return void
+        */
+       public function testApiAccountVerifyCredentials()
+       {
+               $this->assertArrayHasKey('user', api_account_verify_credentials('json'));
+       }
+
+       /**
+        * Test the api_account_verify_credentials() function without an authenticated user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiAccountVerifyCredentialsWithoutAuthenticatedUser()
+       {
+               $_SESSION['authenticated'] = false;
+               api_account_verify_credentials('json');
+       }
+
+       /**
+        * Test the requestdata() function.
+        * @return void
+        */
+       public function testRequestdata()
+       {
+               $this->assertNull(requestdata('variable_name'));
+       }
+
+       /**
+        * Test the requestdata() function with a POST parameter.
+        * @return void
+        */
+       public function testRequestdataWithPost()
+       {
+               $_POST['variable_name'] = 'variable_value';
+               $this->assertEquals('variable_value', requestdata('variable_name'));
+       }
+
+       /**
+        * Test the requestdata() function with a GET parameter.
+        * @return void
+        */
+       public function testRequestdataWithGet()
+       {
+               $_GET['variable_name'] = 'variable_value';
+               $this->assertEquals('variable_value', requestdata('variable_name'));
+       }
+
+       /**
+        * Test the api_statuses_mediap() function.
+        * @return void
+        */
+       public function testApiStatusesMediap()
+       {
+               $this->app->argc = 2;
+
+               $_FILES = [
+                       'media' => [
+                               'id' => 666,
+                               'size' => 666,
+                               'width' => 666,
+                               'height' => 666,
+                               'tmp_name' => $this->getTempImage(),
+                               'type' => 'image/png'
+                       ]
+               ];
+               $_GET['status'] = '<b>Status content</b>';
+
+               $result = api_statuses_mediap('json');
+               $this->assertStatus($result['status']);
+       }
+
+       /**
+        * Test the api_statuses_mediap() function without an authenticated user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiStatusesMediapWithoutAuthenticatedUser()
+       {
+               $_SESSION['authenticated'] = false;
+               api_statuses_mediap('json');
+       }
+
+       /**
+        * Test the api_statuses_update() function.
+        * @return void
+        */
+       public function testApiStatusesUpdate()
+       {
+               $_GET['status'] = 'Status content';
+               $_GET['in_reply_to_status_id'] = -1;
+               $_GET['lat'] = 48;
+               $_GET['long'] = 7;
+               $_FILES = [
+                       'media' => [
+                               'id' => 666,
+                               'size' => 666,
+                               'width' => 666,
+                               'height' => 666,
+                               'tmp_name' => $this->getTempImage(),
+                               'type' => 'image/png'
+                       ]
+               ];
+
+               $result = api_statuses_update('json');
+               $this->assertStatus($result['status']);
+       }
+
+       /**
+        * Test the api_statuses_update() function with an HTML status.
+        * @return void
+        */
+       public function testApiStatusesUpdateWithHtml()
+       {
+               $_GET['htmlstatus'] = '<b>Status content</b>';
+
+               $result = api_statuses_update('json');
+               $this->assertStatus($result['status']);
+       }
+
+       /**
+        * Test the api_statuses_update() function without an authenticated user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiStatusesUpdateWithoutAuthenticatedUser()
+       {
+               $_SESSION['authenticated'] = false;
+               api_statuses_update('json');
+       }
+
+       /**
+        * Test the api_statuses_update() function with a parent status.
+        * @return void
+        */
+       public function testApiStatusesUpdateWithParent()
+       {
+               $this->markTestIncomplete('This triggers an exit() somewhere and kills PHPUnit.');
+       }
+
+       /**
+        * Test the api_statuses_update() function with a media_ids parameter.
+        * @return void
+        */
+       public function testApiStatusesUpdateWithMediaIds()
+       {
+               $this->markTestIncomplete();
+       }
+
+       /**
+        * Test the api_statuses_update() function with the throttle limit reached.
+        * @return void
+        */
+       public function testApiStatusesUpdateWithDayThrottleReached()
+       {
+               $this->markTestIncomplete();
+       }
+
+       /**
+        * Test the api_media_upload() function.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        */
+       public function testApiMediaUpload()
+       {
+               api_media_upload();
+       }
+
+       /**
+        * Test the api_media_upload() function without an authenticated user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiMediaUploadWithoutAuthenticatedUser()
+       {
+               $_SESSION['authenticated'] = false;
+               api_media_upload();
+       }
+
+       /**
+        * Test the api_media_upload() function with an invalid uploaded media.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\InternalServerErrorException
+        */
+       public function testApiMediaUploadWithMedia()
+       {
+               $_FILES = [
+                       'media' => [
+                               'id' => 666
+                       ]
+               ];
+               api_media_upload();
+       }
+
+       /**
+        * Test the api_media_upload() function with an valid uploaded media.
+        * @return void
+        */
+       public function testApiMediaUploadWithValidMedia()
+       {
+               $_FILES = [
+                       'media' => [
+                               'id' => 666,
+                               'size' => 666,
+                               'width' => 666,
+                               'height' => 666,
+                               'tmp_name' => $this->getTempImage(),
+                               'type' => 'image/png'
+                       ]
+               ];
+               $app = get_app();
+               $app->argc = 2;
+
+               $result = api_media_upload();
+               $this->assertEquals('image/png', $result['media']['image']['image_type']);
+               $this->assertEquals(1, $result['media']['image']['w']);
+               $this->assertEquals(1, $result['media']['image']['h']);
+       }
+
+       /**
+        * Test the api_status_show() function.
+        * @return void
+        */
+       public function testApiStatusShow()
+       {
+               $result = api_status_show('json');
+               $this->assertStatus($result['status']);
+       }
+
+       /**
+        * Test the api_status_show() function with an XML result.
+        * @return void
+        */
+       public function testApiStatusShowWithXml()
+       {
+               $result = api_status_show('xml');
+               $this->assertXml($result, 'statuses');
+       }
+
+       /**
+        * Test the api_status_show() function with a raw result.
+        * @return void
+        */
+       public function testApiStatusShowWithRaw()
+       {
+               $this->assertStatus(api_status_show('raw'));
+       }
+
+       /**
+        * Test the api_users_show() function.
+        * @return void
+        */
+       public function testApiUsersShow()
+       {
+               $result = api_users_show('json');
+               // We can't use assertSelfUser() here because the user object is missing some properties.
+               $this->assertEquals($this->selfUser['id'], $result['user']['cid']);
+               $this->assertEquals('Friendica', $result['user']['location']);
+               $this->assertEquals($this->selfUser['name'], $result['user']['name']);
+               $this->assertEquals($this->selfUser['nick'], $result['user']['screen_name']);
+               $this->assertEquals('dfrn', $result['user']['network']);
+               $this->assertTrue($result['user']['verified']);
+       }
+
+       /**
+        * Test the api_users_show() function with an XML result.
+        * @return void
+        */
+       public function testApiUsersShowWithXml()
+       {
+               $result = api_users_show('xml');
+               $this->assertXml($result, 'statuses');
+       }
+
+       /**
+        * Test the api_users_search() function.
+        * @return void
+        */
+       public function testApiUsersSearch()
+       {
+               $_GET['q'] = 'othercontact';
+               $result = api_users_search('json');
+               $this->assertOtherUser($result['users'][0]);
+       }
+
+       /**
+        * Test the api_users_search() function with an XML result.
+        * @return void
+        */
+       public function testApiUsersSearchWithXml()
+       {
+               $_GET['q'] = 'othercontact';
+               $result = api_users_search('xml');
+               $this->assertXml($result, 'users');
+       }
+
+       /**
+        * Test the api_users_search() function without a GET q parameter.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        */
+       public function testApiUsersSearchWithoutQuery()
+       {
+               api_users_search('json');
+       }
+
+       /**
+        * Test the api_users_lookup() function.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\NotFoundException
+        */
+       public function testApiUsersLookup()
+       {
+               api_users_lookup('json');
+       }
+
+       /**
+        * Test the api_users_lookup() function with an user ID.
+        * @return void
+        */
+       public function testApiUsersLookupWithUserId()
+       {
+               $_REQUEST['user_id'] = $this->otherUser['id'];
+               $result = api_users_lookup('json');
+               $this->assertOtherUser($result['users'][0]);
+       }
+
+       /**
+        * Test the api_search() function.
+        * @return void
+        */
+       public function testApiSearch()
+       {
+               $_REQUEST['q'] = 'reply';
+               $_REQUEST['max_id'] = 10;
+               $result = api_search('json');
+               foreach ($result['status'] as $status) {
+                       $this->assertStatus($status);
+                       $this->assertContains('reply', $status['text'], null, true);
+               }
+       }
+
+       /**
+        * Test the api_search() function a count parameter.
+        * @return void
+        */
+       public function testApiSearchWithCount()
+       {
+               $_REQUEST['q'] = 'reply';
+               $_REQUEST['count'] = 20;
+               $result = api_search('json');
+               foreach ($result['status'] as $status) {
+                       $this->assertStatus($status);
+                       $this->assertContains('reply', $status['text'], null, true);
+               }
+       }
+
+       /**
+        * Test the api_search() function with an rpp parameter.
+        * @return void
+        */
+       public function testApiSearchWithRpp()
+       {
+               $_REQUEST['q'] = 'reply';
+               $_REQUEST['rpp'] = 20;
+               $result = api_search('json');
+               foreach ($result['status'] as $status) {
+                       $this->assertStatus($status);
+                       $this->assertContains('reply', $status['text'], null, true);
+               }
+       }
+
+
+       /**
+        * Test the api_search() function without an authenticated user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiSearchWithUnallowedUser()
+       {
+               $_SESSION['allow_api'] = false;
+               $_GET['screen_name'] = $this->selfUser['nick'];
+               api_search('json');
+       }
+
+       /**
+        * Test the api_search() function without any GET query parameter.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        */
+       public function testApiSearchWithoutQuery()
+       {
+               api_search('json');
+       }
+
+       /**
+        * Test the api_statuses_home_timeline() function.
+        * @return void
+        */
+       public function testApiStatusesHomeTimeline()
+       {
+               $_REQUEST['max_id'] = 10;
+               $_REQUEST['exclude_replies'] = true;
+               $_REQUEST['conversation_id'] = 1;
+               $result = api_statuses_home_timeline('json');
+               $this->assertNotEmpty($result['status']);
+               foreach ($result['status'] as $status) {
+                       $this->assertStatus($status);
+               }
+       }
+
+       /**
+        * Test the api_statuses_home_timeline() function with a negative page parameter.
+        * @return void
+        */
+       public function testApiStatusesHomeTimelineWithNegativePage()
+       {
+               $_REQUEST['page'] = -2;
+               $result = api_statuses_home_timeline('json');
+               $this->assertNotEmpty($result['status']);
+               foreach ($result['status'] as $status) {
+                       $this->assertStatus($status);
+               }
+       }
+
+       /**
+        * Test the api_statuses_home_timeline() with an unallowed user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiStatusesHomeTimelineWithUnallowedUser()
+       {
+               $_SESSION['allow_api'] = false;
+               $_GET['screen_name'] = $this->selfUser['nick'];
+               api_statuses_home_timeline('json');
+       }
+
+       /**
+        * Test the api_statuses_home_timeline() function with an RSS result.
+        * @return void
+        */
+       public function testApiStatusesHomeTimelineWithRss()
+       {
+               $result = api_statuses_home_timeline('rss');
+               $this->assertXml($result, 'statuses');
+       }
+
+       /**
+        * Test the api_statuses_public_timeline() function.
+        * @return void
+        */
+       public function testApiStatusesPublicTimeline()
+       {
+               $_REQUEST['max_id'] = 10;
+               $_REQUEST['conversation_id'] = 1;
+               $result = api_statuses_public_timeline('json');
+               $this->assertNotEmpty($result['status']);
+               foreach ($result['status'] as $status) {
+                       $this->assertStatus($status);
+               }
+       }
+
+       /**
+        * Test the api_statuses_public_timeline() function with the exclude_replies parameter.
+        * @return void
+        */
+       public function testApiStatusesPublicTimelineWithExcludeReplies()
+       {
+               $_REQUEST['max_id'] = 10;
+               $_REQUEST['exclude_replies'] = true;
+               $result = api_statuses_public_timeline('json');
+               $this->assertNotEmpty($result['status']);
+               foreach ($result['status'] as $status) {
+                       $this->assertStatus($status);
+               }
+       }
+
+       /**
+        * Test the api_statuses_public_timeline() function with a negative page parameter.
+        * @return void
+        */
+       public function testApiStatusesPublicTimelineWithNegativePage()
+       {
+               $_REQUEST['page'] = -2;
+               $result = api_statuses_public_timeline('json');
+               $this->assertNotEmpty($result['status']);
+               foreach ($result['status'] as $status) {
+                       $this->assertStatus($status);
+               }
+       }
+
+       /**
+        * Test the api_statuses_public_timeline() function with an unallowed user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiStatusesPublicTimelineWithUnallowedUser()
+       {
+               $_SESSION['allow_api'] = false;
+               $_GET['screen_name'] = $this->selfUser['nick'];
+               api_statuses_public_timeline('json');
+       }
+
+       /**
+        * Test the api_statuses_public_timeline() function with an RSS result.
+        * @return void
+        */
+       public function testApiStatusesPublicTimelineWithRss()
+       {
+               $result = api_statuses_public_timeline('rss');
+               $this->assertXml($result, 'statuses');
+       }
+
+       /**
+        * Test the api_statuses_networkpublic_timeline() function.
+        * @return void
+        */
+       public function testApiStatusesNetworkpublicTimeline()
+       {
+               $_REQUEST['max_id'] = 10;
+               $result = api_statuses_networkpublic_timeline('json');
+               $this->assertNotEmpty($result['status']);
+               foreach ($result['status'] as $status) {
+                       $this->assertStatus($status);
+               }
+       }
+
+       /**
+        * Test the api_statuses_networkpublic_timeline() function with a negative page parameter.
+        * @return void
+        */
+       public function testApiStatusesNetworkpublicTimelineWithNegativePage()
+       {
+               $_REQUEST['page'] = -2;
+               $result = api_statuses_networkpublic_timeline('json');
+               $this->assertNotEmpty($result['status']);
+               foreach ($result['status'] as $status) {
+                       $this->assertStatus($status);
+               }
+       }
+
+       /**
+        * Test the api_statuses_networkpublic_timeline() function with an unallowed user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiStatusesNetworkpublicTimelineWithUnallowedUser()
+       {
+               $_SESSION['allow_api'] = false;
+               $_GET['screen_name'] = $this->selfUser['nick'];
+               api_statuses_networkpublic_timeline('json');
+       }
+
+       /**
+        * Test the api_statuses_networkpublic_timeline() function with an RSS result.
+        * @return void
+        */
+       public function testApiStatusesNetworkpublicTimelineWithRss()
+       {
+               $result = api_statuses_networkpublic_timeline('rss');
+               $this->assertXml($result, 'statuses');
+       }
+
+       /**
+        * Test the api_statuses_show() function.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        */
+       public function testApiStatusesShow()
+       {
+               api_statuses_show('json');
+       }
+
+       /**
+        * Test the api_statuses_show() function with an ID.
+        * @return void
+        */
+       public function testApiStatusesShowWithId()
+       {
+               $this->app->argv[3] = 1;
+               $result = api_statuses_show('json');
+               $this->assertStatus($result['status']);
+       }
+
+       /**
+        * Test the api_statuses_show() function with the conversation parameter.
+        * @return void
+        */
+       public function testApiStatusesShowWithConversation()
+       {
+               $this->app->argv[3] = 1;
+               $_REQUEST['conversation'] = 1;
+               $result = api_statuses_show('json');
+               $this->assertNotEmpty($result['status']);
+               foreach ($result['status'] as $status) {
+                       $this->assertStatus($status);
+               }
+       }
+
+       /**
+        * Test the api_statuses_show() function with an unallowed user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiStatusesShowWithUnallowedUser()
+       {
+               $_SESSION['allow_api'] = false;
+               $_GET['screen_name'] = $this->selfUser['nick'];
+               api_statuses_show('json');
+       }
+
+       /**
+        * Test the api_conversation_show() function.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        */
+       public function testApiConversationShow()
+       {
+               api_conversation_show('json');
+       }
+
+       /**
+        * Test the api_conversation_show() function with an ID.
+        * @return void
+        */
+       public function testApiConversationShowWithId()
+       {
+               $this->app->argv[3] = 1;
+               $_REQUEST['max_id'] = 10;
+               $_REQUEST['page'] = -2;
+               $result = api_conversation_show('json');
+               $this->assertNotEmpty($result['status']);
+               foreach ($result['status'] as $status) {
+                       $this->assertStatus($status);
+               }
+       }
+
+       /**
+        * Test the api_conversation_show() function with an unallowed user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiConversationShowWithUnallowedUser()
+       {
+               $_SESSION['allow_api'] = false;
+               $_GET['screen_name'] = $this->selfUser['nick'];
+               api_conversation_show('json');
+       }
+
+       /**
+        * Test the api_statuses_repeat() function.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiStatusesRepeat()
+       {
+               api_statuses_repeat('json');
+       }
+
+       /**
+        * Test the api_statuses_repeat() function without an authenticated user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiStatusesRepeatWithoutAuthenticatedUser()
+       {
+               $_SESSION['authenticated'] = false;
+               api_statuses_repeat('json');
+       }
+
+       /**
+        * Test the api_statuses_repeat() function with an ID.
+        * @return void
+        */
+       public function testApiStatusesRepeatWithId()
+       {
+               $this->app->argv[3] = 1;
+               $result = api_statuses_repeat('json');
+               $this->assertStatus($result['status']);
+
+               // Also test with a shared status
+               $this->app->argv[3] = 5;
+               $result = api_statuses_repeat('json');
+               $this->assertStatus($result['status']);
+       }
+
+       /**
+        * Test the api_statuses_destroy() function.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        */
+       public function testApiStatusesDestroy()
+       {
+               api_statuses_destroy('json');
+       }
+
+       /**
+        * Test the api_statuses_destroy() function without an authenticated user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiStatusesDestroyWithoutAuthenticatedUser()
+       {
+               $_SESSION['authenticated'] = false;
+               api_statuses_destroy('json');
+       }
+
+       /**
+        * Test the api_statuses_destroy() function with an ID.
+        * @return void
+        */
+       public function testApiStatusesDestroyWithId()
+       {
+               $this->app->argv[3] = 1;
+               $result = api_statuses_destroy('json');
+               $this->assertStatus($result['status']);
+       }
+
+       /**
+        * Test the api_statuses_mentions() function.
+        * @return void
+        */
+       public function testApiStatusesMentions()
+       {
+               $this->app->user = ['nickname' => $this->selfUser['nick']];
+               $_REQUEST['max_id'] = 10;
+               $result = api_statuses_mentions('json');
+               $this->assertEmpty($result['status']);
+               // We should test with mentions in the database.
+       }
+
+       /**
+        * Test the api_statuses_mentions() function with a negative page parameter.
+        * @return void
+        */
+       public function testApiStatusesMentionsWithNegativePage()
+       {
+               $_REQUEST['page'] = -2;
+               $result = api_statuses_mentions('json');
+               $this->assertEmpty($result['status']);
+       }
+
+       /**
+        * Test the api_statuses_mentions() function with an unallowed user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiStatusesMentionsWithUnallowedUser()
+       {
+               $_SESSION['allow_api'] = false;
+               $_GET['screen_name'] = $this->selfUser['nick'];
+               api_statuses_mentions('json');
+       }
+
+       /**
+        * Test the api_statuses_mentions() function with an RSS result.
+        * @return void
+        */
+       public function testApiStatusesMentionsWithRss()
+       {
+               $result = api_statuses_mentions('rss');
+               $this->assertXml($result, 'statuses');
+       }
+
+       /**
+        * Test the api_statuses_user_timeline() function.
+        * @return void
+        */
+       public function testApiStatusesUserTimeline()
+       {
+               $_REQUEST['max_id'] = 10;
+               $_REQUEST['exclude_replies'] = true;
+               $_REQUEST['conversation_id'] = 1;
+               $result = api_statuses_user_timeline('json');
+               $this->assertNotEmpty($result['status']);
+               foreach ($result['status'] as $status) {
+                       $this->assertStatus($status);
+               }
+       }
+
+       /**
+        * Test the api_statuses_user_timeline() function with a negative page parameter.
+        * @return void
+        */
+       public function testApiStatusesUserTimelineWithNegativePage()
+       {
+               $_REQUEST['page'] = -2;
+               $result = api_statuses_user_timeline('json');
+               $this->assertNotEmpty($result['status']);
+               foreach ($result['status'] as $status) {
+                       $this->assertStatus($status);
+               }
+       }
+
+       /**
+        * Test the api_statuses_user_timeline() function with an RSS result.
+        * @return void
+        */
+       public function testApiStatusesUserTimelineWithRss()
+       {
+               $result = api_statuses_user_timeline('rss');
+               $this->assertXml($result, 'statuses');
+       }
+
+       /**
+        * Test the api_statuses_user_timeline() function with an unallowed user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiStatusesUserTimelineWithUnallowedUser()
+       {
+               $_SESSION['allow_api'] = false;
+               $_GET['screen_name'] = $this->selfUser['nick'];
+               api_statuses_user_timeline('json');
+       }
+
+       /**
+        * Test the api_favorites_create_destroy() function.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        */
+       public function testApiFavoritesCreateDestroy()
+       {
+               api_favorites_create_destroy('json');
+       }
+
+       /**
+        * Test the api_favorites_create_destroy() function with an invalid ID.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        */
+       public function testApiFavoritesCreateDestroyWithInvalidId()
+       {
+               // This triggers a very specific condition ($action_argv_id + 2)
+               $this->app->argv[1] = '1.1';
+               $this->app->argc = 5;
+               api_favorites_create_destroy('json');
+       }
+
+       /**
+        * Test the api_favorites_create_destroy() function with an invalid action.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        */
+       public function testApiFavoritesCreateDestroyWithInvalidAction()
+       {
+               $this->app->argv[1] = '1.1';
+               $this->app->argc = 10;
+               $_REQUEST['id'] = 1;
+               api_favorites_create_destroy('json');
+       }
+
+       /**
+        * Test the api_favorites_create_destroy() function with the create action.
+        * @return void
+        */
+       public function testApiFavoritesCreateDestroyWithCreateAction()
+       {
+               $this->app->argv[1] = '1.1';
+               $this->app->argv[3] = 'create';
+               $this->app->argc = 10;
+               $_REQUEST['id'] = 1;
+               $result = api_favorites_create_destroy('json');
+               $this->assertStatus($result['status']);
+       }
+
+       /**
+        * Test the api_favorites_create_destroy() function with the create action and an RSS result.
+        * @return void
+        */
+       public function testApiFavoritesCreateDestroyWithCreateActionAndRss()
+       {
+               $this->app->argv[1] = '1.1';
+               $this->app->argv[3] = 'create';
+               $this->app->argc = 10;
+               $_REQUEST['id'] = 1;
+               $result = api_favorites_create_destroy('rss');
+               $this->assertXml($result, 'status');
+       }
+
+       /**
+        * Test the api_favorites_create_destroy() function with the destroy action.
+        * @return void
+        */
+       public function testApiFavoritesCreateDestroyWithDestroyAction()
+       {
+               $this->app->argv[1] = '1.1';
+               $this->app->argv[3] = 'destroy';
+               $this->app->argc = 10;
+               $_REQUEST['id'] = 1;
+               $result = api_favorites_create_destroy('json');
+               $this->assertStatus($result['status']);
+       }
+
+       /**
+        * Test the api_favorites_create_destroy() function without an authenticated user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiFavoritesCreateDestroyWithoutAuthenticatedUser()
+       {
+               $_SESSION['authenticated'] = false;
+               api_favorites_create_destroy('json');
+       }
+
+       /**
+        * Test the api_favorites() function.
+        * @return void
+        */
+       public function testApiFavorites()
+       {
+               $_REQUEST['page'] = -1;
+               $_REQUEST['max_id'] = 10;
+               $result = api_favorites('json');
+               foreach ($result['status'] as $status) {
+                       $this->assertStatus($status);
+               }
+       }
+
+       /**
+        * Test the api_favorites() function with an RSS result.
+        * @return void
+        */
+       public function testApiFavoritesWithRss()
+       {
+               $result = api_favorites('rss');
+               $this->assertXml($result, 'statuses');
+       }
+
+       /**
+        * Test the api_favorites() function with an unallowed user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiFavoritesWithUnallowedUser()
+       {
+               $_SESSION['allow_api'] = false;
+               $_GET['screen_name'] = $this->selfUser['nick'];
+               api_favorites('json');
+       }
+
+       /**
+        * Test the api_format_messages() function.
+        * @return void
+        */
+       public function testApiFormatMessages()
+       {
+               $result = api_format_messages(
+                       ['id' => 1, 'title' => 'item_title', 'body' => '[b]item_body[/b]'],
+                       ['id' => 2, 'screen_name' => 'recipient_name'],
+                       ['id' => 3, 'screen_name' => 'sender_name']
+               );
+               $this->assertEquals('item_title'.PHP_EOL.'item_body', $result['text']);
+               $this->assertEquals(1, $result['id']);
+               $this->assertEquals(2, $result['recipient_id']);
+               $this->assertEquals(3, $result['sender_id']);
+               $this->assertEquals('recipient_name', $result['recipient_screen_name']);
+               $this->assertEquals('sender_name', $result['sender_screen_name']);
+       }
+
+       /**
+        * Test the api_format_messages() function with HTML.
+        * @return void
+        */
+       public function testApiFormatMessagesWithHtmlText()
+       {
+               $_GET['getText'] = 'html';
+               $result = api_format_messages(
+                       ['id' => 1, 'title' => 'item_title', 'body' => '[b]item_body[/b]'],
+                       ['id' => 2, 'screen_name' => 'recipient_name'],
+                       ['id' => 3, 'screen_name' => 'sender_name']
+               );
+               $this->assertEquals('item_title', $result['title']);
+               $this->assertEquals('<strong>item_body</strong>', $result['text']);
+       }
+
+       /**
+        * Test the api_format_messages() function with plain text.
+        * @return void
+        */
+       public function testApiFormatMessagesWithPlainText()
+       {
+               $_GET['getText'] = 'plain';
+               $result = api_format_messages(
+                       ['id' => 1, 'title' => 'item_title', 'body' => '[b]item_body[/b]'],
+                       ['id' => 2, 'screen_name' => 'recipient_name'],
+                       ['id' => 3, 'screen_name' => 'sender_name']
+               );
+               $this->assertEquals('item_title', $result['title']);
+               $this->assertEquals('item_body', $result['text']);
+       }
+
+       /**
+        * Test the api_format_messages() function with the getUserObjects GET parameter set to false.
+        * @return void
+        */
+       public function testApiFormatMessagesWithoutUserObjects()
+       {
+               $_GET['getUserObjects'] = 'false';
+               $result = api_format_messages(
+                       ['id' => 1, 'title' => 'item_title', 'body' => '[b]item_body[/b]'],
+                       ['id' => 2, 'screen_name' => 'recipient_name'],
+                       ['id' => 3, 'screen_name' => 'sender_name']
+               );
+               $this->assertNull($result['sender']);
+               $this->assertNull($result['recipient']);
+       }
+
+       /**
+        * Test the api_convert_item() function.
+        * @return void
+        */
+       public function testApiConvertItem()
+       {
+               $result = api_convert_item(
+                       [
+                               'network' => 'feed',
+                               'title' => 'item_title',
+                               // We need a long string to test that it is correctly cut
+                               'body' => 'perspiciatis impedit voluptatem quis molestiae ea qui '.
+                               'reiciendis dolorum aut ducimus sunt consequatur inventore dolor '.
+                               'officiis pariatur doloremque nemo culpa aut quidem qui dolore '.
+                               'laudantium atque commodi alias voluptatem non possimus aperiam '.
+                               'ipsum rerum consequuntur aut amet fugit quia aliquid praesentium '.
+                               'repellendus quibusdam et et inventore mollitia rerum sit autem '.
+                               'pariatur maiores ipsum accusantium perferendis vel sit possimus '.
+                               'veritatis nihil distinctio qui eum repellat officia illum quos '.
+                               'impedit quam iste esse unde qui suscipit aut facilis ut inventore '.
+                               'omnis exercitationem quo magnam consequatur maxime aut illum '.
+                               'soluta quaerat natus unde aspernatur et sed beatae nihil ullam '.
+                               'temporibus corporis ratione blanditiis perspiciatis impedit '.
+                               'voluptatem quis molestiae ea qui reiciendis dolorum aut ducimus '.
+                               'sunt consequatur inventore dolor officiis pariatur doloremque '.
+                               'nemo culpa aut quidem qui dolore laudantium atque commodi alias '.
+                               'voluptatem non possimus aperiam ipsum rerum consequuntur aut '.
+                               'amet fugit quia aliquid praesentium repellendus quibusdam et et '.
+                               'inventore mollitia rerum sit autem pariatur maiores ipsum accusantium '.
+                               'perferendis vel sit possimus veritatis nihil distinctio qui eum '.
+                               'repellat officia illum quos impedit quam iste esse unde qui '.
+                               'suscipit aut facilis ut inventore omnis exercitationem quo magnam '.
+                               'consequatur maxime aut illum soluta quaerat natus unde aspernatur '.
+                               'et sed beatae nihil ullam temporibus corporis ratione blanditiis'
+                       ]
+               );
+               $this->assertStringStartsWith('item_title', $result['text']);
+               $this->assertStringStartsWith('<h4>item_title</h4><br>perspiciatis impedit voluptatem', $result['html']);
+       }
+
+       /**
+        * Test the api_convert_item() function with an empty item body.
+        * @return void
+        */
+       public function testApiConvertItemWithoutBody()
+       {
+               $result = api_convert_item(
+                       [
+                               'network' => 'feed',
+                               'title' => 'item_title',
+                               'body' => '',
+                               'plink' => 'item_plink'
+                       ]
+               );
+               $this->assertEquals('item_title', $result['text']);
+               $this->assertEquals('<h4>item_title</h4><br>item_plink', $result['html']);
+       }
+
+       /**
+        * Test the api_convert_item() function with the title in the body.
+        * @return void
+        */
+       public function testApiConvertItemWithTitleInBody()
+       {
+               $result = api_convert_item(
+                       [
+                               'title' => 'item_title',
+                               'body' => 'item_title item_body'
+                       ]
+               );
+               $this->assertEquals('item_title item_body', $result['text']);
+               $this->assertEquals('<h4>item_title</h4><br>item_title item_body', $result['html']);
+       }
+
+       /**
+        * Test the api_get_attachments() function.
+        * @return void
+        */
+       public function testApiGetAttachments()
+       {
+               $body = 'body';
+               $this->assertEmpty(api_get_attachments($body));
+       }
+
+       /**
+        * Test the api_get_attachments() function with an img tag.
+        * @return void
+        */
+       public function testApiGetAttachmentsWithImage()
+       {
+               $body = '[img]img_url[/img]';
+               $this->assertInternalType('array', api_get_attachments($body));
+       }
+
+       /**
+        * Test the api_get_attachments() function with an img tag and an AndStatus user agent.
+        * @return void
+        */
+       public function testApiGetAttachmentsWithImageAndAndStatus()
+       {
+               $_SERVER['HTTP_USER_AGENT'] = 'AndStatus';
+               $body = '[img]img_url[/img]';
+               $this->assertInternalType('array', api_get_attachments($body));
+       }
+
+       /**
+        * Test the api_get_entitities() function.
+        * @return void
+        */
+       public function testApiGetEntitities()
+       {
+               $text = 'text';
+               $this->assertInternalType('array', api_get_entitities($text, 'bbcode'));
+       }
+
+       /**
+        * Test the api_get_entitities() function with the include_entities parameter.
+        * @return void
+        */
+       public function testApiGetEntititiesWithIncludeEntities()
+       {
+               $_REQUEST['include_entities'] = 'true';
+               $text = 'text';
+               $result = api_get_entitities($text, 'bbcode');
+               $this->assertInternalType('array', $result['hashtags']);
+               $this->assertInternalType('array', $result['symbols']);
+               $this->assertInternalType('array', $result['urls']);
+               $this->assertInternalType('array', $result['user_mentions']);
+       }
+
+       /**
+        * Test the api_format_items_embeded_images() function.
+        * @return void
+        */
+       public function testApiFormatItemsEmbededImages()
+       {
+               $this->assertEquals(
+                       'text http://localhost/display/item_guid',
+                       api_format_items_embeded_images(['guid' => 'item_guid'], 'text data:image/foo')
+               );
+       }
+
+       /**
+        * Test the api_contactlink_to_array() function.
+        * @return void
+        */
+       public function testApiContactlinkToArray()
+       {
+               $this->assertEquals(
+                       [
+                               'name' => 'text',
+                               'url' => '',
+                       ],
+                       api_contactlink_to_array('text')
+               );
+       }
+
+       /**
+        * Test the api_contactlink_to_array() function with an URL.
+        * @return void
+        */
+       public function testApiContactlinkToArrayWithUrl()
+       {
+               $this->assertEquals(
+                       [
+                               'name' => ['link_text'],
+                               'url' => ['url'],
+                       ],
+                       api_contactlink_to_array('text <a href="url">link_text</a>')
+               );
+       }
+
+       /**
+        * Test the api_format_items_activities() function.
+        * @return void
+        */
+       public function testApiFormatItemsActivities()
+       {
+               $item = [];
+               $result = api_format_items_activities($item);
+               $this->assertArrayHasKey('like', $result);
+               $this->assertArrayHasKey('dislike', $result);
+               $this->assertArrayHasKey('attendyes', $result);
+               $this->assertArrayHasKey('attendno', $result);
+               $this->assertArrayHasKey('attendmaybe', $result);
+       }
+
+       /**
+        * Test the api_format_items_activities() function with an XML result.
+        * @return void
+        */
+       public function testApiFormatItemsActivitiesWithXml()
+       {
+               $item = [];
+               $result = api_format_items_activities($item, 'xml');
+               $this->assertArrayHasKey('friendica:like', $result);
+               $this->assertArrayHasKey('friendica:dislike', $result);
+               $this->assertArrayHasKey('friendica:attendyes', $result);
+               $this->assertArrayHasKey('friendica:attendno', $result);
+               $this->assertArrayHasKey('friendica:attendmaybe', $result);
+       }
+
+       /**
+        * Test the api_format_items_profiles() function.
+        * @return void
+        */
+       public function testApiFormatItemsProfiles()
+       {
+               $profile_row = [
+                       'id' => 'profile_id',
+                       'profile-name' => 'profile_name',
+                       'is-default' => true,
+                       'hide-friends' => true,
+                       'photo' => 'profile_photo',
+                       'thumb' => 'profile_thumb',
+                       'publish' => true,
+                       'net-publish' => true,
+                       'pdesc' => 'description',
+                       'dob' => 'date_of_birth',
+                       'address' => 'address',
+                       'locality' => 'city',
+                       'region' => 'region',
+                       'postal-code' => 'postal_code',
+                       'country-name' => 'country',
+                       'hometown' => 'hometown',
+                       'gender' => 'gender',
+                       'marital' => 'marital',
+                       'with' => 'marital_with',
+                       'howlong' => 'marital_since',
+                       'sexual' => 'sexual',
+                       'politic' => 'politic',
+                       'religion' => 'religion',
+                       'pub_keywords' => 'public_keywords',
+                       'prv_keywords' => 'private_keywords',
+
+                       'likes' => 'likes',
+                       'dislikes' => 'dislikes',
+                       'about' => 'about',
+                       'music' => 'music',
+                       'book' => 'book',
+                       'tv' => 'tv',
+                       'film' => 'film',
+                       'interest' => 'interest',
+                       'romance' => 'romance',
+                       'work' => 'work',
+                       'education' => 'education',
+                       'contact' => 'social_networks',
+                       'homepage' => 'homepage'
+               ];
+               $result = api_format_items_profiles($profile_row);
+               $this->assertEquals(
+                       [
+                               'profile_id' => 'profile_id',
+                               'profile_name' => 'profile_name',
+                               'is_default' => true,
+                               'hide_friends' => true,
+                               'profile_photo' => 'profile_photo',
+                               'profile_thumb' => 'profile_thumb',
+                               'publish' => true,
+                               'net_publish' => true,
+                               'description' => 'description',
+                               'date_of_birth' => 'date_of_birth',
+                               'address' => 'address',
+                               'city' => 'city',
+                               'region' => 'region',
+                               'postal_code' => 'postal_code',
+                               'country' => 'country',
+                               'hometown' => 'hometown',
+                               'gender' => 'gender',
+                               'marital' => 'marital',
+                               'marital_with' => 'marital_with',
+                               'marital_since' => 'marital_since',
+                               'sexual' => 'sexual',
+                               'politic' => 'politic',
+                               'religion' => 'religion',
+                               'public_keywords' => 'public_keywords',
+                               'private_keywords' => 'private_keywords',
+
+                               'likes' => 'likes',
+                               'dislikes' => 'dislikes',
+                               'about' => 'about',
+                               'music' => 'music',
+                               'book' => 'book',
+                               'tv' => 'tv',
+                               'film' => 'film',
+                               'interest' => 'interest',
+                               'romance' => 'romance',
+                               'work' => 'work',
+                               'education' => 'education',
+                               'social_networks' => 'social_networks',
+                               'homepage' => 'homepage',
+                               'users' => null
+                       ],
+                       $result
+               );
+       }
+
+       /**
+        * Test the api_format_items() function.
+        * @return void
+        */
+       public function testApiFormatItems()
+       {
+               $items = [
+                       [
+                               'item_network' => 'item_network',
+                               'source' => 'web',
+                               'coord' => '5 7'
+                       ]
+               ];
+               $result = api_format_items($items, [], true);
+               foreach ($result as $status) {
+                       $this->assertStatus($status);
+               }
+       }
+
+       /**
+        * Test the api_format_items() function with an XML result.
+        * @return void
+        */
+       public function testApiFormatItemsWithXml()
+       {
+               $items = [
+                       [
+                               'coord' => '5 7'
+                       ]
+               ];
+               $result = api_format_items($items, [], true, 'xml');
+               foreach ($result as $status) {
+                       $this->assertStatus($status);
+               }
+       }
+
+       /**
+        * Test the api_format_items() function.
+        * @return void
+        */
+       public function testApiAccountRateLimitStatus()
+       {
+               $result = api_account_rate_limit_status('json');
+               $this->assertEquals(150, $result['hash']['remaining_hits']);
+               $this->assertEquals(150, $result['hash']['hourly_limit']);
+               $this->assertInternalType('int', $result['hash']['reset_time_in_seconds']);
+       }
+
+       /**
+        * Test the api_format_items() function with an XML result.
+        * @return void
+        */
+       public function testApiAccountRateLimitStatusWithXml()
+       {
+               $result = api_account_rate_limit_status('xml');
+               $this->assertXml($result, 'hash');
+       }
+
+       /**
+        * Test the api_help_test() function.
+        * @return void
+        */
+       public function testApiHelpTest()
+       {
+               $result = api_help_test('json');
+               $this->assertEquals(['ok' => 'ok'], $result);
+       }
+
+       /**
+        * Test the api_help_test() function with an XML result.
+        * @return void
+        */
+       public function testApiHelpTestWithXml()
+       {
+               $this->markTestIncomplete('Triggers this error: "key() expects parameter 1 to be array, string given"');
+               $result = api_help_test('xml');
+               $this->assertXml($result, 'ok');
+       }
+
+       /**
+        * Test the api_lists_list() function.
+        * @return void
+        */
+       public function testApiListsList()
+       {
+               $result = api_lists_list('json');
+               $this->assertEquals(['lists_list' => []], $result);
+       }
+
+       /**
+        * Test the api_lists_ownerships() function.
+        * @return void
+        */
+       public function testApiListsOwnerships()
+       {
+               $result = api_lists_ownerships('json');
+               foreach ($result['lists']['lists'] as $list) {
+                       $this->assertList($list);
+               }
+       }
+
+       /**
+        * Test the api_lists_ownerships() function without an authenticated user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiListsOwnershipsWithoutAuthenticatedUser()
+       {
+               $_SESSION['authenticated'] = false;
+               api_lists_ownerships('json');
+       }
+
+       /**
+        * Test the api_lists_statuses() function.
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        * @return void
+        */
+       public function testApiListsStatuses()
+       {
+               api_lists_statuses('json');
+       }
+
+       /**
+        * Test the api_lists_statuses() function with a list ID.
+        * @return void
+        */
+       public function testApiListsStatusesWithListId()
+       {
+               $_REQUEST['list_id'] = 1;
+               $_REQUEST['page'] = -1;
+               $_REQUEST['max_id'] = 10;
+               $result = api_lists_statuses('json');
+               foreach ($result['status'] as $status) {
+                       $this->assertStatus($status);
+               }
+       }
+
+       /**
+        * Test the api_lists_statuses() function with a list ID and a RSS result.
+        * @return void
+        */
+       public function testApiListsStatusesWithListIdAndRss()
+       {
+               $_REQUEST['list_id'] = 1;
+               $result = api_lists_statuses('rss');
+               $this->assertXml($result, 'statuses');
+       }
+
+       /**
+        * Test the api_lists_statuses() function with an unallowed user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiListsStatusesWithUnallowedUser()
+       {
+               $_SESSION['allow_api'] = false;
+               $_GET['screen_name'] = $this->selfUser['nick'];
+               api_lists_statuses('json');
+       }
+
+       /**
+        * Test the api_statuses_f() function.
+        * @return void
+        */
+       public function testApiStatusesFWithFriends()
+       {
+               $_GET['page'] = -1;
+               $result = api_statuses_f('friends');
+               $this->assertArrayHasKey('user', $result);
+       }
+
+       /**
+        * Test the api_statuses_f() function.
+        * @return void
+        */
+       public function testApiStatusesFWithFollowers()
+       {
+               $result = api_statuses_f('followers');
+               $this->assertArrayHasKey('user', $result);
+       }
+
+       /**
+        * Test the api_statuses_f() function.
+        * @return void
+        */
+       public function testApiStatusesFWithBlocks()
+       {
+               $result = api_statuses_f('blocks');
+               $this->assertArrayHasKey('user', $result);
+       }
+
+       /**
+        * Test the api_statuses_f() function.
+        * @return void
+        */
+       public function testApiStatusesFWithIncoming()
+       {
+               $result = api_statuses_f('incoming');
+               $this->assertArrayHasKey('user', $result);
+       }
+
+       /**
+        * Test the api_statuses_f() function an undefined cursor GET variable.
+        * @return void
+        */
+       public function testApiStatusesFWithUndefinedCursor()
+       {
+               $_GET['cursor'] = 'undefined';
+               $this->assertFalse(api_statuses_f('friends'));
+       }
+
+       /**
+        * Test the api_statuses_friends() function.
+        * @return void
+        */
+       public function testApiStatusesFriends()
+       {
+               $result = api_statuses_friends('json');
+               $this->assertArrayHasKey('user', $result);
+       }
+
+       /**
+        * Test the api_statuses_friends() function an undefined cursor GET variable.
+        * @return void
+        */
+       public function testApiStatusesFriendsWithUndefinedCursor()
+       {
+               $_GET['cursor'] = 'undefined';
+               $this->assertFalse(api_statuses_friends('json'));
+       }
+
+       /**
+        * Test the api_statuses_followers() function.
+        * @return void
+        */
+       public function testApiStatusesFollowers()
+       {
+               $result = api_statuses_followers('json');
+               $this->assertArrayHasKey('user', $result);
+       }
+
+       /**
+        * Test the api_statuses_followers() function an undefined cursor GET variable.
+        * @return void
+        */
+       public function testApiStatusesFollowersWithUndefinedCursor()
+       {
+               $_GET['cursor'] = 'undefined';
+               $this->assertFalse(api_statuses_followers('json'));
+       }
+
+       /**
+        * Test the api_blocks_list() function.
+        * @return void
+        */
+       public function testApiBlocksList()
+       {
+               $result = api_blocks_list('json');
+               $this->assertArrayHasKey('user', $result);
+       }
+
+       /**
+        * Test the api_blocks_list() function an undefined cursor GET variable.
+        * @return void
+        */
+       public function testApiBlocksListWithUndefinedCursor()
+       {
+               $_GET['cursor'] = 'undefined';
+               $this->assertFalse(api_blocks_list('json'));
+       }
+
+       /**
+        * Test the api_friendships_incoming() function.
+        * @return void
+        */
+       public function testApiFriendshipsIncoming()
+       {
+               $result = api_friendships_incoming('json');
+               $this->assertArrayHasKey('id', $result);
+       }
+
+       /**
+        * Test the api_friendships_incoming() function an undefined cursor GET variable.
+        * @return void
+        */
+       public function testApiFriendshipsIncomingWithUndefinedCursor()
+       {
+               $_GET['cursor'] = 'undefined';
+               $this->assertFalse(api_friendships_incoming('json'));
+       }
+
+       /**
+        * Test the api_statusnet_config() function.
+        * @return void
+        */
+       public function testApiStatusnetConfig()
+       {
+               $result = api_statusnet_config('json');
+               $this->assertEquals('localhost', $result['config']['site']['server']);
+               $this->assertEquals('default', $result['config']['site']['theme']);
+               $this->assertEquals('http://localhost/images/friendica-64.png', $result['config']['site']['logo']);
+               $this->assertTrue($result['config']['site']['fancy']);
+               $this->assertEquals('en', $result['config']['site']['language']);
+               $this->assertEquals('UTC', $result['config']['site']['timezone']);
+               $this->assertEquals(200000, $result['config']['site']['textlimit']);
+               $this->assertEquals('false', $result['config']['site']['private']);
+               $this->assertEquals('false', $result['config']['site']['ssl']);
+               $this->assertEquals(30, $result['config']['site']['shorturllength']);
+       }
+
+       /**
+        * Test the api_statusnet_version() function.
+        * @return void
+        */
+       public function testApiStatusnetVersion()
+       {
+               $result = api_statusnet_version('json');
+               $this->assertEquals('0.9.7', $result['version']);
+       }
+
+       /**
+        * Test the api_ff_ids() function.
+        * @return void
+        */
+       public function testApiFfIds()
+       {
+               $result = api_ff_ids('json');
+               $this->assertNull($result);
+       }
+
+       /**
+        * Test the api_ff_ids() function with a result.
+        * @return void
+        */
+       public function testApiFfIdsWithResult()
+       {
+               $this->markTestIncomplete();
+       }
+
+       /**
+        * Test the api_ff_ids() function without an authenticated user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiFfIdsWithoutAuthenticatedUser()
+       {
+               $_SESSION['authenticated'] = false;
+               api_ff_ids('json');
+       }
+
+       /**
+        * Test the api_friends_ids() function.
+        * @return void
+        */
+       public function testApiFriendsIds()
+       {
+               $result = api_friends_ids('json');
+               $this->assertNull($result);
+       }
+
+       /**
+        * Test the api_followers_ids() function.
+        * @return void
+        */
+       public function testApiFollowersIds()
+       {
+               $result = api_followers_ids('json');
+               $this->assertNull($result);
+       }
+
+       /**
+        * Test the api_direct_messages_new() function.
+        * @return void
+        */
+       public function testApiDirectMessagesNew()
+       {
+               $result = api_direct_messages_new('json');
+               $this->assertNull($result);
+       }
+
+       /**
+        * Test the api_direct_messages_new() function without an authenticated user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiDirectMessagesNewWithoutAuthenticatedUser()
+       {
+               $_SESSION['authenticated'] = false;
+               api_direct_messages_new('json');
+       }
+
+       /**
+        * Test the api_direct_messages_new() function with an user ID.
+        * @return void
+        */
+       public function testApiDirectMessagesNewWithUserId()
+       {
+               $_POST['text'] = 'message_text';
+               $_POST['user_id'] = $this->otherUser['id'];
+               $result = api_direct_messages_new('json');
+               $this->assertEquals(['direct_message' => ['error' => -1]], $result);
+       }
+
+       /**
+        * Test the api_direct_messages_new() function with a screen name.
+        * @return void
+        */
+       public function testApiDirectMessagesNewWithScreenName()
+       {
+               $_POST['text'] = 'message_text';
+               $_POST['screen_name'] = $this->otherUser['nick'];
+               $result = api_direct_messages_new('json');
+               $this->assertEquals(1, $result['direct_message']['id']);
+               $this->assertContains('message_text', $result['direct_message']['text']);
+               $this->assertEquals('selfcontact', $result['direct_message']['sender_screen_name']);
+               $this->assertEquals(1, $result['direct_message']['friendica_seen']);
+       }
+
+       /**
+        * Test the api_direct_messages_new() function with a title.
+        * @return void
+        */
+       public function testApiDirectMessagesNewWithTitle()
+       {
+               $_POST['text'] = 'message_text';
+               $_POST['screen_name'] = $this->otherUser['nick'];
+               $_REQUEST['title'] = 'message_title';
+               $result = api_direct_messages_new('json');
+               $this->assertEquals(1, $result['direct_message']['id']);
+               $this->assertContains('message_text', $result['direct_message']['text']);
+               $this->assertContains('message_title', $result['direct_message']['text']);
+               $this->assertEquals('selfcontact', $result['direct_message']['sender_screen_name']);
+               $this->assertEquals(1, $result['direct_message']['friendica_seen']);
+       }
+
+       /**
+        * Test the api_direct_messages_new() function with an RSS result.
+        * @return void
+        */
+       public function testApiDirectMessagesNewWithRss()
+       {
+               $_POST['text'] = 'message_text';
+               $_POST['screen_name'] = $this->otherUser['nick'];
+               $result = api_direct_messages_new('rss');
+               $this->assertXml($result, 'direct-messages');
+       }
+
+       /**
+        * Test the api_direct_messages_destroy() function.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        */
+       public function testApiDirectMessagesDestroy()
+       {
+               api_direct_messages_destroy('json');
+       }
+
+       /**
+        * Test the api_direct_messages_destroy() function with the friendica_verbose GET param.
+        * @return void
+        */
+       public function testApiDirectMessagesDestroyWithVerbose()
+       {
+               $_GET['friendica_verbose'] = 'true';
+               $result = api_direct_messages_destroy('json');
+               $this->assertEquals(
+                       [
+                               '$result' => [
+                                       'result' => 'error',
+                                       'message' => 'message id or parenturi not specified'
+                               ]
+                       ],
+                       $result
+               );
+       }
+
+       /**
+        * Test the api_direct_messages_destroy() function without an authenticated user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiDirectMessagesDestroyWithoutAuthenticatedUser()
+       {
+               $_SESSION['authenticated'] = false;
+               api_direct_messages_destroy('json');
+       }
+
+       /**
+        * Test the api_direct_messages_destroy() function with a non-zero ID.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        */
+       public function testApiDirectMessagesDestroyWithId()
+       {
+               $_REQUEST['id'] = 1;
+               api_direct_messages_destroy('json');
+       }
+
+       /**
+        * Test the api_direct_messages_destroy() with a non-zero ID and the friendica_verbose GET param.
+        * @return void
+        */
+       public function testApiDirectMessagesDestroyWithIdAndVerbose()
+       {
+               $_REQUEST['id'] = 1;
+               $_REQUEST['friendica_parenturi'] = 'parent_uri';
+               $_GET['friendica_verbose'] = 'true';
+               $result = api_direct_messages_destroy('json');
+               $this->assertEquals(
+                       [
+                               '$result' => [
+                                       'result' => 'error',
+                                       'message' => 'message id not in database'
+                               ]
+                       ],
+                       $result
+               );
+       }
+
+       /**
+        * Test the api_direct_messages_destroy() function with a non-zero ID.
+        * @return void
+        */
+       public function testApiDirectMessagesDestroyWithCorrectId()
+       {
+               $this->markTestIncomplete('We need to add a dataset for this.');
+       }
+
+       /**
+        * Test the api_direct_messages_box() function.
+        * @return void
+        */
+       public function testApiDirectMessagesBoxWithSentbox()
+       {
+               $_REQUEST['page'] = -1;
+               $_REQUEST['max_id'] = 10;
+               $result = api_direct_messages_box('json', 'sentbox', 'false');
+               $this->assertArrayHasKey('direct_message', $result);
+       }
+
+       /**
+        * Test the api_direct_messages_box() function.
+        * @return void
+        */
+       public function testApiDirectMessagesBoxWithConversation()
+       {
+               $result = api_direct_messages_box('json', 'conversation', 'false');
+               $this->assertArrayHasKey('direct_message', $result);
+       }
+
+       /**
+        * Test the api_direct_messages_box() function.
+        * @return void
+        */
+       public function testApiDirectMessagesBoxWithAll()
+       {
+               $result = api_direct_messages_box('json', 'all', 'false');
+               $this->assertArrayHasKey('direct_message', $result);
+       }
+
+       /**
+        * Test the api_direct_messages_box() function.
+        * @return void
+        */
+       public function testApiDirectMessagesBoxWithInbox()
+       {
+               $result = api_direct_messages_box('json', 'inbox', 'false');
+               $this->assertArrayHasKey('direct_message', $result);
+       }
+
+       /**
+        * Test the api_direct_messages_box() function.
+        * @return void
+        */
+       public function testApiDirectMessagesBoxWithVerbose()
+       {
+               $result = api_direct_messages_box('json', 'sentbox', 'true');
+               $this->assertEquals(
+                       [
+                               '$result' => [
+                                       'result' => 'error',
+                                       'message' => 'no mails available'
+                               ]
+                       ],
+                       $result
+               );
+       }
+
+       /**
+        * Test the api_direct_messages_box() function with a RSS result.
+        * @return void
+        */
+       public function testApiDirectMessagesBoxWithRss()
+       {
+               $result = api_direct_messages_box('rss', 'sentbox', 'false');
+               $this->assertXml($result, 'direct-messages');
+       }
+
+       /**
+        * Test the api_direct_messages_box() function without an authenticated user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiDirectMessagesBoxWithUnallowedUser()
+       {
+               $_SESSION['allow_api'] = false;
+               $_GET['screen_name'] = $this->selfUser['nick'];
+               api_direct_messages_box('json', 'sentbox', 'false');
+       }
+
+       /**
+        * Test the api_direct_messages_sentbox() function.
+        * @return void
+        */
+       public function testApiDirectMessagesSentbox()
+       {
+               $result = api_direct_messages_sentbox('json');
+               $this->assertArrayHasKey('direct_message', $result);
+       }
+
+       /**
+        * Test the api_direct_messages_inbox() function.
+        * @return void
+        */
+       public function testApiDirectMessagesInbox()
+       {
+               $result = api_direct_messages_inbox('json');
+               $this->assertArrayHasKey('direct_message', $result);
+       }
+
+       /**
+        * Test the api_direct_messages_all() function.
+        * @return void
+        */
+       public function testApiDirectMessagesAll()
+       {
+               $result = api_direct_messages_all('json');
+               $this->assertArrayHasKey('direct_message', $result);
+       }
+
+       /**
+        * Test the api_direct_messages_conversation() function.
+        * @return void
+        */
+       public function testApiDirectMessagesConversation()
+       {
+               $result = api_direct_messages_conversation('json');
+               $this->assertArrayHasKey('direct_message', $result);
+       }
+
+       /**
+        * Test the api_oauth_request_token() function.
+        * @return void
+        */
+       public function testApiOauthRequestToken()
+       {
+               $this->markTestIncomplete('killme() kills phpunit as well');
+       }
+
+       /**
+        * Test the api_oauth_access_token() function.
+        * @return void
+        */
+       public function testApiOauthAccessToken()
+       {
+               $this->markTestIncomplete('killme() kills phpunit as well');
+       }
+
+       /**
+        * Test the api_fr_photoalbum_delete() function.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        */
+       public function testApiFrPhotoalbumDelete()
+       {
+               api_fr_photoalbum_delete('json');
+       }
+
+       /**
+        * Test the api_fr_photoalbum_delete() function with an album name.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        */
+       public function testApiFrPhotoalbumDeleteWithAlbum()
+       {
+               $_REQUEST['album'] = 'album_name';
+               api_fr_photoalbum_delete('json');
+       }
+
+       /**
+        * Test the api_fr_photoalbum_delete() function with an album name.
+        * @return void
+        */
+       public function testApiFrPhotoalbumDeleteWithValidAlbum()
+       {
+               $this->markTestIncomplete('We need to add a dataset for this.');
+       }
+
+       /**
+        * Test the api_fr_photoalbum_delete() function.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        */
+       public function testApiFrPhotoalbumUpdate()
+       {
+               api_fr_photoalbum_update('json');
+       }
+
+       /**
+        * Test the api_fr_photoalbum_delete() function with an album name.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        */
+       public function testApiFrPhotoalbumUpdateWithAlbum()
+       {
+               $_REQUEST['album'] = 'album_name';
+               api_fr_photoalbum_update('json');
+       }
+
+       /**
+        * Test the api_fr_photoalbum_delete() function with an album name.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        */
+       public function testApiFrPhotoalbumUpdateWithAlbumAndNewAlbum()
+       {
+               $_REQUEST['album'] = 'album_name';
+               $_REQUEST['album_new'] = 'album_name';
+               api_fr_photoalbum_update('json');
+       }
+
+       /**
+        * Test the api_fr_photoalbum_update() function without an authenticated user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiFrPhotoalbumUpdateWithoutAuthenticatedUser()
+       {
+               $_SESSION['authenticated'] = false;
+               api_fr_photoalbum_update('json');
+       }
+
+       /**
+        * Test the api_fr_photoalbum_delete() function with an album name.
+        * @return void
+        */
+       public function testApiFrPhotoalbumUpdateWithValidAlbum()
+       {
+               $this->markTestIncomplete('We need to add a dataset for this.');
+       }
+
+       /**
+        * Test the api_fr_photos_list() function.
+        * @return void
+        */
+       public function testApiFrPhotosList()
+       {
+               $result = api_fr_photos_list('json');
+               $this->assertArrayHasKey('photo', $result);
+       }
+
+       /**
+        * Test the api_fr_photos_list() function without an authenticated user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiFrPhotosListWithoutAuthenticatedUser()
+       {
+               $_SESSION['authenticated'] = false;
+               api_fr_photos_list('json');
+       }
+
+       /**
+        * Test the api_fr_photo_create_update() function.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        */
+       public function testApiFrPhotoCreateUpdate()
+       {
+               api_fr_photo_create_update('json');
+       }
+
+       /**
+        * Test the api_fr_photo_create_update() function without an authenticated user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiFrPhotoCreateUpdateWithoutAuthenticatedUser()
+       {
+               $_SESSION['authenticated'] = false;
+               api_fr_photo_create_update('json');
+       }
+
+       /**
+        * Test the api_fr_photo_create_update() function with an album name.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        */
+       public function testApiFrPhotoCreateUpdateWithAlbum()
+       {
+               $_REQUEST['album'] = 'album_name';
+               api_fr_photo_create_update('json');
+       }
+
+       /**
+        * Test the api_fr_photo_create_update() function with the update mode.
+        * @return void
+        */
+       public function testApiFrPhotoCreateUpdateWithUpdate()
+       {
+               $this->markTestIncomplete('We need to create a dataset for this');
+       }
+
+       /**
+        * Test the api_fr_photo_create_update() function with an uploaded file.
+        * @return void
+        */
+       public function testApiFrPhotoCreateUpdateWithFile()
+       {
+               $this->markTestIncomplete();
+       }
+
+       /**
+        * Test the api_fr_photo_delete() function.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        */
+       public function testApiFrPhotoDelete()
+       {
+               api_fr_photo_delete('json');
+       }
+
+       /**
+        * Test the api_fr_photo_delete() function without an authenticated user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiFrPhotoDeleteWithoutAuthenticatedUser()
+       {
+               $_SESSION['authenticated'] = false;
+               api_fr_photo_delete('json');
+       }
+
+       /**
+        * Test the api_fr_photo_delete() function with a photo ID.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        */
+       public function testApiFrPhotoDeleteWithPhotoId()
+       {
+               $_REQUEST['photo_id'] = 1;
+               api_fr_photo_delete('json');
+       }
+
+       /**
+        * Test the api_fr_photo_delete() function with a correct photo ID.
+        * @return void
+        */
+       public function testApiFrPhotoDeleteWithCorrectPhotoId()
+       {
+               $this->markTestIncomplete('We need to create a dataset for this.');
+       }
+
+       /**
+        * Test the api_fr_photo_detail() function.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        */
+       public function testApiFrPhotoDetail()
+       {
+               api_fr_photo_detail('json');
+       }
+
+       /**
+        * Test the api_fr_photo_detail() function without an authenticated user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiFrPhotoDetailWithoutAuthenticatedUser()
+       {
+               $_SESSION['authenticated'] = false;
+               api_fr_photo_detail('json');
+       }
+
+       /**
+        * Test the api_fr_photo_detail() function with a photo ID.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\NotFoundException
+        */
+       public function testApiFrPhotoDetailWithPhotoId()
+       {
+               $_REQUEST['photo_id'] = 1;
+               api_fr_photo_detail('json');
+       }
+
+       /**
+        * Test the api_fr_photo_detail() function with a correct photo ID.
+        * @return void
+        */
+       public function testApiFrPhotoDetailCorrectPhotoId()
+       {
+               $this->markTestIncomplete('We need to create a dataset for this.');
+       }
+
+       /**
+        * Test the api_account_update_profile_image() function.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        */
+       public function testApiAccountUpdateProfileImage()
+       {
+               api_account_update_profile_image('json');
+       }
+
+       /**
+        * Test the api_account_update_profile_image() function without an authenticated user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiAccountUpdateProfileImageWithoutAuthenticatedUser()
+       {
+               $_SESSION['authenticated'] = false;
+               api_account_update_profile_image('json');
+       }
+
+       /**
+        * Test the api_account_update_profile_image() function with an uploaded file.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        */
+       public function testApiAccountUpdateProfileImageWithUpload()
+       {
+               $this->markTestIncomplete();
+       }
+
+
+       /**
+        * Test the api_account_update_profile() function.
+        * @return void
+        */
+       public function testApiAccountUpdateProfile()
+       {
+               $_POST['name'] = 'new_name';
+               $_POST['description'] = 'new_description';
+               $result = api_account_update_profile('json');
+               // We can't use assertSelfUser() here because the user object is missing some properties.
+               $this->assertEquals($this->selfUser['id'], $result['user']['cid']);
+               $this->assertEquals('Friendica', $result['user']['location']);
+               $this->assertEquals($this->selfUser['nick'], $result['user']['screen_name']);
+               $this->assertEquals('dfrn', $result['user']['network']);
+               $this->assertEquals('new_name', $result['user']['name']);
+               $this->assertEquals('new_description', $result['user']['description']);
+       }
+
+       /**
+        * Test the check_acl_input() function.
+        * @return void
+        */
+       public function testCheckAclInput()
+       {
+               $result = check_acl_input('<aclstring>');
+               // Where does this result come from?
+               $this->assertEquals(1, $result);
+       }
+
+       /**
+        * Test the check_acl_input() function with an empty ACL string.
+        * @return void
+        */
+       public function testCheckAclInputWithEmptyAclString()
+       {
+               $result = check_acl_input(' ');
+               $this->assertFalse($result);
+       }
+
+       /**
+        * Test the save_media_to_database() function.
+        * @return void
+        */
+       public function testSaveMediaToDatabase()
+       {
+               $this->markTestIncomplete();
+       }
+
+       /**
+        * Test the post_photo_item() function.
+        * @return void
+        */
+       public function testPostPhotoItem()
+       {
+               $this->markTestIncomplete();
+       }
+
+       /**
+        * Test the prepare_photo_data() function.
+        * @return void
+        */
+       public function testPreparePhotoData()
+       {
+               $this->markTestIncomplete();
+       }
+
+       /**
+        * Test the api_friendica_remoteauth() function.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        */
+       public function testApiFriendicaRemoteauth()
+       {
+               api_friendica_remoteauth();
+       }
+
+       /**
+        * Test the api_friendica_remoteauth() function with an URL.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        */
+       public function testApiFriendicaRemoteauthWithUrl()
+       {
+               $_GET['url'] = 'url';
+               $_GET['c_url'] = 'url';
+               api_friendica_remoteauth();
+       }
+
+       /**
+        * Test the api_friendica_remoteauth() function with a correct URL.
+        * @return void
+        */
+       public function testApiFriendicaRemoteauthWithCorrectUrl()
+       {
+               $this->markTestIncomplete("We can't use an assertion here because of goaway().");
+               $_GET['url'] = 'url';
+               $_GET['c_url'] = $this->selfUser['nurl'];
+               api_friendica_remoteauth();
+       }
+
+       /**
+        * Test the api_share_as_retweet() function.
+        * @return void
+        */
+       public function testApiShareAsRetweet()
+       {
+               $item = [];
+               $result = api_share_as_retweet($item);
+               $this->assertFalse($result);
+       }
+
+       /**
+        * Test the api_share_as_retweet() function with a valid item.
+        * @return void
+        */
+       public function testApiShareAsRetweetWithValidItem()
+       {
+               $this->markTestIncomplete();
+       }
+
+       /**
+        * Test the api_get_nick() function.
+        * @return void
+        */
+       public function testApiGetNick()
+       {
+               $result = api_get_nick($this->otherUser['nurl']);
+               $this->assertEquals('othercontact', $result);
+       }
+
+       /**
+        * Test the api_get_nick() function with a wrong URL.
+        * @return void
+        */
+       public function testApiGetNickWithWrongUrl()
+       {
+               $result = api_get_nick('wrong_url');
+               $this->assertFalse($result);
+       }
+
+       /**
+        * Test the api_in_reply_to() function.
+        * @return void
+        */
+       public function testApiInReplyTo()
+       {
+               $result = api_in_reply_to([]);
+               $this->assertArrayHasKey('status_id', $result);
+               $this->assertArrayHasKey('user_id', $result);
+               $this->assertArrayHasKey('status_id_str', $result);
+               $this->assertArrayHasKey('user_id_str', $result);
+               $this->assertArrayHasKey('screen_name', $result);
+       }
+
+       /**
+        * Test the api_in_reply_to() function with a valid item.
+        * @return void
+        */
+       public function testApiInReplyToWithValidItem()
+       {
+               $this->markTestIncomplete();
+       }
+
+       /**
+        * Test the api_clean_plain_items() function.
+        * @return void
+        */
+       public function testApiCleanPlainItems()
+       {
+               $_REQUEST['include_entities'] = 'true';
+               $result = api_clean_plain_items('some_text [url="some_url"]some_text[/url]');
+               $this->assertEquals('some_text [url="some_url"]"some_url"[/url]', $result);
+       }
+
+       /**
+        * Test the api_clean_attachments() function.
+        * @return void
+        */
+       public function testApiCleanAttachments()
+       {
+               $this->markTestIncomplete();
+       }
+
+       /**
+        * Test the api_best_nickname() function.
+        * @return void
+        */
+       public function testApiBestNickname()
+       {
+               $contacts = [];
+               $result = api_best_nickname($contacts);
+               $this->assertNull($result);
+       }
+
+       /**
+        * Test the api_best_nickname() function with contacts.
+        * @return void
+        */
+       public function testApiBestNicknameWithContacts()
+       {
+               $this->markTestIncomplete();
+       }
+
+       /**
+        * Test the api_friendica_group_show() function.
+        * @return void
+        */
+       public function testApiFriendicaGroupShow()
+       {
+               $this->markTestIncomplete();
+       }
+
+       /**
+        * Test the api_friendica_group_delete() function.
+        * @return void
+        */
+       public function testApiFriendicaGroupDelete()
+       {
+               $this->markTestIncomplete();
+       }
+
+       /**
+        * Test the api_lists_destroy() function.
+        * @return void
+        */
+       public function testApiListsDestroy()
+       {
+               $this->markTestIncomplete();
+       }
+
+       /**
+        * Test the group_create() function.
+        * @return void
+        */
+       public function testGroupCreate()
+       {
+               $this->markTestIncomplete();
+       }
+
+       /**
+        * Test the api_friendica_group_create() function.
+        * @return void
+        */
+       public function testApiFriendicaGroupCreate()
+       {
+               $this->markTestIncomplete();
+       }
+
+       /**
+        * Test the api_lists_create() function.
+        * @return void
+        */
+       public function testApiListsCreate()
+       {
+               $this->markTestIncomplete();
+       }
+
+       /**
+        * Test the api_friendica_group_update() function.
+        * @return void
+        */
+       public function testApiFriendicaGroupUpdate()
+       {
+               $this->markTestIncomplete();
+       }
+
+       /**
+        * Test the api_lists_update() function.
+        * @return void
+        */
+       public function testApiListsUpdate()
+       {
+               $this->markTestIncomplete();
+       }
+
+       /**
+        * Test the api_friendica_activity() function.
+        * @return void
+        */
+       public function testApiFriendicaActivity()
+       {
+               $this->markTestIncomplete();
+       }
+
+       /**
+        * Test the api_friendica_notification() function.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        */
+       public function testApiFriendicaNotification()
+       {
+               api_friendica_notification('json');
+       }
+
+       /**
+        * Test the api_friendica_notification() function without an authenticated user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiFriendicaNotificationWithoutAuthenticatedUser()
+       {
+               $_SESSION['authenticated'] = false;
+               api_friendica_notification('json');
+       }
+
+       /**
+        * Test the api_friendica_notification() function with an argument count.
+        * @return void
+        */
+       public function testApiFriendicaNotificationWithArgumentCount()
+       {
+               $this->app->argc = 3;
+               $result = api_friendica_notification('json');
+               $this->assertEquals(['note' => false], $result);
+       }
+
+       /**
+        * Test the api_friendica_notification() function with an XML result.
+        * @return void
+        */
+       public function testApiFriendicaNotificationWithXmlResult()
+       {
+               $this->markTestIncomplete('Fails with "Invalid argument supplied for foreach()".');
+               $this->app->argc = 3;
+               $result = api_friendica_notification('xml');
+               $this->assertXml($result, 'notes');
+       }
+
+       /**
+        * Test the api_friendica_notification_seen() function.
+        * @return void
+        */
+       public function testApiFriendicaNotificationSeen()
+       {
+               $this->markTestIncomplete();
+       }
+
+       /**
+        * Test the api_friendica_direct_messages_setseen() function.
+        * @return void
+        */
+       public function testApiFriendicaDirectMessagesSetseen()
+       {
+               $this->markTestIncomplete();
+       }
+
+       /**
+        * Test the api_friendica_direct_messages_search() function.
+        * @return void
+        */
+       public function testApiFriendicaDirectMessagesSearch()
+       {
+               $this->markTestIncomplete();
+       }
+
+       /**
+        * Test the api_friendica_profile_show() function.
+        * @return void
+        */
+       public function testApiFriendicaProfileShow()
+       {
+               $result = api_friendica_profile_show('json');
+               // We can't use assertSelfUser() here because the user object is missing some properties.
+               $this->assertEquals($this->selfUser['id'], $result['$result']['friendica_owner']['cid']);
+               $this->assertEquals('Friendica', $result['$result']['friendica_owner']['location']);
+               $this->assertEquals($this->selfUser['name'], $result['$result']['friendica_owner']['name']);
+               $this->assertEquals($this->selfUser['nick'], $result['$result']['friendica_owner']['screen_name']);
+               $this->assertEquals('dfrn', $result['$result']['friendica_owner']['network']);
+               $this->assertTrue($result['$result']['friendica_owner']['verified']);
+               $this->assertFalse($result['$result']['multi_profiles']);
+       }
+
+       /**
+        * Test the api_friendica_profile_show() function with a profile ID.
+        * @return void
+        */
+       public function testApiFriendicaProfileShowWithProfileId()
+       {
+               $this->markTestIncomplete('We need to add a dataset for this.');
+       }
+
+       /**
+        * Test the api_friendica_profile_show() function with a wrong profile ID.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\BadRequestException
+        */
+       public function testApiFriendicaProfileShowWithWrongProfileId()
+       {
+               $_REQUEST['profile_id'] = 666;
+               api_friendica_profile_show('json');
+       }
+
+       /**
+        * Test the api_friendica_profile_show() function without an authenticated user.
+        * @return void
+        * @expectedException Friendica\Network\HTTPException\ForbiddenException
+        */
+       public function testApiFriendicaProfileShowWithoutAuthenticatedUser()
+       {
+               $_SESSION['authenticated'] = false;
+               api_friendica_profile_show('json');
+       }
+
+       /**
+        * Test the api_saved_searches_list() function.
+        * @return void
+        */
+       public function testApiSavedSearchesList()
+       {
+               $result = api_saved_searches_list('json');
+               $this->assertEquals(1, $result['terms'][0]['id']);
+               $this->assertEquals(1, $result['terms'][0]['id_str']);
+               $this->assertEquals('Saved search', $result['terms'][0]['name']);
+               $this->assertEquals('Saved search', $result['terms'][0]['query']);
+       }
+}
index b7b90b138e2914f2c006a74b76f7d854d7159b28..b3d018958354b845245269e2a5a08e1611f27a90 100644 (file)
@@ -7,14 +7,12 @@ namespace Friendica\Test;
 
 use Friendica\App;
 use Friendica\BaseObject;
-// backward compatibility
-if (!class_exists('\PHPUnit\Framework\TestCase')) {
-    class_alias('\PHPUnit_Framework_TestCase', '\PHPUnit\Framework\TestCase');
-}
+use PHPUnit\Framework\TestCase;
+
 /**
  * Tests for the BaseObject class.
  */
-class BaseObjectTest extends \PHPUnit\Framework\TestCase
+class BaseObjectTest extends TestCase
 {
 
        /**
diff --git a/tests/DatabaseTest.php b/tests/DatabaseTest.php
new file mode 100644 (file)
index 0000000..1215093
--- /dev/null
@@ -0,0 +1,63 @@
+<?php
+/**
+ * DatabaseTest class.
+ */
+
+namespace Friendica\Test;
+
+use dba;
+use Friendica\Database\DBStructure;
+use PHPUnit_Extensions_Database_DB_IDatabaseConnection;
+use PHPUnit\DbUnit\DataSet\YamlDataSet;
+use PHPUnit\DbUnit\TestCaseTrait;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * Abstract class used by tests that need a database.
+ */
+abstract class DatabaseTest extends TestCase
+{
+
+       use TestCaseTrait;
+
+       /**
+        * Get database connection.
+        *
+        * This function is executed before each test in order to get a database connection that can be used by tests.
+        * If no prior connection is available, it tries to create one using the USER, PASS and DB environment variables.
+        *
+        * If it could not connect to the database, the test is skipped.
+        *
+        * @return PHPUnit_Extensions_Database_DB_IDatabaseConnection
+        * @see https://phpunit.de/manual/5.7/en/database.html
+        */
+       protected function getConnection()
+       {
+               if (!dba::$connected) {
+                       dba::connect('localhost', getenv('USER'), getenv('PASS'), getenv('DB'));
+
+                       if (dba::$connected) {
+                               $app = get_app();
+                               // We need to do this in order to disable logging
+                               $app->module = 'install';
+
+                               // Create database structure
+                               DBStructure::update(false, true, true);
+                       } else {
+                               $this->markTestSkipped('Could not connect to the database.');
+                       }
+               }
+
+               return $this->createDefaultDBConnection(dba::get_db(), getenv('DB'));
+       }
+
+       /**
+        * Get dataset to populate the database with.
+        * @return YamlDataSet
+        * @see https://phpunit.de/manual/5.7/en/database.html
+        */
+       protected function getDataSet()
+       {
+               return new YamlDataSet(__DIR__ . '/datasets/api.yml');
+       }
+}
index 3cda2342f36b88aa36f7a5ff1759fed4ddc23b67..ac1b7d7757b580eeccc38fa160b4cd983c4dcc1d 100644 (file)
@@ -5,15 +5,12 @@
 
 namespace Friendica\Test;
 
-// backward compatibility
-if (!class_exists('\PHPUnit\Framework\TestCase')) {
-    class_alias('\PHPUnit_Framework_TestCase', '\PHPUnit\Framework\TestCase');
-}
+use PHPUnit\Framework\TestCase;
 
 /**
  * Tests for text functions.
  */
-class TextTest extends \PHPUnit\Framework\TestCase
+class TextTest extends TestCase
 {
 
        /**
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
new file mode 100644 (file)
index 0000000..4474e4e
--- /dev/null
@@ -0,0 +1,22 @@
+<?php
+/**
+ * This file is loaded by PHPUnit before any test.
+ */
+
+use PHPUnit\DbUnit\DataSet\YamlDataSet;
+use PHPUnit\DbUnit\TestCaseTrait;
+use PHPUnit\Framework\TestCase;
+
+require_once __DIR__.'/../boot.php';
+require_once __DIR__.'/../include/api.php';
+
+// Backward compatibility
+if (!class_exists(TestCase::class)) {
+       class_alias(PHPUnit_Framework_TestCase::class, TestCase::class);
+}
+if (!trait_exists(TestCaseTrait::class)) {
+       class_alias(PHPUnit_Extensions_Database_TestCase_Trait::class, TestCaseTrait::class);
+}
+if (!class_exists(YamlDataSet::class)) {
+       class_alias(PHPUnit_Extensions_Database_DataSet_YamlDataSet::class, YamlDataSet::class);
+}
diff --git a/tests/datasets/api.yml b/tests/datasets/api.yml
new file mode 100644 (file)
index 0000000..ae1fd32
--- /dev/null
@@ -0,0 +1,192 @@
+---
+# Empty these tables
+cache:
+config:
+conversation:
+pconfig:
+photo:
+workerqueue:
+mail:
+
+# Populate tables with test data
+user:
+    -
+        uid: 42
+        username: Test user
+        nickname: selfcontact
+        verified: true
+        password: $2y$10$DLRNTRmJgKe1cSrFJ5Jb0edCqvXlA9sh/RHdSnfxjbR.04yZRm4Qm
+        theme: frio
+
+contact:
+    -
+        id: 42
+        uid: 42
+        name: Self contact
+        nick: selfcontact
+        self: true
+        nurl: http://localhost/profile/selfcontact
+        url: http://localhost/profile/selfcontact
+        about: User used in tests
+        pending: false
+        blocked: false
+        rel: 1
+        network: dfrn
+    -
+        id: 43
+        uid: 0
+        # Having the same name and nick allows us to test
+        # the fallback to api_get_nick() in api_get_user()
+        name: othercontact
+        nick: othercontact
+        self: false
+        nurl: http://localhost/profile/othercontact
+        url: http://localhost/profile/othercontact
+        pending: false
+        blocked: false
+        rel: 0
+        network: dfrn
+    -
+        id: 44
+        uid: 42
+        name: Friend contact
+        nick: friendcontact
+        self: false
+        nurl: http://localhost/profile/friendcontact
+        url: http://localhost/profile/friendcontact
+        pending: false
+        blocked: false
+        rel: 2
+        network: dfrn
+
+item:
+    -
+        id: 1
+        visible: true
+        contact-id: 42
+        author-id: 42
+        owner-id: 42
+        uid: 42
+        verb: http://activitystrea.ms/schema/1.0/post
+        unseen: true
+        body: Parent status
+        parent: 1
+        author-link: http://localhost/profile/selfcontact
+        wall: true
+        starred: true
+        allow_cid: ''
+        allow_gid: ''
+        deny_cid: ''
+        deny_gid: ''
+    -
+        id: 2
+        visible: true
+        contact-id: 42
+        author-id: 42
+        owner-id: 42
+        uid: 42
+        verb: http://activitystrea.ms/schema/1.0/post
+        unseen: false
+        body: Reply
+        parent: 1
+        author-link: http://localhost/profile/selfcontact
+        wall: true
+        starred: false
+    -
+        id: 3
+        visible: true
+        contact-id: 43
+        author-id: 43
+        owner-id: 42
+        uid: 42
+        verb: http://activitystrea.ms/schema/1.0/post
+        unseen: false
+        body: Other user status
+        parent: 3
+        author-link: http://localhost/profile/othercontact
+        wall: true
+        starred: false
+    -
+        id: 4
+        visible: true
+        contact-id: 43
+        author-id: 43
+        owner-id: 42
+        uid: 42
+        verb: http://activitystrea.ms/schema/1.0/post
+        unseen: false
+        body: Other user reply
+        parent: 1
+        author-link: http://localhost/profile/othercontact
+        wall: true
+        starred: false
+    -
+        id: 5
+        visible: true
+        contact-id: 42
+        author-id: 42
+        owner-id: 42
+        uid: 42
+        verb: http://activitystrea.ms/schema/1.0/post
+        unseen: false
+        body: '[share]Shared status[/share]'
+        parent: 1
+        author-link: http://localhost/profile/othercontact
+        wall: true
+        starred: false
+        allow_cid: ''
+        allow_gid: ''
+        deny_cid: ''
+        deny_gid: ''
+    -
+        id: 6
+        visible: true
+        contact-id: 44
+        author-id: 44
+        owner-id: 42
+        uid: 42
+        verb: http://activitystrea.ms/schema/1.0/post
+        unseen: false
+        body: Friend user status
+        parent: 6
+        author-link: http://localhost/profile/othercontact
+        wall: true
+        starred: false
+
+thread:
+    -
+        iid: 1
+        visible: true
+        contact-id: 42
+        uid: 42
+        wall: true
+    -
+        iid: 3
+        visible: true
+        contact-id: 43
+        uid: 0
+        wall: true
+    -
+        iid: 6
+        visible: true
+        contact-id: 44
+        uid: 0
+        wall: true
+
+group:
+    -
+        id: 1
+        uid: 42
+        visible: true
+        name: Visible list
+    -
+        id: 2
+        uid: 42
+        visible: false
+        name: Private list
+
+search:
+    -
+        id: 1
+        term: Saved search
+        uid: 42