diff --git a/bin/worker.php b/bin/worker.php index cb09a4929d..d5cd1f6b4b 100755 --- a/bin/worker.php +++ b/bin/worker.php @@ -4,12 +4,9 @@ * @file bin/worker.php * @brief Starts the background processing */ - use Friendica\App; -use Friendica\Core\Addon; use Friendica\Core\Config; use Friendica\Core\Worker; -use Friendica\Core\L10n; // Get options $shortopts = 'sn'; @@ -20,10 +17,10 @@ $options = getopt($shortopts, $longopts); if (!file_exists("boot.php") && (sizeof($_SERVER["argv"]) != 0)) { $directory = dirname($_SERVER["argv"][0]); - if (substr($directory, 0, 1) != "/") { - $directory = $_SERVER["PWD"]."/".$directory; + if (substr($directory, 0, 1) != '/') { + $directory = $_SERVER["PWD"] . '/' . $directory; } - $directory = realpath($directory."/.."); + $directory = realpath($directory . '/..'); chdir($directory); } @@ -32,23 +29,16 @@ require_once "boot.php"; $a = new App(dirname(__DIR__)); -Config::load(); - -$lang = L10n::getBrowserLanguage(); -L10n::loadTranslationTable($lang); - // Check the database structure and possibly fixes it check_db(true); // Quit when in maintenance -if (Config::get('system', 'maintenance', false, true)) { +if (!$a->getMode()->has(App\Mode::MAINTENANCEDISABLED)) { return; } $a->setBaseURL(Config::get('system', 'url')); -Addon::loadHooks(); - $spawn = array_key_exists('s', $options) || array_key_exists('spawn', $options); if ($spawn) { @@ -63,5 +53,3 @@ Worker::processQueue($run_cron); Worker::unclaimProcess(); Worker::endProcess(); - -killme(); diff --git a/boot.php b/boot.php index d55f4b7bc9..7fb87ca4eb 100644 --- a/boot.php +++ b/boot.php @@ -41,7 +41,6 @@ define('FRIENDICA_PLATFORM', 'Friendica'); define('FRIENDICA_CODENAME', 'The Tazmans Flax-lily'); define('FRIENDICA_VERSION', '2018.12-dev'); define('DFRN_PROTOCOL_VERSION', '2.23'); -define('DB_UPDATE_VERSION', 1289); define('NEW_UPDATE_ROUTINE_VERSION', 1170); /** @@ -345,11 +344,6 @@ define('SR_SCOPE_ALL', 'all'); define('SR_SCOPE_TAGS', 'tags'); /* @}*/ -/** - * Lowest possible date time value - */ -define('NULL_DATE', '0001-01-01 00:00:00'); - // Normally this constant is defined - but not if "pcntl" isn't installed if (!defined("SIGTERM")) { define("SIGTERM", 15); @@ -598,21 +592,6 @@ function killme() exit(); } -/** - * @brief Redirect to another URL and terminate this process. - */ -function goaway($path = '') -{ - if (strstr(normalise_link($path), 'http://')) { - $url = $path; - } else { - $url = System::baseUrl() . '/' . ltrim($path, '/'); - } - - header("Location: $url"); - killme(); -} - /** * @brief Returns the user id of locally logged in user or false. * diff --git a/config/config.ini.php b/config/config.ini.php index a324e709ec..3031d7d504 100644 --- a/config/config.ini.php +++ b/config/config.ini.php @@ -369,6 +369,18 @@ throttle_limit_month = 0 ; For instance if your URL is 'http://example.com/directory/subdirectory', set urlpath to 'directory/subdirectory'. urlpath = +; username_min_length (Integer) +; The minimum character length a username can be. +; This length is check once the username has been trimmed and multiple spaces have been collapsed into one. +; Minimum for this config value is 1. Maximum is 64 as the resulting profile URL mustn't be longer than 255 chars. +username_min_length = 3 + +; username_max_length (Integer) +; The maximum character length a username can be. +; This length is check once the username has been trimmed and multiple spaces have been collapsed into one. +; Minimum for this config value is 1. Maximum is 64 as the resulting profile URL mustn't be longer than 255 chars. +username_max_length = 48 + ; worker_cooldown (Integer) ; Cooldown period in seconds after each worker function call. worker_cooldown = 0 diff --git a/config/dbstructure.json b/config/dbstructure.json deleted file mode 100644 index 43fce1d2f9..0000000000 --- a/config/dbstructure.json +++ /dev/null @@ -1,1326 +0,0 @@ -{ - "addon": { - "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": "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"], - "name": ["UNIQUE", "name"] - } - }, - "apcontact": { - "comment": "ActivityPub compatible contacts - used in the ActivityPub implementation", - "fields": { - "url": {"type": "varbinary(255)", "not null": "1", "primary": "1", "comment": "URL of the contact"}, - "uuid": {"type": "varchar(255)", "comment": ""}, - "type": {"type": "varchar(20)", "not null": "1", "comment": ""}, - "following": {"type": "varchar(255)", "comment": ""}, - "followers": {"type": "varchar(255)", "comment": ""}, - "inbox": {"type": "varchar(255)", "not null": "1", "comment": ""}, - "outbox": {"type": "varchar(255)", "comment": ""}, - "sharedinbox": {"type": "varchar(255)", "comment": ""}, - "nick": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "name": {"type": "varchar(255)", "comment": ""}, - "about": {"type": "text", "comment": ""}, - "photo": {"type": "varchar(255)", "comment": ""}, - "addr": {"type": "varchar(255)", "comment": ""}, - "alias": {"type": "varchar(255)", "comment": ""}, - "pubkey": {"type": "text", "comment": ""}, - "baseurl": {"type": "varchar(255)", "comment": "baseurl of the ap contact"}, - "updated": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": ""} - - }, - "indexes": { - "PRIMARY": ["url"], - "addr": ["addr(32)"], - "alias": ["alias(190)"], - "url": ["followers(190)"] - } - }, - "attach": { - "comment": "file attachments", - "fields": { - "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": "0001-01-01 00:00:00", "comment": "creation time"}, - "edited": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "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"] - } - }, - "auth_codes": { - "comment": "OAuth usage", - "fields": { - "id": {"type": "varchar(40)", "not null": "1", "primary": "1", "comment": ""}, - "client_id": {"type": "varchar(20)", "not null": "1", "default": "", "relation": {"clients": "client_id"}, "comment": ""}, - "redirect_uri": {"type": "varchar(200)", "not null": "1", "default": "", "comment": ""}, - "expires": {"type": "int", "not null": "1", "default": "0", "comment": ""}, - "scope": {"type": "varchar(250)", "not null": "1", "default": "", "comment": ""} - }, - "indexes": { - "PRIMARY": ["id"] - } - }, - "cache": { - "comment": "Stores temporary data", - "fields": { - "k": {"type": "varbinary(255)", "not null": "1", "primary": "1", "comment": "cache key"}, - "v": {"type": "mediumtext", "comment": "cached serialized value"}, - "expires": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": "datetime of cache expiration"}, - "updated": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": "datetime of cache insertion"} - }, - "indexes": { - "PRIMARY": ["k"], - "k_expires": ["k", "expires"] - } - }, - "challenge": { - "comment": "", - "fields": { - "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": ""}, - "type": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "last_update": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""} - }, - "indexes": { - "PRIMARY": ["id"] - } - }, - "clients": { - "comment": "OAuth usage", - "fields": { - "client_id": {"type": "varchar(20)", "not null": "1", "primary": "1", "comment": ""}, - "pw": {"type": "varchar(20)", "not null": "1", "default": "", "comment": ""}, - "redirect_uri": {"type": "varchar(200)", "not null": "1", "default": "", "comment": ""}, - "name": {"type": "text", "comment": ""}, - "icon": {"type": "text", "comment": ""}, - "uid": {"type": "mediumint unsigned", "not null": "1", "default": "0", "relation": {"user": "uid"}, "comment": "User id"} - }, - "indexes": { - "PRIMARY": ["client_id"] - } - }, - "config": { - "comment": "main configuration storage", - "fields": { - "id": {"type": "int unsigned", "not null": "1", "extra": "auto_increment", "primary": "1", "comment": ""}, - "cat": {"type": "varbinary(50)", "not null": "1", "default": "", "comment": ""}, - "k": {"type": "varbinary(50)", "not null": "1", "default": "", "comment": ""}, - "v": {"type": "mediumtext", "comment": ""} - }, - "indexes": { - "PRIMARY": ["id"], - "cat_k": ["UNIQUE", "cat", "k"] - } - }, - "contact": { - "comment": "contact table", - "fields": { - "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": "0001-01-01 00:00:00", "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": "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": "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": "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": "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": ""}, - "url": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "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": "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": ""}, - "poll": {"type": "varchar(255)", "comment": ""}, - "confirm": {"type": "varchar(255)", "comment": ""}, - "poco": {"type": "varchar(255)", "comment": ""}, - "aes_allow": {"type": "boolean", "not null": "1", "default": "0", "comment": ""}, - "ret-aes": {"type": "boolean", "not null": "1", "default": "0", "comment": ""}, - "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": "0001-01-01 00:00:00", "comment": "Date of the last try to update the contact info"}, - "success_update": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": "Date of the last successful contact update"}, - "failure_update": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": "Date of the last failed update"}, - "name-date": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": ""}, - "uri-date": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": ""}, - "avatar-date": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": ""}, - "term-date": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": ""}, - "last-item": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "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": "posts of the contact are readonly"}, - "writable": {"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": ""}, - "pending": {"type": "boolean", "not null": "1", "default": "1", "comment": ""}, - "deleted": {"type": "boolean", "not null": "1", "default": "0", "comment": "Contact has been deleted"}, - "rating": {"type": "tinyint", "not null": "1", "default": "0", "comment": ""}, - "reason": {"type": "text", "comment": ""}, - "closeness": {"type": "tinyint unsigned", "not null": "1", "default": "99", "comment": ""}, - "info": {"type": "mediumtext", "comment": ""}, - "profile-id": {"type": "int unsigned", "not null": "1", "default": "0", "comment": ""}, - "bdyear": {"type": "varchar(4)", "not null": "1", "default": "", "comment": ""}, - "bd": {"type": "date", "not null": "1", "default": "0001-01-01", "comment": ""}, - "notify_new_posts": {"type": "boolean", "not null": "1", "default": "0", "comment": ""}, - "fetch_further_information": {"type": "tinyint unsigned", "not null": "1", "default": "0", "comment": ""}, - "ffi_keyword_blacklist": {"type": "text", "comment": ""} - }, - "indexes": { - "PRIMARY": ["id"], - "uid_name": ["uid", "name(190)"], - "self_uid": ["self", "uid"], - "alias_uid": ["alias(32)", "uid"], - "pending_uid": ["pending", "uid"], - "blocked_uid": ["blocked", "uid"], - "uid_rel_network_poll": ["uid", "rel", "network", "poll(64)", "archive"], - "uid_network_batch": ["uid", "network", "batch(64)"], - "addr_uid": ["addr(32)", "uid"], - "nurl_uid": ["nurl(32)", "uid"], - "nick_uid": ["nick(32)", "uid"], - "dfrn-id": ["dfrn-id(64)"], - "issued-id": ["issued-id(64)"] - } - }, - "conv": { - "comment": "private messages", - "fields": { - "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": "0001-01-01 00:00:00", "comment": "creation timestamp"}, - "updated": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": "edited timestamp"}, - "subject": {"type": "text", "comment": "subject of initial message"} - }, - "indexes": { - "PRIMARY": ["id"], - "uid": ["uid"] - } - }, - "conversation": { - "comment": "Raw data and structure information for messages", - "fields": { - "item-uri": {"type": "varbinary(255)", "not null": "1", "primary": "1", "comment": "Original URI of the item - unrelated to the table with the same name"}, - "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": "255", "comment": "The protocol of the item"}, - "source": {"type": "mediumtext", "comment": "Original source"}, - "received": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": "Receiving date"} - }, - "indexes": { - "PRIMARY": ["item-uri"], - "conversation-uri": ["conversation-uri"], - "received": ["received"] - } - }, - "diaspora-interaction": { - "comment": "Signed Diaspora Interaction", - "fields": { - "uri-id": {"type": "int unsigned", "not null": "1", "primary": "1", "relation": {"item-uri": "id"}, "comment": "Id of the item-uri table entry that contains the item uri"}, - "interaction": {"type": "mediumtext", "comment": "The Diaspora interaction"} - }, - "indexes": { - "PRIMARY": ["uri-id"] - } - }, - "event": { - "comment": "Events", - "fields": { - "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": "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": "0001-01-01 00:00:00", "comment": "creation time"}, - "edited": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": "last edit time"}, - "start": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": "event start time"}, - "finish": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "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"], - "uid_start": ["uid", "start"] - } - }, - "fcontact": { - "comment": "Diaspora compatible contacts - used in the Diaspora implementation", - "fields": { - "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": ""}, - "request": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "nick": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "addr": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "batch": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "notify": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "poll": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "confirm": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "priority": {"type": "tinyint unsigned", "not null": "1", "default": "0", "comment": ""}, - "network": {"type": "char(4)", "not null": "1", "default": "", "comment": ""}, - "alias": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "pubkey": {"type": "text", "comment": ""}, - "updated": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": ""} - }, - "indexes": { - "PRIMARY": ["id"], - "addr": ["addr(32)"], - "url": ["UNIQUE", "url(190)"] - } - }, - "fsuggest": { - "comment": "friend suggestion stuff", - "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"}, - "cid": {"type": "int unsigned", "not null": "1", "default": "0", "relation": {"contact": "id"}, "comment": ""}, - "name": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "url": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "request": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "photo": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "note": {"type": "text", "comment": ""}, - "created": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": ""} - }, - "indexes": { - "PRIMARY": ["id"] - } - }, - "gcign": { - "comment": "contacts ignored by friend suggestions", - "fields": { - "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"], - "uid": ["uid"], - "gcid": ["gcid"] - } - }, - "gcontact": { - "comment": "global contacts", - "fields": { - "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": "Link to the profile photo"}, - "connect": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "created": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": ""}, - "updated": {"type": "datetime", "default": "0001-01-01 00:00:00", "comment": ""}, - "last_contact": {"type": "datetime", "default": "0001-01-01 00:00:00", "comment": ""}, - "last_failure": {"type": "datetime", "default": "0001-01-01 00:00:00", "comment": ""}, - "location": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "about": {"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": "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": "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": "baseurl of the contacts server"} - }, - "indexes": { - "PRIMARY": ["id"], - "nurl": ["UNIQUE", "nurl(190)"], - "name": ["name(64)"], - "nick": ["nick(32)"], - "addr": ["addr(64)"], - "hide_network_updated": ["hide", "network", "updated"], - "updated": ["updated"] - } - }, - "glink": { - "comment": "'friends of friends' linkages derived from poco", - "fields": { - "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": ""}, - "zcid": {"type": "int unsigned", "not null": "1", "default": "0", "relation": {"gcontact": "id"}, "comment": ""}, - "updated": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": ""} - }, - "indexes": { - "PRIMARY": ["id"], - "cid_uid_gcid_zcid": ["UNIQUE", "cid", "uid", "gcid", "zcid"], - "gcid": ["gcid"] - } - }, - "group": { - "comment": "privacy groups, group info", - "fields": { - "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"], - "uid": ["uid"] - } - }, - "group_member": { - "comment": "privacy groups, member info", - "fields": { - "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"], - "contactid": ["contact-id"], - "gid_contactid": ["UNIQUE", "gid", "contact-id"] - } - }, - "gserver": { - "comment": "Global servers", - "fields": { - "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": "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": ""}, - "platform": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "relay-subscribe": {"type": "boolean", "not null": "1", "default": "0", "comment": "Has the server subscribed to the relay system"}, - "relay-scope": {"type": "varchar(10)", "not null": "1", "default": "", "comment": "The scope of messages that the server wants to get"}, - "created": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": ""}, - "last_poco_query": {"type": "datetime", "default": "0001-01-01 00:00:00", "comment": ""}, - "last_contact": {"type": "datetime", "default": "0001-01-01 00:00:00", "comment": ""}, - "last_failure": {"type": "datetime", "default": "0001-01-01 00:00:00", "comment": ""} - }, - "indexes": { - "PRIMARY": ["id"], - "nurl": ["UNIQUE", "nurl(190)"] - } - }, - "gserver-tag": { - "comment": "Tags that the server has subscribed", - "fields": { - "gserver-id": {"type": "int unsigned", "not null": "1", "default": "0", "relation": {"gserver": "id"}, "primary": "1", "comment": "The id of the gserver"}, - "tag": {"type": "varchar(100)", "not null": "1", "default": "", "primary": "1", "comment": "Tag that the server has subscribed"} - }, - "indexes": { - "PRIMARY": ["gserver-id", "tag"], - "tag": ["tag"] - } - }, - "hook": { - "comment": "addon hook registry", - "fields": { - "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"], - "hook_file_function": ["UNIQUE", "hook", "file", "function"] - } - }, - "intro": { - "comment": "", - "fields": { - "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": ""}, - "knowyou": {"type": "boolean", "not null": "1", "default": "0", "comment": ""}, - "duplex": {"type": "boolean", "not null": "1", "default": "0", "comment": ""}, - "note": {"type": "text", "comment": ""}, - "hash": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "datetime": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": ""}, - "blocked": {"type": "boolean", "not null": "1", "default": "1", "comment": ""}, - "ignore": {"type": "boolean", "not null": "1", "default": "0", "comment": ""} - }, - "indexes": { - "PRIMARY": ["id"] - } - }, - "item": { - "comment": "Structure for 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": "A unique identifier for this item"}, - "uri": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "uri-id": {"type": "int unsigned", "relation": {"item-uri": "id"}, "comment": "Id of the item-uri table entry that contains the item uri"}, - "uri-hash": {"type": "varchar(80)", "not null": "1", "default": "", "comment": "RIPEMD-128 hash from uri"}, - "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"}, - "parent-uri-id": {"type": "int unsigned", "relation": {"item-uri": "id"}, "comment": "Id of the item-uri table that contains the parent uri"}, - "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"}, - "thr-parent-id": {"type": "int unsigned", "relation": {"item-uri": "id"}, "comment": "Id of the item-uri table that contains the thread parent uri"}, - "created": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": "Creation timestamp."}, - "edited": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": "Date of last edit (default is created)"}, - "commented": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": "Date of last comment/reply to this item"}, - "received": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": "datetime"}, - "changed": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": "Date that something in the conversation changed, indicating clients should fetch the conversation again"}, - "gravity": {"type": "tinyint unsigned", "not null": "1", "default": "0", "comment": ""}, - "network": {"type": "char(4)", "not null": "1", "default": "", "comment": "Network from where the item comes from"}, - "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"}, - "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"}, - "icid": {"type": "int unsigned", "relation": {"item-content": "id"}, "comment": "Id of the item-content table entry that contains the whole item content"}, - "iaid": {"type": "int unsigned", "relation": {"item-activity": "id"}, "comment": "Id of the item-activity table entry that contains the activity data"}, - "extid": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "post-type": {"type": "tinyint unsigned", "not null": "1", "default": "0", "comment": "Post type (personal note, bookmark, ...)"}, - "global": {"type": "boolean", "not null": "1", "default": "0", "comment": ""}, - "private": {"type": "boolean", "not null": "1", "default": "0", "comment": "distribution is restricted"}, - "visible": {"type": "boolean", "not null": "1", "default": "0", "comment": ""}, - "moderated": {"type": "boolean", "not null": "1", "default": "0", "comment": ""}, - "deleted": {"type": "boolean", "not null": "1", "default": "0", "comment": "item has been deleted"}, - "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"}, - "wall": {"type": "boolean", "not null": "1", "default": "0", "comment": "This item was posted to the wall of uid"}, - "origin": {"type": "boolean", "not null": "1", "default": "0", "comment": "item originated at this site"}, - "pubmail": {"type": "boolean", "not null": "1", "default": "0", "comment": ""}, - "starred": {"type": "boolean", "not null": "1", "default": "0", "comment": "item has been favourited"}, - "unseen": {"type": "boolean", "not null": "1", "default": "1", "comment": "item has not been seen"}, - "mention": {"type": "boolean", "not null": "1", "default": "0", "comment": "The owner of this item was mentioned in it"}, - "forum_mode": {"type": "tinyint unsigned", "not null": "1", "default": "0", "comment": ""}, - "psid": {"type": "int unsigned", "relation": {"permissionset": "id"}, "comment": "ID of the permission set of this post"}, - "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"}, - "attach": {"type": "mediumtext", "comment": "JSON structure representing attachments to this item"}, - "allow_cid": {"type": "mediumtext", "comment": "Deprecated"}, - "allow_gid": {"type": "mediumtext", "comment": "Deprecated"}, - "deny_cid": {"type": "mediumtext", "comment": "Deprecated"}, - "deny_gid": {"type": "mediumtext", "comment": "Deprecated"}, - "postopts": {"type": "text", "comment": "Deprecated"}, - "inform": {"type": "mediumtext", "comment": "Deprecated"}, - "type": {"type": "varchar(20)", "comment": "Deprecated"}, - "bookmark": {"type": "boolean", "comment": "Deprecated"}, - "file": {"type": "mediumtext", "comment": "Deprecated"}, - "location": {"type": "varchar(255)", "comment": "Deprecated"}, - "coord": {"type": "varchar(255)", "comment": "Deprecated"}, - "tag": {"type": "mediumtext", "comment": "Deprecated"}, - "plink": {"type": "varchar(255)", "comment": "Deprecated"}, - "title": {"type": "varchar(255)", "comment": "Deprecated"}, - "content-warning": {"type": "varchar(255)", "comment": "Deprecated"}, - "body": {"type": "mediumtext", "comment": "Deprecated"}, - "app": {"type": "varchar(255)", "comment": "Deprecated"}, - "verb": {"type": "varchar(100)", "comment": "Deprecated"}, - "object-type": {"type": "varchar(100)", "comment": "Deprecated"}, - "object": {"type": "text", "comment": "Deprecated"}, - "target-type": {"type": "varchar(100)", "comment": "Deprecated"}, - "target": {"type": "text", "comment": "Deprecated"}, - "author-name": {"type": "varchar(255)", "comment": "Deprecated"}, - "author-link": {"type": "varchar(255)", "comment": "Deprecated"}, - "author-avatar": {"type": "varchar(255)", "comment": "Deprecated"}, - "owner-name": {"type": "varchar(255)", "comment": "Deprecated"}, - "owner-link": {"type": "varchar(255)", "comment": "Deprecated"}, - "owner-avatar": {"type": "varchar(255)", "comment": "Deprecated"}, - "rendered-hash": {"type": "varchar(32)", "comment": "Deprecated"}, - "rendered-html": {"type": "mediumtext", "comment": "Deprecated"} - }, - "indexes": { - "PRIMARY": ["id"], - "guid": ["guid(191)"], - "uri": ["uri(191)"], - "parent": ["parent"], - "parent-uri": ["parent-uri(191)"], - "extid": ["extid(191)"], - "uid_id": ["uid", "id"], - "uid_contactid_id": ["uid", "contact-id", "id"], - "uid_created": ["uid", "created"], - "uid_commented": ["uid", "commented"], - "uid_unseen_contactid": ["uid", "unseen", "contact-id"], - "uid_network_received": ["uid", "network", "received"], - "uid_network_commented": ["uid", "network", "commented"], - "uid_thrparent": ["uid", "thr-parent(190)"], - "uid_parenturi": ["uid", "parent-uri(190)"], - "uid_contactid_created": ["uid", "contact-id", "created"], - "authorid_created": ["author-id", "created"], - "ownerid": ["owner-id"], - "uid_uri": ["uid", "uri(190)"], - "resource-id": ["resource-id"], - "deleted_changed": ["deleted", "changed"], - "uid_wall_changed": ["uid", "wall", "changed"], - "uid_eventid": ["uid", "event-id"], - "icid": ["icid"], - "iaid": ["iaid"], - "psid_wall": ["psid", "wall"] - } - }, - "item-activity": { - "comment": "Activities for items", - "fields": { - "id": {"type": "int unsigned", "not null": "1", "extra": "auto_increment", "primary": "1", "relation": {"thread": "iid"}}, - "uri": {"type": "varchar(255)", "comment": ""}, - "uri-id": {"type": "int unsigned", "relation": {"item-uri": "id"}, "comment": "Id of the item-uri table entry that contains the item uri"}, - "uri-hash": {"type": "varchar(80)", "not null": "1", "default": "", "comment": "RIPEMD-128 hash from uri"}, - "activity": {"type": "smallint unsigned", "not null": "1", "default": "0", "comment": ""} - }, - "indexes": { - "PRIMARY": ["id"], - "uri-hash": ["UNIQUE", "uri-hash"], - "uri": ["uri(191)"], - "uri-id": ["uri-id"] - } - }, - "item-content": { - "comment": "Content for all posts", - "fields": { - "id": {"type": "int unsigned", "not null": "1", "extra": "auto_increment", "primary": "1", "relation": {"thread": "iid"}}, - "uri": {"type": "varchar(255)", "comment": ""}, - "uri-id": {"type": "int unsigned", "relation": {"item-uri": "id"}, "comment": "Id of the item-uri table entry that contains the item uri"}, - "uri-plink-hash": {"type": "varchar(80)", "not null": "1", "default": "", "comment": "RIPEMD-128 hash from uri"}, - "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": "item body content"}, - "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"}, - "language": {"type": "text", "comment": "Language information about this post"}, - "app": {"type": "varchar(255)", "not null": "1", "default": "", "comment": "application which generated this item"}, - "rendered-hash": {"type": "varchar(32)", "not null": "1", "default": "", "comment": ""}, - "rendered-html": {"type": "mediumtext", "comment": "item.body converted to html"}, - "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"}, - "plink": {"type": "varchar(255)", "not null": "1", "default": "", "comment": "permalink or URL to a displayable copy of the message at its source"}, - "verb": {"type": "varchar(100)", "not null": "1", "default": "", "comment": "ActivityStreams verb"} - }, - "indexes": { - "PRIMARY": ["id"], - "uri-plink-hash": ["UNIQUE", "uri-plink-hash"], - "uri": ["uri(191)"], - "uri-id": ["uri-id"] - } - }, - "item-delivery-data": { - "comment": "Delivery data for items", - "fields": { - "iid": {"type": "int unsigned", "not null": "1", "primary": "1", "relation": {"item": "id"}, "comment": "Item id"}, - "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"}, - "inform": {"type": "mediumtext", "comment": "Additional receivers of the linked item"} - }, - "indexes": { - "PRIMARY": ["iid"] - } - }, - "item-uri": { - "comment": "URI and GUID for items", - "fields": { - "id": {"type": "int unsigned", "not null": "1", "extra": "auto_increment", "primary": "1"}, - "uri": {"type": "varbinary(255)", "not null": "1", "comment": "URI of an item"}, - "guid": {"type": "varbinary(255)", "comment": "A unique identifier for an item"} - }, - "indexes": { - "PRIMARY": ["id"], - "uri": ["UNIQUE", "uri"], - "guid": ["guid"] - } - }, - "locks": { - "comment": "", - "fields": { - "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": "Process ID"}, - "expires": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": "datetime of cache expiration"} - }, - "indexes": { - "PRIMARY": ["id"], - "name_expires": ["name", "expires"] - } - }, - "mail": { - "comment": "private messages", - "fields": { - "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": "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": "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": "0001-01-01 00:00:00", "comment": "creation time of the private message"} - }, - "indexes": { - "PRIMARY": ["id"], - "uid_seen": ["uid", "seen"], - "convid": ["convid"], - "uri": ["uri(64)"], - "parent-uri": ["parent-uri(64)"], - "contactid": ["contact-id(32)"] - } - }, - "mailacct": { - "comment": "Mail account data for fetching mails", - "fields": { - "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": ""}, - "ssltype": {"type": "varchar(16)", "not null": "1", "default": "", "comment": ""}, - "mailbox": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "user": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "pass": {"type": "text", "comment": ""}, - "reply_to": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "action": {"type": "tinyint unsigned", "not null": "1", "default": "0", "comment": ""}, - "movetofolder": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "pubmail": {"type": "boolean", "not null": "1", "default": "0", "comment": ""}, - "last_check": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": ""} - }, - "indexes": { - "PRIMARY": ["id"] - } - }, - "manage": { - "comment": "table of accounts that can manage each other", - "fields": { - "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"} - }, - "indexes": { - "PRIMARY": ["id"], - "uid_mid": ["UNIQUE", "uid", "mid"] - } - }, - "notify": { - "comment": "notifications", - "fields": { - "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": ""}, - "url": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "photo": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "date": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": ""}, - "msg": {"type": "mediumtext", "comment": ""}, - "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": "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": "Cached bbcode parsing of name"}, - "msg_cache": {"type": "mediumtext", "comment": "Cached bbcode parsing of msg"} - }, - "indexes": { - "PRIMARY": ["id"], - "hash_uid": ["hash", "uid"], - "seen_uid_date": ["seen", "uid", "date"], - "uid_date": ["uid", "date"], - "uid_type_link": ["uid", "type", "link(190)"] - } - }, - "notify-threads": { - "comment": "", - "fields": { - "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": ""}, - "receiver-uid": {"type": "mediumint unsigned", "not null": "1", "default": "0", "relation": {"user": "uid"}, "comment": "User id"} - }, - "indexes": { - "PRIMARY": ["id"] - } - }, - "oembed": { - "comment": "cache for OEmbed queries", - "fields": { - "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": "0001-01-01 00:00:00", "comment": "datetime of creation"} - }, - "indexes": { - "PRIMARY": ["url", "maxwidth"], - "created": ["created"] - } - }, - "openwebauth-token": { - "comment": "Store OpenWebAuth token to verify contacts", - "fields": { - "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"}, - "type": {"type": "varchar(32)", "not null": "1", "default": "", "comment": "Verify type"}, - "token": {"type": "varchar(255)", "not null": "1", "default": "", "comment": "A generated token"}, - "meta": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "created": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": "datetime of creation"} - }, - "indexes": { - "PRIMARY": ["id"] - } - }, - "parsed_url": { - "comment": "cache for 'parse_url' queries", - "fields": { - "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": "0001-01-01 00:00:00", "comment": "datetime of creation"} - }, - "indexes": { - "PRIMARY": ["url", "guessing", "oembed"], - "created": ["created"] - } - }, - "participation": { - "comment": "Storage for participation messages from Diaspora", - "fields": { - "iid": {"type": "int unsigned", "not null": "1", "primary": "1", "relation": {"item": "id"}, "comment": ""}, - "server": {"type": "varchar(60)", "not null": "1", "primary": "1", "comment": ""}, - "cid": {"type": "int unsigned", "not null": "1", "relation": {"contact": "id"}, "comment": ""}, - "fid": {"type": "int unsigned", "not null": "1", "relation": {"fcontact": "id"}, "comment": ""} - }, - "indexes": { - "PRIMARY": ["iid", "server"] - } - }, - "pconfig": { - "comment": "personal (per user) configuration 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"}, - "cat": {"type": "varbinary(50)", "not null": "1", "default": "", "comment": ""}, - "k": {"type": "varbinary(100)", "not null": "1", "default": "", "comment": ""}, - "v": {"type": "mediumtext", "comment": ""} - }, - "indexes": { - "PRIMARY": ["id"], - "uid_cat_k": ["UNIQUE", "uid", "cat", "k"] - } - }, - "permissionset": { - "comment": "", - "fields": { - "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 id of this permission set"}, - "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"], - "uid_allow_cid_allow_gid_deny_cid_deny_gid": ["allow_cid(50)", "allow_gid(30)", "deny_cid(50)", "deny_gid(30)"] - } - }, - "photo": { - "comment": "photo storage", - "fields": { - "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": "0001-01-01 00:00:00", "comment": "creation date"}, - "edited": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "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": "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": ""}, - "width": {"type": "smallint unsigned", "not null": "1", "default": "0", "comment": ""}, - "datasize": {"type": "int unsigned", "not null": "1", "default": "0", "comment": ""}, - "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": "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"], - "contactid": ["contact-id"], - "uid_contactid": ["uid", "contact-id"], - "uid_profile": ["uid", "profile"], - "uid_album_scale_created": ["uid", "album(32)", "scale", "created"], - "uid_album_resource-id_created": ["uid", "album(32)", "resource-id", "created"], - "resource-id": ["resource-id"] - } - }, - "poll": { - "comment": "Currently unused table for storing poll results", - "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"}, - "q0": {"type": "text", "comment": ""}, - "q1": {"type": "text", "comment": ""}, - "q2": {"type": "text", "comment": ""}, - "q3": {"type": "text", "comment": ""}, - "q4": {"type": "text", "comment": ""}, - "q5": {"type": "text", "comment": ""}, - "q6": {"type": "text", "comment": ""}, - "q7": {"type": "text", "comment": ""}, - "q8": {"type": "text", "comment": ""}, - "q9": {"type": "text", "comment": ""} - }, - "indexes": { - "PRIMARY": ["id"], - "uid": ["uid"] - } - }, - "poll_result": { - "comment": "data for polls - currently unused", - "fields": { - "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": ""} - }, - "indexes": { - "PRIMARY": ["id"], - "poll_id": ["poll_id"] - } - }, - "process": { - "comment": "Currently running system processes", - "fields": { - "pid": {"type": "int unsigned", "not null": "1", "primary": "1", "comment": ""}, - "command": {"type": "varbinary(32)", "not null": "1", "default": "", "comment": ""}, - "created": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": ""} - }, - "indexes": { - "PRIMARY": ["pid"], - "command": ["command"] - } - }, - "profile": { - "comment": "user profiles data", - "fields": { - "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": "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": ""}, - "postal-code": {"type": "varchar(32)", "not null": "1", "default": "", "comment": ""}, - "country-name": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "hometown": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "gender": {"type": "varchar(32)", "not null": "1", "default": "", "comment": ""}, - "marital": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "with": {"type": "text", "comment": ""}, - "howlong": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": ""}, - "sexual": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "politic": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "religion": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "pub_keywords": {"type": "text", "comment": ""}, - "prv_keywords": {"type": "text", "comment": ""}, - "likes": {"type": "text", "comment": ""}, - "dislikes": {"type": "text", "comment": ""}, - "about": {"type": "text", "comment": ""}, - "summary": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "music": {"type": "text", "comment": ""}, - "book": {"type": "text", "comment": ""}, - "tv": {"type": "text", "comment": ""}, - "film": {"type": "text", "comment": ""}, - "interest": {"type": "text", "comment": ""}, - "romance": {"type": "text", "comment": ""}, - "work": {"type": "text", "comment": ""}, - "education": {"type": "text", "comment": ""}, - "contact": {"type": "text", "comment": ""}, - "homepage": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "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": "publish default profile in local directory"}, - "net-publish": {"type": "boolean", "not null": "1", "default": "0", "comment": "publish profile in global directory"} - }, - "indexes": { - "PRIMARY": ["id"], - "uid_is-default": ["uid", "is-default"] - } - }, - "profile_check": { - "comment": "DFRN remote auth use", - "fields": { - "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": "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": ""} - }, - "indexes": { - "PRIMARY": ["id"] - } - }, - "push_subscriber": { - "comment": "Used for OStatus: Contains feed subscribers", - "fields": { - "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": ""}, - "nickname": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "push": {"type": "tinyint", "not null": "1", "default": "0", "comment": "Retrial counter"}, - "last_update": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": "Date of last successful trial"}, - "next_try": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": "Next retrial date"}, - "renewed": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": "Date of last subscription renewal"}, - "secret": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""} - }, - "indexes": { - "PRIMARY": ["id"], - "next_try": ["next_try"] - } - }, - "queue": { - "comment": "Queue for messages that couldn't be delivered", - "fields": { - "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"}, - "created": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": "Date, when the message was created"}, - "last": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": "Date of last trial"}, - "next": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": "Next retrial date"}, - "retrial": {"type": "tinyint", "not null": "1", "default": "0", "comment": "Retrial counter"}, - "content": {"type": "mediumtext", "comment": ""}, - "batch": {"type": "boolean", "not null": "1", "default": "0", "comment": ""} - }, - "indexes": { - "PRIMARY": ["id"], - "last": ["last"], - "next": ["next"] - } - }, - "register": { - "comment": "registrations requiring admin approval", - "fields": { - "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": "0001-01-01 00:00:00", "comment": ""}, - "uid": {"type": "mediumint unsigned", "not null": "1", "default": "0", "relation": {"user": "uid"}, "comment": "User id"}, - "password": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "language": {"type": "varchar(16)", "not null": "1", "default": "", "comment": ""}, - "note": {"type": "text", "comment": ""} - }, - "indexes": { - "PRIMARY": ["id"] - } - }, - "search": { - "comment": "", - "fields": { - "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": ""} - }, - "indexes": { - "PRIMARY": ["id"], - "uid": ["uid"] - } - }, - "session": { - "comment": "web session storage", - "fields": { - "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": ""} - }, - "indexes": { - "PRIMARY": ["id"], - "sid": ["sid(64)"], - "expire": ["expire"] - } - }, - "sign": { - "comment": "Diaspora signatures", - "fields": { - "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": ""} - }, - "indexes": { - "PRIMARY": ["id"], - "iid": ["UNIQUE", "iid"] - } - }, - "term": { - "comment": "item taxonomy (categories, tags, etc.) table", - "fields": { - "tid": {"type": "int unsigned", "not null": "1", "extra": "auto_increment", "primary": "1", "comment": ""}, - "oid": {"type": "int unsigned", "not null": "1", "default": "0", "relation": {"item": "id"}, "comment": ""}, - "otype": {"type": "tinyint unsigned", "not null": "1", "default": "0", "comment": ""}, - "type": {"type": "tinyint unsigned", "not null": "1", "default": "0", "comment": ""}, - "term": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "url": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "guid": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, - "created": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": ""}, - "received": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": ""}, - "global": {"type": "boolean", "not null": "1", "default": "0", "comment": ""}, - "uid": {"type": "mediumint unsigned", "not null": "1", "default": "0", "relation": {"user": "uid"}, "comment": "User id"} - }, - "indexes": { - "PRIMARY": ["tid"], - "oid_otype_type_term": ["oid", "otype", "type", "term(32)"], - "uid_otype_type_term_global_created": ["uid", "otype", "type", "term(32)", "global", "created"], - "uid_otype_type_url": ["uid", "otype", "type", "url(64)"], - "guid": ["guid(64)"] - } - }, - "thread": { - "comment": "Thread related data", - "fields": { - "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": "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": "0001-01-01 00:00:00", "comment": ""}, - "edited": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": ""}, - "commented": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": ""}, - "received": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": ""}, - "changed": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": ""}, - "wall": {"type": "boolean", "not null": "1", "default": "0", "comment": ""}, - "private": {"type": "boolean", "not null": "1", "default": "0", "comment": ""}, - "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": ""}, - "starred": {"type": "boolean", "not null": "1", "default": "0", "comment": ""}, - "ignored": {"type": "boolean", "not null": "1", "default": "0", "comment": ""}, - "post-type": {"type": "tinyint unsigned", "not null": "1", "default": "0", "comment": "Post type (personal note, bookmark, ...)"}, - "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": ""}, - "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": ""}, - "bookmark": {"type": "boolean", "comment": ""} - }, - "indexes": { - "PRIMARY": ["iid"], - "uid_network_commented": ["uid", "network", "commented"], - "uid_network_created": ["uid", "network", "created"], - "uid_contactid_commented": ["uid", "contact-id", "commented"], - "uid_contactid_created": ["uid", "contact-id", "created"], - "contactid": ["contact-id"], - "ownerid": ["owner-id"], - "authorid": ["author-id"], - "uid_created": ["uid", "created"], - "uid_commented": ["uid", "commented"], - "uid_wall_created": ["uid", "wall", "created"], - "private_wall_origin_commented": ["private", "wall", "origin", "commented"] - } - }, - "tokens": { - "comment": "OAuth usage", - "fields": { - "id": {"type": "varchar(40)", "not null": "1", "primary": "1", "comment": ""}, - "secret": {"type": "text", "comment": ""}, - "client_id": {"type": "varchar(20)", "not null": "1", "default": "", "relation": {"clients": "client_id"}}, - "expires": {"type": "int", "not null": "1", "default": "0", "comment": ""}, - "scope": {"type": "varchar(200)", "not null": "1", "default": "", "comment": ""}, - "uid": {"type": "mediumint unsigned", "not null": "1", "default": "0", "relation": {"user": "uid"}, "comment": "User id"} - }, - "indexes": { - "PRIMARY": ["id"] - } - }, - "user": { - "comment": "The local users", - "fields": { - "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": "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": "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": "PHP-legal timezone"}, - "language": {"type": "varchar(32)", "not null": "1", "default": "en", "comment": "default language"}, - "register_date": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": "timestamp of registration"}, - "login_date": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "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": "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": "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": "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": "0001-01-01 00:00:00", "comment": "timestamp when account expires and will be deleted"}, - "expire_notification_sent": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": "timestamp of last warning of account expiration"}, - "def_gid": {"type": "int unsigned", "not null": "1", "default": "0", "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": { - "PRIMARY": ["uid"], - "nickname": ["nickname(32)"] - } - }, - "userd": { - "comment": "Deleted usernames", - "fields": { - "id": {"type": "int unsigned", "not null": "1", "extra": "auto_increment", "primary": "1", "comment": "sequential ID"}, - "username": {"type": "varchar(255)", "not null": "1", "comment": ""} - }, - "indexes": { - "PRIMARY": ["id"], - "username": ["username(32)"] - } - }, - "user-contact": { - "comment": "User specific public contact data", - "fields": { - "cid": {"type": "int unsigned", "not null": "1", "default": "0", "primary": "1", "relation": {"contact": "id"}, "comment": "Contact id of the linked public contact"}, - "uid": {"type": "mediumint unsigned", "not null": "1", "default": "0", "primary": "1", "relation": {"user": "uid"}, "comment": "User id"}, - "blocked": {"type": "boolean", "comment": "Contact is completely blocked for this user"}, - "ignored": {"type": "boolean", "comment": "Posts from this contact are ignored"}, - "collapsed": {"type": "boolean", "comment": "Posts from this contact are collapsed"} - }, - "indexes": { - "PRIMARY": ["uid", "cid"] - } - }, - "user-item": { - "comment": "User specific item data", - "fields": { - "iid": {"type": "int unsigned", "not null": "1", "default": "0", "primary": "1", "relation": {"item": "id"}, "comment": "Item id"}, - "uid": {"type": "mediumint unsigned", "not null": "1", "default": "0", "primary": "1", "relation": {"user": "uid"}, "comment": "User id"}, - "hidden": {"type": "boolean", "not null": "1", "default": "0", "comment": "Marker to hide an item from the user"}, - "ignored": {"type": "boolean", "comment": "Ignore this thread if set"} - }, - "indexes": { - "PRIMARY": ["uid", "iid"] - } - }, - "worker-ipc": { - "comment": "Inter process communication between the frontend and the worker", - "fields": { - "key": {"type": "int", "not null": "1", "primary": "1", "comment": ""}, - "jobs": {"type": "boolean", "comment": "Flag for outstanding jobs"} - }, - "indexes": { - "PRIMARY": ["key"] - }, - "engine": "MEMORY" - }, - "workerqueue": { - "comment": "Background tasks queue entries", - "fields": { - "id": {"type": "int unsigned", "not null": "1", "extra": "auto_increment", "primary": "1", "comment": "Auto incremented worker task id"}, - "parameter": {"type": "mediumblob", "comment": "Task command"}, - "priority": {"type": "tinyint unsigned", "not null": "1", "default": "0", "comment": "Task priority"}, - "created": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "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": "0001-01-01 00:00:00", "comment": "Execution date"}, - "next_try": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": "Next retrial date"}, - "retrial": {"type": "tinyint", "not null": "1", "default": "0", "comment": "Retrial counter"}, - "done": {"type": "boolean", "not null": "1", "default": "0", "comment": "Marked 1 when the task was done - will be deleted later"} - }, - "indexes": { - "PRIMARY": ["id"], - "pid": ["pid"], - "parameter": ["parameter(64)"], - "priority_created_next_try": ["priority", "created", "next_try"], - "done_executed_next_try": ["done", "executed", "next_try"] - } - } -} diff --git a/config/dbstructure.php b/config/dbstructure.php new file mode 100644 index 0000000000..96f90fb824 --- /dev/null +++ b/config/dbstructure.php @@ -0,0 +1,1374 @@ +" => [ + * "comment" => "Description of the table", + * "fields" => [ + * "" => [ + * "type" => "{()} ", + * "not null" => 0|1, + * {"extra" => "auto_increment",} + * {"default" => "",} + * {"default" => NULL_DATE,} (for datetime fields) + * {"primary" => "1",} + * {"relation" => ["" => ""],} + * "comment" => "Description of the fields" + * ], + * ... + * ], + * "indexes" => [ + * "PRIMARY" => ["", ...], + * "" => [{"UNIQUE",} "{()}", ...] + * ... + * ], + * ], + * + * If you need to make any change, make sure to increment the DB_UPDATE_VERSION constant value below. + * + */ + +use Friendica\Database\DBA; + +if (!defined('DB_UPDATE_VERSION')) { + define('DB_UPDATE_VERSION', 1289); +} + +return [ + "addon" => [ + "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" => "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"], + "name" => ["UNIQUE", "name"], + ] + ], + "apcontact" => [ + "comment" => "ActivityPub compatible contacts - used in the ActivityPub implementation", + "fields" => [ + "url" => ["type" => "varbinary(255)", "not null" => "1", "primary" => "1", "comment" => "URL of the contact"], + "uuid" => ["type" => "varchar(255)", "comment" => ""], + "type" => ["type" => "varchar(20)", "not null" => "1", "comment" => ""], + "following" => ["type" => "varchar(255)", "comment" => ""], + "followers" => ["type" => "varchar(255)", "comment" => ""], + "inbox" => ["type" => "varchar(255)", "not null" => "1", "comment" => ""], + "outbox" => ["type" => "varchar(255)", "comment" => ""], + "sharedinbox" => ["type" => "varchar(255)", "comment" => ""], + "nick" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "name" => ["type" => "varchar(255)", "comment" => ""], + "about" => ["type" => "text", "comment" => ""], + "photo" => ["type" => "varchar(255)", "comment" => ""], + "addr" => ["type" => "varchar(255)", "comment" => ""], + "alias" => ["type" => "varchar(255)", "comment" => ""], + "pubkey" => ["type" => "text", "comment" => ""], + "baseurl" => ["type" => "varchar(255)", "comment" => "baseurl of the ap contact"], + "updated" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""] + ], + "indexes" => [ + "PRIMARY" => ["url"], + "addr" => ["addr(32)"], + "alias" => ["alias(190)"], + "url" => ["followers(190)"] + ] + ], + "attach" => [ + "comment" => "file attachments", + "fields" => [ + "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" => DBA::NULL_DATETIME, "comment" => "creation time"], + "edited" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "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"], + ] + ], + "auth_codes" => [ + "comment" => "OAuth usage", + "fields" => [ + "id" => ["type" => "varchar(40)", "not null" => "1", "primary" => "1", "comment" => ""], + "client_id" => ["type" => "varchar(20)", "not null" => "1", "default" => "", "relation" => ["clients" => "client_id"], + "comment" => ""], + "redirect_uri" => ["type" => "varchar(200)", "not null" => "1", "default" => "", "comment" => ""], + "expires" => ["type" => "int", "not null" => "1", "default" => "0", "comment" => ""], + "scope" => ["type" => "varchar(250)", "not null" => "1", "default" => "", "comment" => ""], + ], + "indexes" => [ + "PRIMARY" => ["id"], + ] + ], + "cache" => [ + "comment" => "Stores temporary data", + "fields" => [ + "k" => ["type" => "varbinary(255)", "not null" => "1", "primary" => "1", "comment" => "cache key"], + "v" => ["type" => "mediumtext", "comment" => "cached serialized value"], + "expires" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "datetime of cache expiration"], + "updated" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "datetime of cache insertion"], + ], + "indexes" => [ + "PRIMARY" => ["k"], + "k_expires" => ["k", "expires"], + ] + ], + "challenge" => [ + "comment" => "", + "fields" => [ + "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" => ""], + "type" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "last_update" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + ], + "indexes" => [ + "PRIMARY" => ["id"], + ] + ], + "clients" => [ + "comment" => "OAuth usage", + "fields" => [ + "client_id" => ["type" => "varchar(20)", "not null" => "1", "primary" => "1", "comment" => ""], + "pw" => ["type" => "varchar(20)", "not null" => "1", "default" => "", "comment" => ""], + "redirect_uri" => ["type" => "varchar(200)", "not null" => "1", "default" => "", "comment" => ""], + "name" => ["type" => "text", "comment" => ""], + "icon" => ["type" => "text", "comment" => ""], + "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "User id"], + ], + "indexes" => [ + "PRIMARY" => ["client_id"], + ] + ], + "config" => [ + "comment" => "main configuration storage", + "fields" => [ + "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""], + "cat" => ["type" => "varbinary(50)", "not null" => "1", "default" => "", "comment" => ""], + "k" => ["type" => "varbinary(50)", "not null" => "1", "default" => "", "comment" => ""], + "v" => ["type" => "mediumtext", "comment" => ""], + ], + "indexes" => [ + "PRIMARY" => ["id"], + "cat_k" => ["UNIQUE", "cat", "k"], + ] + ], + "contact" => [ + "comment" => "contact table", + "fields" => [ + "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" => DBA::NULL_DATETIME, "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" => "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" => "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" => "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" => "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" => ""], + "url" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "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" => "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" => ""], + "poll" => ["type" => "varchar(255)", "comment" => ""], + "confirm" => ["type" => "varchar(255)", "comment" => ""], + "poco" => ["type" => "varchar(255)", "comment" => ""], + "aes_allow" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], + "ret-aes" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], + "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" => DBA::NULL_DATETIME, "comment" => "Date of the last try to update the contact info"], + "success_update" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Date of the last successful contact update"], + "failure_update" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Date of the last failed update"], + "name-date" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], + "uri-date" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], + "avatar-date" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], + "term-date" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], + "last-item" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "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" => "posts of the contact are readonly"], + "writable" => ["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" => ""], + "pending" => ["type" => "boolean", "not null" => "1", "default" => "1", "comment" => ""], + "deleted" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Contact has been deleted"], + "rating" => ["type" => "tinyint", "not null" => "1", "default" => "0", "comment" => ""], + "reason" => ["type" => "text", "comment" => ""], + "closeness" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "99", "comment" => ""], + "info" => ["type" => "mediumtext", "comment" => ""], + "profile-id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "comment" => ""], + "bdyear" => ["type" => "varchar(4)", "not null" => "1", "default" => "", "comment" => ""], + "bd" => ["type" => "date", "not null" => "1", "default" => DBA::NULL_DATE, "comment" => ""], + "notify_new_posts" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], + "fetch_further_information" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""], + "ffi_keyword_blacklist" => ["type" => "text", "comment" => ""], + ], + "indexes" => [ + "PRIMARY" => ["id"], + "uid_name" => ["uid", "name(190)"], + "self_uid" => ["self", "uid"], + "alias_uid" => ["alias(32)", "uid"], + "pending_uid" => ["pending", "uid"], + "blocked_uid" => ["blocked", "uid"], + "uid_rel_network_poll" => ["uid", "rel", "network", "poll(64)", "archive"], + "uid_network_batch" => ["uid", "network", "batch(64)"], + "addr_uid" => ["addr(32)", "uid"], + "nurl_uid" => ["nurl(32)", "uid"], + "nick_uid" => ["nick(32)", "uid"], + "dfrn-id" => ["dfrn-id(64)"], + "issued-id" => ["issued-id(64)"], + ] + ], + "conv" => [ + "comment" => "private messages", + "fields" => [ + "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" => DBA::NULL_DATETIME, "comment" => "creation timestamp"], + "updated" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "edited timestamp"], + "subject" => ["type" => "text", "comment" => "subject of initial message"], + ], + "indexes" => [ + "PRIMARY" => ["id"], + "uid" => ["uid"], + ] + ], + "conversation" => [ + "comment" => "Raw data and structure information for messages", + "fields" => [ + "item-uri" => ["type" => "varbinary(255)", "not null" => "1", "primary" => "1", "comment" => "Original URI of the item - unrelated to the table with the same name"], + "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" => "255", "comment" => "The protocol of the item"], + "source" => ["type" => "mediumtext", "comment" => "Original source"], + "received" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Receiving date"], + ], + "indexes" => [ + "PRIMARY" => ["item-uri"], + "conversation-uri" => ["conversation-uri"], + "received" => ["received"], + ] + ], + "diaspora-interaction" => [ + "comment" => "Signed Diaspora Interaction", + "fields" => [ + "uri-id" => ["type" => "int unsigned", "not null" => "1", "primary" => "1", "relation" => ["item-uri" => "id"], "comment" => "Id of the item-uri table entry that contains the item uri"], + "interaction" => ["type" => "mediumtext", "comment" => "The Diaspora interaction"] + ], + "indexes" => [ + "PRIMARY" => ["uri-id"] + ] + ], + "event" => [ + "comment" => "Events", + "fields" => [ + "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" => "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" => DBA::NULL_DATETIME, "comment" => "creation time"], + "edited" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "last edit time"], + "start" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "event start time"], + "finish" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "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"], + "uid_start" => ["uid", "start"], + ] + ], + "fcontact" => [ + "comment" => "Diaspora compatible contacts - used in the Diaspora implementation", + "fields" => [ + "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" => ""], + "request" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "nick" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "addr" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "batch" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "notify" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "poll" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "confirm" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "priority" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""], + "network" => ["type" => "char(4)", "not null" => "1", "default" => "", "comment" => ""], + "alias" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "pubkey" => ["type" => "text", "comment" => ""], + "updated" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], + ], + "indexes" => [ + "PRIMARY" => ["id"], + "addr" => ["addr(32)"], + "url" => ["UNIQUE", "url(190)"], + ] + ], + "fsuggest" => [ + "comment" => "friend suggestion stuff", + "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"], + "cid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["contact" => "id"], "comment" => ""], + "name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "url" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "request" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "photo" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "note" => ["type" => "text", "comment" => ""], + "created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], + ], + "indexes" => [ + "PRIMARY" => ["id"], + ] + ], + "gcign" => [ + "comment" => "contacts ignored by friend suggestions", + "fields" => [ + "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"], + "uid" => ["uid"], + "gcid" => ["gcid"], + ] + ], + "gcontact" => [ + "comment" => "global contacts", + "fields" => [ + "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" => "Link to the profile photo"], + "connect" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], + "updated" => ["type" => "datetime", "default" => DBA::NULL_DATETIME, "comment" => ""], + "last_contact" => ["type" => "datetime", "default" => DBA::NULL_DATETIME, "comment" => ""], + "last_failure" => ["type" => "datetime", "default" => DBA::NULL_DATETIME, "comment" => ""], + "location" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "about" => ["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" => DBA::NULL_DATE, "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" => "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" => "baseurl of the contacts server"], + ], + "indexes" => [ + "PRIMARY" => ["id"], + "nurl" => ["UNIQUE", "nurl(190)"], + "name" => ["name(64)"], + "nick" => ["nick(32)"], + "addr" => ["addr(64)"], + "hide_network_updated" => ["hide", "network", "updated"], + "updated" => ["updated"], + ] + ], + "glink" => [ + "comment" => "'friends of friends' linkages derived from poco", + "fields" => [ + "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" => ""], + "zcid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["gcontact" => "id"], "comment" => ""], + "updated" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], + ], + "indexes" => [ + "PRIMARY" => ["id"], + "cid_uid_gcid_zcid" => ["UNIQUE", "cid", "uid", "gcid", "zcid"], + "gcid" => ["gcid"], + ] + ], + "group" => [ + "comment" => "privacy groups, group info", + "fields" => [ + "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"], + "uid" => ["uid"], + ] + ], + "group_member" => [ + "comment" => "privacy groups, member info", + "fields" => [ + "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"], + "contactid" => ["contact-id"], + "gid_contactid" => ["UNIQUE", "gid", "contact-id"], + ] + ], + "gserver" => [ + "comment" => "Global servers", + "fields" => [ + "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" => "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" => ""], + "platform" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "relay-subscribe" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Has the server subscribed to the relay system"], + "relay-scope" => ["type" => "varchar(10)", "not null" => "1", "default" => "", "comment" => "The scope of messages that the server wants to get"], + "created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], + "last_poco_query" => ["type" => "datetime", "default" => DBA::NULL_DATETIME, "comment" => ""], + "last_contact" => ["type" => "datetime", "default" => DBA::NULL_DATETIME, "comment" => ""], + "last_failure" => ["type" => "datetime", "default" => DBA::NULL_DATETIME, "comment" => ""], + ], + "indexes" => [ + "PRIMARY" => ["id"], + "nurl" => ["UNIQUE", "nurl(190)"], + ] + ], + "gserver-tag" => [ + "comment" => "Tags that the server has subscribed", + "fields" => [ + "gserver-id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["gserver" => "id"], "primary" => "1", + "comment" => "The id of the gserver"], + "tag" => ["type" => "varchar(100)", "not null" => "1", "default" => "", "primary" => "1", "comment" => "Tag that the server has subscribed"], + ], + "indexes" => [ + "PRIMARY" => ["gserver-id", "tag"], + "tag" => ["tag"], + ] + ], + "hook" => [ + "comment" => "addon hook registry", + "fields" => [ + "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"], + "hook_file_function" => ["UNIQUE", "hook", "file", "function"], + ] + ], + "intro" => [ + "comment" => "", + "fields" => [ + "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" => ""], + "knowyou" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], + "duplex" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], + "note" => ["type" => "text", "comment" => ""], + "hash" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "datetime" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], + "blocked" => ["type" => "boolean", "not null" => "1", "default" => "1", "comment" => ""], + "ignore" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], + ], + "indexes" => [ + "PRIMARY" => ["id"], + ] + ], + "item" => [ + "comment" => "Structure for 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" => "A unique identifier for this item"], + "uri" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "uri-id" => ["type" => "int unsigned", "relation" => ["item-uri" => "id"], "comment" => "Id of the item-uri table entry that contains the item uri"], + "uri-hash" => ["type" => "varchar(80)", "not null" => "1", "default" => "", "comment" => "RIPEMD-128 hash from uri"], + "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"], + "parent-uri-id" => ["type" => "int unsigned", "relation" => ["item-uri" => "id"], "comment" => "Id of the item-uri table that contains the parent uri"], + "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"], + "thr-parent-id" => ["type" => "int unsigned", "relation" => ["item-uri" => "id"], "comment" => "Id of the item-uri table that contains the thread parent uri"], + "created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Creation timestamp."], + "edited" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Date of last edit (default is created)"], + "commented" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Date of last comment/reply to this item"], + "received" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "datetime"], + "changed" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Date that something in the conversation changed, indicating clients should fetch the conversation again"], + "gravity" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""], + "network" => ["type" => "char(4)", "not null" => "1", "default" => "", "comment" => "Network from where the item comes from"], + "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"], + "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"], + "icid" => ["type" => "int unsigned", "relation" => ["item-content" => "id"], "comment" => "Id of the item-content table entry that contains the whole item content"], + "iaid" => ["type" => "int unsigned", "relation" => ["item-activity" => "id"], "comment" => "Id of the item-activity table entry that contains the activity data"], + "extid" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "post-type" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => "Post type (personal note, bookmark, ...)"], + "global" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], + "private" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "distribution is restricted"], + "visible" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], + "moderated" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], + "deleted" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "item has been deleted"], + // User specific fields. Eventually they will move to user-item + "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"], + "wall" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "This item was posted to the wall of uid"], + "origin" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "item originated at this site"], + "pubmail" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], + "starred" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "item has been favourited"], + "unseen" => ["type" => "boolean", "not null" => "1", "default" => "1", "comment" => "item has not been seen"], + "mention" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "The owner of this item was mentioned in it"], + "forum_mode" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""], + "psid" => ["type" => "int unsigned", "relation" => ["permissionset" => "id"], "comment" => "ID of the permission set of this post"], + // It has to be decided whether these fields belong to the user or the structure + "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"], + // Could possibly be replaced by the "attach" table? + "attach" => ["type" => "mediumtext", "comment" => "JSON structure representing attachments to this item"], + // Deprecated fields. Will be removed in upcoming versions + "allow_cid" => ["type" => "mediumtext", "comment" => "Deprecated"], + "allow_gid" => ["type" => "mediumtext", "comment" => "Deprecated"], + "deny_cid" => ["type" => "mediumtext", "comment" => "Deprecated"], + "deny_gid" => ["type" => "mediumtext", "comment" => "Deprecated"], + "postopts" => ["type" => "text", "comment" => "Deprecated"], + "inform" => ["type" => "mediumtext", "comment" => "Deprecated"], + "type" => ["type" => "varchar(20)", "comment" => "Deprecated"], + "bookmark" => ["type" => "boolean", "comment" => "Deprecated"], + "file" => ["type" => "mediumtext", "comment" => "Deprecated"], + "location" => ["type" => "varchar(255)", "comment" => "Deprecated"], + "coord" => ["type" => "varchar(255)", "comment" => "Deprecated"], + "tag" => ["type" => "mediumtext", "comment" => "Deprecated"], + "plink" => ["type" => "varchar(255)", "comment" => "Deprecated"], + "title" => ["type" => "varchar(255)", "comment" => "Deprecated"], + "content-warning" => ["type" => "varchar(255)", "comment" => "Deprecated"], + "body" => ["type" => "mediumtext", "comment" => "Deprecated"], + "app" => ["type" => "varchar(255)", "comment" => "Deprecated"], + "verb" => ["type" => "varchar(100)", "comment" => "Deprecated"], + "object-type" => ["type" => "varchar(100)", "comment" => "Deprecated"], + "object" => ["type" => "text", "comment" => "Deprecated"], + "target-type" => ["type" => "varchar(100)", "comment" => "Deprecated"], + "target" => ["type" => "text", "comment" => "Deprecated"], + "author-name" => ["type" => "varchar(255)", "comment" => "Deprecated"], + "author-link" => ["type" => "varchar(255)", "comment" => "Deprecated"], + "author-avatar" => ["type" => "varchar(255)", "comment" => "Deprecated"], + "owner-name" => ["type" => "varchar(255)", "comment" => "Deprecated"], + "owner-link" => ["type" => "varchar(255)", "comment" => "Deprecated"], + "owner-avatar" => ["type" => "varchar(255)", "comment" => "Deprecated"], + "rendered-hash" => ["type" => "varchar(32)", "comment" => "Deprecated"], + "rendered-html" => ["type" => "mediumtext", "comment" => "Deprecated"], + ], + "indexes" => [ + "PRIMARY" => ["id"], + "guid" => ["guid(191)"], + "uri" => ["uri(191)"], + "parent" => ["parent"], + "parent-uri" => ["parent-uri(191)"], + "extid" => ["extid(191)"], + "uid_id" => ["uid", "id"], + "uid_contactid_id" => ["uid", "contact-id", "id"], + "uid_created" => ["uid", "created"], + "uid_commented" => ["uid", "commented"], + "uid_unseen_contactid" => ["uid", "unseen", "contact-id"], + "uid_network_received" => ["uid", "network", "received"], + "uid_network_commented" => ["uid", "network", "commented"], + "uid_thrparent" => ["uid", "thr-parent(190)"], + "uid_parenturi" => ["uid", "parent-uri(190)"], + "uid_contactid_created" => ["uid", "contact-id", "created"], + "authorid_created" => ["author-id", "created"], + "ownerid" => ["owner-id"], + "uid_uri" => ["uid", "uri(190)"], + "resource-id" => ["resource-id"], + "deleted_changed" => ["deleted", "changed"], + "uid_wall_changed" => ["uid", "wall", "changed"], + "uid_eventid" => ["uid", "event-id"], + "icid" => ["icid"], + "iaid" => ["iaid"], + "psid_wall" => ["psid", "wall"], + ] + ], + "item-activity" => [ + "comment" => "Activities for items", + "fields" => [ + "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "relation" => ["thread" => "iid"]], + "uri" => ["type" => "varchar(255)", "comment" => ""], + "uri-id" => ["type" => "int unsigned", "relation" => ["item-uri" => "id"], "comment" => "Id of the item-uri table entry that contains the item uri"], + "uri-hash" => ["type" => "varchar(80)", "not null" => "1", "default" => "", "comment" => "RIPEMD-128 hash from uri"], + "activity" => ["type" => "smallint unsigned", "not null" => "1", "default" => "0", "comment" => ""] + ], + "indexes" => [ + "PRIMARY" => ["id"], + "uri-hash" => ["UNIQUE", "uri-hash"], + "uri" => ["uri(191)"], + "uri-id" => ["uri-id"] + ] + ], + "item-content" => [ + "comment" => "Content for all posts", + "fields" => [ + "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "relation" => ["thread" => "iid"]], + "uri" => ["type" => "varchar(255)", "comment" => ""], + "uri-id" => ["type" => "int unsigned", "relation" => ["item-uri" => "id"], "comment" => "Id of the item-uri table entry that contains the item uri"], + "uri-plink-hash" => ["type" => "varchar(80)", "not null" => "1", "default" => "", "comment" => "RIPEMD-128 hash from uri"], + "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" => "item body content"], + "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"], + "language" => ["type" => "text", "comment" => "Language information about this post"], + "app" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "application which generated this item"], + "rendered-hash" => ["type" => "varchar(32)", "not null" => "1", "default" => "", "comment" => ""], + "rendered-html" => ["type" => "mediumtext", "comment" => "item.body converted to html"], + "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"], + "plink" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "permalink or URL to a displayable copy of the message at its source"], + "verb" => ["type" => "varchar(100)", "not null" => "1", "default" => "", "comment" => "ActivityStreams verb"] + ], + "indexes" => [ + "PRIMARY" => ["id"], + "uri-plink-hash" => ["UNIQUE", "uri-plink-hash"], + "uri" => ["uri(191)"], + "uri-id" => ["uri-id"] + ] + ], + "item-delivery-data" => [ + "comment" => "Delivery data for items", + "fields" => [ + "iid" => ["type" => "int unsigned", "not null" => "1", "primary" => "1", "relation" => ["item" => "id"], "comment" => "Item id"], + "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"], + "inform" => ["type" => "mediumtext", "comment" => "Additional receivers of the linked item"], + ], + "indexes" => [ + "PRIMARY" => ["iid"], + ] + ], + "item-uri" => [ + "comment" => "URI and GUID for items", + "fields" => [ + "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1"], + "uri" => ["type" => "varbinary(255)", "not null" => "1", "comment" => "URI of an item"], + "guid" => ["type" => "varbinary(255)", "comment" => "A unique identifier for an item"] + ], + "indexes" => [ + "PRIMARY" => ["id"], + "uri" => ["UNIQUE", "uri"], + "guid" => ["guid"] + ] + ], + "locks" => [ + "comment" => "", + "fields" => [ + "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" => "Process ID"], + "expires" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "datetime of cache expiration"], + ], + "indexes" => [ + "PRIMARY" => ["id"], + "name_expires" => ["name", "expires"] + ] + ], + "mail" => [ + "comment" => "private messages", + "fields" => [ + "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" => "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" => "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" => DBA::NULL_DATETIME, "comment" => "creation time of the private message"], + ], + "indexes" => [ + "PRIMARY" => ["id"], + "uid_seen" => ["uid", "seen"], + "convid" => ["convid"], + "uri" => ["uri(64)"], + "parent-uri" => ["parent-uri(64)"], + "contactid" => ["contact-id(32)"], + ] + ], + "mailacct" => [ + "comment" => "Mail account data for fetching mails", + "fields" => [ + "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" => ""], + "ssltype" => ["type" => "varchar(16)", "not null" => "1", "default" => "", "comment" => ""], + "mailbox" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "user" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "pass" => ["type" => "text", "comment" => ""], + "reply_to" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "action" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""], + "movetofolder" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "pubmail" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], + "last_check" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], + ], + "indexes" => [ + "PRIMARY" => ["id"], + ] + ], + "manage" => [ + "comment" => "table of accounts that can manage each other", + "fields" => [ + "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"], + ], + "indexes" => [ + "PRIMARY" => ["id"], + "uid_mid" => ["UNIQUE", "uid", "mid"], + ] + ], + "notify" => [ + "comment" => "notifications", + "fields" => [ + "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" => ""], + "url" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "photo" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "date" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], + "msg" => ["type" => "mediumtext", "comment" => ""], + "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" => "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" => "Cached bbcode parsing of name"], + "msg_cache" => ["type" => "mediumtext", "comment" => "Cached bbcode parsing of msg"] + ], + "indexes" => [ + "PRIMARY" => ["id"], + "hash_uid" => ["hash", "uid"], + "seen_uid_date" => ["seen", "uid", "date"], + "uid_date" => ["uid", "date"], + "uid_type_link" => ["uid", "type", "link(190)"], + ] + ], + "notify-threads" => [ + "comment" => "", + "fields" => [ + "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" => ""], + "receiver-uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], + "comment" => "User id"], + ], + "indexes" => [ + "PRIMARY" => ["id"], + ] + ], + "oembed" => [ + "comment" => "cache for OEmbed queries", + "fields" => [ + "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" => DBA::NULL_DATETIME, "comment" => "datetime of creation"], + ], + "indexes" => [ + "PRIMARY" => ["url", "maxwidth"], + "created" => ["created"], + ] + ], + "openwebauth-token" => [ + "comment" => "Store OpenWebAuth token to verify contacts", + "fields" => [ + "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"], + "type" => ["type" => "varchar(32)", "not null" => "1", "default" => "", "comment" => "Verify type"], + "token" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "A generated token"], + "meta" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "datetime of creation"], + ], + "indexes" => [ + "PRIMARY" => ["id"], + ] + ], + "parsed_url" => [ + "comment" => "cache for 'parse_url' queries", + "fields" => [ + "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" => DBA::NULL_DATETIME, "comment" => "datetime of creation"], + ], + "indexes" => [ + "PRIMARY" => ["url", "guessing", "oembed"], + "created" => ["created"], + ] + ], + "participation" => [ + "comment" => "Storage for participation messages from Diaspora", + "fields" => [ + "iid" => ["type" => "int unsigned", "not null" => "1", "primary" => "1", "relation" => ["item" => "id"], "comment" => ""], + "server" => ["type" => "varchar(60)", "not null" => "1", "primary" => "1", "comment" => ""], + "cid" => ["type" => "int unsigned", "not null" => "1", "relation" => ["contact" => "id"], "comment" => ""], + "fid" => ["type" => "int unsigned", "not null" => "1", "relation" => ["fcontact" => "id"], "comment" => ""], + ], + "indexes" => [ + "PRIMARY" => ["iid", "server"] + ] + ], + "pconfig" => [ + "comment" => "personal (per user) configuration 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"], + "cat" => ["type" => "varbinary(50)", "not null" => "1", "default" => "", "comment" => ""], + "k" => ["type" => "varbinary(100)", "not null" => "1", "default" => "", "comment" => ""], + "v" => ["type" => "mediumtext", "comment" => ""], + ], + "indexes" => [ + "PRIMARY" => ["id"], + "uid_cat_k" => ["UNIQUE", "uid", "cat", "k"], + ] + ], + "permissionset" => [ + "comment" => "", + "fields" => [ + "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 id of this permission set"], + "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"], + "uid_allow_cid_allow_gid_deny_cid_deny_gid" => ["allow_cid(50)", "allow_gid(30)", "deny_cid(50)", "deny_gid(30)"], + ] + ], + "photo" => [ + "comment" => "photo storage", + "fields" => [ + "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" => DBA::NULL_DATETIME, "comment" => "creation date"], + "edited" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "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" => "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" => ""], + "width" => ["type" => "smallint unsigned", "not null" => "1", "default" => "0", "comment" => ""], + "datasize" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "comment" => ""], + "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" => "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"], + "contactid" => ["contact-id"], + "uid_contactid" => ["uid", "contact-id"], + "uid_profile" => ["uid", "profile"], + "uid_album_scale_created" => ["uid", "album(32)", "scale", "created"], + "uid_album_resource-id_created" => ["uid", "album(32)", "resource-id", "created"], + "resource-id" => ["resource-id"], + ] + ], + "poll" => [ + "comment" => "Currently unused table for storing poll results", + "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"], + "q0" => ["type" => "text", "comment" => ""], + "q1" => ["type" => "text", "comment" => ""], + "q2" => ["type" => "text", "comment" => ""], + "q3" => ["type" => "text", "comment" => ""], + "q4" => ["type" => "text", "comment" => ""], + "q5" => ["type" => "text", "comment" => ""], + "q6" => ["type" => "text", "comment" => ""], + "q7" => ["type" => "text", "comment" => ""], + "q8" => ["type" => "text", "comment" => ""], + "q9" => ["type" => "text", "comment" => ""], + ], + "indexes" => [ + "PRIMARY" => ["id"], + "uid" => ["uid"], + ] + ], + "poll_result" => [ + "comment" => "data for polls - currently unused", + "fields" => [ + "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" => ""], + ], + "indexes" => [ + "PRIMARY" => ["id"], + "poll_id" => ["poll_id"], + ] + ], + "process" => [ + "comment" => "Currently running system processes", + "fields" => [ + "pid" => ["type" => "int unsigned", "not null" => "1", "primary" => "1", "comment" => ""], + "command" => ["type" => "varbinary(32)", "not null" => "1", "default" => "", "comment" => ""], + "created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], + ], + "indexes" => [ + "PRIMARY" => ["pid"], + "command" => ["command"], + ] + ], + "profile" => [ + "comment" => "user profiles data", + "fields" => [ + "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" => "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" => ""], + "postal-code" => ["type" => "varchar(32)", "not null" => "1", "default" => "", "comment" => ""], + "country-name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "hometown" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "gender" => ["type" => "varchar(32)", "not null" => "1", "default" => "", "comment" => ""], + "marital" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "with" => ["type" => "text", "comment" => ""], + "howlong" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], + "sexual" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "politic" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "religion" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "pub_keywords" => ["type" => "text", "comment" => ""], + "prv_keywords" => ["type" => "text", "comment" => ""], + "likes" => ["type" => "text", "comment" => ""], + "dislikes" => ["type" => "text", "comment" => ""], + "about" => ["type" => "text", "comment" => ""], + "summary" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "music" => ["type" => "text", "comment" => ""], + "book" => ["type" => "text", "comment" => ""], + "tv" => ["type" => "text", "comment" => ""], + "film" => ["type" => "text", "comment" => ""], + "interest" => ["type" => "text", "comment" => ""], + "romance" => ["type" => "text", "comment" => ""], + "work" => ["type" => "text", "comment" => ""], + "education" => ["type" => "text", "comment" => ""], + "contact" => ["type" => "text", "comment" => ""], + "homepage" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "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" => "publish default profile in local directory"], + "net-publish" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "publish profile in global directory"], + ], + "indexes" => [ + "PRIMARY" => ["id"], + "uid_is-default" => ["uid", "is-default"], + ] + ], + "profile_check" => [ + "comment" => "DFRN remote auth use", + "fields" => [ + "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" => "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" => ""], + ], + "indexes" => [ + "PRIMARY" => ["id"], + ] + ], + "push_subscriber" => [ + "comment" => "Used for OStatus: Contains feed subscribers", + "fields" => [ + "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" => ""], + "nickname" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "push" => ["type" => "tinyint", "not null" => "1", "default" => "0", "comment" => "Retrial counter"], + "last_update" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Date of last successful trial"], + "next_try" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Next retrial date"], + "renewed" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Date of last subscription renewal"], + "secret" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + ], + "indexes" => [ + "PRIMARY" => ["id"], + "next_try" => ["next_try"], + ] + ], + "queue" => [ + "comment" => "Queue for messages that couldn't be delivered", + "fields" => [ + "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"], + "created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Date, when the message was created"], + "last" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Date of last trial"], + "next" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Next retrial date"], + "retrial" => ["type" => "tinyint", "not null" => "1", "default" => "0", "comment" => "Retrial counter"], + "content" => ["type" => "mediumtext", "comment" => ""], + "batch" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], + ], + "indexes" => [ + "PRIMARY" => ["id"], + "last" => ["last"], + "next" => ["next"], + ] + ], + "register" => [ + "comment" => "registrations requiring admin approval", + "fields" => [ + "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" => DBA::NULL_DATETIME, "comment" => ""], + "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "User id"], + "password" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "language" => ["type" => "varchar(16)", "not null" => "1", "default" => "", "comment" => ""], + "note" => ["type" => "text", "comment" => ""], + ], + "indexes" => [ + "PRIMARY" => ["id"], + ] + ], + "search" => [ + "comment" => "", + "fields" => [ + "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" => ""], + ], + "indexes" => [ + "PRIMARY" => ["id"], + "uid" => ["uid"], + ] + ], + "session" => [ + "comment" => "web session storage", + "fields" => [ + "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" => ""], + ], + "indexes" => [ + "PRIMARY" => ["id"], + "sid" => ["sid(64)"], + "expire" => ["expire"], + ] + ], + "sign" => [ + "comment" => "Diaspora signatures", + "fields" => [ + "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" => ""], + ], + "indexes" => [ + "PRIMARY" => ["id"], + "iid" => ["UNIQUE", "iid"], + ] + ], + "term" => [ + "comment" => "item taxonomy (categories, tags, etc.) table", + "fields" => [ + "tid" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""], + "oid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["item" => "id"], "comment" => ""], + "otype" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""], + "type" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""], + "term" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "url" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "guid" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], + "received" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], + "global" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], + "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "User id"], + ], + "indexes" => [ + "PRIMARY" => ["tid"], + "oid_otype_type_term" => ["oid", "otype", "type", "term(32)"], + "uid_otype_type_term_global_created" => ["uid", "otype", "type", "term(32)", "global", "created"], + "uid_otype_type_url" => ["uid", "otype", "type", "url(64)"], + "guid" => ["guid(64)"], + ] + ], + "thread" => [ + "comment" => "Thread related data", + "fields" => [ + "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" => "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" => DBA::NULL_DATETIME, "comment" => ""], + "edited" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], + "commented" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], + "received" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], + "changed" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], + "wall" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], + "private" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], + "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" => ""], + "starred" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], + "ignored" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], + "post-type" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => "Post type (personal note, bookmark, ...)"], + "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" => ""], + "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" => ""], + "bookmark" => ["type" => "boolean", "comment" => ""], + ], + "indexes" => [ + "PRIMARY" => ["iid"], + "uid_network_commented" => ["uid", "network", "commented"], + "uid_network_created" => ["uid", "network", "created"], + "uid_contactid_commented" => ["uid", "contact-id", "commented"], + "uid_contactid_created" => ["uid", "contact-id", "created"], + "contactid" => ["contact-id"], + "ownerid" => ["owner-id"], + "authorid" => ["author-id"], + "uid_created" => ["uid", "created"], + "uid_commented" => ["uid", "commented"], + "uid_wall_created" => ["uid", "wall", "created"], + "private_wall_origin_commented" => ["private", "wall", "origin", "commented"], + ] + ], + "tokens" => [ + "comment" => "OAuth usage", + "fields" => [ + "id" => ["type" => "varchar(40)", "not null" => "1", "primary" => "1", "comment" => ""], + "secret" => ["type" => "text", "comment" => ""], + "client_id" => ["type" => "varchar(20)", "not null" => "1", "default" => "", "relation" => ["clients" => "client_id"]], + "expires" => ["type" => "int", "not null" => "1", "default" => "0", "comment" => ""], + "scope" => ["type" => "varchar(200)", "not null" => "1", "default" => "", "comment" => ""], + "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "User id"], + ], + "indexes" => [ + "PRIMARY" => ["id"], + ] + ], + "user" => [ + "comment" => "The local users", + "fields" => [ + "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" => "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" => "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" => "PHP-legal timezone"], + "language" => ["type" => "varchar(32)", "not null" => "1", "default" => "en", "comment" => "default language"], + "register_date" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "timestamp of registration"], + "login_date" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "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" => "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" => "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" => "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" => DBA::NULL_DATETIME, "comment" => "timestamp when account expires and will be deleted"], + "expire_notification_sent" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "timestamp of last warning of account expiration"], + "def_gid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "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" => [ + "PRIMARY" => ["uid"], + "nickname" => ["nickname(32)"], + ] + ], + "userd" => [ + "comment" => "Deleted usernames", + "fields" => [ + "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"], + "username" => ["type" => "varchar(255)", "not null" => "1", "comment" => ""], + ], + "indexes" => [ + "PRIMARY" => ["id"], + "username" => ["username(32)"], + ] + ], + "user-contact" => [ + "comment" => "User specific public contact data", + "fields" => [ + "cid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "primary" => "1", "relation" => ["contact" => "id"], "comment" => "Contact id of the linked public contact"], + "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "primary" => "1", "relation" => ["user" => "uid"], "comment" => "User id"], + "blocked" => ["type" => "boolean", "comment" => "Contact is completely blocked for this user"], + "ignored" => ["type" => "boolean", "comment" => "Posts from this contact are ignored"], + "collapsed" => ["type" => "boolean", "comment" => "Posts from this contact are collapsed"] + ], + "indexes" => [ + "PRIMARY" => ["uid", "cid"] + ] + ], + "user-item" => [ + "comment" => "User specific item data", + "fields" => [ + "iid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "primary" => "1", "relation" => ["item" => "id"], "comment" => "Item id"], + "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "primary" => "1", "relation" => ["user" => "uid"], "comment" => "User id"], + "hidden" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Marker to hide an item from the user"], + "ignored" => ["type" => "boolean", "comment" => "Ignore this thread if set"] + ], + "indexes" => [ + "PRIMARY" => ["uid", "iid"] + ] + ], + "worker-ipc" => [ + "comment" => "Inter process communication between the frontend and the worker", + "fields" => [ + "key" => ["type" => "int", "not null" => "1", "primary" => "1", "comment" => ""], + "jobs" => ["type" => "boolean", "comment" => "Flag for outstanding jobs"], + ], + "indexes" => [ + "PRIMARY" => ["key"], + ], + "engine" => "MEMORY", + ], + "workerqueue" => [ + "comment" => "Background tasks queue entries", + "fields" => [ + "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "Auto incremented worker task id"], + "parameter" => ["type" => "mediumblob", "comment" => "Task command"], + "priority" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => "Task priority"], + "created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "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" => DBA::NULL_DATETIME, "comment" => "Execution date"], + "next_try" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Next retrial date"], + "retrial" => ["type" => "tinyint", "not null" => "1", "default" => "0", "comment" => "Retrial counter"], + "done" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Marked 1 when the task was done - will be deleted later"], + ], + "indexes" => [ + "PRIMARY" => ["id"], + "pid" => ["pid"], + "parameter" => ["parameter(64)"], + "priority_created_next_try" => ["priority", "created", "next_try"], + "done_executed_next_try" => ["done", "executed", "next_try"] + ] + ] +]; diff --git a/include/api.php b/include/api.php index 5e108632c9..7e54fa382a 100644 --- a/include/api.php +++ b/include/api.php @@ -1335,9 +1335,9 @@ function api_status_show($type, $item_id = 0) } if ($status_info["source"] == 'web') { - $status_info["source"] = ContactSelector::networkToName($lastwall['network'], $user_info['url']); - } elseif (ContactSelector::networkToName($lastwall['network'], $user_info['url']) != $status_info["source"]) { - $status_info["source"] = trim($status_info["source"].' ('.ContactSelector::networkToName($lastwall['network'], $user_info['url']).')'); + $status_info["source"] = ContactSelector::networkToName($lastwall['network'], $lastwall['author-link']); + } elseif (ContactSelector::networkToName($lastwall['network'], $lastwall['author-link']) != $status_info["source"]) { + $status_info["source"] = trim($status_info["source"].' ('.ContactSelector::networkToName($lastwall['network'], $lastwall['author-link']).')'); } // "uid" and "self" are only needed for some internal stuff, so remove it from here @@ -1410,11 +1410,11 @@ function api_users_show($type) } if ($user_info["status"]["source"] == 'web') { - $user_info["status"]["source"] = ContactSelector::networkToName($lastwall['network'], $user_info['url']); + $user_info["status"]["source"] = ContactSelector::networkToName($lastwall['network'], $lastwall['author-link']); } if (ContactSelector::networkToName($lastwall['network'], $user_info['url']) != $user_info["status"]["source"]) { - $user_info["status"]["source"] = trim($user_info["status"]["source"] . ' (' . ContactSelector::networkToName($lastwall['network'], $user_info['url']) . ')'); + $user_info["status"]["source"] = trim($user_info["status"]["source"] . ' (' . ContactSelector::networkToName($lastwall['network'], $lastwall['author-link']) . ')'); } } @@ -2912,9 +2912,9 @@ function api_format_items($r, $user_info, $filter_user = false, $type = "json") } if ($status["source"] == 'web') { - $status["source"] = ContactSelector::networkToName($item['network'], $user_info['url']); - } elseif (ContactSelector::networkToName($item['network'], $user_info['url']) != $status["source"]) { - $status["source"] = trim($status["source"].' ('.ContactSelector::networkToName($item['network'], $user_info['url']).')'); + $status["source"] = ContactSelector::networkToName($item['network'], $item['author-link']); + } elseif (ContactSelector::networkToName($item['network'], $item['author-link']) != $status["source"]) { + $status["source"] = trim($status["source"].' ('.ContactSelector::networkToName($item['network'], $item['author-link']).')'); } if ($item["id"] == $item["parent"]) { @@ -4809,7 +4809,8 @@ function api_friendica_remoteauth() logger($contact['name'] . ' ' . $sec, LOGGER_DEBUG); $dest = ($url ? '&destination_url=' . $url : ''); - goaway( + + System::externalRedirect( $contact['poll'] . '?dfrn_id=' . $dfrn_id . '&dfrn_version=' . DFRN_PROTOCOL_VERSION . '&type=profile&sec=' . $sec . $dest diff --git a/include/conversation.php b/include/conversation.php index 31920c2fcb..4573f44a45 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -353,7 +353,8 @@ function localize_item(&$item) $author = ['uid' => 0, 'id' => $item['author-id'], 'network' => $item['author-network'], 'url' => $item['author-link']]; - if (!empty($item['plink'])) { + // Only create a redirection to a magic link when logged in + if (!empty($item['plink']) && (local_user() || remote_user())) { $item['plink'] = Contact::magicLinkbyContact($author, $item['plink']); } } @@ -533,7 +534,7 @@ function conversation(App $a, array $items, $mode, $update, $preview = false, $o $page_dropping = ((local_user() && local_user() == $profile_owner) ? true : false); if (!$update) { - $_SESSION['return_url'] = $a->query_string; + $_SESSION['return_path'] = $a->query_string; } $cb = ['items' => $items, 'mode' => $mode, 'update' => $update, 'preview' => $preview]; diff --git a/include/items.php b/include/items.php index 27a7db767b..54ae7a82ce 100644 --- a/include/items.php +++ b/include/items.php @@ -354,7 +354,7 @@ function drop_item($id) if (!DBA::isResult($item)) { notice(L10n::t('Item not found.') . EOL); - goaway('/network'); + $a->internalRedirect('network'); } if ($item['deleted']) { @@ -401,17 +401,17 @@ function drop_item($id) } // Now check how the user responded to the confirmation query if (!empty($_REQUEST['canceled'])) { - goaway('/display/' . $item['guid']); + $a->internalRedirect('display/' . $item['guid']); } // delete the item Item::deleteForUser(['id' => $item['id']], local_user()); - goaway('/network'); + $a->internalRedirect('network'); //NOTREACHED } else { notice(L10n::t('Permission denied.') . EOL); - goaway('/display/' . $item['guid']); + $a->internalRedirect('display/' . $item['guid']); //NOTREACHED } } diff --git a/index.php b/index.php index c834688ffb..43bfd3800e 100644 --- a/index.php +++ b/index.php @@ -4,482 +4,12 @@ * Friendica */ -/** - * Bootstrap the application - */ - use Friendica\App; -use Friendica\Content\Nav; -use Friendica\Core\Addon; -use Friendica\Core\Config; -use Friendica\Core\L10n; -use Friendica\Core\Session; -use Friendica\Core\System; -use Friendica\Core\Theme; -use Friendica\Core\Worker; -use Friendica\Database\DBA; -use Friendica\Model\Profile; -use Friendica\Module\Login; require_once 'boot.php'; // We assume that the index.php is called by a frontend process -// The value is set to "true" by default in boot.php +// The value is set to "true" by default in App $a = new App(__DIR__, false); -/** - * Try to open the database; - */ - -require_once "include/dba.php"; - -// Missing DB connection: ERROR -if ($a->getMode()->has(App\Mode::LOCALCONFIGPRESENT) && !$a->getMode()->has(App\Mode::DBAVAILABLE)) { - System::httpExit(500, ['title' => 'Error 500 - Internal Server Error', 'description' => 'Apologies but the website is unavailable at the moment.']); -} - -// Max Load Average reached: ERROR -if ($a->isMaxProcessesReached() || $a->isMaxLoadReached()) { - header('Retry-After: 120'); - header('Refresh: 120; url=' . System::baseUrl() . "/" . $a->query_string); - - System::httpExit(503, ['title' => 'Error 503 - Service Temporarily Unavailable', 'description' => 'System is currently overloaded. Please try again later.']); -} - -if (strstr($a->query_string, '.well-known/host-meta') && ($a->query_string != '.well-known/host-meta')) { - System::httpExit(404); -} - -if (!$a->getMode()->isInstall()) { - if (Config::get('system', 'force_ssl') && ($a->getScheme() == "http") - && (intval(Config::get('system', 'ssl_policy')) == SSL_POLICY_FULL) - && (substr(System::baseUrl(), 0, 8) == "https://") - && ($_SERVER['REQUEST_METHOD'] == 'GET')) { - header("HTTP/1.1 302 Moved Temporarily"); - header("Location: " . System::baseUrl() . "/" . $a->query_string); - exit(); - } - - Config::init(); - Session::init(); - Addon::loadHooks(); - Addon::callHooks('init_1'); -} - -$lang = L10n::getBrowserLanguage(); - -L10n::loadTranslationTable($lang); - -/** - * Important stuff we always need to do. - * - * The order of these may be important so use caution if you think they're all - * intertwingled with no logical order and decide to sort it out. Some of the - * dependencies have changed, but at least at one time in the recent past - the - * order was critical to everything working properly - */ - -// Exclude the backend processes from the session management -if (!$a->isBackend()) { - $stamp1 = microtime(true); - session_start(); - $a->saveTimestamp($stamp1, "parser"); -} else { - $_SESSION = []; - Worker::executeIfIdle(); -} - -/** - * Language was set earlier, but we can over-ride it in the session. - * We have to do it here because the session was just now opened. - */ -if (!empty($_SESSION['authenticated']) && empty($_SESSION['language'])) { - $_SESSION['language'] = $lang; - // we haven't loaded user data yet, but we need user language - if (!empty($_SESSION['uid'])) { - $user = DBA::selectFirst('user', ['language'], ['uid' => $_SESSION['uid']]); - if (DBA::isResult($user)) { - $_SESSION['language'] = $user['language']; - } - } -} - -if (!empty($_SESSION['language']) && $_SESSION['language'] !== $lang) { - $lang = $_SESSION['language']; - L10n::loadTranslationTable($lang); -} - -if (!empty($_GET['zrl']) && $a->getMode()->isNormal()) { - $a->query_string = Profile::stripZrls($a->query_string); - if (!local_user()) { - // Only continue when the given profile link seems valid - // Valid profile links contain a path with "/profile/" and no query parameters - if ((parse_url($_GET['zrl'], PHP_URL_QUERY) == "") && - strstr(parse_url($_GET['zrl'], PHP_URL_PATH), "/profile/")) { - if (defaults($_SESSION, "visitor_home", "") != $_GET["zrl"]) { - $_SESSION['my_url'] = $_GET['zrl']; - $_SESSION['authenticated'] = 0; - } - Profile::zrlInit($a); - } else { - // Someone came with an invalid parameter, maybe as a DDoS attempt - // We simply stop processing here - logger("Invalid ZRL parameter " . $_GET['zrl'], LOGGER_DEBUG); - header('HTTP/1.1 403 Forbidden'); - echo "

403 Forbidden

"; - exit(); - } - } -} - -if (!empty($_GET['owt']) && $a->getMode()->isNormal()) { - $token = $_GET['owt']; - $a->query_string = Profile::stripQueryParam($a->query_string, 'owt'); - Profile::openWebAuthInit($token); -} - -/** - * For Mozilla auth manager - still needs sorting, and this might conflict with LRDD header. - * Apache/PHP lumps the Link: headers into one - and other services might not be able to parse it - * this way. There's a PHP flag to link the headers because by default this will over-write any other - * link header. - * - * What we really need to do is output the raw headers ourselves so we can keep them separate. - */ - -// header('Link: <' . System::baseUrl() . '/amcd>; rel="acct-mgmt";'); - -Login::sessionAuth(); - -if (empty($_SESSION['authenticated'])) { - header('X-Account-Management-Status: none'); -} - -$_SESSION['sysmsg'] = defaults($_SESSION, 'sysmsg' , []); -$_SESSION['sysmsg_info'] = defaults($_SESSION, 'sysmsg_info' , []); -$_SESSION['last_updated'] = defaults($_SESSION, 'last_updated', []); - -/* - * check_config() is responsible for running update scripts. These automatically - * update the DB schema whenever we push a new one out. It also checks to see if - * any addons have been added or removed and reacts accordingly. - */ - -// in install mode, any url loads install module -// but we need "view" module for stylesheet -if ($a->getMode()->isInstall() && $a->module != 'view') { - $a->module = 'install'; -} elseif (!$a->getMode()->has(App\Mode::MAINTENANCEDISABLED) && $a->module != 'view') { - $a->module = 'maintenance'; -} else { - $a->checkURL(); - check_db(false); - Addon::check(); -} - -Nav::setSelected('nothing'); - -//Don't populate apps_menu if apps are private -$privateapps = Config::get('config', 'private_addons'); -if ((local_user()) || (! $privateapps === "1")) { - $arr = ['app_menu' => $a->apps]; - - Addon::callHooks('app_menu', $arr); - - $a->apps = $arr['app_menu']; -} - -/** - * We have already parsed the server path into $a->argc and $a->argv - * - * $a->argv[0] is our module name. We will load the file mod/{$a->argv[0]}.php - * and use it for handling our URL request. - * The module file contains a few functions that we call in various circumstances - * and in the following order: - * - * "module"_init - * "module"_post (only called if there are $_POST variables) - * "module"_afterpost - * "module"_content - the string return of this function contains our page body - * - * Modules which emit other serialisations besides HTML (XML,JSON, etc.) should do - * so within the module init and/or post functions and then invoke killme() to terminate - * further processing. - */ -if (strlen($a->module)) { - - /** - * We will always have a module name. - * First see if we have an addon which is masquerading as a module. - */ - - // Compatibility with the Android Diaspora client - if ($a->module == 'stream') { - goaway('network?f=&order=post'); - } - - if ($a->module == 'conversations') { - goaway('message'); - } - - if ($a->module == 'commented') { - goaway('network?f=&order=comment'); - } - - if ($a->module == 'liked') { - goaway('network?f=&order=comment'); - } - - if ($a->module == 'activity') { - goaway('network/?f=&conv=1'); - } - - if (($a->module == 'status_messages') && ($a->cmd == 'status_messages/new')) { - goaway('bookmarklet'); - } - - if (($a->module == 'user') && ($a->cmd == 'user/edit')) { - goaway('settings'); - } - - if (($a->module == 'tag_followings') && ($a->cmd == 'tag_followings/manage')) { - goaway('search'); - } - - // Compatibility with the Firefox App - if (($a->module == "users") && ($a->cmd == "users/sign_in")) { - $a->module = "login"; - } - - $privateapps = Config::get('config', 'private_addons'); - - if (is_array($a->addons) && in_array($a->module, $a->addons) && file_exists("addon/{$a->module}/{$a->module}.php")) { - //Check if module is an app and if public access to apps is allowed or not - if ((!local_user()) && Addon::isApp($a->module) && $privateapps === "1") { - info(L10n::t("You must be logged in to use addons. ")); - } else { - include_once "addon/{$a->module}/{$a->module}.php"; - if (function_exists($a->module . '_module')) { - Friendica\LegacyModule::setModuleFile("addon/{$a->module}/{$a->module}.php"); - $a->module_class = 'Friendica\\LegacyModule'; - $a->module_loaded = true; - } - } - } - - // Controller class routing - if (! $a->module_loaded && class_exists('Friendica\\Module\\' . ucfirst($a->module))) { - $a->module_class = 'Friendica\\Module\\' . ucfirst($a->module); - $a->module_loaded = true; - } - - /** - * If not, next look for a 'standard' program module in the 'mod' directory - * We emulate a Module class through the LegacyModule class - */ - if (! $a->module_loaded && file_exists("mod/{$a->module}.php")) { - Friendica\LegacyModule::setModuleFile("mod/{$a->module}.php"); - $a->module_class = 'Friendica\\LegacyModule'; - $a->module_loaded = true; - } - - /** - * The URL provided does not resolve to a valid module. - * - * On Dreamhost sites, quite often things go wrong for no apparent reason and they send us to '/internal_error.html'. - * We don't like doing this, but as it occasionally accounts for 10-20% or more of all site traffic - - * we are going to trap this and redirect back to the requested page. As long as you don't have a critical error on your page - * this will often succeed and eventually do the right thing. - * - * Otherwise we are going to emit a 404 not found. - */ - - if (! $a->module_loaded) { - // Stupid browser tried to pre-fetch our Javascript img template. Don't log the event or return anything - just quietly exit. - if (!empty($_SERVER['QUERY_STRING']) && preg_match('/{[0-9]}/', $_SERVER['QUERY_STRING']) !== 0) { - killme(); - } - - if (!empty($_SERVER['QUERY_STRING']) && ($_SERVER['QUERY_STRING'] === 'q=internal_error.html') && isset($dreamhost_error_hack)) { - logger('index.php: dreamhost_error_hack invoked. Original URI =' . $_SERVER['REQUEST_URI']); - goaway(System::baseUrl() . $_SERVER['REQUEST_URI']); - } - - logger('index.php: page not found: ' . $_SERVER['REQUEST_URI'] . ' ADDRESS: ' . $_SERVER['REMOTE_ADDR'] . ' QUERY: ' . $_SERVER['QUERY_STRING'], LOGGER_DEBUG); - header($_SERVER["SERVER_PROTOCOL"] . ' 404 ' . L10n::t('Not Found')); - $tpl = get_markup_template("404.tpl"); - $a->page['content'] = replace_macros($tpl, [ - '$message' => L10n::t('Page not found.') - ]); - } -} - -/** - * Load current theme info - */ -$theme_info_file = 'view/theme/' . $a->getCurrentTheme() . '/theme.php'; -if (file_exists($theme_info_file)) { - require_once $theme_info_file; -} - - -/* initialise content region */ - -if ($a->getMode()->isNormal()) { - Addon::callHooks('page_content_top', $a->page['content']); -} - -/** - * Call module functions - */ - -if ($a->module_loaded) { - $a->page['page_title'] = $a->module; - $placeholder = ''; - - Addon::callHooks($a->module . '_mod_init', $placeholder); - - call_user_func([$a->module_class, 'init']); - - // "rawContent" is especially meant for technical endpoints. - // This endpoint doesn't need any theme initialization or other comparable stuff. - if (!$a->error) { - call_user_func([$a->module_class, 'rawContent']); - } - - if (function_exists(str_replace('-', '_', $a->getCurrentTheme()) . '_init')) { - $func = str_replace('-', '_', $a->getCurrentTheme()) . '_init'; - $func($a); - } - - if (! $a->error && $_SERVER['REQUEST_METHOD'] === 'POST') { - Addon::callHooks($a->module . '_mod_post', $_POST); - call_user_func([$a->module_class, 'post']); - } - - if (! $a->error) { - Addon::callHooks($a->module . '_mod_afterpost', $placeholder); - call_user_func([$a->module_class, 'afterpost']); - } - - if (! $a->error) { - $arr = ['content' => $a->page['content']]; - Addon::callHooks($a->module . '_mod_content', $arr); - $a->page['content'] = $arr['content']; - $arr = ['content' => call_user_func([$a->module_class, 'content'])]; - Addon::callHooks($a->module . '_mod_aftercontent', $arr); - $a->page['content'] .= $arr['content']; - } - - if (function_exists(str_replace('-', '_', $a->getCurrentTheme()) . '_content_loaded')) { - $func = str_replace('-', '_', $a->getCurrentTheme()) . '_content_loaded'; - $func($a); - } -} - -/* - * Create the page head after setting the language - * and getting any auth credentials. - * - * Moved init_pagehead() and init_page_end() to after - * all the module functions have executed so that all - * theme choices made by the modules can take effect. - */ - -$a->initHead(); - -/* - * Build the page ending -- this is stuff that goes right before - * the closing tag - */ -$a->initFooter(); - -/* - * now that we've been through the module content, see if the page reported - * a permission problem and if so, a 403 response would seem to be in order. - */ -if (stristr(implode("", $_SESSION['sysmsg']), L10n::t('Permission denied'))) { - header($_SERVER["SERVER_PROTOCOL"] . ' 403 ' . L10n::t('Permission denied.')); -} - -/* - * Report anything which needs to be communicated in the notification area (before the main body) - */ -Addon::callHooks('page_end', $a->page['content']); - -/* - * Add the navigation (menu) template - */ -if ($a->module != 'install' && $a->module != 'maintenance') { - Nav::build($a); -} - -/** - * Build the page - now that we have all the components - */ -if (isset($_GET["mode"]) && (($_GET["mode"] == "raw") || ($_GET["mode"] == "minimal"))) { - $doc = new DOMDocument(); - - $target = new DOMDocument(); - $target->loadXML(""); - - $content = mb_convert_encoding($a->page["content"], 'HTML-ENTITIES', "UTF-8"); - - /// @TODO one day, kill those error-surpressing @ stuff, or PHP should ban it - @$doc->loadHTML($content); - - $xpath = new DOMXPath($doc); - - $list = $xpath->query("//*[contains(@id,'tread-wrapper-')]"); /* */ - - foreach ($list as $item) { - $item = $target->importNode($item, true); - - // And then append it to the target - $target->documentElement->appendChild($item); - } -} - -if (isset($_GET["mode"]) && ($_GET["mode"] == "raw")) { - header("Content-type: text/html; charset=utf-8"); - - echo substr($target->saveHTML(), 6, -8); - - exit(); -} - -$page = $a->page; -$profile = $a->profile; - -header("X-Friendica-Version: " . FRIENDICA_VERSION); -header("Content-type: text/html; charset=utf-8"); - -if (Config::get('system', 'hsts') && (Config::get('system', 'ssl_policy') == SSL_POLICY_FULL)) { - header("Strict-Transport-Security: max-age=31536000"); -} - -// Some security stuff -header('X-Content-Type-Options: nosniff'); -header('X-XSS-Protection: 1; mode=block'); -header('X-Permitted-Cross-Domain-Policies: none'); -header('X-Frame-Options: sameorigin'); - -// Things like embedded OSM maps don't work, when this is enabled -// header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; connect-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self'; img-src 'self' https: data:; media-src 'self' https:; child-src 'self' https:; object-src 'none'"); - -/* - * We use $_GET["mode"] for special page templates. So we will check if we have - * to load another page template than the default one. - * The page templates are located in /view/php/ or in the theme directory. - */ -if (isset($_GET["mode"])) { - $template = Theme::getPathForFile($_GET["mode"] . '.php'); -} - -// If there is no page template use the default page template -if (empty($template)) { - $template = Theme::getPathForFile("default.php"); -} - -/// @TODO Looks unsafe (remote-inclusion), is maybe not but Theme::getPathForFile() uses file_exists() but does not escape anything -require_once $template; +$a->runFrontend(); diff --git a/mod/admin.php b/mod/admin.php index 2714b0b864..e3b537fcf0 100644 --- a/mod/admin.php +++ b/mod/admin.php @@ -82,7 +82,7 @@ function admin_post(App $a) if ($a->isAjax()) { return; } - goaway('admin/'); + $a->internalRedirect('admin/'); return; } @@ -135,7 +135,7 @@ function admin_post(App $a) } } - goaway($return_path); + $a->internalRedirect($return_path); return; // NOTREACHED } @@ -214,11 +214,12 @@ function admin_content(App $a) $r = q("SELECT `name` FROM `addon` WHERE `plugin_admin` = 1 ORDER BY `name`"); $aside_tools['addons_admin'] = []; + $addons_admin = []; foreach ($r as $h) { $addon = $h['name']; $aside_tools['addons_admin'][] = ["admin/addons/" . $addon, $addon, "addon"]; // temp addons with admin - $a->addons_admin[] = $addon; + $addons_admin[] = $addon; } $t = get_markup_template('admin/aside.tpl'); @@ -243,7 +244,7 @@ function admin_content(App $a) $o = admin_page_users($a); break; case 'addons': - $o = admin_page_addons($a); + $o = admin_page_addons($a, $addons_admin); break; case 'themes': $o = admin_page_themes($a); @@ -340,7 +341,7 @@ function admin_page_tos_post(App $a) Config::set('system', 'tosprivstatement', $displayprivstatement); Config::set('system', 'tostext', $tostext); - goaway('admin/tos'); + $a->internalRedirect('admin/tos'); return; // NOTREACHED } @@ -429,7 +430,7 @@ function admin_page_blocklist_post(App $a) Config::set('system', 'blocklist', $blocklist); info(L10n::t('Site blocklist updated.') . EOL); } - goaway('admin/blocklist'); + $a->internalRedirect('admin/blocklist'); return; // NOTREACHED } @@ -461,7 +462,7 @@ function admin_page_contactblock_post(App $a) } notice(L10n::tt("%s contact unblocked", "%s contacts unblocked", count($contacts))); } - goaway('admin/contactblock'); + $a->internalRedirect('admin/contactblock'); return; // NOTREACHED } @@ -569,7 +570,7 @@ function admin_page_deleteitem_post(App $a) } info(L10n::t('Item marked for deletion.') . EOL); - goaway('admin/deleteitem'); + $a->internalRedirect('admin/deleteitem'); return; // NOTREACHED } @@ -932,7 +933,7 @@ function admin_page_summary(App $a) '$platform' => FRIENDICA_PLATFORM, '$codename' => FRIENDICA_CODENAME, '$build' => Config::get('system', 'build'), - '$addons' => [L10n::t('Active addons'), $a->addons], + '$addons' => [L10n::t('Active addons'), Addon::getEnabledList()], '$serversettings' => $server_settings, '$showwarning' => $showwarning, '$warningtext' => $warningtext @@ -965,7 +966,7 @@ function admin_page_site_post(App $a) $parsed = @parse_url($new_url); if (!is_array($parsed) || !x($parsed, 'host') || !x($parsed, 'scheme')) { notice(L10n::t("Can not parse base url. Must have at least ://")); - goaway('admin/site'); + $a->internalRedirect('admin/site'); } /* steps: @@ -973,13 +974,13 @@ function admin_page_site_post(App $a) * send relocate for every local user * */ - $old_url = System::baseUrl(true); + $old_url = $a->getBaseURL(true); // Generate host names for relocation the addresses in the format user@address.tld $new_host = str_replace("http://", "@", normalise_link($new_url)); $old_host = str_replace("http://", "@", normalise_link($old_url)); - function update_table($table_name, $fields, $old_url, $new_url) + function update_table(App $a, $table_name, $fields, $old_url, $new_url) { $dbold = DBA::escape($old_url); $dbnew = DBA::escape($new_url); @@ -995,20 +996,20 @@ function admin_page_site_post(App $a) if (!DBA::isResult($r)) { notice("Failed updating '$table_name': " . DBA::errorMessage()); - goaway('admin/site'); + $a->internalRedirect('admin/site'); } } // update tables // update profile links in the format "http://server.tld" - update_table("profile", ['photo', 'thumb'], $old_url, $new_url); - update_table("term", ['url'], $old_url, $new_url); - update_table("contact", ['photo', 'thumb', 'micro', 'url', 'nurl', 'alias', 'request', 'notify', 'poll', 'confirm', 'poco', 'avatar'], $old_url, $new_url); - update_table("gcontact", ['url', 'nurl', 'photo', 'server_url', 'notify', 'alias'], $old_url, $new_url); - update_table("item", ['owner-link', 'author-link', 'body', 'plink', 'tag'], $old_url, $new_url); + update_table($a, "profile", ['photo', 'thumb'], $old_url, $new_url); + update_table($a, "term", ['url'], $old_url, $new_url); + update_table($a, "contact", ['photo', 'thumb', 'micro', 'url', 'nurl', 'alias', 'request', 'notify', 'poll', 'confirm', 'poco', 'avatar'], $old_url, $new_url); + update_table($a, "gcontact", ['url', 'nurl', 'photo', 'server_url', 'notify', 'alias'], $old_url, $new_url); + update_table($a, "item", ['owner-link', 'author-link', 'body', 'plink', 'tag'], $old_url, $new_url); // update profile addresses in the format "user@server.tld" - update_table("contact", ['addr'], $old_host, $new_host); - update_table("gcontact", ['connect', 'addr'], $old_host, $new_host); + update_table($a, "contact", ['addr'], $old_host, $new_host); + update_table($a, "gcontact", ['connect', 'addr'], $old_host, $new_host); // update config Config::set('system', 'hostname', parse_url($new_url, PHP_URL_HOST)); @@ -1024,7 +1025,7 @@ function admin_page_site_post(App $a) info("Relocation started. Could take a while to complete."); - goaway('admin/site'); + $a->internalRedirect('admin/site'); } // end relocate @@ -1298,7 +1299,7 @@ function admin_page_site_post(App $a) Config::set('system', 'rino_encrypt', $rino); info(L10n::t('Site settings updated.') . EOL); - goaway('admin/site'); + $a->internalRedirect('admin/site'); return; // NOTREACHED } @@ -1570,7 +1571,7 @@ function admin_page_dbsync(App $a) Config::set('system', 'build', intval($curr) + 1); } info(L10n::t('Update has been marked successful') . EOL); - goaway('admin/dbsync'); + $a->internalRedirect('admin/dbsync'); } if (($a->argc > 2) && (intval($a->argv[2]) || ($a->argv[2] === 'check'))) { @@ -1745,7 +1746,7 @@ function admin_page_users_post(App $a) user_deny($hash); } } - goaway('admin/users'); + $a->internalRedirect('admin/users'); return; // NOTREACHED } @@ -1768,7 +1769,7 @@ function admin_page_users(App $a) $user = DBA::selectFirst('user', ['username', 'blocked'], ['uid' => $uid]); if (!DBA::isResult($user)) { notice('User not found' . EOL); - goaway('admin/users'); + $a->internalRedirect('admin/users'); return ''; // NOTREACHED } switch ($a->argv[2]) { @@ -1788,7 +1789,7 @@ function admin_page_users(App $a) notice(sprintf(($user['blocked'] ? L10n::t("User '%s' unblocked") : L10n::t("User '%s' blocked")), $user['username']) . EOL); break; } - goaway('admin/users'); + $a->internalRedirect('admin/users'); return ''; // NOTREACHED } @@ -1956,10 +1957,11 @@ function admin_page_users(App $a) * * The returned string returned hulds the HTML code of the page. * - * @param App $a + * @param App $a + * @param array $addons_admin A list of admin addon names * @return string */ -function admin_page_addons(App $a) +function admin_page_addons(App $a, array $addons_admin) { /* * Single addon @@ -1971,27 +1973,25 @@ function admin_page_addons(App $a) return ''; } - if (x($_GET, "a") && $_GET['a'] == "t") { + if (defaults($_GET, 'a', '') == "t") { BaseModule::checkFormSecurityTokenRedirectOnError('/admin/addons', 'admin_themes', 't'); // Toggle addon status - $idx = array_search($addon, $a->addons); - if ($idx !== false) { - unset($a->addons[$idx]); + if (Addon::isEnabled($addon)) { Addon::uninstall($addon); info(L10n::t("Addon %s disabled.", $addon)); } else { - $a->addons[] = $addon; Addon::install($addon); info(L10n::t("Addon %s enabled.", $addon)); } - Config::set("system", "addon", implode(", ", $a->addons)); - goaway('admin/addons'); + + Addon::saveEnabledList(); + $a->internalRedirect('admin/addons'); return ''; // NOTREACHED } // display addon details - if (in_array($addon, $a->addons)) { + if (Addon::isEnabled($addon)) { $status = "on"; $action = L10n::t("Disable"); } else { @@ -2007,7 +2007,7 @@ function admin_page_addons(App $a) } $admin_form = ""; - if (in_array($addon, $a->addons_admin)) { + if (in_array($addon, $addons_admin)) { require_once "addon/$addon/$addon.php"; $func = $addon . '_addon_admin'; $func($a, $admin_form); @@ -2020,7 +2020,7 @@ function admin_page_addons(App $a) '$page' => L10n::t('Addons'), '$toggle' => L10n::t('Toggle'), '$settings' => L10n::t('Settings'), - '$baseurl' => System::baseUrl(true), + '$baseurl' => $a->getBaseURL(true), '$addon' => $addon, '$status' => $status, @@ -2042,10 +2042,10 @@ function admin_page_addons(App $a) * List addons */ if (x($_GET, "a") && $_GET['a'] == "r") { - BaseModule::checkFormSecurityTokenRedirectOnError(System::baseUrl() . '/admin/addons', 'admin_themes', 't'); + BaseModule::checkFormSecurityTokenRedirectOnError($a->getBaseURL() . '/admin/addons', 'admin_themes', 't'); Addon::reload(); info("Addons reloaded"); - goaway(System::baseUrl() . '/admin/addons'); + $a->internalRedirect('admin/addons'); } $addons = []; @@ -2058,7 +2058,7 @@ function admin_page_addons(App $a) $show_addon = true; // If the addon is unsupported, then only show it, when it is enabled - if ((strtolower($info["status"]) == "unsupported") && !in_array($id, $a->addons)) { + if ((strtolower($info["status"]) == "unsupported") && !Addon::isEnabled($id)) { $show_addon = false; } @@ -2068,7 +2068,7 @@ function admin_page_addons(App $a) } if ($show_addon) { - $addons[] = [$id, (in_array($id, $a->addons) ? "on" : "off"), $info]; + $addons[] = [$id, (Addon::isEnabled($id) ? "on" : "off"), $info]; } } } @@ -2235,7 +2235,7 @@ function admin_page_themes(App $a) } Config::set('system', 'allowed_themes', $s); - goaway('admin/themes'); + $a->internalRedirect('admin/themes'); return ''; // NOTREACHED } @@ -2316,7 +2316,7 @@ function admin_page_themes(App $a) } } info("Themes reloaded"); - goaway(System::baseUrl() . '/admin/themes'); + $a->internalRedirect('admin/themes'); } /* @@ -2365,7 +2365,7 @@ function admin_page_logs_post(App $a) } info(L10n::t("Log settings updated.")); - goaway('admin/logs'); + $a->internalRedirect('admin/logs'); return; // NOTREACHED } @@ -2513,7 +2513,7 @@ function admin_page_features_post(App $a) } } - goaway('admin/features'); + $a->internalRedirect('admin/features'); return; // NOTREACHED } diff --git a/mod/api.php b/mod/api.php index e978461655..716b484461 100644 --- a/mod/api.php +++ b/mod/api.php @@ -5,6 +5,7 @@ use Friendica\App; use Friendica\Core\Config; use Friendica\Core\L10n; +use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\Module\Login; @@ -76,7 +77,7 @@ function api_content(App $a) if (strstr($consumer->callback_url, $glue)) { $glue = "?"; } - goaway($consumer->callback_url . $glue . "oauth_token=" . OAuthUtil::urlencode_rfc3986($params['oauth_token']) . "&oauth_verifier=" . OAuthUtil::urlencode_rfc3986($verifier)); + $a->internalRedirect($consumer->callback_url . $glue . 'oauth_token=' . OAuthUtil::urlencode_rfc3986($params['oauth_token']) . '&oauth_verifier=' . OAuthUtil::urlencode_rfc3986($verifier)); killme(); } diff --git a/mod/apps.php b/mod/apps.php index 85a3d9fe26..80138f78dc 100644 --- a/mod/apps.php +++ b/mod/apps.php @@ -2,11 +2,11 @@ /** * @file mod/apps.php */ -use Friendica\App; +use Friendica\Content\Nav; use Friendica\Core\Config; use Friendica\Core\L10n; -function apps_content(App $a) +function apps_content() { $privateaddons = Config::get('config', 'private_addons'); if ($privateaddons === "1") { @@ -18,13 +18,15 @@ function apps_content(App $a) $title = L10n::t('Applications'); - if (count($a->apps) == 0) { + $apps = Nav::getAppMenu(); + + if (count($apps) == 0) { notice(L10n::t('No installed applications.') . EOL); } $tpl = get_markup_template('apps.tpl'); return replace_macros($tpl, [ '$title' => $title, - '$apps' => $a->apps, + '$apps' => $apps, ]); } diff --git a/mod/cal.php b/mod/cal.php index b55e078d83..6f483acc16 100644 --- a/mod/cal.php +++ b/mod/cal.php @@ -301,7 +301,7 @@ function cal_content(App $a) // Respect the export feature setting for all other /cal pages if it's not the own profile if ((local_user() !== intval($owner_uid)) && !Feature::isEnabled($owner_uid, "export_calendar")) { notice(L10n::t('Permission denied.') . EOL); - goaway('cal/' . $nick); + $a->internalRedirect('cal/' . $nick); } // Get the export data by uid @@ -322,7 +322,7 @@ function cal_content(App $a) $return_path = "cal/" . $nick; } - goaway($return_path); + $a->internalRedirect($return_path); } // If nothing went wrong we can echo the export content diff --git a/mod/delegate.php b/mod/delegate.php index 2b29632dda..e38ce058e5 100644 --- a/mod/delegate.php +++ b/mod/delegate.php @@ -62,7 +62,7 @@ function delegate_content(App $a) if ($a->argc > 2 && $a->argv[1] === 'add' && intval($a->argv[2])) { // delegated admins can view but not change delegation permissions if (x($_SESSION, 'submanage')) { - goaway(System::baseUrl() . '/delegate'); + $a->internalRedirect('delegate'); } $user_id = $a->argv[2]; @@ -77,17 +77,17 @@ function delegate_content(App $a) DBA::insert('manage', ['uid' => $user_id, 'mid' => local_user()]); } } - goaway(System::baseUrl() . '/delegate'); + $a->internalRedirect('delegate'); } if ($a->argc > 2 && $a->argv[1] === 'remove' && intval($a->argv[2])) { // delegated admins can view but not change delegation permissions if (x($_SESSION, 'submanage')) { - goaway(System::baseUrl() . '/delegate'); + $a->internalRedirect('delegate'); } DBA::delete('manage', ['uid' => $a->argv[2], 'mid' => local_user()]); - goaway(System::baseUrl() . '/delegate'); + $a->internalRedirect('delegate'); } // find everybody that currently has delegated management to this account/page diff --git a/mod/dfrn_confirm.php b/mod/dfrn_confirm.php index 48ce3c6aa6..f685d9e237 100644 --- a/mod/dfrn_confirm.php +++ b/mod/dfrn_confirm.php @@ -400,7 +400,7 @@ function dfrn_confirm_post(App $a, $handsfree = null) // Let's send our user to the contact editor in case they want to // do anything special with this new friend. if ($handsfree === null) { - goaway(System::baseUrl() . '/contact/' . intval($contact_id)); + $a->internalRedirect('contact/' . intval($contact_id)); } else { return; } @@ -620,6 +620,6 @@ function dfrn_confirm_post(App $a, $handsfree = null) } // somebody arrived here by mistake or they are fishing. Send them to the homepage. - goaway(System::baseUrl()); + $a->internalRedirect(); // NOTREACHED } diff --git a/mod/dfrn_poll.php b/mod/dfrn_poll.php index af597d76ff..4e7521b0ed 100644 --- a/mod/dfrn_poll.php +++ b/mod/dfrn_poll.php @@ -90,7 +90,7 @@ function dfrn_poll_init(App $a) $my_id = '0:' . $dfrn_id; break; default: - goaway(System::baseUrl()); + $a->internalRedirect(); break; // NOTREACHED } @@ -109,7 +109,7 @@ function dfrn_poll_init(App $a) if (strlen($s)) { $xml = XML::parseString($s); - if ((int) $xml->status === 1) { + if ((int)$xml->status === 1) { $_SESSION['authenticated'] = 1; if (!x($_SESSION, 'remote')) { $_SESSION['remote'] = []; @@ -135,10 +135,15 @@ function dfrn_poll_init(App $a) ); } } - $profile = $r[0]['nickname']; - goaway((strlen($destination_url)) ? $destination_url : System::baseUrl() . '/profile/' . $profile); + + $profile = (count($r) > 0 && isset($r[0]['nickname']) ? $r[0]['nickname'] : ''); + if (!empty($destination_url)) { + System::externalRedirect($destination_url); + } else { + $a->internalRedirect('profile/' . $profile); + } } - goaway(System::baseUrl()); + $a->internalRedirect(); } if ($type === 'profile-check' && $dfrn_version < 2.2) { @@ -325,7 +330,7 @@ function dfrn_poll_post(App $a) $my_id = '0:' . $dfrn_id; break; default: - goaway(System::baseUrl()); + $a->internalRedirect(); break; // NOTREACHED } @@ -446,7 +451,7 @@ function dfrn_poll_content(App $a) $my_id = '0:' . $dfrn_id; break; default: - goaway(System::baseUrl()); + $a->internalRedirect(); break; // NOTREACHED } @@ -505,25 +510,6 @@ function dfrn_poll_content(App $a) ])->getBody(); } - $profile = ((DBA::isResult($r) && $r[0]['nickname']) ? $r[0]['nickname'] : $nickname); - - switch ($destination_url) { - case 'profile': - $dest = System::baseUrl() . '/profile/' . $profile . '?f=&tab=profile'; - break; - case 'photos': - $dest = System::baseUrl() . '/photos/' . $profile; - break; - case 'status': - case '': - $dest = System::baseUrl() . '/profile/' . $profile; - break; - default: - $appendix = (strstr($destination_url, '?') ? '&f=&redir=1' : '?f=&redir=1'); - $dest = $destination_url . $appendix; - break; - } - logger("dfrn_poll: sec profile: " . $s, LOGGER_DATA); if (strlen($s) && strstr($s, 'internalRedirect('profile/' . $profile . '?f=&tab=profile'; + break; + case 'photos': + $a->internalRedirect('photos/' . $profile; + break; + case 'status': + case '': + $a->internalRedirect('profile/' . $profile; + break; + default: + $appendix = (strstr($destination_url, '?') ? '&f=&redir=1' : '?f=&redir=1'); + System::externalRedirect($destination_url . $appendix); + break; + } // NOTREACHED } else { // XML reply diff --git a/mod/dfrn_request.php b/mod/dfrn_request.php index 67db2c6285..141e5e5aca 100644 --- a/mod/dfrn_request.php +++ b/mod/dfrn_request.php @@ -62,7 +62,7 @@ function dfrn_request_post(App $a) } if (x($_POST, 'cancel')) { - goaway(System::baseUrl()); + $a->internalRedirect(); } /* @@ -173,9 +173,9 @@ function dfrn_request_post(App $a) Contact::updateAvatar($photo, local_user(), $r[0]["id"], true); } - $forwardurl = System::baseUrl() . "/contact/" . $r[0]['id']; + $forward_path = "contact/" . $r[0]['id']; } else { - $forwardurl = System::baseUrl() . "/contact"; + $forward_path = "contact"; } // Allow the blocked remote notification to complete @@ -188,14 +188,14 @@ function dfrn_request_post(App $a) } // (ignore reply, nothing we can do it failed) - goaway($forwardurl); + $a->internalRedirect($forward_path); return; // NOTREACHED } } // invalid/bogus request notice(L10n::t('Unrecoverable protocol error.') . EOL); - goaway(System::baseUrl()); + $a->internalRedirect(); return; // NOTREACHED } @@ -331,19 +331,19 @@ function dfrn_request_post(App $a) $url = Network::isUrlValid($url); if (!$url) { notice(L10n::t('Invalid profile URL.') . EOL); - goaway(System::baseUrl() . '/' . $a->cmd); + $a->internalRedirect($a->cmd); return; // NOTREACHED } if (!Network::isUrlAllowed($url)) { notice(L10n::t('Disallowed profile URL.') . EOL); - goaway(System::baseUrl() . '/' . $a->cmd); + $a->internalRedirect($a->cmd); return; // NOTREACHED } if (Network::isUrlBlocked($url)) { notice(L10n::t('Blocked domain') . EOL); - goaway(System::baseUrl() . '/' . $a->cmd); + $a->internalRedirect($a->cmd); return; // NOTREACHED } @@ -351,7 +351,7 @@ function dfrn_request_post(App $a) if (!count($parms)) { notice(L10n::t('Profile location is not valid or does not contain profile information.') . EOL); - goaway(System::baseUrl() . '/' . $a->cmd); + $a->internalRedirect($a->cmd); } else { if (!x($parms, 'fn')) { notice(L10n::t('Warning: profile location has no identifiable owner name.') . EOL); @@ -433,10 +433,10 @@ function dfrn_request_post(App $a) } // "Homecoming" - send the requestor back to their site to record the introduction. - $dfrn_url = bin2hex(System::baseUrl() . '/profile/' . $nickname); + $dfrn_url = bin2hex($a->getBaseURL() . '/profile/' . $nickname); $aes_allow = ((function_exists('openssl_encrypt')) ? 1 : 0); - goaway($parms['dfrn-request'] . "?dfrn_url=$dfrn_url" + System::externalRedirect($parms['dfrn-request'] . "?dfrn_url=$dfrn_url" . '&dfrn_version=' . DFRN_PROTOCOL_VERSION . '&confirm_key=' . $hash . (($aes_allow) ? "&aes_allow=1" : "") @@ -459,11 +459,11 @@ function dfrn_request_post(App $a) $uri = urlencode($uri); } else { - $uri = System::baseUrl() . '/profile/' . $nickname; + $uri = 'profile/' . $nickname; } $url = str_replace('{uri}', $uri, $url); - goaway($url); + System::externalRedirect($url); // NOTREACHED // END $network != Protocol::PHANTOM } else { diff --git a/mod/display.php b/mod/display.php index 081c3ce6cf..38cdfe41d3 100644 --- a/mod/display.php +++ b/mod/display.php @@ -79,7 +79,7 @@ function display_init(App $a) } if (ActivityPub::isRequest()) { - goaway(str_replace('display/', 'objects/', $a->query_string)); + $a->internalRedirect(str_replace('display/', 'objects/', $a->query_string)); } if ($item["id"] != $item["parent"]) { diff --git a/mod/events.php b/mod/events.php index d6ad97eac6..81ab79c722 100644 --- a/mod/events.php +++ b/mod/events.php @@ -15,9 +15,9 @@ use Friendica\Database\DBA; use Friendica\Model\Event; use Friendica\Model\Item; use Friendica\Model\Profile; +use Friendica\Module\Login; use Friendica\Util\DateTimeFormat; use Friendica\Util\Temporal; -use Friendica\Module\Login; require_once 'include/items.php'; @@ -66,8 +66,8 @@ function events_post(App $a) // The default setting for the `private` field in event_store() is false, so mirror that $private_event = false; - $start = NULL_DATE; - $finish = NULL_DATE; + $start = DBA::NULL_DATETIME; + $finish = DBA::NULL_DATETIME; if ($start_text) { $start = $start_text; @@ -100,7 +100,7 @@ function events_post(App $a) $type = 'event'; $action = ($event_id == '') ? 'new' : "event/" . $event_id; - $onerror_url = System::baseUrl() . "/events/" . $action . "?summary=$summary&description=$desc&location=$location&start=$start_text&finish=$finish_text&adjust=$adjust&nofinish=$nofinish"; + $onerror_path = "events/" . $action . "?summary=$summary&description=$desc&location=$location&start=$start_text&finish=$finish_text&adjust=$adjust&nofinish=$nofinish"; if (strcmp($finish, $start) < 0 && !$nofinish) { notice(L10n::t('Event can not end before it has started.') . EOL); @@ -108,16 +108,16 @@ function events_post(App $a) echo L10n::t('Event can not end before it has started.'); killme(); } - goaway($onerror_url); + $a->internalRedirect($onerror_path); } - if (!$summary || ($start === NULL_DATE)) { + if (!$summary || ($start === DBA::NULL_DATETIME)) { notice(L10n::t('Event title and start time are required.') . EOL); if (intval($_REQUEST['preview'])) { echo L10n::t('Event title and start time are required.'); killme(); } - goaway($onerror_url); + $a->internalRedirect($onerror_path); } $share = intval(defaults($_POST, 'share', 0)); @@ -187,7 +187,7 @@ function events_post(App $a) Worker::add(PRIORITY_HIGH, "Notifier", "event", $item_id); } - goaway('/events'); + $a->internalRedirect('events'); } function events_content(App $a) @@ -198,7 +198,7 @@ function events_content(App $a) } if ($a->argc == 1) { - $_SESSION['return_url'] = System::baseUrl() . '/' . $a->cmd; + $_SESSION['return_path'] = $a->cmd; } if (($a->argc > 2) && ($a->argv[1] === 'ignore') && intval($a->argv[2])) { @@ -577,6 +577,6 @@ function events_content(App $a) info(L10n::t('Event removed') . EOL); } - goaway(System::baseUrl() . '/events'); + $a->internalRedirect('events'); } } diff --git a/mod/filerm.php b/mod/filerm.php index 7fb978ae69..733d67b593 100644 --- a/mod/filerm.php +++ b/mod/filerm.php @@ -25,7 +25,7 @@ function filerm_content(App $a) { file_tag_unsave_file(local_user(),$item_id,$term, $category); } - //goaway('/network'); + //$a->internalRedirect('network'); killme(); } diff --git a/mod/follow.php b/mod/follow.php index 70dfb627ed..adc3fcc3bd 100644 --- a/mod/follow.php +++ b/mod/follow.php @@ -20,12 +20,12 @@ function follow_post(App $a) } if (isset($_REQUEST['cancel'])) { - goaway('contacts'); + $a->internalRedirect('contacts'); } $uid = local_user(); $url = notags(trim($_REQUEST['url'])); - $return_url = 'contacts'; + $return_path = 'contacts'; // Makes the connection request for friendica contacts easier // This is just a precaution if maybe this page is called somewhere directly via POST @@ -37,24 +37,24 @@ function follow_post(App $a) if ($result['message']) { notice($result['message']); } - goaway($return_url); + $a->internalRedirect($return_path); } elseif ($result['cid']) { - goaway('contact/' . $result['cid']); + $a->internalRedirect('contact/' . $result['cid']); } info(L10n::t('The contact could not be added.')); - goaway($return_url); + $a->internalRedirect($return_path); // NOTREACHED } function follow_content(App $a) { - $return_url = 'contacts'; + $return_path = 'contacts'; if (!local_user()) { notice(L10n::t('Permission denied.')); - goaway($return_url); + $a->internalRedirect($return_path); // NOTREACHED } @@ -74,7 +74,7 @@ function follow_content(App $a) if ($r[0]['pending']) { notice(L10n::t('You already added this contact.')); $submit = ''; - //goaway($_SESSION['return_url']); + //$a->internalRedirect($_SESSION['return_path']); // NOTREACHED } } @@ -84,21 +84,21 @@ function follow_content(App $a) if (($ret['network'] == Protocol::DIASPORA) && !Config::get('system', 'diaspora_enabled')) { notice(L10n::t("Diaspora support isn't enabled. Contact can't be added.")); $submit = ''; - //goaway($_SESSION['return_url']); + //$a->internalRedirect($_SESSION['return_path']); // NOTREACHED } if (($ret['network'] == Protocol::OSTATUS) && Config::get('system', 'ostatus_disabled')) { notice(L10n::t("OStatus support is disabled. Contact can't be added.")); $submit = ''; - //goaway($_SESSION['return_url']); + //$a->internalRedirect($_SESSION['return_path']); // NOTREACHED } if ($ret['network'] == Protocol::PHANTOM) { notice(L10n::t("The network type couldn't be detected. Contact can't be added.")); $submit = ''; - //goaway($_SESSION['return_url']); + //$a->internalRedirect($_SESSION['return_path']); // NOTREACHED } @@ -118,7 +118,7 @@ function follow_content(App $a) if (!$r) { notice(L10n::t('Permission denied.')); - goaway($return_url); + $a->internalRedirect($return_path); // NOTREACHED } diff --git a/mod/friendica.php b/mod/friendica.php index f2cb5c50b6..bf3f7942f9 100644 --- a/mod/friendica.php +++ b/mod/friendica.php @@ -31,15 +31,7 @@ function friendica_init(App $a) $admin = false; } - $visible_addons = []; - if (is_array($a->addons) && count($a->addons)) { - $r = q("SELECT * FROM `addon` WHERE `hidden` = 0"); - if (DBA::isResult($r)) { - foreach ($r as $rr) { - $visible_addons[] = $rr['name']; - } - } - } + $visible_addons = Addon::getVisibleList(); Config::load('feature_lock'); $locked_features = []; @@ -91,16 +83,7 @@ function friendica_content(App $a) $o .= L10n::t('Suggestions, praise, etc. - please email "info" at "friendi - dot - ca'); $o .= '

' . PHP_EOL; - $visible_addons = []; - if (is_array($a->addons) && count($a->addons)) { - $r = q("SELECT * FROM `addon` WHERE `hidden` = 0"); - if (DBA::isResult($r)) { - foreach ($r as $rr) { - $visible_addons[] = $rr['name']; - } - } - } - + $visible_addons = Addon::getVisibleList(); if (count($visible_addons)) { $o .= '

' . L10n::t('Installed addons/apps:') . '

' . PHP_EOL; $sorted = $visible_addons; diff --git a/mod/group.php b/mod/group.php index 129cf18c2a..404448ebb7 100644 --- a/mod/group.php +++ b/mod/group.php @@ -38,12 +38,12 @@ function group_post(App $a) { info(L10n::t('Group created.') . EOL); $r = Model\Group::getIdByName(local_user(), $name); if ($r) { - goaway(System::baseUrl() . '/group/' . $r); + $a->internalRedirect('group/' . $r); } } else { notice(L10n::t('Could not create group.') . EOL); } - goaway(System::baseUrl() . '/group'); + $a->internalRedirect('group'); return; // NOTREACHED } @@ -56,7 +56,7 @@ function group_post(App $a) { ); if (!DBA::isResult($r)) { notice(L10n::t('Group not found.') . EOL); - goaway(System::baseUrl() . '/contact'); + $a->internalRedirect('contact'); return; // NOTREACHED } $group = $r[0]; @@ -88,7 +88,7 @@ function group_content(App $a) { // With no group number provided we jump to the unassigned contacts as a starting point if ($a->argc == 1) { - goaway('group/none'); + $a->internalRedirect('group/none'); } // Switch to text mode interface if we have more than 'n' contacts or group members @@ -159,7 +159,7 @@ function group_content(App $a) { notice(L10n::t('Unable to remove group.') . EOL); } } - goaway(System::baseUrl() . '/group'); + $a->internalRedirect('group'); // NOTREACHED } @@ -183,7 +183,7 @@ function group_content(App $a) { if (!DBA::isResult($r)) { notice(L10n::t('Group not found.') . EOL); - goaway(System::baseUrl() . '/contact'); + $a->internalRedirect('contact'); } $group = $r[0]; diff --git a/mod/home.php b/mod/home.php index 33d736a4e1..bf5b5d27ff 100644 --- a/mod/home.php +++ b/mod/home.php @@ -16,11 +16,11 @@ function home_init(App $a) { Addon::callHooks('home_init',$ret); if (local_user() && ($a->user['nickname'])) { - goaway(System::baseUrl()."/network"); + $a->internalRedirect('network'); } if (strlen(Config::get('system','singleuser'))) { - goaway(System::baseUrl()."/profile/" . Config::get('system','singleuser')); + $a->internalRedirect('profile/' . Config::get('system','singleuser')); } }} diff --git a/mod/ignored.php b/mod/ignored.php index 8502874ce5..4f14119fef 100644 --- a/mod/ignored.php +++ b/mod/ignored.php @@ -43,7 +43,7 @@ function ignored_init(App $a) $rand = "?$rand"; } - goaway(System::baseUrl() . "/" . $return_path . $rand); + $a->internalRedirect($return_path . $rand); } // the json doesn't really matter, it will either be 0 or 1 diff --git a/mod/item.php b/mod/item.php index 5d4a23caa7..cd64b70f85 100644 --- a/mod/item.php +++ b/mod/item.php @@ -115,7 +115,7 @@ function item_post(App $a) { if (!DBA::isResult($parent_item)) { notice(L10n::t('Unable to locate original post.') . EOL); if (!empty($_REQUEST['return'])) { - goaway($return_path); + $a->internalRedirect($return_path); } killme(); } @@ -165,7 +165,7 @@ function item_post(App $a) { notice(L10n::t('Permission denied.') . EOL) ; if (!empty($_REQUEST['return'])) { - goaway($return_path); + $a->internalRedirect($return_path); } killme(); @@ -283,7 +283,7 @@ function item_post(App $a) { } info(L10n::t('Empty post discarded.') . EOL); if (!empty($_REQUEST['return'])) { - goaway($return_path); + $a->internalRedirect($return_path); } killme(); } @@ -678,7 +678,7 @@ function item_post(App $a) { if (!empty($datarray['cancel'])) { logger('mod_item: post cancelled by addon.'); if ($return_path) { - goaway($return_path); + $a->internalRedirect($return_path); } $json = ['cancel' => 1]; @@ -714,7 +714,7 @@ function item_post(App $a) { if (!empty($_REQUEST['return']) && strlen($return_path)) { logger('return: ' . $return_path); - goaway($return_path); + $a->internalRedirect($return_path); } killme(); } else { @@ -729,14 +729,14 @@ function item_post(App $a) { if (!$post_id) { logger("Item wasn't stored."); - goaway($return_path); + $a->internalRedirect($return_path); } $datarray = Item::selectFirst(Item::ITEM_FIELDLIST, ['id' => $post_id]); if (!DBA::isResult($datarray)) { logger("Item with id ".$post_id." couldn't be fetched."); - goaway($return_path); + $a->internalRedirect($return_path); } // update filetags in pconfig @@ -844,13 +844,14 @@ function item_post(App $a) { function item_post_return($baseurl, $api_source, $return_path) { // figure out how to return, depending on from whence we came + $a = get_app(); if ($api_source) { return; } if ($return_path) { - goaway($return_path); + $a->internalRedirect($return_path); } $json = ['success' => 1]; diff --git a/mod/like.php b/mod/like.php index 08e3febbbc..296e563bf4 100644 --- a/mod/like.php +++ b/mod/like.php @@ -28,7 +28,7 @@ function like_content(App $a) { // See if we've been passed a return path to redirect to $return_path = ((x($_REQUEST,'return')) ? $_REQUEST['return'] : ''); - like_content_return(System::baseUrl(), $return_path); + like_content_return($a, $return_path); killme(); // NOTREACHED } @@ -36,7 +36,7 @@ function like_content(App $a) { // Decide how to return. If we were called with a 'return' argument, // then redirect back to the calling page. If not, just quietly end -function like_content_return($baseurl, $return_path) { +function like_content_return(App $a, $return_path) { if ($return_path) { $rand = '_=' . time(); if (strpos($return_path, '?')) { @@ -45,7 +45,7 @@ function like_content_return($baseurl, $return_path) { $rand = "?$rand"; } - goaway($baseurl . "/" . $return_path . $rand); + $a->internalRedirect($return_path . $rand); } killme(); diff --git a/mod/lostpass.php b/mod/lostpass.php index 166da25fc2..9cde1c9ff4 100644 --- a/mod/lostpass.php +++ b/mod/lostpass.php @@ -19,14 +19,14 @@ function lostpass_post(App $a) { $loginame = notags(trim($_POST['login-name'])); if (!$loginame) { - goaway(System::baseUrl()); + $a->internalRedirect(); } $condition = ['(`email` = ? OR `nickname` = ?) AND `verified` = 1 AND `blocked` = 0', $loginame, $loginame]; $user = DBA::selectFirst('user', ['uid', 'username', 'email', 'language'], $condition); if (!DBA::isResult($user)) { notice(L10n::t('No valid account found.') . EOL); - goaway(System::baseUrl()); + $a->internalRedirect(); } $pwdreset_token = autoname(12) . mt_rand(1000, 9999); @@ -78,7 +78,7 @@ function lostpass_post(App $a) 'body' => $body ]); - goaway(System::baseUrl()); + $a->internalRedirect(); } function lostpass_content(App $a) diff --git a/mod/manage.php b/mod/manage.php index d38d90ce60..b98fcac6f7 100644 --- a/mod/manage.php +++ b/mod/manage.php @@ -99,7 +99,7 @@ function manage_post(App $a) { unset($_SESSION['theme']); unset($_SESSION['mobile-theme']); unset($_SESSION['page_flags']); - unset($_SESSION['return_url']); + unset($_SESSION['return_path']); if (x($_SESSION, 'submanage')) { unset($_SESSION['submanage']); } @@ -119,7 +119,7 @@ function manage_post(App $a) { $ret = []; Addon::callHooks('home_init',$ret); - goaway( System::baseUrl() . "/profile/" . $a->user['nickname'] ); + $a->internalRedirect('profile/' . $a->user['nickname'] ); // NOTREACHED } diff --git a/mod/match.php b/mod/match.php index 7e805d5baf..b299619940 100644 --- a/mod/match.php +++ b/mod/match.php @@ -35,7 +35,7 @@ function match_content(App $a) $a->page['aside'] .= Widget::findPeople(); $a->page['aside'] .= Widget::follow(); - $_SESSION['return_url'] = System::baseUrl() . '/' . $a->cmd; + $_SESSION['return_path'] = $a->cmd; $r = q( "SELECT `pub_keywords`, `prv_keywords` FROM `profile` WHERE `is-default` = 1 AND `uid` = %d LIMIT 1", diff --git a/mod/message.php b/mod/message.php index f9c5c29ec7..8a04f9abef 100644 --- a/mod/message.php +++ b/mod/message.php @@ -87,7 +87,7 @@ function message_post(App $a) $a->argc = 2; $a->argv[1] = 'new'; } else { - goaway($a->cmd . '/' . $ret); + $a->internalRedirect($a->cmd . '/' . $ret); } } @@ -155,7 +155,7 @@ function message_content(App $a) // Now check how the user responded to the confirmation query if (!empty($_REQUEST['canceled'])) { - goaway('/message'); + $a->internalRedirect('message'); } $cmd = $a->argv[1]; @@ -163,7 +163,7 @@ function message_content(App $a) $message = DBA::selectFirst('mail', ['convid'], ['id' => $a->argv[2], 'uid' => local_user()]); if(!DBA::isResult($message)){ info(L10n::t('Conversation not found.') . EOL); - goaway('/message'); + $a->internalRedirect('message'); } if (DBA::delete('mail', ['id' => $a->argv[2], 'uid' => local_user()])) { @@ -173,10 +173,10 @@ function message_content(App $a) $conversation = DBA::selectFirst('mail', ['id'], ['convid' => $message['convid'], 'uid' => local_user()]); if(!DBA::isResult($conversation)){ info(L10n::t('Conversation removed.') . EOL); - goaway('/message'); + $a->internalRedirect('message'); } - goaway('/message/' . $conversation['id'] ); + $a->internalRedirect('message/' . $conversation['id'] ); } else { $r = q("SELECT `parent-uri`,`convid` FROM `mail` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($a->argv[2]), @@ -190,7 +190,7 @@ function message_content(App $a) info(L10n::t('Conversation removed.') . EOL); } } - goaway('/message' ); + $a->internalRedirect('message'); } } @@ -265,7 +265,7 @@ function message_content(App $a) } - $_SESSION['return_url'] = $a->query_string; + $_SESSION['return_path'] = $a->query_string; if ($a->argc == 1) { diff --git a/mod/network.php b/mod/network.php index fb0093849e..b697cb3a63 100644 --- a/mod/network.php +++ b/mod/network.php @@ -38,7 +38,7 @@ function network_init(App $a) $search = (x($_GET, 'search') ? escape_tags($_GET['search']) : ''); if (($search != '') && !empty($_GET['submit'])) { - goaway('search?search=' . urlencode($search)); + $a->internalRedirect('search?search=' . urlencode($search)); } if (x($_GET, 'save')) { @@ -140,7 +140,7 @@ function network_init(App $a) $redir_url = ($net_queries ? $net_baseurl . '?' . $net_queries : $net_baseurl); - goaway(System::baseUrl() . $redir_url); + $a->internalRedirect($redir_url); } } @@ -618,7 +618,7 @@ function networkThreadedView(App $a, $update, $parent) killme(); } notice(L10n::t('No such group') . EOL); - goaway('network/0'); + $a->internalRedirect('network/0'); // NOTREACHED } @@ -672,7 +672,7 @@ function networkThreadedView(App $a, $update, $parent) } } else { notice(L10n::t('Invalid contact.') . EOL); - goaway('network'); + $a->internalRedirect('network'); // NOTREACHED } } diff --git a/mod/nogroup.php b/mod/nogroup.php index 18681d7683..438c4ff440 100644 --- a/mod/nogroup.php +++ b/mod/nogroup.php @@ -24,5 +24,5 @@ function nogroup_content(App $a) return ''; } - goaway(System::baseUrl() . '/group/none'); + $a->internalRedirect('group/none'); } diff --git a/mod/notice.php b/mod/notice.php index 133fd22fce..b40f0ee69c 100644 --- a/mod/notice.php +++ b/mod/notice.php @@ -15,8 +15,7 @@ function notice_init(App $a) $r = q("SELECT `user`.`nickname` FROM `user` LEFT JOIN `item` ON `item`.`uid` = `user`.`uid` WHERE `item`.`id` = %d", intval($id)); if (DBA::isResult($r)) { $nick = $r[0]['nickname']; - $url = System::baseUrl() . "/display/$nick/$id"; - goaway($url); + $a->internalRedirect('display/' . $nick . '/' . $id); } else { $a->error = 404; notice(L10n::t('Item not found.') . EOL); diff --git a/mod/notifications.php b/mod/notifications.php index 1885f96447..d5cfbf276d 100644 --- a/mod/notifications.php +++ b/mod/notifications.php @@ -17,7 +17,7 @@ use Friendica\Module\Login; function notifications_post(App $a) { if (!local_user()) { - goaway(System::baseUrl()); + $a->internalRedirect(); } $request_id = (($a->argc > 1) ? $a->argv[1] : 0); @@ -52,12 +52,12 @@ function notifications_post(App $a) 'self' => false, 'blocked' => true, 'pending' => true]; DBA::delete('contact', $condition); } - goaway('notifications/intros'); + $a->internalRedirect('notifications/intros'); } if ($_POST['submit'] == L10n::t('Ignore')) { DBA::update('intro', ['ignore' => true], ['id' => $intro_id]); - goaway('notifications/intros'); + $a->internalRedirect('notifications/intros'); } } } diff --git a/mod/notify.php b/mod/notify.php index a277e59813..6ec36d8f99 100644 --- a/mod/notify.php +++ b/mod/notify.php @@ -37,10 +37,10 @@ function notify_init(App $a) } } - goaway($note['link']); + System::externalRedirect($note['link']); } - goaway(System::baseUrl(true)); + $a->internalRedirect(); } if ($a->argc > 2 && $a->argv[1] === 'mark' && $a->argv[2] === 'all') { diff --git a/mod/openid.php b/mod/openid.php index 41aabe7a97..93a07a4b43 100644 --- a/mod/openid.php +++ b/mod/openid.php @@ -14,7 +14,7 @@ function openid_content(App $a) { $noid = Config::get('system','no_openid'); if($noid) - goaway(System::baseUrl()); + $a->internalRedirect(); logger('mod_openid ' . print_r($_REQUEST,true), LOGGER_DATA); @@ -28,7 +28,7 @@ function openid_content(App $a) { if(! strlen($authid)) { logger(L10n::t('OpenID protocol error. No ID returned.') . EOL); - goaway(System::baseUrl()); + $a->internalRedirect(); } // NOTE: we search both for normalised and non-normalised form of $authid @@ -56,7 +56,7 @@ function openid_content(App $a) { // just in case there was no return url set // and we fell through - goaway(System::baseUrl()); + $a->internalRedirect(); } // Successful OpenID login - but we can't match it to an existing account. @@ -64,7 +64,7 @@ function openid_content(App $a) { if (intval(Config::get('config', 'register_policy')) === REGISTER_CLOSED) { notice(L10n::t('Account not found and OpenID registration is not permitted on this site.') . EOL); - goaway(System::baseUrl()); + $a->internalRedirect(); } unset($_SESSION['register']); @@ -108,12 +108,12 @@ function openid_content(App $a) { $args .= '&openid_url=' . urlencode(notags(trim($authid))); - goaway(System::baseUrl() . '/register?' . $args); + $a->internalRedirect('register?' . $args); // NOTREACHED } } notice(L10n::t('Login failed.') . EOL); - goaway(System::baseUrl()); + $a->internalRedirect(); // NOTREACHED } diff --git a/mod/ostatus_subscribe.php b/mod/ostatus_subscribe.php index 7012ecd4bc..7fce9d0b69 100644 --- a/mod/ostatus_subscribe.php +++ b/mod/ostatus_subscribe.php @@ -15,7 +15,7 @@ function ostatus_subscribe_content(App $a) { if (! local_user()) { notice(L10n::t('Permission denied.') . EOL); - goaway('/ostatus_subscribe'); + $a->internalRedirect('ostatus_subscribe'); // NOTREACHED } diff --git a/mod/photos.php b/mod/photos.php index 55c8881e4c..ef6428d7ab 100644 --- a/mod/photos.php +++ b/mod/photos.php @@ -196,7 +196,7 @@ function photos_post(App $a) $album = hex2bin($a->argv[3]); if ($album === L10n::t('Profile Photos') || $album === 'Contact Photos' || $album === L10n::t('Contact Photos')) { - goaway($_SESSION['photo_return']); + $a->internalRedirect($_SESSION['photo_return']); return; // NOTREACHED } @@ -207,13 +207,13 @@ function photos_post(App $a) if (!DBA::isResult($r)) { notice(L10n::t('Album not found.') . EOL); - goaway($_SESSION['photo_return']); + $a->internalRedirect($_SESSION['photo_return']); return; // NOTREACHED } // Check if the user has responded to a delete confirmation query if (!empty($_REQUEST['canceled'])) { - goaway($_SESSION['photo_return']); + $a->internalRedirect($_SESSION['photo_return']); } // RENAME photo album @@ -227,8 +227,7 @@ function photos_post(App $a) // Update the photo albums cache Photo::clearAlbumCache($page_owner_uid); - $newurl = System::baseUrl() . '/photos/' . $a->user['nickname'] . '/album/' . bin2hex($newalbum); - goaway($newurl); + $a->internalRedirect('photos/' . $a->user['nickname'] . '/album/' . bin2hex($newalbum)); return; // NOTREACHED } @@ -281,7 +280,7 @@ function photos_post(App $a) $res[] = "'" . DBA::escape($rr['rid']) . "'" ; } } else { - goaway($_SESSION['photo_return']); + $a->internalRedirect($_SESSION['photo_return']); return; // NOTREACHED } @@ -299,14 +298,14 @@ function photos_post(App $a) Photo::clearAlbumCache($page_owner_uid); } - goaway('photos/' . $a->data['user']['nickname']); + $a->internalRedirect('photos/' . $a->data['user']['nickname']); return; // NOTREACHED } // Check if the user has responded to a delete confirmation query for a single photo if ($a->argc > 2 && !empty($_REQUEST['canceled'])) { - goaway($_SESSION['photo_return']); + $a->internalRedirect($_SESSION['photo_return']); } if ($a->argc > 2 && defaults($_POST, 'delete', '') === L10n::t('Delete Photo')) { @@ -356,7 +355,7 @@ function photos_post(App $a) Photo::clearAlbumCache($page_owner_uid); } - goaway('photos/' . $a->data['user']['nickname']); + $a->internalRedirect('photos/' . $a->data['user']['nickname']); return; // NOTREACHED } @@ -697,7 +696,7 @@ function photos_post(App $a) } } } - goaway($_SESSION['photo_return']); + $a->internalRedirect($_SESSION['photo_return']); return; // NOTREACHED } @@ -928,7 +927,7 @@ function photos_post(App $a) // addon uploaders should call "killme()" [e.g. exit] within the photo_post_end hook // if they do not wish to be redirected - goaway($_SESSION['photo_return']); + $a->internalRedirect($_SESSION['photo_return']); // NOTREACHED } @@ -1470,7 +1469,7 @@ function photos_content(App $a) if (count($linked_items)) { $cmnt_tpl = get_markup_template('comment_item.tpl'); $tpl = get_markup_template('photo_item.tpl'); - $return_url = $a->cmd; + $return_path = $a->cmd; if ($can_post || Security::canWriteToUserWall($owner_uid)) { $like_tpl = get_markup_template('like_noshare.tpl'); @@ -1487,7 +1486,7 @@ function photos_content(App $a) if (($can_post || Security::canWriteToUserWall($owner_uid))) { $comments .= replace_macros($cmnt_tpl, [ '$return_path' => '', - '$jsreload' => $return_url, + '$jsreload' => $return_path, '$id' => $link_item['id'], '$parent' => $link_item['id'], '$profile_uid' => $owner_uid, @@ -1526,7 +1525,7 @@ function photos_content(App $a) if (($can_post || Security::canWriteToUserWall($owner_uid))) { $comments .= replace_macros($cmnt_tpl,[ '$return_path' => '', - '$jsreload' => $return_url, + '$jsreload' => $return_path, '$id' => $link_item['id'], '$parent' => $link_item['id'], '$profile_uid' => $owner_uid, @@ -1586,7 +1585,7 @@ function photos_content(App $a) if (($can_post || Security::canWriteToUserWall($owner_uid))) { $comments .= replace_macros($cmnt_tpl, [ '$return_path' => '', - '$jsreload' => $return_url, + '$jsreload' => $return_path, '$id' => $item['item_id'], '$parent' => $item['parent'], '$profile_uid' => $owner_uid, diff --git a/mod/profile.php b/mod/profile.php index 8d5ae87585..6f0ab9e077 100644 --- a/mod/profile.php +++ b/mod/profile.php @@ -34,7 +34,7 @@ function profile_init(App $a) } else { $r = q("SELECT `nickname` FROM `user` WHERE `blocked` = 0 AND `account_expired` = 0 AND `account_removed` = 0 AND `verified` = 1 ORDER BY RAND() LIMIT 1"); if (DBA::isResult($r)) { - goaway(System::baseUrl() . '/profile/' . $r[0]['nickname']); + $a->internalRedirect('profile/' . $r[0]['nickname']); } else { logger('profile error: mod_profile ' . $a->query_string, LOGGER_DEBUG); notice(L10n::t('Requested profile is not available.') . EOL); diff --git a/mod/profile_photo.php b/mod/profile_photo.php index 5fdff41e8c..19188ba23e 100644 --- a/mod/profile_photo.php +++ b/mod/profile_photo.php @@ -74,7 +74,7 @@ function profile_photo_post(App $a) $r = q("SELECT * FROM `photo` WHERE `resource-id` = '%s' AND `uid` = %d AND `scale` = %d LIMIT 1", DBA::escape($image_id), DBA::escape(local_user()), intval($scale)); - $url = System::baseUrl() . '/profile/' . $a->user['nickname']; + $path = 'profile/' . $a->user['nickname']; if (DBA::isResult($r)) { $base_image = $r[0]; @@ -125,8 +125,8 @@ function profile_photo_post(App $a) info(L10n::t('Shift-reload the page or clear browser cache if the new photo does not display immediately.') . EOL); // Update global directory in background - if ($url && strlen(Config::get('system', 'directory'))) { - Worker::add(PRIORITY_LOW, "Directory", $url); + if ($path && strlen(Config::get('system', 'directory'))) { + Worker::add(PRIORITY_LOW, "Directory", $a->getBaseURL() . '/' . $path); } Worker::add(PRIORITY_LOW, 'ProfileUpdate', local_user()); @@ -135,7 +135,7 @@ function profile_photo_post(App $a) } } - goaway($url); + $a->internalRedirect($path); return; // NOTREACHED } @@ -168,7 +168,7 @@ function profile_photo_post(App $a) @unlink($src); $imagecrop = profile_photo_crop_ui_head($a, $ph); - goaway(System::baseUrl() . '/profile_photo/use/' . $imagecrop['hash']); + $a->internalRedirect('profile_photo/use/' . $imagecrop['hash']); } function profile_photo_content(App $a) @@ -225,7 +225,7 @@ function profile_photo_content(App $a) Worker::add(PRIORITY_LOW, "Directory", $url); } - goaway(System::baseUrl() . '/profile/' . $a->user['nickname']); + $a->internalRedirect('profile/' . $a->user['nickname']); return; // NOTREACHED } $ph = new Image($r[0]['data'], $r[0]['type']); diff --git a/mod/profiles.php b/mod/profiles.php index 22f192b4ce..a4a49ec785 100644 --- a/mod/profiles.php +++ b/mod/profiles.php @@ -18,10 +18,10 @@ use Friendica\Database\DBA; use Friendica\Model\Contact; use Friendica\Model\GContact; use Friendica\Model\Profile; +use Friendica\Module\Login; use Friendica\Network\Probe; use Friendica\Util\DateTimeFormat; use Friendica\Util\Temporal; -use Friendica\Module\Login; function profiles_init(App $a) { @@ -38,7 +38,7 @@ function profiles_init(App $a) { ); if (! DBA::isResult($r)) { notice(L10n::t('Profile not found.') . EOL); - goaway('profiles'); + $a->internalRedirect('profiles'); return; // NOTREACHED } @@ -59,7 +59,7 @@ function profiles_init(App $a) { info(L10n::t('Profile deleted.').EOL); } - goaway('profiles'); + $a->internalRedirect('profiles'); return; // NOTREACHED } @@ -93,10 +93,10 @@ function profiles_init(App $a) { info(L10n::t('New profile created.') . EOL); if (DBA::isResult($r3) && count($r3) == 1) { - goaway('profiles/' . $r3[0]['id']); + $a->internalRedirect('profiles/' . $r3[0]['id']); } - goaway('profiles'); + $a->internalRedirect('profiles'); } if (($a->argc > 2) && ($a->argv[1] === 'clone')) { @@ -132,10 +132,10 @@ function profiles_init(App $a) { ); info(L10n::t('New profile created.') . EOL); if ((DBA::isResult($r3)) && (count($r3) == 1)) { - goaway('profiles/'.$r3[0]['id']); + $a->internalRedirect('profiles/'.$r3[0]['id']); } - goaway('profiles'); + $a->internalRedirect('profiles'); return; // NOTREACHED } @@ -252,7 +252,7 @@ function profiles_post(App $a) { $with = ((x($_POST,'with')) ? notags(trim($_POST['with'])) : ''); if (! strlen($howlong)) { - $howlong = NULL_DATE; + $howlong = DBA::NULL_DATETIME; } else { $howlong = DateTimeFormat::convert($howlong, 'UTC', date_default_timezone_get()); } @@ -619,7 +619,7 @@ function profiles_content(App $a) { '$gender' => ContactSelector::gender($r[0]['gender']), '$marital' => ['selector' => ContactSelector::maritalStatus($r[0]['marital']), 'value' => $r[0]['marital']], '$with' => ['with', L10n::t("Who: \x28if applicable\x29"), strip_tags($r[0]['with']), L10n::t('Examples: cathy123, Cathy Williams, cathy@example.com')], - '$howlong' => ['howlong', L10n::t('Since [date]:'), ($r[0]['howlong'] <= NULL_DATE ? '' : DateTimeFormat::local($r[0]['howlong']))], + '$howlong' => ['howlong', L10n::t('Since [date]:'), ($r[0]['howlong'] <= DBA::NULL_DATETIME ? '' : DateTimeFormat::local($r[0]['howlong']))], '$sexual' => ['selector' => ContactSelector::sexualPreference($r[0]['sexual']), 'value' => $r[0]['sexual']], '$about' => ['about', L10n::t('Tell us about yourself...'), $r[0]['about']], '$xmpp' => ['xmpp', L10n::t("XMPP \x28Jabber\x29 address:"), $r[0]['xmpp'], L10n::t("The XMPP address will be propagated to your contacts so that they can follow you.")], @@ -654,7 +654,7 @@ function profiles_content(App $a) { ); if (DBA::isResult($r)) { //Go to the default profile. - goaway('profiles/' . $r[0]['id']); + $a->internalRedirect('profiles/' . $r[0]['id']); } } diff --git a/mod/randprof.php b/mod/randprof.php index 18bcb236f8..055b3dcbe8 100644 --- a/mod/randprof.php +++ b/mod/randprof.php @@ -13,8 +13,14 @@ function randprof_init(App $a) $x = GContact::getRandomUrl(); if ($x) { - goaway(Contact::magicLink($x)); + $link = Contact::magicLink($x); + // @TODO making the return of magicLink save to use either externalRedirect or internalRedirect + if (filter_var($link, FILTER_VALIDATE_URL)) { + System::externalRedirect($link); + } else { + $a->internalRedirect($link); + } } - goaway(System::baseUrl() . '/profile'); + $a->internalRedirect('profile'); } diff --git a/mod/redir.php b/mod/redir.php index e989ad015a..ad42bc8abc 100644 --- a/mod/redir.php +++ b/mod/redir.php @@ -27,7 +27,7 @@ function redir_init(App $a) { $contact = DBA::selectFirst('contact', $fields, ['id' => $cid, 'uid' => [0, local_user()]]); if (!DBA::isResult($contact)) { notice(L10n::t('Contact not found.')); - goaway(System::baseUrl()); + $a->internalRedirect(); } $contact_url = $contact['url']; @@ -36,7 +36,7 @@ function redir_init(App $a) { || (!local_user() && !remote_user()) // Visitors (not logged in or not remotes) can't authenticate. || (!empty($a->contact['id']) && $a->contact['id'] == $cid)) // Local user is already authenticated. { - goaway($url != '' ? $url : $contact_url); + System::externalRedirect(defaults($url, $contact_url)); } if ($contact['uid'] == 0 && local_user()) { @@ -50,14 +50,14 @@ function redir_init(App $a) { if (!empty($a->contact['id']) && $a->contact['id'] == $cid) { // Local user is already authenticated. - $target_url = $url != '' ? $url : $contact_url; + $target_url = defaults($url, $contact_url); logger($contact['name'] . " is already authenticated. Redirecting to " . $target_url, LOGGER_DEBUG); - goaway($target_url); + System::externalRedirect($target_url); } } if (remote_user()) { - $host = substr(System::baseUrl() . ($a->getURLPath() ? '/' . $a->getURLPath() : ''), strpos(System::baseUrl(), '://') + 3); + $host = substr($a->getBaseURL() . ($a->getURLPath() ? '/' . $a->getURLPath() : ''), strpos($a->getBaseURL(), '://') + 3); $remotehost = substr($contact['addr'], strpos($contact['addr'], '@') + 1); // On a local instance we have to check if the local user has already authenticated @@ -71,9 +71,9 @@ function redir_init(App $a) { foreach ($_SESSION['remote'] as $v) { if ($v['uid'] == $_SESSION['visitor_visiting'] && $v['cid'] == $_SESSION['visitor_id']) { // Remote user is already authenticated. - $target_url = $url != '' ? $url : $contact_url; + $target_url = defaults($url, $contact_url); logger($contact['name'] . " is already authenticated. Redirecting to " . $target_url, LOGGER_DEBUG); - goaway($target_url); + System::externalRedirect($target_url); } } } @@ -102,11 +102,11 @@ function redir_init(App $a) { $dest = (!empty($url) ? '&destination_url=' . $url : ''); - goaway($contact['poll'] . '?dfrn_id=' . $dfrn_id + System::externalRedirect($contact['poll'] . '?dfrn_id=' . $dfrn_id . '&dfrn_version=' . DFRN_PROTOCOL_VERSION . '&type=profile&sec=' . $sec . $dest . $quiet); } - $url = $url != '' ? $url : $contact_url; + $url = defaults($url, $contact_url); } // If we don't have a connected contact, redirect with @@ -121,9 +121,9 @@ function redir_init(App $a) { } logger('redirecting to ' . $url, LOGGER_DEBUG); - goaway($url); + System::externalRedirect($url); } notice(L10n::t('Contact not found.')); - goaway(System::baseUrl()); + $a->internalRedirect(); } diff --git a/mod/register.php b/mod/register.php index 41d39f4158..0a139ad752 100644 --- a/mod/register.php +++ b/mod/register.php @@ -63,7 +63,7 @@ function register_post(App $a) $arr['blocked'] = $blocked; $arr['verified'] = $verified; - $arr['language'] = L10n::getBrowserLanguage(); + $arr['language'] = L10n::detectLanguage(); try { $result = Model\User::create($arr); @@ -100,7 +100,7 @@ function register_post(App $a) if ($res) { info(L10n::t('Registration successful. Please check your email for further instructions.') . EOL); - goaway(); + $a->internalRedirect(); } else { notice( L10n::t('Failed to send email message. Here your accout details:
login: %s
password: %s

You can change your password after login.', @@ -111,12 +111,12 @@ function register_post(App $a) } } else { info(L10n::t('Registration successful.') . EOL); - goaway(); + $a->internalRedirect(); } } elseif (intval(Config::get('config', 'register_policy')) === REGISTER_APPROVE) { if (!strlen(Config::get('config', 'admin_email'))) { notice(L10n::t('Your registration can not be processed.') . EOL); - goaway(); + $a->internalRedirect(); } Model\Register::createForApproval($user['uid'], Config::get('system', 'language'), $_POST['permonlybox']); @@ -159,7 +159,7 @@ function register_post(App $a) ); info(L10n::t('Your registration is pending approval by the site owner.') . EOL); - goaway(); + $a->internalRedirect(); } return; diff --git a/mod/regmod.php b/mod/regmod.php index 3f6f0e04e3..a7aebf6b0a 100644 --- a/mod/regmod.php +++ b/mod/regmod.php @@ -101,11 +101,11 @@ function regmod_content(App $a) if ($cmd === 'deny') { user_deny($hash); - goaway('admin/users/'); + $a->internalRedirect('admin/users/'); } if ($cmd === 'allow') { user_allow($hash); - goaway('admin/users/'); + $a->internalRedirect('admin/users/'); } } diff --git a/mod/removeme.php b/mod/removeme.php index b386ec12f5..86d46a177b 100644 --- a/mod/removeme.php +++ b/mod/removeme.php @@ -64,7 +64,7 @@ function removeme_post(App $a) function removeme_content(App $a) { if (!local_user()) { - goaway(System::baseUrl()); + $a->internalRedirect(); } $hash = random_string(); @@ -76,7 +76,7 @@ function removeme_content(App $a) $tpl = get_markup_template('removeme.tpl'); $o = replace_macros($tpl, [ - '$basedir' => System::baseUrl(), + '$basedir' => $a->getBaseURL(), '$hash' => $hash, '$title' => L10n::t('Remove My Account'), '$desc' => L10n::t('This will completely remove your account. Once this has been done it is not recoverable.'), diff --git a/mod/repair_ostatus.php b/mod/repair_ostatus.php index 4499220817..3a3ce42067 100644 --- a/mod/repair_ostatus.php +++ b/mod/repair_ostatus.php @@ -14,7 +14,7 @@ function repair_ostatus_content(App $a) { if (! local_user()) { notice(L10n::t('Permission denied.') . EOL); - goaway('/ostatus_repair'); + $a->internalRedirect('ostatus_repair'); // NOTREACHED } diff --git a/mod/settings.php b/mod/settings.php index cb88823997..52c5f42cf0 100644 --- a/mod/settings.php +++ b/mod/settings.php @@ -20,11 +20,10 @@ use Friendica\Model\Contact; use Friendica\Model\GContact; use Friendica\Model\Group; use Friendica\Model\User; +use Friendica\Module\Login; use Friendica\Protocol\Email; use Friendica\Util\Network; use Friendica\Util\Temporal; -use Friendica\Util\Security; -use Friendica\Module\Login; function get_theme_config_file($theme) { @@ -160,7 +159,7 @@ function settings_post(App $a) $key = $_POST['remove']; DBA::delete('tokens', ['id' => $key, 'uid' => local_user()]); - goaway(System::baseUrl(true)."/settings/oauth/"); + $a->internalRedirect('settings/oauth/', true); return; } @@ -206,7 +205,7 @@ function settings_post(App $a) ); } } - goaway(System::baseUrl(true)."/settings/oauth/"); + $a->internalRedirect('settings/oauth/', true); return; } @@ -371,7 +370,7 @@ function settings_post(App $a) ); Addon::callHooks('display_settings_post', $_POST); - goaway('settings/display'); + $a->internalRedirect('settings/display'); return; // NOTREACHED } @@ -380,7 +379,7 @@ function settings_post(App $a) if (x($_POST,'resend_relocate')) { Worker::add(PRIORITY_HIGH, 'Notifier', 'relocate', local_user()); info(L10n::t("Relocate message has been send to your contacts")); - goaway('settings'); + $a->internalRedirect('settings'); } Addon::callHooks('settings_post', $_POST); @@ -649,7 +648,7 @@ function settings_post(App $a) // Update the global contact for the user GContact::updateForUser(local_user()); - goaway('settings'); + $a->internalRedirect('settings'); return; // NOTREACHED } @@ -716,7 +715,7 @@ function settings_content(App $a) BaseModule::checkFormSecurityTokenRedirectOnError('/settings/oauth', 'settings_oauth', 't'); DBA::delete('clients', ['client_id' => $a->argv[3], 'uid' => local_user()]); - goaway(System::baseUrl(true)."/settings/oauth/"); + $a->internalRedirect('settings/oauth/', true); return; } @@ -732,7 +731,7 @@ function settings_content(App $a) $tpl = get_markup_template('settings/oauth.tpl'); $o .= replace_macros($tpl, [ '$form_security_token' => BaseModule::getFormSecurityToken("settings_oauth"), - '$baseurl' => System::baseUrl(true), + '$baseurl' => $a->getBaseURL(true), '$title' => L10n::t('Connected Apps'), '$add' => L10n::t('Add application'), '$edit' => L10n::t('Edit'), @@ -795,7 +794,7 @@ function settings_content(App $a) $legacy_contact = PConfig::get(local_user(), 'ostatus', 'legacy_contact'); if (x($legacy_contact)) { - /// @todo Isn't it supposed to be a goaway() call? + /// @todo Isn't it supposed to be a $a->internalRedirect() call? $a->page['htmlhead'] = ''; } @@ -830,7 +829,7 @@ function settings_content(App $a) $mail_pubmail = ((DBA::isResult($r)) ? $r[0]['pubmail'] : 0); $mail_action = ((DBA::isResult($r)) ? $r[0]['action'] : 0); $mail_movetofolder = ((DBA::isResult($r)) ? $r[0]['movetofolder'] : ''); - $mail_chk = ((DBA::isResult($r)) ? $r[0]['last_check'] : NULL_DATE); + $mail_chk = ((DBA::isResult($r)) ? $r[0]['last_check'] : DBA::NULL_DATETIME); $tpl = get_markup_template('settings/connectors.tpl'); diff --git a/mod/starred.php b/mod/starred.php index e75a096740..9b46b522bb 100644 --- a/mod/starred.php +++ b/mod/starred.php @@ -42,7 +42,7 @@ function starred_init(App $a) { $rand = "?$rand"; } - goaway(System::baseUrl() . "/" . $return_path . $rand); + $a->internalRedirect($return_path . $rand); } // the json doesn't really matter, it will either be 0 or 1 diff --git a/mod/suggest.php b/mod/suggest.php index 81030842dc..1e33cb6602 100644 --- a/mod/suggest.php +++ b/mod/suggest.php @@ -62,7 +62,7 @@ function suggest_content(App $a) return; } - $_SESSION['return_url'] = System::baseUrl() . '/' . $a->cmd; + $_SESSION['return_path'] = $a->cmd; $a->page['aside'] .= Widget::findPeople(); $a->page['aside'] .= Widget::follow(); diff --git a/mod/tagrm.php b/mod/tagrm.php index db0b765799..105cc0b3d5 100644 --- a/mod/tagrm.php +++ b/mod/tagrm.php @@ -13,11 +13,11 @@ use Friendica\Model\Item; function tagrm_post(App $a) { if (!local_user()) { - goaway(System::baseUrl() . '/' . $_SESSION['photo_return']); + $a->internalRedirect($_SESSION['photo_return']); } if (x($_POST,'submit') && ($_POST['submit'] === L10n::t('Cancel'))) { - goaway(System::baseUrl() . '/' . $_SESSION['photo_return']); + $a->internalRedirect($_SESSION['photo_return']); } $tag = (x($_POST,'tag') ? hex2bin(notags(trim($_POST['tag']))) : ''); @@ -25,7 +25,7 @@ function tagrm_post(App $a) $item = Item::selectFirst(['tag'], ['id' => $item_id, 'uid' => local_user()]); if (!DBA::isResult($item)) { - goaway(System::baseUrl() . '/' . $_SESSION['photo_return']); + $a->internalRedirect($_SESSION['photo_return']); } $arr = explode(',', $item['tag']); @@ -41,7 +41,7 @@ function tagrm_post(App $a) Item::update(['tag' => $tag_str], ['id' => $item_id]); info(L10n::t('Tag removed') . EOL ); - goaway(System::baseUrl() . '/' . $_SESSION['photo_return']); + $a->internalRedirect($_SESSION['photo_return']); // NOTREACHED } @@ -53,25 +53,25 @@ function tagrm_content(App $a) $o = ''; if (!local_user()) { - goaway(System::baseUrl() . '/' . $_SESSION['photo_return']); + $a->internalRedirect($_SESSION['photo_return']); // NOTREACHED } $item_id = (($a->argc > 1) ? intval($a->argv[1]) : 0); if (!$item_id) { - goaway(System::baseUrl() . '/' . $_SESSION['photo_return']); + $a->internalRedirect($_SESSION['photo_return']); // NOTREACHED } $item = Item::selectFirst(['tag'], ['id' => $item_id, 'uid' => local_user()]); if (!DBA::isResult($item)) { - goaway(System::baseUrl() . '/' . $_SESSION['photo_return']); + $a->internalRedirect($_SESSION['photo_return']); } $arr = explode(',', $item['tag']); if (!count($arr)) { - goaway(System::baseUrl() . '/' . $_SESSION['photo_return']); + $a->internalRedirect($_SESSION['photo_return']); } $o .= '

' . L10n::t('Remove Item Tag') . '

'; diff --git a/mod/toggle_mobile.php b/mod/toggle_mobile.php index 2449de4aa2..ad77dd1ccd 100644 --- a/mod/toggle_mobile.php +++ b/mod/toggle_mobile.php @@ -14,8 +14,8 @@ function toggle_mobile_init(App $a) { if (isset($_GET['address'])) { $address = $_GET['address']; } else { - $address = System::baseUrl(); + $address = ''; } - goaway($address); + $a->internalRedirect($address); } diff --git a/mod/unfollow.php b/mod/unfollow.php index 6a058608e7..2a60322f02 100644 --- a/mod/unfollow.php +++ b/mod/unfollow.php @@ -12,13 +12,13 @@ use Friendica\Model\Contact; use Friendica\Model\Profile; use Friendica\Model\User; -function unfollow_post() +function unfollow_post(App $a) { - $return_url = 'contacts'; + $return_path = 'contacts'; if (!local_user()) { notice(L10n::t('Permission denied.')); - goaway('/login'); + $a->internalRedirect('login'); // NOTREACHED } @@ -32,17 +32,17 @@ function unfollow_post() if (!DBA::isResult($contact)) { notice(L10n::t("You aren't following this contact.")); - goaway($return_url); + $a->internalRedirect($return_path); // NOTREACHED } if (!empty($_REQUEST['cancel'])) { - goaway($return_url . '/' . $contact['id']); + $a->internalRedirect($return_path . '/' . $contact['id']); } if (!in_array($contact['network'], Protocol::NATIVE_SUPPORT)) { notice(L10n::t('Unfollowing is currently not supported by your network.')); - goaway($return_url . '/' . $contact['id']); + $a->internalRedirect($return_path . '/' . $contact['id']); // NOTREACHED } @@ -63,17 +63,17 @@ function unfollow_post() } info(L10n::t('Contact unfollowed')); - goaway($return_path); + $a->internalRedirect($return_path); // NOTREACHED } function unfollow_content(App $a) { - $return_url = 'contacts'; + $return_path = 'contacts'; if (!local_user()) { notice(L10n::t('Permission denied.')); - goaway('/login'); + $a->internalRedirect('login'); // NOTREACHED } @@ -88,13 +88,13 @@ function unfollow_content(App $a) if (!DBA::isResult($contact)) { notice(L10n::t("You aren't following this contact.")); - goaway($return_url); + $a->internalRedirect($return_path); // NOTREACHED } if (!in_array($contact['network'], Protocol::NATIVE_SUPPORT)) { notice(L10n::t('Unfollowing is currently not supported by your network.')); - goaway('contact/' . $contact['id']); + $a->internalRedirect('contact/' . $contact['id']); // NOTREACHED } @@ -105,7 +105,7 @@ function unfollow_content(App $a) if (!DBA::isResult($self)) { notice(L10n::t('Permission denied.')); - goaway($return_url); + $a->internalRedirect($return_path); // NOTREACHED } diff --git a/mod/videos.php b/mod/videos.php index b66a7cbcda..521201394b 100644 --- a/mod/videos.php +++ b/mod/videos.php @@ -115,14 +115,14 @@ function videos_post(App $a) $owner_uid = $a->data['user']['uid']; if (local_user() != $owner_uid) { - goaway(System::baseUrl() . '/videos/' . $a->data['user']['nickname']); + $a->internalRedirect('videos/' . $a->data['user']['nickname']); } if (($a->argc == 2) && !empty($_POST['delete']) && !empty($_POST['id'])) { // Check if we should do HTML-based delete confirmation if (empty($_REQUEST['confirm'])) { if (!empty($_REQUEST['canceled'])) { - goaway(System::baseUrl() . '/videos/' . $a->data['user']['nickname']); + $a->internalRedirect('videos/' . $a->data['user']['nickname']); } $drop_url = $a->query_string; @@ -169,11 +169,11 @@ function videos_post(App $a) } } - goaway(System::baseUrl() . '/videos/' . $a->data['user']['nickname']); + $a->internalRedirect('videos/' . $a->data['user']['nickname']); return; // NOTREACHED } - goaway(System::baseUrl() . '/videos/' . $a->data['user']['nickname']); + $a->internalRedirect('videos/' . $a->data['user']['nickname']); } function videos_content(App $a) diff --git a/mod/wallmessage.php b/mod/wallmessage.php index 5e08420ecb..dcec6ef9c6 100644 --- a/mod/wallmessage.php +++ b/mod/wallmessage.php @@ -69,7 +69,7 @@ function wallmessage_post(App $a) { info(L10n::t('Message sent.') . EOL); } - goaway('profile/'.$user['nickname']); + $a->internalRedirect('profile/'.$user['nickname']); } diff --git a/src/App.php b/src/App.php index ddffa867ab..e184f6c631 100644 --- a/src/App.php +++ b/src/App.php @@ -5,16 +5,13 @@ namespace Friendica; use Detection\MobileDetect; +use DOMDocument; +use DOMXPath; use Exception; -use Friendica\Core\Config; -use Friendica\Core\L10n; -use Friendica\Core\PConfig; -use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\Network\HTTPException\InternalServerErrorException; require_once 'boot.php'; -require_once 'include/dba.php'; require_once 'include/text.php'; /** @@ -53,20 +50,14 @@ class App public $argv; public $argc; public $module; - public $strings; - public $hooks = []; public $timezone; public $interactive = true; - public $addons; - public $addons_admin = []; - public $apps = []; public $identities; public $is_mobile = false; public $is_tablet = false; public $performance = []; public $callstack = []; public $theme_info = []; - public $nav_sel; public $category; // Allow themes to control internal parameters // by changing App values in theme.php @@ -120,7 +111,7 @@ class App * Inclusion is done in App->initHead(). * The path can be absolute or relative to the Friendica installation base folder. * - * @see App->initHead() + * @see initHead() * * @param string $path */ @@ -136,7 +127,7 @@ class App * Inclusion is done in App->initFooter(). * The path can be absolute or relative to the Friendica installation base folder. * - * @see App->initFooter() + * @see initFooter() * * @param string $path */ @@ -187,12 +178,12 @@ class App /** * @brief App constructor. * - * @param string $basePath Path to the app base folder - * @param bool $backend true, if the call is from backend, otherwise set to true (Default true) + * @param string $basePath Path to the app base folder + * @param bool $isBackend Whether it is used for backend or frontend (Default true=backend) * * @throws Exception if the Basepath is not usable */ - public function __construct($basePath, $backend = true) + public function __construct($basePath, $isBackend = true) { if (!static::isDirectoryUsable($basePath, false)) { throw new Exception('Basepath ' . $basePath . ' isn\'t usable.'); @@ -201,7 +192,7 @@ class App BaseObject::setApp($this); $this->basePath = rtrim($basePath, DIRECTORY_SEPARATOR); - $this->checkBackend($backend); + $this->checkBackend($isBackend); $this->checkFriendicaApp(); $this->performance['start'] = microtime(true); @@ -236,20 +227,20 @@ class App $this->scheme = 'http'; - if ((x($_SERVER, 'HTTPS') && $_SERVER['HTTPS']) || - (x($_SERVER, 'HTTP_FORWARDED') && preg_match('/proto=https/', $_SERVER['HTTP_FORWARDED'])) || - (x($_SERVER, 'HTTP_X_FORWARDED_PROTO') && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') || - (x($_SERVER, 'HTTP_X_FORWARDED_SSL') && $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on') || - (x($_SERVER, 'FRONT_END_HTTPS') && $_SERVER['FRONT_END_HTTPS'] == 'on') || - (x($_SERVER, 'SERVER_PORT') && (intval($_SERVER['SERVER_PORT']) == 443)) // XXX: reasonable assumption, but isn't this hardcoding too much? + if (!empty($_SERVER['HTTPS']) || + !empty($_SERVER['HTTP_FORWARDED']) && preg_match('/proto=https/', $_SERVER['HTTP_FORWARDED']) || + !empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' || + !empty($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on' || + !empty($_SERVER['FRONT_END_HTTPS']) && $_SERVER['FRONT_END_HTTPS'] == 'on' || + !empty($_SERVER['SERVER_PORT']) && (intval($_SERVER['SERVER_PORT']) == 443) // XXX: reasonable assumption, but isn't this hardcoding too much? ) { $this->scheme = 'https'; } - if (x($_SERVER, 'SERVER_NAME')) { + if (!empty($_SERVER['SERVER_NAME'])) { $this->hostname = $_SERVER['SERVER_NAME']; - if (x($_SERVER, 'SERVER_PORT') && $_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443) { + if (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443) { $this->hostname .= ':' . $_SERVER['SERVER_PORT']; } } @@ -260,9 +251,9 @@ class App . $this->getBasePath(). DIRECTORY_SEPARATOR . 'library' . PATH_SEPARATOR . $this->getBasePath()); - if ((x($_SERVER, 'QUERY_STRING')) && substr($_SERVER['QUERY_STRING'], 0, 9) === 'pagename=') { + if (!empty($_SERVER['QUERY_STRING']) && strpos($_SERVER['QUERY_STRING'], 'pagename=') === 0) { $this->query_string = substr($_SERVER['QUERY_STRING'], 9); - } elseif ((x($_SERVER, 'QUERY_STRING')) && substr($_SERVER['QUERY_STRING'], 0, 2) === 'q=') { + } elseif (!empty($_SERVER['QUERY_STRING']) && strpos($_SERVER['QUERY_STRING'], 'q=') === 0) { $this->query_string = substr($_SERVER['QUERY_STRING'], 2); } @@ -313,7 +304,7 @@ class App } // See if there is any page number information, and initialise pagination - $this->pager['page'] = ((x($_GET, 'page') && intval($_GET['page']) > 0) ? intval($_GET['page']) : 1); + $this->pager['page'] = !empty($_GET['page']) && intval($_GET['page']) > 0 ? intval($_GET['page']) : 1; $this->pager['itemspage'] = 50; $this->pager['start'] = ($this->pager['page'] * $this->pager['itemspage']) - $this->pager['itemspage']; @@ -363,30 +354,19 @@ class App $this->determineURLPath(); - Config::load(); + Core\Config::load(); if ($this->getMode()->has(App\Mode::DBAVAILABLE)) { - Core\Addon::loadHooks(); + Core\Hook::loadHooks(); $this->loadAddonConfig(); } $this->loadDefaultTimezone(); - $this->page = [ - 'aside' => '', - 'bottom' => '', - 'content' => '', - 'footer' => '', - 'htmlhead' => '', - 'nav' => '', - 'page_title' => '', - 'right_aside' => '', - 'template' => '', - 'title' => '' - ]; + Core\L10n::init(); - $this->process_id = System::processID('log'); + $this->process_id = Core\System::processID('log'); } /** @@ -593,7 +573,11 @@ class App $stamp1 = microtime(true); - DBA::connect($db_host, $db_user, $db_pass, $db_data, $charset); + if (DBA::connect($db_host, $db_user, $db_pass, $db_data, $charset)) { + // Loads DB_UPDATE_VERSION constant + Database\DBStructure::definition(false); + } + unset($db_host, $db_user, $db_pass, $db_data, $charset); $this->saveTimestamp($stamp1, 'network'); @@ -612,14 +596,14 @@ class App $basepath = $this->basePath; if (!$basepath) { - $basepath = Config::get('system', 'basepath'); + $basepath = Core\Config::get('system', 'basepath'); } - if (!$basepath && x($_SERVER, 'DOCUMENT_ROOT')) { + if (!$basepath && !empty($_SERVER['DOCUMENT_ROOT'])) { $basepath = $_SERVER['DOCUMENT_ROOT']; } - if (!$basepath && x($_SERVER, 'PWD')) { + if (!$basepath && !empty($_SERVER['PWD'])) { $basepath = $_SERVER['PWD']; } @@ -670,14 +654,14 @@ class App { $scheme = $this->scheme; - if (Config::get('system', 'ssl_policy') == SSL_POLICY_FULL) { + if (Core\Config::get('system', 'ssl_policy') == SSL_POLICY_FULL) { $scheme = 'https'; } // Basically, we have $ssl = true on any links which can only be seen by a logged in user // (and also the login link). Anything seen by an outsider will have it turned off. - if (Config::get('system', 'ssl_policy') == SSL_POLICY_SELFSIGN) { + if (Core\Config::get('system', 'ssl_policy') == SSL_POLICY_SELFSIGN) { if ($ssl) { $scheme = 'https'; } else { @@ -685,8 +669,8 @@ class App } } - if (Config::get('config', 'hostname') != '') { - $this->hostname = Config::get('config', 'hostname'); + if (Core\Config::get('config', 'hostname') != '') { + $this->hostname = Core\Config::get('config', 'hostname'); } return $scheme . '://' . $this->hostname . (!empty($this->getURLPath()) ? '/' . $this->getURLPath() : '' ); @@ -704,7 +688,7 @@ class App $parsed = @parse_url($url); $hostname = ''; - if (x($parsed)) { + if (!empty($parsed)) { if (!empty($parsed['scheme'])) { $this->scheme = $parsed['scheme']; } @@ -713,10 +697,10 @@ class App $hostname = $parsed['host']; } - if (x($parsed, 'port')) { + if (!empty($parsed['port'])) { $hostname .= ':' . $parsed['port']; } - if (x($parsed, 'path')) { + if (!empty($parsed['path'])) { $this->urlPath = trim($parsed['path'], '\\/'); } @@ -724,8 +708,8 @@ class App include $this->getBasePath() . DIRECTORY_SEPARATOR . '.htpreconfig.php'; } - if (Config::get('config', 'hostname') != '') { - $this->hostname = Config::get('config', 'hostname'); + if (Core\Config::get('config', 'hostname') != '') { + $this->hostname = Core\Config::get('config', 'hostname'); } if (!isset($this->hostname) || ($this->hostname == '')) { @@ -736,8 +720,8 @@ class App public function getHostName() { - if (Config::get('config', 'hostname') != '') { - $this->hostname = Config::get('config', 'hostname'); + if (Core\Config::get('config', 'hostname') != '') { + $this->hostname = Core\Config::get('config', 'hostname'); } return $this->hostname; @@ -777,7 +761,7 @@ class App */ public function initHead() { - $interval = ((local_user()) ? PConfig::get(local_user(), 'system', 'update_interval') : 40000); + $interval = ((local_user()) ? Core\PConfig::get(local_user(), 'system', 'update_interval') : 40000); // If the update is 'deactivated' set it to the highest integer number (~24 days) if ($interval < 0) { @@ -804,12 +788,12 @@ class App $this->registerStylesheet($stylesheet); - $shortcut_icon = Config::get('system', 'shortcut_icon'); + $shortcut_icon = Core\Config::get('system', 'shortcut_icon'); if ($shortcut_icon == '') { $shortcut_icon = 'images/friendica-32.png'; } - $touch_icon = Config::get('system', 'touch_icon'); + $touch_icon = Core\Config::get('system', 'touch_icon'); if ($touch_icon == '') { $touch_icon = 'images/friendica-128.png'; } @@ -828,14 +812,14 @@ class App '$baseurl' => $this->getBaseURL(), '$local_user' => local_user(), '$generator' => 'Friendica' . ' ' . FRIENDICA_VERSION, - '$delitem' => L10n::t('Delete this item?'), - '$showmore' => L10n::t('show more'), - '$showfewer' => L10n::t('show fewer'), + '$delitem' => Core\L10n::t('Delete this item?'), + '$showmore' => Core\L10n::t('show more'), + '$showfewer' => Core\L10n::t('show fewer'), '$update_interval' => $interval, '$shortcut_icon' => $shortcut_icon, '$touch_icon' => $touch_icon, '$infinite_scroll' => $infinite_scroll, - '$block_public' => intval(Config::get('system', 'block_public')), + '$block_public' => intval(Core\Config::get('system', 'block_public')), '$stylesheets' => $this->stylesheets, ]) . $this->page['htmlhead']; } @@ -916,7 +900,7 @@ class App private function registerTemplateEngine($class) { $v = get_class_vars($class); - if (x($v, 'name')) { + if (!empty($v['name'])) { $name = $v['name']; $this->template_engines[$name] = $class; } else { @@ -935,10 +919,7 @@ class App */ public function getTemplateEngine() { - $template_engine = 'smarty3'; - if (x($this->theme, 'template_engine')) { - $template_engine = $this->theme['template_engine']; - } + $template_engine = defaults($this->theme, 'template_engine', 'smarty3'); if (isset($this->template_engines[$template_engine])) { if (isset($this->template_engine_instance[$template_engine])) { @@ -952,7 +933,7 @@ class App } echo "template engine $template_engine is not registered!\n"; - killme(); + exit(); } /** @@ -1030,7 +1011,7 @@ class App $this->performance[$value] += (float) $duration; $this->performance['marktime'] += (float) $duration; - $callstack = System::callstack(); + $callstack = Core\System::callstack(); if (!isset($this->callstack[$value][$callstack])) { // Prevent ugly E_NOTICE @@ -1138,13 +1119,13 @@ class App * if ($this->is_backend()) { $process = 'backend'; - $max_processes = Config::get('system', 'max_processes_backend'); + $max_processes = Core\Config::get('system', 'max_processes_backend'); if (intval($max_processes) == 0) { $max_processes = 5; } } else { $process = 'frontend'; - $max_processes = Config::get('system', 'max_processes_frontend'); + $max_processes = Core\Config::get('system', 'max_processes_frontend'); if (intval($max_processes) == 0) { $max_processes = 20; } @@ -1170,7 +1151,7 @@ class App */ public function isMinMemoryReached() { - $min_memory = Config::get('system', 'min_memory', 0); + $min_memory = Core\Config::get('system', 'min_memory', 0); if ($min_memory == 0) { return false; } @@ -1216,19 +1197,19 @@ class App { if ($this->isBackend()) { $process = 'backend'; - $maxsysload = intval(Config::get('system', 'maxloadavg')); + $maxsysload = intval(Core\Config::get('system', 'maxloadavg')); if ($maxsysload < 1) { $maxsysload = 50; } } else { $process = 'frontend'; - $maxsysload = intval(Config::get('system', 'maxloadavg_frontend')); + $maxsysload = intval(Core\Config::get('system', 'maxloadavg_frontend')); if ($maxsysload < 1) { $maxsysload = 50; } } - $load = System::currentLoad(); + $load = Core\System::currentLoad(); if ($load) { if (intval($load) > $maxsysload) { logger('system: load ' . $load . ' for ' . $process . ' tasks (' . $maxsysload . ') too high.'); @@ -1480,7 +1461,7 @@ class App */ public function getSenderEmailAddress() { - $sender_email = Config::get('config', 'sender_email'); + $sender_email = Core\Config::get('config', 'sender_email'); if (empty($sender_email)) { $hostname = $this->getHostName(); if (strpos($hostname, ':')) { @@ -1519,15 +1500,15 @@ class App */ private function computeCurrentTheme() { - $system_theme = Config::get('system', 'theme'); + $system_theme = Core\Config::get('system', 'theme'); if (!$system_theme) { - throw new Exception(L10n::t('No system theme config value set.')); + throw new Exception(Core\L10n::t('No system theme config value set.')); } // Sane default $this->currentTheme = $system_theme; - $allowed_themes = explode(',', Config::get('system', 'allowed_themes', $system_theme)); + $allowed_themes = explode(',', Core\Config::get('system', 'allowed_themes', $system_theme)); $page_theme = null; // Find the theme that belongs to the user whose stuff we are looking at @@ -1535,7 +1516,7 @@ class App // Allow folks to override user themes and always use their own on their own site. // This works only if the user is on the same server $user = DBA::selectFirst('user', ['theme'], ['uid' => $this->profile_uid]); - if (DBA::isResult($user) && !PConfig::get(local_user(), 'system', 'always_my_theme')) { + if (DBA::isResult($user) && !Core\PConfig::get(local_user(), 'system', 'always_my_theme')) { $page_theme = $user['theme']; } } @@ -1544,7 +1525,7 @@ class App // Specific mobile theme override if (($this->is_mobile || $this->is_tablet) && Core\Session::get('show-mobile', true)) { - $system_mobile_theme = Config::get('system', 'mobile-theme'); + $system_mobile_theme = Core\Config::get('system', 'mobile-theme'); $user_mobile_theme = Core\Session::get('mobile-theme', $system_mobile_theme); // --- means same mobile theme as desktop @@ -1614,7 +1595,7 @@ class App */ public function checkURL() { - $url = Config::get('system', 'url'); + $url = Core\Config::get('system', 'url'); // if the url isn't set or the stored url is radically different // than the currently visited url, store the current value accordingly. @@ -1623,7 +1604,405 @@ class App // We will only change the url to an ip address if there is no existing setting if (empty($url) || (!link_compare($url, $this->getBaseURL())) && (!preg_match("/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/", $this->getHostName()))) { - Config::set('system', 'url', $this->getBaseURL()); + Core\Config::set('system', 'url', $this->getBaseURL()); } } + + /** + * Frontend App script + * + * The App object behaves like a container and a dispatcher at the same time, including a representation of the + * request and a representation of the response. + * + * This probably should change to limit the size of this monster method. + */ + public function runFrontend() + { + // Missing DB connection: ERROR + if ($this->getMode()->has(App\Mode::LOCALCONFIGPRESENT) && !$this->getMode()->has(App\Mode::DBAVAILABLE)) { + Core\System::httpExit(500, ['title' => 'Error 500 - Internal Server Error', 'description' => 'Apologies but the website is unavailable at the moment.']); + } + + // Max Load Average reached: ERROR + if ($this->isMaxProcessesReached() || $this->isMaxLoadReached()) { + header('Retry-After: 120'); + header('Refresh: 120; url=' . $this->getBaseURL() . "/" . $this->query_string); + + Core\System::httpExit(503, ['title' => 'Error 503 - Service Temporarily Unavailable', 'description' => 'Core\System is currently overloaded. Please try again later.']); + } + + if (strstr($this->query_string, '.well-known/host-meta') && ($this->query_string != '.well-known/host-meta')) { + Core\System::httpExit(404); + } + + if (!$this->getMode()->isInstall()) { + // Force SSL redirection + if (Core\Config::get('system', 'force_ssl') && ($this->getScheme() == "http") + && intval(Core\Config::get('system', 'ssl_policy')) == SSL_POLICY_FULL + && strpos($this->getBaseURL(), 'https://') === 0 + && $_SERVER['REQUEST_METHOD'] == 'GET') { + header('HTTP/1.1 302 Moved Temporarily'); + header('Location: ' . $this->getBaseURL() . '/' . $this->query_string); + exit(); + } + + Core\Session::init(); + Core\Addon::callHooks('init_1'); + } + + // Exclude the backend processes from the session management + if (!$this->isBackend()) { + $stamp1 = microtime(true); + session_start(); + $this->saveTimestamp($stamp1, 'parser'); + Core\L10n::setSessionVariable(); + Core\L10n::setLangFromSession(); + } else { + $_SESSION = []; + Core\Worker::executeIfIdle(); + } + + // ZRL + if (!empty($_GET['zrl']) && $this->getMode()->isNormal()) { + $this->query_string = Model\Profile::stripZrls($this->query_string); + if (!local_user()) { + // Only continue when the given profile link seems valid + // Valid profile links contain a path with "/profile/" and no query parameters + if ((parse_url($_GET['zrl'], PHP_URL_QUERY) == "") && + strstr(parse_url($_GET['zrl'], PHP_URL_PATH), "/profile/")) { + if (defaults($_SESSION, "visitor_home", "") != $_GET["zrl"]) { + $_SESSION['my_url'] = $_GET['zrl']; + $_SESSION['authenticated'] = 0; + } + Model\Profile::zrlInit($this); + } else { + // Someone came with an invalid parameter, maybe as a DDoS attempt + // We simply stop processing here + logger("Invalid ZRL parameter " . $_GET['zrl'], LOGGER_DEBUG); + Core\System::httpExit(403, ['title' => '403 Forbidden']); + } + } + } + + if (!empty($_GET['owt']) && $this->getMode()->isNormal()) { + $token = $_GET['owt']; + $this->query_string = Model\Profile::stripQueryParam($this->query_string, 'owt'); + Model\Profile::openWebAuthInit($token); + } + + Module\Login::sessionAuth(); + + if (empty($_SESSION['authenticated'])) { + header('X-Account-Management-Status: none'); + } + + $_SESSION['sysmsg'] = defaults($_SESSION, 'sysmsg' , []); + $_SESSION['sysmsg_info'] = defaults($_SESSION, 'sysmsg_info' , []); + $_SESSION['last_updated'] = defaults($_SESSION, 'last_updated', []); + + /* + * check_config() is responsible for running update scripts. These automatically + * update the DB schema whenever we push a new one out. It also checks to see if + * any addons have been added or removed and reacts accordingly. + */ + + // in install mode, any url loads install module + // but we need "view" module for stylesheet + if ($this->getMode()->isInstall() && $this->module != 'view') { + $this->module = 'install'; + } elseif (!$this->getMode()->has(App\Mode::MAINTENANCEDISABLED) && $this->module != 'view') { + $this->module = 'maintenance'; + } else { + $this->checkURL(); + check_db(false); + Core\Addon::check(); + } + + $this->page = [ + 'aside' => '', + 'bottom' => '', + 'content' => '', + 'footer' => '', + 'htmlhead' => '', + 'nav' => '', + 'page_title' => '', + 'right_aside' => '', + 'template' => '', + 'title' => '' + ]; + + if (strlen($this->module)) { + // Compatibility with the Android Diaspora client + if ($this->module == 'stream') { + $this->internalRedirect('network?f=&order=post'); + } + + if ($this->module == 'conversations') { + $this->internalRedirect('message'); + } + + if ($this->module == 'commented') { + $this->internalRedirect('network?f=&order=comment'); + } + + if ($this->module == 'liked') { + $this->internalRedirect('network?f=&order=comment'); + } + + if ($this->module == 'activity') { + $this->internalRedirect('network/?f=&conv=1'); + } + + if (($this->module == 'status_messages') && ($this->cmd == 'status_messages/new')) { + $this->internalRedirect('bookmarklet'); + } + + if (($this->module == 'user') && ($this->cmd == 'user/edit')) { + $this->internalRedirect('settings'); + } + + if (($this->module == 'tag_followings') && ($this->cmd == 'tag_followings/manage')) { + $this->internalRedirect('search'); + } + + // Compatibility with the Firefox App + if (($this->module == "users") && ($this->cmd == "users/sign_in")) { + $this->module = "login"; + } + + $privateapps = Core\Config::get('config', 'private_addons', false); + if (is_array($this->addons) && in_array($this->module, $this->addons) && file_exists("addon/{$this->module}/{$this->module}.php")) { + //Check if module is an app and if public access to apps is allowed or not + if ((!local_user()) && Core\Addon::isApp($this->module) && $privateapps) { + info(Core\L10n::t("You must be logged in to use addons. ")); + } else { + include_once "addon/{$this->module}/{$this->module}.php"; + if (function_exists($this->module . '_module')) { + LegacyModule::setModuleFile("addon/{$this->module}/{$this->module}.php"); + $this->module_class = 'Friendica\\LegacyModule'; + $this->module_loaded = true; + } + } + } + + // Controller class routing + if (! $this->module_loaded && class_exists('Friendica\\Module\\' . ucfirst($this->module))) { + $this->module_class = 'Friendica\\Module\\' . ucfirst($this->module); + $this->module_loaded = true; + } + + /* If not, next look for a 'standard' program module in the 'mod' directory + * We emulate a Module class through the LegacyModule class + */ + if (! $this->module_loaded && file_exists("mod/{$this->module}.php")) { + LegacyModule::setModuleFile("mod/{$this->module}.php"); + $this->module_class = 'Friendica\\LegacyModule'; + $this->module_loaded = true; + } + + /* The URL provided does not resolve to a valid module. + * + * On Dreamhost sites, quite often things go wrong for no apparent reason and they send us to '/internal_error.html'. + * We don't like doing this, but as it occasionally accounts for 10-20% or more of all site traffic - + * we are going to trap this and redirect back to the requested page. As long as you don't have a critical error on your page + * this will often succeed and eventually do the right thing. + * + * Otherwise we are going to emit a 404 not found. + */ + if (! $this->module_loaded) { + // Stupid browser tried to pre-fetch our Javascript img template. Don't log the event or return anything - just quietly exit. + if (!empty($_SERVER['QUERY_STRING']) && preg_match('/{[0-9]}/', $_SERVER['QUERY_STRING']) !== 0) { + exit(); + } + + if (!empty($_SERVER['QUERY_STRING']) && ($_SERVER['QUERY_STRING'] === 'q=internal_error.html') && isset($dreamhost_error_hack)) { + logger('index.php: dreamhost_error_hack invoked. Original URI =' . $_SERVER['REQUEST_URI']); + $this->internalRedirect($_SERVER['REQUEST_URI']); + } + + logger('index.php: page not found: ' . $_SERVER['REQUEST_URI'] . ' ADDRESS: ' . $_SERVER['REMOTE_ADDR'] . ' QUERY: ' . $_SERVER['QUERY_STRING'], LOGGER_DEBUG); + + header($_SERVER["SERVER_PROTOCOL"] . ' 404 ' . Core\L10n::t('Not Found')); + $tpl = get_markup_template("404.tpl"); + $this->page['content'] = replace_macros($tpl, [ + '$message' => Core\L10n::t('Page not found.') + ]); + } + } + + // Load current theme info + $theme_info_file = 'view/theme/' . $this->getCurrentTheme() . '/theme.php'; + if (file_exists($theme_info_file)) { + require_once $theme_info_file; + } + + // initialise content region + if ($this->getMode()->isNormal()) { + Core\Addon::callHooks('page_content_top', $this->page['content']); + } + + // Call module functions + if ($this->module_loaded) { + $this->page['page_title'] = $this->module; + $placeholder = ''; + + Core\Addon::callHooks($this->module . '_mod_init', $placeholder); + + call_user_func([$this->module_class, 'init']); + + // "rawContent" is especially meant for technical endpoints. + // This endpoint doesn't need any theme initialization or other comparable stuff. + if (!$this->error) { + call_user_func([$this->module_class, 'rawContent']); + } + + if (function_exists(str_replace('-', '_', $this->getCurrentTheme()) . '_init')) { + $func = str_replace('-', '_', $this->getCurrentTheme()) . '_init'; + $func($this); + } + + if (! $this->error && $_SERVER['REQUEST_METHOD'] === 'POST') { + Core\Addon::callHooks($this->module . '_mod_post', $_POST); + call_user_func([$this->module_class, 'post']); + } + + if (! $this->error) { + Core\Addon::callHooks($this->module . '_mod_afterpost', $placeholder); + call_user_func([$this->module_class, 'afterpost']); + } + + if (! $this->error) { + $arr = ['content' => $this->page['content']]; + Core\Addon::callHooks($this->module . '_mod_content', $arr); + $this->page['content'] = $arr['content']; + $arr = ['content' => call_user_func([$this->module_class, 'content'])]; + Core\Addon::callHooks($this->module . '_mod_aftercontent', $arr); + $this->page['content'] .= $arr['content']; + } + + if (function_exists(str_replace('-', '_', $this->getCurrentTheme()) . '_content_loaded')) { + $func = str_replace('-', '_', $this->getCurrentTheme()) . '_content_loaded'; + $func($this); + } + } + + /* Create the page head after setting the language + * and getting any auth credentials. + * + * Moved initHead() and initFooter() to after + * all the module functions have executed so that all + * theme choices made by the modules can take effect. + */ + $this->initHead(); + + /* Build the page ending -- this is stuff that goes right before + * the closing tag + */ + $this->initFooter(); + + /* now that we've been through the module content, see if the page reported + * a permission problem and if so, a 403 response would seem to be in order. + */ + if (stristr(implode("", $_SESSION['sysmsg']), Core\L10n::t('Permission denied'))) { + header($_SERVER["SERVER_PROTOCOL"] . ' 403 ' . Core\L10n::t('Permission denied.')); + } + + // Report anything which needs to be communicated in the notification area (before the main body) + Core\Addon::callHooks('page_end', $this->page['content']); + + // Add the navigation (menu) template + if ($this->module != 'install' && $this->module != 'maintenance') { + $this->page['htmlhead'] .= replace_macros(get_markup_template('nav_head.tpl'), []); + $this->page['nav'] = Content\Nav::build($this); + } + + // Build the page - now that we have all the components + if (isset($_GET["mode"]) && (($_GET["mode"] == "raw") || ($_GET["mode"] == "minimal"))) { + $doc = new DOMDocument(); + + $target = new DOMDocument(); + $target->loadXML(""); + + $content = mb_convert_encoding($this->page["content"], 'HTML-ENTITIES', "UTF-8"); + + /// @TODO one day, kill those error-surpressing @ stuff, or PHP should ban it + @$doc->loadHTML($content); + + $xpath = new DOMXPath($doc); + + $list = $xpath->query("//*[contains(@id,'tread-wrapper-')]"); /* */ + + foreach ($list as $item) { + $item = $target->importNode($item, true); + + // And then append it to the target + $target->documentElement->appendChild($item); + } + } + + if (isset($_GET["mode"]) && ($_GET["mode"] == "raw")) { + header("Content-type: text/html; charset=utf-8"); + + echo substr($target->saveHTML(), 6, -8); + + exit(); + } + + $page = $this->page; + $profile = $this->profile; + + header("X-Friendica-Version: " . FRIENDICA_VERSION); + header("Content-type: text/html; charset=utf-8"); + + if (Core\Config::get('system', 'hsts') && (Core\Config::get('system', 'ssl_policy') == SSL_POLICY_FULL)) { + header("Strict-Transport-Security: max-age=31536000"); + } + + // Some security stuff + header('X-Content-Type-Options: nosniff'); + header('X-XSS-Protection: 1; mode=block'); + header('X-Permitted-Cross-Domain-Policies: none'); + header('X-Frame-Options: sameorigin'); + + // Things like embedded OSM maps don't work, when this is enabled + // header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; connect-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self'; img-src 'self' https: data:; media-src 'self' https:; child-src 'self' https:; object-src 'none'"); + + /* We use $_GET["mode"] for special page templates. So we will check if we have + * to load another page template than the default one. + * The page templates are located in /view/php/ or in the theme directory. + */ + if (isset($_GET["mode"])) { + $template = Core\Theme::getPathForFile($_GET["mode"] . '.php'); + } + + // If there is no page template use the default page template + if (empty($template)) { + $template = Core\Theme::getPathForFile("default.php"); + } + + // Theme templates expect $a as an App instance + $a = $this; + + /// @TODO Looks unsafe (remote-inclusion), is maybe not but Core\Theme::getPathForFile() uses file_exists() but does not escape anything + require_once $template; + } + + /** + * Redirects to another module relative to the current Friendica base. + * If you want to redirect to a external URL, use System::externalRedirectTo() + * + * @param string $toUrl The destination URL (Default is empty, which is the default page of the Friendica node) + * @param bool $ssl if true, base URL will try to get called with https:// (works just for relative paths) + * + * @throws InternalServerErrorException In Case the given URL is not relative to the Friendica node + */ + public function internalRedirect($toUrl = '', $ssl = false) + { + if (filter_var($toUrl, FILTER_VALIDATE_URL)) { + throw new InternalServerErrorException('URL is not a relative path, please use System::externalRedirectTo'); + } + + $redirectTo = $this->getBaseURL($ssl) . '/' . ltrim($toUrl, '/'); + System::externalRedirect($redirectTo); + } } diff --git a/src/BaseModule.php b/src/BaseModule.php index e77b1a1491..522f0b783f 100644 --- a/src/BaseModule.php +++ b/src/BaseModule.php @@ -60,7 +60,8 @@ abstract class BaseModule extends BaseObject */ public static function post() { - // goaway('module'); + // $a = self::getApp(); + // $a->internalRedirect('module'); } /** @@ -138,7 +139,7 @@ abstract class BaseModule extends BaseObject logger('checkFormSecurityToken failed: user ' . $a->user['guid'] . ' - form element ' . $typename); logger('checkFormSecurityToken failed: _REQUEST data: ' . print_r($_REQUEST, true), LOGGER_DATA); notice(self::getFormSecurityStandardErrorMessage()); - goaway(System::baseUrl() . $err_redirect); + $a->internalRedirect($err_redirect); } } diff --git a/src/Content/Nav.php b/src/Content/Nav.php index 4f6f4ae0b9..8289825ead 100644 --- a/src/Content/Nav.php +++ b/src/Content/Nav.php @@ -15,50 +15,102 @@ use Friendica\Model\Contact; use Friendica\Model\Profile; require_once 'boot.php'; -require_once 'dba.php'; require_once 'include/text.php'; class Nav { + private static $selected = [ + 'global' => null, + 'community' => null, + 'network' => null, + 'home' => null, + 'profiles' => null, + 'introductions' => null, + 'notifications' => null, + 'messages' => null, + 'directory' => null, + 'settings' => null, + 'contacts' => null, + 'manage' => null, + 'events' => null, + 'register' => null + ]; + + /** + * An array of HTML links provided by addons providing a module via the app_menu hook + * + * @var array + */ + private static $app_menu = null; + + /** + * Set a menu item in navbar as selected + */ + public static function setSelected($item) + { + self::$selected[$item] = 'selected'; + } + /** * Build page header and site navigation bars */ public static function build(App $a) { - if (!(x($a->page, 'nav'))) { - $a->page['nav'] = ''; - } - - $a->page['htmlhead'] .= replace_macros(get_markup_template('nav_head.tpl'), []); - - /* - * Placeholder div for popup panel - */ - - $a->page['nav'] .= '' ; + // Placeholder div for popup panel + $nav = '' ; $nav_info = self::getInfo($a); - /* - * Build the page - */ - $tpl = get_markup_template('nav.tpl'); - $a->page['nav'] .= replace_macros($tpl, [ - '$baseurl' => System::baseUrl(), + $nav .= replace_macros($tpl, [ + '$baseurl' => System::baseUrl(), '$sitelocation' => $nav_info['sitelocation'], - '$nav' => $nav_info['nav'], - '$banner' => $nav_info['banner'], + '$nav' => $nav_info['nav'], + '$banner' => $nav_info['banner'], '$emptynotifications' => L10n::t('Nothing new here'), - '$userinfo' => $nav_info['userinfo'], - '$sel' => $a->nav_sel, - '$apps' => $a->apps, + '$userinfo' => $nav_info['userinfo'], + '$sel' => self::$selected, + '$apps' => self::getAppMenu(), '$clear_notifs' => L10n::t('Clear notifications'), - '$search_hint' => L10n::t('@name, !forum, #tags, content') + '$search_hint' => L10n::t('@name, !forum, #tags, content') ]); - Addon::callHooks('page_header', $a->page['nav']); + Addon::callHooks('page_header', $nav); + + return $nav; + } + + /** + * Returns the addon app menu + * + * @return array + */ + public static function getAppMenu() + { + if (is_null(self::$app_menu)) { + self::populateAppMenu(); + } + + return self::$app_menu; + } + + /** + * Fills the apps static variable with apps that require a menu + */ + private static function populateAppMenu() + { + self::$app_menu = []; + + //Don't populate apps_menu if apps are private + $privateapps = Config::get('config', 'private_addons', false); + if (local_user() || !$privateapps) { + $arr = ['app_menu' => self::$app_menu]; + + Addon::callHooks('app_menu', $arr); + + self::$app_menu = $arr['app_menu']; + } } /** @@ -134,7 +186,7 @@ class Nav $nav['help'] = [$help_url, L10n::t('Help'), '', L10n::t('Help and documentation')]; } - if (count($a->apps) > 0) { + if (count(self::getAppMenu()) > 0) { $nav['apps'] = ['apps', L10n::t('Apps'), '', L10n::t('Addon applications, utilities, games')]; } @@ -235,29 +287,4 @@ class Nav 'userinfo' => $userinfo, ]; } - - /** - * Set a menu item in navbar as selected - */ - public static function setSelected($item) - { - $a = get_app(); - $a->nav_sel = [ - 'global' => null, - 'community' => null, - 'network' => null, - 'home' => null, - 'profiles' => null, - 'introductions' => null, - 'notifications' => null, - 'messages' => null, - 'directory' => null, - 'settings' => null, - 'contacts' => null, - 'manage' => null, - 'events' => null, - 'register' => null - ]; - $a->nav_sel[$item] = 'selected'; - } } diff --git a/src/Core/Addon.php b/src/Core/Addon.php index d2f89ce279..c3f559c708 100644 --- a/src/Core/Addon.php +++ b/src/Core/Addon.php @@ -8,15 +8,20 @@ use Friendica\App; use Friendica\BaseObject; use Friendica\Database\DBA; -require_once 'include/dba.php'; - /** * Some functions to handle addons */ class Addon extends BaseObject { /** - * @brief Synchronise addons: + * List of the names of enabled addons + * + * @var array + */ + private static $addons = []; + + /** + * @brief Synchronize addons: * * system.addon contains a comma-separated list of names * of addons which are used on this system. @@ -27,15 +32,13 @@ class Addon extends BaseObject * call the install procedure and add it to the database. * */ - public static function check() + public static function loadAddons() { - $a = self::getApp(); + $installed_addons = []; $r = DBA::select('addon', [], ['installed' => 1]); if (DBA::isResult($r)) { - $installed = DBA::toArray($r); - } else { - $installed = []; + $installed_addons = DBA::toArray($r); } $addons = Config::get('system', 'addon'); @@ -45,31 +48,23 @@ class Addon extends BaseObject $addons_arr = explode(',', str_replace(' ', '', $addons)); } - $a->addons = $addons_arr; + self::$addons = $addons_arr; $installed_arr = []; - if (count($installed)) { - foreach ($installed as $i) { - if (!in_array($i['name'], $addons_arr)) { - self::uninstall($i['name']); - } else { - $installed_arr[] = $i['name']; - } + foreach ($installed_addons as $addon) { + if (!self::isEnabled($addon['name'])) { + self::uninstall($addon['name']); + } else { + $installed_arr[] = $addon['name']; } } - if (count($addons_arr)) { - foreach ($addons_arr as $p) { - if (!in_array($p, $installed_arr)) { - self::install($p); - } + foreach (self::$addons as $p) { + if (!in_array($p, $installed_arr)) { + self::install($p); } } - - self::loadHooks(); - - return; } /** @@ -88,6 +83,8 @@ class Addon extends BaseObject $func = $addon . '_uninstall'; $func(); } + + unset(self::$addons[$idx]); } /** @@ -110,10 +107,10 @@ class Addon extends BaseObject $func = $addon . '_install'; $func(); - $addon_admin = (function_exists($addon."_addon_admin") ? 1 : 0); + $addon_admin = (function_exists($addon . "_addon_admin") ? 1 : 0); DBA::insert('addon', ['name' => $addon, 'installed' => true, - 'timestamp' => $t, 'plugin_admin' => $addon_admin]); + 'timestamp' => $t, 'plugin_admin' => $addon_admin]); // we can add the following with the previous SQL // once most site tables have been updated. @@ -122,6 +119,10 @@ class Addon extends BaseObject if (file_exists('addon/' . $addon . '/.hidden')) { DBA::update('addon', ['hidden' => true], ['name' => $addon]); } + + if (!self::isEnabled($addon)) { + self::$addons[] = $addon; + } return true; } else { logger("Addons: FAILED installing " . $addon); @@ -174,165 +175,6 @@ class Addon extends BaseObject } } - /** - * @brief check if addon is enabled - * - * @param string $addon - * @return boolean - */ - public static function isEnabled($addon) - { - return DBA::exists('addon', ['installed' => true, 'name' => $addon]); - } - - - /** - * @brief registers a hook. - * - * @param string $hook the name of the hook - * @param string $file the name of the file that hooks into - * @param string $function the name of the function that the hook will call - * @param int $priority A priority (defaults to 0) - * @return mixed|bool - */ - public static function registerHook($hook, $file, $function, $priority = 0) - { - $file = str_replace(self::getApp()->getBasePath() . DIRECTORY_SEPARATOR, '', $file); - - $condition = ['hook' => $hook, 'file' => $file, 'function' => $function]; - $exists = DBA::exists('hook', $condition); - if ($exists) { - return true; - } - - $r = DBA::insert('hook', ['hook' => $hook, 'file' => $file, 'function' => $function, 'priority' => $priority]); - - return $r; - } - - /** - * @brief unregisters a hook. - * - * @param string $hook the name of the hook - * @param string $file the name of the file that hooks into - * @param string $function the name of the function that the hook called - * @return array - */ - public static function unregisterHook($hook, $file, $function) - { - $relative_file = str_replace(self::getApp()->getBasePath() . DIRECTORY_SEPARATOR, '', $file); - - // This here is only needed for fixing a problem that existed on the develop branch - $condition = ['hook' => $hook, 'file' => $file, 'function' => $function]; - DBA::delete('hook', $condition); - - $condition = ['hook' => $hook, 'file' => $relative_file, 'function' => $function]; - $r = DBA::delete('hook', $condition); - return $r; - } - - /** - * Load hooks - */ - public static function loadHooks() - { - $a = self::getApp(); - $a->hooks = []; - $r = DBA::select('hook', ['hook', 'file', 'function'], [], ['order' => ['priority' => 'desc', 'file']]); - - while ($rr = DBA::fetch($r)) { - if (! array_key_exists($rr['hook'], $a->hooks)) { - $a->hooks[$rr['hook']] = []; - } - $a->hooks[$rr['hook']][] = [$rr['file'],$rr['function']]; - } - DBA::close($r); - } - - /** - * @brief Forks a hook. - * - * Use this function when you want to fork a hook via the worker. - * - * @param string $name of the hook to call - * @param string|array $data to transmit to the callback handler - */ - public static function forkHooks($priority, $name, $data = null) - { - $a = self::getApp(); - - if (is_array($a->hooks) && array_key_exists($name, $a->hooks)) { - foreach ($a->hooks[$name] as $hook) { - Worker::add($priority, 'ForkHook', $name, $hook, $data); - } - } - } - - /** - * @brief Calls a hook. - * - * Use this function when you want to be able to allow a hook to manipulate - * the provided data. - * - * @param string $name of the hook to call - * @param string|array &$data to transmit to the callback handler - */ - public static function callHooks($name, &$data = null) - { - $a = self::getApp(); - - if (is_array($a->hooks) && array_key_exists($name, $a->hooks)) { - foreach ($a->hooks[$name] as $hook) { - self::callSingleHook($a, $name, $hook, $data); - } - } - } - - /** - * @brief Calls a single hook. - * - * @param App $a - * @param string $name of the hook to call - * @param array $hook Hook data - * @param string|array &$data to transmit to the callback handler - */ - public static function callSingleHook(App $a, $name, $hook, &$data = null) - { - // Don't run a theme's hook if the user isn't using the theme - if (strpos($hook[0], 'view/theme/') !== false && strpos($hook[0], 'view/theme/' . $a->getCurrentTheme()) === false) { - return; - } - - @include_once($hook[0]); - if (function_exists($hook[1])) { - $func = $hook[1]; - $func($a, $data); - } else { - // remove orphan hooks - $condition = ['hook' => $name, 'file' => $hook[0], 'function' => $hook[1]]; - DBA::delete('hook', $condition, ['cascade' => false]); - } - } - - /** - * check if an app_menu hook exist for addon $name. - * Return true if the addon is an app - */ - public static function isApp($name) - { - $a = self::getApp(); - - if (is_array($a->hooks) && (array_key_exists('app_menu', $a->hooks))) { - foreach ($a->hooks['app_menu'] as $hook) { - if ($hook[0] == 'addon/'.$name.'/'.$name.'.php') { - return true; - } - } - } - - return false; - } - /** * @brief Parse addon comment in search of addon infos. * @@ -401,4 +243,97 @@ class Addon extends BaseObject } return $info; } + + /** + * Checks if the provided addon is enabled + * + * @param string $addon + * @return boolean + */ + public static function isEnabled($addon) + { + return in_array($addon, self::$addons); + } + + /** + * Returns a list of the enabled addon names + * + * @return array + */ + public static function getEnabledList() + { + return self::$addons; + } + + /** + * Saves the current enabled addon list in the system.addon config key + * + * @return boolean + */ + public static function saveEnabledList() + { + return Config::set("system", "addon", implode(", ", self::$addons)); + } + + /** + * Returns the list of non-hidden enabled addon names + * + * @return array + */ + public static function getVisibleList() + { + $visible_addons = []; + $stmt = DBA::select('addon', ['name'], ['hidden' => false, 'installed' => true]); + if (DBA::isResult($stmt)) { + foreach (DBA::toArray($stmt) as $addon) { + $visible_addons[] = $addon['name']; + } + } + + return $visible_addons; + } + + /** + * Shim of Hook::register left for backward compatibility purpose. + * + * @see Hook::register + * @deprecated since version 2018.12 + * @param string $hook the name of the hook + * @param string $file the name of the file that hooks into + * @param string $function the name of the function that the hook will call + * @param int $priority A priority (defaults to 0) + * @return mixed|bool + */ + public static function registerHook($hook, $file, $function, $priority = 0) + { + return Hook::register($hook, $file, $function, $priority); + } + + /** + * Shim of Hook::unregister left for backward compatibility purpose. + * + * @see Hook::unregister + * @deprecated since version 2018.12 + * @param string $hook the name of the hook + * @param string $file the name of the file that hooks into + * @param string $function the name of the function that the hook called + * @return boolean + */ + public static function unregisterHook($hook, $file, $function) + { + return Hook::unregister($hook, $file, $function); + } + + /** + * Shim of Hook::callAll left for backward-compatibility purpose. + * + * @see Hook::callAll + * @deprecated since version 2018.12 + * @param string $name of the hook to call + * @param string|array &$data to transmit to the callback handler + */ + public static function callHooks($name, &$data = null) + { + Hook::callAll($name, $data); + } } diff --git a/src/Core/Authentication.php b/src/Core/Authentication.php index 3a4471d2a4..5371cc91ec 100644 --- a/src/Core/Authentication.php +++ b/src/Core/Authentication.php @@ -5,17 +5,17 @@ namespace Friendica\Core; -use Friendica\Core\Addon; use Friendica\BaseObject; +use Friendica\Core\Addon; use Friendica\Core\Config; -use Friendica\Util\DateTimeFormat; -use Friendica\Database\DBA; use Friendica\Core\L10n; use Friendica\Core\PConfig; +use Friendica\Database\DBA; +use Friendica\Util\DateTimeFormat; /** * Handle Authentification, Session and Cookies -*/ +*/ class Authentication extends BaseObject { /** @@ -81,8 +81,8 @@ class Authentication extends BaseObject $a->user = $user_record; if ($interactive) { - if ($a->user['login_date'] <= NULL_DATE) { - $_SESSION['return_url'] = 'profile_photo/new'; + if ($a->user['login_date'] <= DBA::NULL_DATETIME) { + $_SESSION['return_path'] = 'profile_photo/new'; $a->module = 'profile_photo'; info(L10n::t("Welcome ") . $a->user['username'] . EOL); info(L10n::t('Please upload a profile photo.') . EOL); @@ -193,8 +193,8 @@ class Authentication extends BaseObject if ($login_initial) { Addon::callHooks('logged_in', $a->user); - if (($a->module !== 'home') && isset($_SESSION['return_url'])) { - goaway($a->getbaseUrl() . '/' . $_SESSION['return_url']); + if (($a->module !== 'home') && isset($_SESSION['return_path'])) { + $a->internalRedirect($_SESSION['return_path']); } } } diff --git a/src/Core/Console/Maintenance.php b/src/Core/Console/Maintenance.php index 212edabcc1..c8214b1614 100644 --- a/src/Core/Console/Maintenance.php +++ b/src/Core/Console/Maintenance.php @@ -68,11 +68,6 @@ HELP; throw new \RuntimeException('Database isn\'t ready or populated yet'); } - Core\Config::load(); - - $lang = Core\L10n::getBrowserLanguage(); - Core\L10n::loadTranslationTable($lang); - $enabled = intval($this->getArgument(0)); Core\Config::set('system', 'maintenance', $enabled); diff --git a/src/Core/Hook.php b/src/Core/Hook.php new file mode 100644 index 0000000000..85ed98e886 --- /dev/null +++ b/src/Core/Hook.php @@ -0,0 +1,191 @@ +"] => [ + * 0 => "", + * 1 => "" + * ], + * ... + * ] + * + * @var array + */ + private static $hooks = []; + + /** + * Load hooks + */ + public static function loadHooks() + { + self::$hooks = []; + $stmt = DBA::select('hook', ['hook', 'file', 'function'], [], ['order' => ['priority' => 'desc', 'file']]); + + while ($hook = DBA::fetch($stmt)) { + if (!array_key_exists($hook['hook'], self::$hooks)) { + self::$hooks[$hook['hook']] = []; + } + self::$hooks[$hook['hook']][] = [$hook['file'], $hook['function']]; + } + DBA::close($stmt); + } + + /** + * Registers a hook. + * + * @param string $hook the name of the hook + * @param string $file the name of the file that hooks into + * @param string $function the name of the function that the hook will call + * @param int $priority A priority (defaults to 0) + * @return mixed|bool + */ + public static function register($hook, $file, $function, $priority = 0) + { + $file = str_replace(self::getApp()->getBasePath() . DIRECTORY_SEPARATOR, '', $file); + + $condition = ['hook' => $hook, 'file' => $file, 'function' => $function]; + if (DBA::exists('hook', $condition)) { + return true; + } + + $result = DBA::insert('hook', ['hook' => $hook, 'file' => $file, 'function' => $function, 'priority' => $priority]); + + return $result; + } + + /** + * Unregisters a hook. + * + * @param string $hook the name of the hook + * @param string $file the name of the file that hooks into + * @param string $function the name of the function that the hook called + * @return boolean + */ + public static function unregister($hook, $file, $function) + { + $relative_file = str_replace(self::getApp()->getBasePath() . DIRECTORY_SEPARATOR, '', $file); + + // This here is only needed for fixing a problem that existed on the develop branch + $condition = ['hook' => $hook, 'file' => $file, 'function' => $function]; + DBA::delete('hook', $condition); + + $condition = ['hook' => $hook, 'file' => $relative_file, 'function' => $function]; + $result = DBA::delete('hook', $condition); + return $result; + } + + /** + * Returns the list of callbacks for a single hook + * + * @param string $name Name of the hook + * @return array + */ + public static function getByName($name) + { + $return = []; + + if (isset(self::$hooks[$name])) { + $return = self::$hooks[$name]; + } + + return $return; + } + + /** + * @brief Forks a hook. + * + * Use this function when you want to fork a hook via the worker. + * + * @param integer $priority of the hook + * @param string $name of the hook to call + * @param mixed $data to transmit to the callback handler + */ + public static function fork($priority, $name, $data = null) + { + if (array_key_exists($name, self::$hooks)) { + foreach (self::$hooks[$name] as $hook) { + Worker::add($priority, 'ForkHook', $name, $hook, $data); + } + } + } + + /** + * @brief Calls a hook. + * + * Use this function when you want to be able to allow a hook to manipulate + * the provided data. + * + * @param string $name of the hook to call + * @param string|array &$data to transmit to the callback handler + */ + public static function callAll($name, &$data = null) + { + if (array_key_exists($name, self::$hooks)) { + foreach (self::$hooks[$name] as $hook) { + self::callSingle(self::getApp(), $name, $hook, $data); + } + } + } + + /** + * @brief Calls a single hook. + * + * @param App $a + * @param string $name of the hook to call + * @param array $hook Hook data + * @param string|array &$data to transmit to the callback handler + */ + public static function callSingle(App $a, $name, $hook, &$data = null) + { + // Don't run a theme's hook if the user isn't using the theme + if (strpos($hook[0], 'view/theme/') !== false && strpos($hook[0], 'view/theme/' . $a->getCurrentTheme()) === false) { + return; + } + + @include_once($hook[0]); + if (function_exists($hook[1])) { + $func = $hook[1]; + $func($a, $data); + } else { + // remove orphan hooks + $condition = ['hook' => $name, 'file' => $hook[0], 'function' => $hook[1]]; + DBA::delete('hook', $condition, ['cascade' => false]); + } + } + + /** + * Checks if an app_menu hook exist for the provided addon name. + * Return true if the addon is an app + * + * @param string $name Name of the addon + * @return boolean + */ + public static function isAddonApp($name) + { + if (array_key_exists('app_menu', self::$hooks)) { + foreach (self::$hooks['app_menu'] as $hook) { + if ($hook[0] == 'addon/' . $name . '/' . $name . '.php') { + return true; + } + } + } + + return false; + } +} diff --git a/src/Core/L10n.php b/src/Core/L10n.php index 542590646d..45b70e0625 100644 --- a/src/Core/L10n.php +++ b/src/Core/L10n.php @@ -12,19 +12,90 @@ require_once 'boot.php'; require_once 'include/dba.php'; /** - * Provide Languange, Translation, and Localisation functions to the application - * Localisation can be referred to by the numeronym L10N (as in: "L", followed by ten more letters, and then "N"). + * Provide Language, Translation, and Localization functions to the application + * Localization can be referred to by the numeronym L10N (as in: "L", followed by ten more letters, and then "N"). */ class L10n extends BaseObject { /** - * @brief get the prefered language from the HTTP_ACCEPT_LANGUAGE header + * A string indicating the current language used for translation: + * - Two-letter ISO 639-1 code. + * - Two-letter ISO 639-1 code + dash + Two-letter ISO 3166-1 alpha-2 country code. + * @var string */ - public static function getBrowserLanguage() + private static $lang = ''; + /** + * A language code saved for later after pushLang() has been called. + * + * @var string + */ + private static $langSave = ''; + + /** + * An array of translation strings whose key is the neutral english message. + * + * @var array + */ + private static $strings = []; + /** + * An array of translation strings saved for later after pushLang() has been called. + * + * @var array + */ + private static $stringsSave = []; + + /** + * Detects the language and sets the translation table + */ + public static function init() + { + $lang = self::detectLanguage(); + self::loadTranslationTable($lang); + } + + /** + * Returns the current language code + * + * @return string Language code + */ + public static function getCurrentLang() + { + return self::$lang; + } + + /** + * Sets the language session variable + */ + public static function setSessionVariable() + { + if (!empty($_SESSION['authenticated']) && empty($_SESSION['language'])) { + $_SESSION['language'] = self::$lang; + // we haven't loaded user data yet, but we need user language + if (!empty($_SESSION['uid'])) { + $user = DBA::selectFirst('user', ['language'], ['uid' => $_SESSION['uid']]); + if (DBA::isResult($user)) { + $_SESSION['language'] = $user['language']; + } + } + } + } + + public static function setLangFromSession() + { + if (!empty($_SESSION['language']) && $_SESSION['language'] !== self::$lang) { + self::loadTranslationTable($_SESSION['language']); + } + } + + /** + * @brief Returns the preferred language from the HTTP_ACCEPT_LANGUAGE header + * @return string The two-letter language code + */ + public static function detectLanguage() { $lang_list = []; - if (x($_SERVER, 'HTTP_ACCEPT_LANGUAGE')) { + if (!empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { // break up string into pieces (languages and q factors) preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $lang_parse); @@ -59,58 +130,69 @@ class L10n extends BaseObject } /** - * @param string $language language + * This function should be called before formatting messages in a specific target language + * different from the current user/system language. + * + * It saves the current translation strings in a separate variable and loads new translations strings. + * + * If called repeatedly, it won't save the translation strings again, just load the new ones. + * + * @see popLang() + * @brief Stores the current language strings and load a different language. + * @param string $lang Language code */ - public static function pushLang($language) + public static function pushLang($lang) { - $a = self::getApp(); + if (!self::$lang) { + self::init(); + } - $a->langsave = Config::get('system', 'language'); - - if ($language === $a->langsave) { + if ($lang === self::$lang) { return; } - if (isset($a->strings) && count($a->strings)) { - $a->stringsave = $a->strings; + if (!self::$langSave) { + self::$langSave = self::$lang; + self::$stringsSave = self::$strings; } - $a->strings = []; - self::loadTranslationTable($language); - Config::set('system', 'language', $language); + + self::loadTranslationTable($lang); } /** - * Pop language off the top of the stack + * Restores the original user/system language after having used pushLang() */ public static function popLang() { - $a = self::getApp(); - - if (Config::get('system', 'language') === $a->langsave) { + if (!self::$langSave) { return; } - if (isset($a->stringsave)) { - $a->strings = $a->stringsave; - } else { - $a->strings = []; - } + self::$strings = self::$stringsSave; + self::$lang = self::$langSave; - Config::set('system', 'language', $a->langsave); + self::$stringsSave = []; + self::$langSave = ''; } /** - * load string translation table for alternate language + * Loads string translation table * - * first addon strings are loaded, then globals + * First addon strings are loaded, then globals + * + * Uses an App object shim since all the strings files refer to $a->strings * * @param string $lang language code to load */ - public static function loadTranslationTable($lang) + private static function loadTranslationTable($lang) { - $a = self::getApp(); + if ($lang === self::$lang) { + return; + } + $a = new \stdClass(); $a->strings = []; + // load enabled addons strings $addons = DBA::select('addon', ['name'], ['installed' => true]); while ($p = DBA::fetch($addons)) { @@ -123,6 +205,11 @@ class L10n extends BaseObject if (file_exists("view/lang/$lang/strings.php")) { include "view/lang/$lang/strings.php"; } + + self::$lang = $lang; + self::$strings = $a->strings; + + unset($a); } /** @@ -143,14 +230,16 @@ class L10n extends BaseObject */ public static function t($s, ...$vars) { - $a = self::getApp(); - if (empty($s)) { return ''; } - if (x($a->strings, $s)) { - $t = $a->strings[$s]; + if (!self::$lang) { + self::init(); + } + + if (!empty(self::$strings[$s])) { + $t = self::$strings[$s]; $s = is_array($t) ? $t[0] : $t; } @@ -181,18 +270,18 @@ class L10n extends BaseObject */ public static function tt($singular, $plural, $count) { - $a = self::getApp(); - if (!is_numeric($count)) { logger('Non numeric count called by ' . System::callstack(20)); } - $lang = Config::get('system', 'language'); + if (!self::$lang) { + self::init(); + } - if (!empty($a->strings[$singular])) { - $t = $a->strings[$singular]; + if (!empty(self::$strings[$singular])) { + $t = self::$strings[$singular]; if (is_array($t)) { - $plural_function = 'string_plural_select_' . str_replace('-', '_', $lang); + $plural_function = 'string_plural_select_' . str_replace('-', '_', self::$lang); if (function_exists($plural_function)) { $i = $plural_function($count); } else { @@ -227,8 +316,6 @@ class L10n extends BaseObject return $n != 1; } - - /** * @brief Return installed languages codes as associative array * diff --git a/src/Core/System.php b/src/Core/System.php index 5b5fac82f0..e071866ee9 100644 --- a/src/Core/System.php +++ b/src/Core/System.php @@ -5,6 +5,7 @@ namespace Friendica\Core; use Friendica\BaseObject; +use Friendica\Network\HTTPException\InternalServerErrorException; use Friendica\Util\XML; /** @@ -142,7 +143,7 @@ class System extends BaseObject '$description' => defaults($description, 'description', '')]); } - killme(); + exit(); } /** @@ -236,10 +237,26 @@ class System extends BaseObject return max($load_arr[0], $load_arr[1]); } + /** + * Redirects to an external URL (fully qualified URL) + * If you want to route relative to the current Friendica base, use App->internalRedirect() + * + * @param string $url The new Location to redirect + * @throws InternalServerErrorException If the URL is not fully qualified + */ + public static function externalRedirect($url) + { + if (!filter_var($url, FILTER_VALIDATE_URL)) { + throw new InternalServerErrorException('URL is not a fully qualified URL, please use App->internalRedirect() instead'); + } + + header("Location: $url"); + exit(); + } + /// @todo Move the following functions from boot.php /* function killme() - function goaway($s) function local_user() function public_contact() function remote_user() diff --git a/src/Core/UserImport.php b/src/Core/UserImport.php index e62084049e..18aabec08a 100644 --- a/src/Core/UserImport.php +++ b/src/Core/UserImport.php @@ -180,7 +180,7 @@ class UserImport } if ($contact['uid'] == $olduid && $contact['self'] == '0') { // set contacts 'avatar-date' to NULL_DATE to let worker to update urls - $contact["avatar-date"] = NULL_DATE; + $contact["avatar-date"] = DBA::NULL_DATETIME; switch ($contact['network']) { case Protocol::DFRN: @@ -272,6 +272,6 @@ class UserImport Worker::add(PRIORITY_HIGH, 'Notifier', 'relocate', $newuid); info(L10n::t("Done. You can now login with your username and password")); - goaway(System::baseUrl() . "/login"); + $a->internalRedirect('login'); } } diff --git a/src/Core/Worker.php b/src/Core/Worker.php index 723cd809da..a06a11043d 100644 --- a/src/Core/Worker.php +++ b/src/Core/Worker.php @@ -4,11 +4,11 @@ */ namespace Friendica\Core; +use Friendica\BaseObject; use Friendica\Database\DBA; use Friendica\Model\Process; use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; -use Friendica\BaseObject; require_once 'include/dba.php'; @@ -154,7 +154,7 @@ class Worker private static function totalEntries() { return DBA::count('workerqueue', ["`executed` <= ? AND NOT `done` AND `next_try` < ?", - NULL_DATE, DateTimeFormat::utcNow()]); + DBA::NULL_DATETIME, DateTimeFormat::utcNow()]); } /** @@ -164,7 +164,7 @@ class Worker */ private static function highestPriority() { - $condition = ["`executed` <= ? AND NOT `done` AND `next_try` < ?", NULL_DATE, DateTimeFormat::utcNow()]; + $condition = ["`executed` <= ? AND NOT `done` AND `next_try` < ?", DBA::NULL_DATETIME, DateTimeFormat::utcNow()]; $workerqueue = DBA::selectFirst('workerqueue', ['priority'], $condition, ['order' => ['priority']]); if (DBA::isResult($workerqueue)) { return $workerqueue["priority"]; @@ -183,7 +183,7 @@ class Worker private static function processWithPriorityActive($priority) { $condition = ["`priority` <= ? AND `executed` > ? AND NOT `done` AND `next_try` < ?", - $priority, NULL_DATE, DateTimeFormat::utcNow()]; + $priority, DBA::NULL_DATETIME, DateTimeFormat::utcNow()]; return DBA::exists('workerqueue', $condition); } @@ -553,7 +553,7 @@ class Worker $entries = DBA::select( 'workerqueue', ['id', 'pid', 'executed', 'priority', 'parameter'], - ['`executed` > ? AND NOT `done` AND `pid` != 0', NULL_DATE], + ['`executed` > ? AND NOT `done` AND `pid` != 0', DBA::NULL_DATETIME], ['order' => ['priority', 'created']] ); @@ -561,7 +561,7 @@ class Worker if (!posix_kill($entry["pid"], 0)) { DBA::update( 'workerqueue', - ['executed' => NULL_DATE, 'pid' => 0], + ['executed' => DBA::NULL_DATETIME, 'pid' => 0], ['id' => $entry["id"]] ); } else { @@ -597,7 +597,7 @@ class Worker } DBA::update( 'workerqueue', - ['executed' => NULL_DATE, 'created' => DateTimeFormat::utcNow(), 'priority' => $new_priority, 'pid' => 0], + ['executed' => DBA::NULL_DATETIME, 'created' => DateTimeFormat::utcNow(), 'priority' => $new_priority, 'pid' => 0], ['id' => $entry["id"]] ); } else { @@ -809,7 +809,7 @@ class Worker 'workerqueue', ['id'], ["`executed` <= ? AND `priority` < ? AND NOT `done` AND `next_try` < ?", - NULL_DATE, $highest_priority, DateTimeFormat::utcNow()], + DBA::NULL_DATETIME, $highest_priority, DateTimeFormat::utcNow()], ['limit' => $limit, 'order' => ['priority', 'created']] ); @@ -826,7 +826,7 @@ class Worker 'workerqueue', ['id'], ["`executed` <= ? AND `priority` > ? AND NOT `done` AND `next_try` < ?", - NULL_DATE, $highest_priority, DateTimeFormat::utcNow()], + DBA::NULL_DATETIME, $highest_priority, DateTimeFormat::utcNow()], ['limit' => $limit, 'order' => ['priority', 'created']] ); @@ -846,7 +846,7 @@ class Worker 'workerqueue', ['id'], ["`executed` <= ? AND NOT `done` AND `next_try` < ?", - NULL_DATE, DateTimeFormat::utcNow()], + DBA::NULL_DATETIME, DateTimeFormat::utcNow()], ['limit' => $limit, 'order' => ['priority', 'created']] ); @@ -912,7 +912,7 @@ class Worker { $mypid = getmypid(); - DBA::update('workerqueue', ['executed' => NULL_DATE, 'pid' => 0], ['pid' => $mypid, 'done' => false]); + DBA::update('workerqueue', ['executed' => DBA::NULL_DATETIME, 'pid' => 0], ['pid' => $mypid, 'done' => false]); } /** @@ -1147,7 +1147,7 @@ class Worker logger('Defer execution ' . $retrial . ' of id ' . $id . ' to ' . $next, LOGGER_DEBUG); - $fields = ['retrial' => $retrial + 1, 'next_try' => $next, 'executed' => NULL_DATE, 'pid' => 0]; + $fields = ['retrial' => $retrial + 1, 'next_try' => $next, 'executed' => DBA::NULL_DATETIME, 'pid' => 0]; DBA::update('workerqueue', $fields, ['id' => $id]); } diff --git a/src/Database/DBA.php b/src/Database/DBA.php index 8fd117e5d2..6249537c06 100644 --- a/src/Database/DBA.php +++ b/src/Database/DBA.php @@ -24,6 +24,15 @@ require_once 'include/dba.php'; */ class DBA { + /** + * Lowest possible date value + */ + const NULL_DATE = '0001-01-01'; + /** + * Lowest possible datetime value + */ + const NULL_DATETIME = '0001-01-01 00:00:00'; + public static $connected = false; private static $server_info = ''; diff --git a/src/Database/DBStructure.php b/src/Database/DBStructure.php index 50566dc877..9abae944ae 100644 --- a/src/Database/DBStructure.php +++ b/src/Database/DBStructure.php @@ -5,8 +5,8 @@ namespace Friendica\Database; use Exception; -use Friendica\Core\Addon; use Friendica\Core\Config; +use Friendica\Core\Hook; use Friendica\Core\L10n; use Friendica\Util\DateTimeFormat; @@ -22,6 +22,13 @@ require_once 'include/text.php'; */ class DBStructure { + /** + * Database structure definition loaded from config/dbstructure.php + * + * @var array + */ + private static $definition = []; + /* * Converts all tables from MyISAM to InnoDB */ @@ -166,7 +173,7 @@ class DBStructure } public static function printStructure() { - $database = self::definition(); + $database = self::definition(false); echo "-- ------------------------------------------\n"; echo "-- ".FRIENDICA_PLATFORM." ".FRIENDICA_VERSION." (".FRIENDICA_CODENAME,")\n"; @@ -822,43 +829,40 @@ class DBStructure } /** - * Loads the database structure definition from the /config/dbstructure.json file - * - * Expected format: - * "table_name": { - * "comment": "meaningful table comment", - * "fields": { - * "field_name1": {"type": "int unsigned", "not null": "1", "extra": "auto_increment", "primary": "1", "comment": "meaningful field comment"}, - * "field_name2": {"type": "varchar(50)", "not null": "1", "default": "", "comment": "meaningful field comment"}, - * }, - * "indexes": { - * "PRIMARY": ["field_name1"], - * "name": ["UNIQUE", "field_name2"] - * } - * } + * Loads the database structure definition from the config/dbstructure.php file. + * On first pass, defines DB_UPDATE_VERSION constant. * + * @see config/dbstructure.php + * @param boolean $with_addons_structure Whether to tack on addons additional tables * @return array * @throws Exception */ - public static function definition() { - $a = \Friendica\BaseObject::getApp(); + public static function definition($with_addons_structure = true) + { + if (!self::$definition) { + $a = \Friendica\BaseObject::getApp(); - $filename = $a->getBasePath() . '/config/dbstructure.json'; + $filename = $a->getBasePath() . '/config/dbstructure.php'; - if (!is_readable($filename)) { - throw new Exception('Missing database structure config file config/dbstructure.json'); + if (!is_readable($filename)) { + throw new Exception('Missing database structure config file config/dbstructure.php'); + } + + $definition = require $filename; + + if (!$definition) { + throw new Exception('Corrupted database structure config file config/dbstructure.php'); + } + + self::$definition = $definition; + } else { + $definition = self::$definition; } - $json = file_get_contents($filename); - - $database = json_decode($json, true); - - if (!$database) { - throw new Exception('Corrupted database structure config file config/dbstructure.json'); + if ($with_addons_structure) { + Hook::callAll('dbstructure_definition', $definition); } - Addon::callHooks('dbstructure_definition', $database); - - return $database; + return $definition; } } diff --git a/src/Model/APContact.php b/src/Model/APContact.php index 4593e0377b..72c644ab9a 100644 --- a/src/Model/APContact.php +++ b/src/Model/APContact.php @@ -99,32 +99,55 @@ class APContact extends BaseObject } $data = ActivityPub::fetchContent($url); - - if (empty($data) || empty($data['id']) || empty($data['inbox'])) { + if (empty($data)) { return false; } + $compacted = JsonLD::compact($data); + $apcontact = []; - $apcontact['url'] = $data['id']; - $apcontact['uuid'] = defaults($data, 'diaspora:guid', null); - $apcontact['type'] = defaults($data, 'type', null); - $apcontact['following'] = defaults($data, 'following', null); - $apcontact['followers'] = defaults($data, 'followers', null); - $apcontact['inbox'] = defaults($data, 'inbox', null); - $apcontact['outbox'] = defaults($data, 'outbox', null); - $apcontact['sharedinbox'] = JsonLD::fetchElement($data, 'endpoints', 'sharedInbox'); - $apcontact['nick'] = defaults($data, 'preferredUsername', null); - $apcontact['name'] = defaults($data, 'name', $apcontact['nick']); - $apcontact['about'] = HTML::toBBCode(defaults($data, 'summary', '')); - $apcontact['photo'] = JsonLD::fetchElement($data, 'icon', 'url'); - $apcontact['alias'] = JsonLD::fetchElement($data, 'url', 'href'); + $apcontact['url'] = $compacted['@id']; + $apcontact['uuid'] = JsonLD::fetchElement($compacted, 'diaspora:guid'); + $apcontact['type'] = str_replace('as:', '', JsonLD::fetchElement($compacted, '@type')); + $apcontact['following'] = JsonLD::fetchElement($compacted, 'as:following', '@id'); + $apcontact['followers'] = JsonLD::fetchElement($compacted, 'as:followers', '@id'); + $apcontact['inbox'] = JsonLD::fetchElement($compacted, 'ldp:inbox', '@id'); + $apcontact['outbox'] = JsonLD::fetchElement($compacted, 'as:outbox', '@id'); + + $apcontact['sharedinbox'] = ''; + if (!empty($compacted['as:endpoints'])) { + $apcontact['sharedinbox'] = JsonLD::fetchElement($compacted['as:endpoints'], 'as:sharedInbox', '@id'); + } + + $apcontact['nick'] = JsonLD::fetchElement($compacted, 'as:preferredUsername'); + $apcontact['name'] = JsonLD::fetchElement($compacted, 'as:name'); + + if (empty($apcontact['name'])) { + $apcontact['name'] = $apcontact['nick']; + } + + $apcontact['about'] = HTML::toBBCode(JsonLD::fetchElement($compacted, 'as:summary')); + + $apcontact['photo'] = JsonLD::fetchElement($compacted, 'as:icon', '@id'); + if (is_array($apcontact['photo'])) { + $apcontact['photo'] = JsonLD::fetchElement($compacted['as:icon'], 'as:url', '@id'); + } + + $apcontact['alias'] = JsonLD::fetchElement($compacted, 'as:url', '@id'); + if (is_array($apcontact['alias'])) { + $apcontact['alias'] = JsonLD::fetchElement($compacted['as:url'], 'as:href', '@id'); + } + + if (empty($apcontact['url']) || empty($apcontact['inbox'])) { + return false; + } $parts = parse_url($apcontact['url']); unset($parts['scheme']); unset($parts['path']); $apcontact['addr'] = $apcontact['nick'] . '@' . str_replace('//', '', Network::unparseURL($parts)); - $apcontact['pubkey'] = trim(JsonLD::fetchElement($data, 'publicKey', 'publicKeyPem')); + $apcontact['pubkey'] = trim(JsonLD::fetchElement($compacted, 'w3id:publicKey', 'w3id:publicKeyPem')); // To-Do // manuallyApprovesFollowers diff --git a/src/Model/Contact.php b/src/Model/Contact.php index 472875a80b..3524cd4ce1 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -8,7 +8,6 @@ use Friendica\BaseObject; use Friendica\Core\Addon; use Friendica\Core\Config; use Friendica\Core\L10n; -use Friendica\Core\PConfig; use Friendica\Core\Protocol; use Friendica\Core\System; use Friendica\Core\Worker; @@ -17,8 +16,8 @@ use Friendica\Model\Profile; use Friendica\Network\Probe; use Friendica\Object\Image; use Friendica\Protocol\ActivityPub; -use Friendica\Protocol\Diaspora; use Friendica\Protocol\DFRN; +use Friendica\Protocol\Diaspora; use Friendica\Protocol\OStatus; use Friendica\Protocol\PortableContact; use Friendica\Protocol\Salmon; @@ -594,9 +593,9 @@ class Contact extends BaseObject return; } - if ($contact['term-date'] <= NULL_DATE) { + if ($contact['term-date'] <= DBA::NULL_DATETIME) { DBA::update('contact', ['term-date' => DateTimeFormat::utcNow()], ['id' => $contact['id']]); - DBA::update('contact', ['term-date' => DateTimeFormat::utcNow()], ['`nurl` = ? AND `term-date` <= ? AND NOT `self`', normalise_link($contact['url']), NULL_DATE]); + DBA::update('contact', ['term-date' => DateTimeFormat::utcNow()], ['`nurl` = ? AND `term-date` <= ? AND NOT `self`', normalise_link($contact['url']), DBA::NULL_DATETIME]); } else { /* @todo * We really should send a notification to the owner after 2-3 weeks @@ -629,7 +628,7 @@ class Contact extends BaseObject */ public static function unmarkForArchival(array $contact) { - $condition = ['`id` = ? AND (`term-date` > ? OR `archive`)', $contact['id'], NULL_DATE]; + $condition = ['`id` = ? AND (`term-date` > ? OR `archive`)', $contact['id'], DBA::NULL_DATETIME]; $exists = DBA::exists('contact', $condition); // We don't need to update, we never marked this contact for archival @@ -646,7 +645,7 @@ class Contact extends BaseObject } // It's a miracle. Our dead contact has inexplicably come back to life. - $fields = ['term-date' => NULL_DATE, 'archive' => false]; + $fields = ['term-date' => DBA::NULL_DATETIME, 'archive' => false]; DBA::update('contact', $fields, ['id' => $contact['id']]); DBA::update('contact', $fields, ['nurl' => normalise_link($contact['url'])]); @@ -1639,7 +1638,7 @@ class Contact extends BaseObject $myaddr = bin2hex($a->user['nickname'] . '@' . $a->getHostName()); } - goaway($ret['request'] . "&addr=$myaddr"); + $a->internalRedirect($ret['request'] . "&addr=$myaddr"); // NOTREACHED } @@ -2024,8 +2023,10 @@ class Contact extends BaseObject /** * @brief Returns a magic link to authenticate remote visitors * + * @todo check if the return is either a fully qualified URL or a relative path to Friendica basedir + * * @param string $contact_url The address of the target contact profile - * @param integer $url An url that we will be redirected to after the authentication + * @param string $url An url that we will be redirected to after the authentication * * @return string with "redir" link */ @@ -2058,7 +2059,7 @@ class Contact extends BaseObject * @brief Returns a magic link to authenticate remote visitors * * @param array $contact The contact array with "uid", "network" and "url" - * @param integer $url An url that we will be redirected to after the authentication + * @param string $url An url that we will be redirected to after the authentication * * @return string with "redir" link */ diff --git a/src/Model/Event.php b/src/Model/Event.php index 452017e69d..e9a4d4b3fd 100644 --- a/src/Model/Event.php +++ b/src/Model/Event.php @@ -257,10 +257,10 @@ class Event extends BaseObject $event['created'] = DateTimeFormat::utc(defaults($arr, 'created' , 'now')); $event['edited'] = DateTimeFormat::utc(defaults($arr, 'edited' , 'now')); - $event['start'] = DateTimeFormat::utc(defaults($arr, 'start' , NULL_DATE)); - $event['finish'] = DateTimeFormat::utc(defaults($arr, 'finish' , NULL_DATE)); - if ($event['finish'] < NULL_DATE) { - $event['finish'] = NULL_DATE; + $event['start'] = DateTimeFormat::utc(defaults($arr, 'start' , DBA::NULL_DATETIME)); + $event['finish'] = DateTimeFormat::utc(defaults($arr, 'finish' , DBA::NULL_DATETIME)); + if ($event['finish'] < DBA::NULL_DATETIME) { + $event['finish'] = DBA::NULL_DATETIME; } $private = intval(defaults($arr, 'private', 0)); diff --git a/src/Model/GContact.php b/src/Model/GContact.php index 681c1c3709..20e6f0751e 100644 --- a/src/Model/GContact.php +++ b/src/Model/GContact.php @@ -176,7 +176,7 @@ class GContact if (!isset($gcontact['network']) && ($gcnt["network"] != Protocol::STATUSNET)) { $gcontact['network'] = $gcnt["network"]; } - if ($gcontact['updated'] <= NULL_DATE) { + if ($gcontact['updated'] <= DBA::NULL_DATETIME) { $gcontact['updated'] = $gcnt["updated"]; } if (!isset($gcontact['server_url']) && (normalise_link($gcnt["server_url"]) != normalise_link($gcnt["url"]))) { @@ -457,7 +457,7 @@ class GContact intval($uid), intval($uid), intval($uid), - DBA::escape(NULL_DATE), + DBA::NULL_DATETIME, $sql_network, intval($start), intval($limit) @@ -486,7 +486,7 @@ class GContact intval($uid), intval($uid), intval($uid), - DBA::escape(NULL_DATE), + DBA::NULL_DATETIME, $sql_network, intval($start), intval($limit) diff --git a/src/Model/Profile.php b/src/Model/Profile.php index f6fb3167d7..53b98fb625 100644 --- a/src/Model/Profile.php +++ b/src/Model/Profile.php @@ -774,7 +774,7 @@ class Profile $profile['marital']['with'] = $a->profile['with']; } - if (strlen($a->profile['howlong']) && $a->profile['howlong'] >= NULL_DATE) { + if (strlen($a->profile['howlong']) && $a->profile['howlong'] >= DBA::NULL_DATETIME) { $profile['howlong'] = Temporal::getRelativeDate($a->profile['howlong'], L10n::t('for %1$d %2$s')); } @@ -1047,7 +1047,7 @@ class Profile // Try to avoid recursion - but send them home to do a proper magic auth. $query = str_replace(array('?zrl=', '&zid='), array('?rzrl=', '&rzrl='), $a->query_string); // The other instance needs to know where to redirect. - $dest = urlencode(System::baseUrl() . '/' . $query); + $dest = urlencode($a->getBaseURL() . '/' . $query); // We need to extract the basebath from the profile url // to redirect the visitors '/magic' module. @@ -1055,14 +1055,14 @@ class Profile $urlarr = explode('/profile/', $contact['url']); $basepath = $urlarr[0]; - if ($basepath != System::baseUrl() && !strstr($dest, '/magic') && !strstr($dest, '/rmagic')) { + if ($basepath != $a->getBaseURL() && !strstr($dest, '/magic') && !strstr($dest, '/rmagic')) { $magic_path = $basepath . '/magic' . '?f=&owa=1&dest=' . $dest; // We have to check if the remote server does understand /magic without invoking something $serverret = Network::curl($basepath . '/magic'); if ($serverret->isSuccess()) { logger('Doing magic auth for visitor ' . $my_url . ' to ' . $magic_path, LOGGER_DEBUG); - goaway($magic_path); + System::externalRedirect($magic_path); } } } diff --git a/src/Model/PushSubscriber.php b/src/Model/PushSubscriber.php index 9680d359d0..e024878a58 100644 --- a/src/Model/PushSubscriber.php +++ b/src/Model/PushSubscriber.php @@ -21,7 +21,7 @@ class PushSubscriber public static function publishFeed($uid, $default_priority = PRIORITY_HIGH) { $condition = ['push' => 0, 'uid' => $uid]; - DBA::update('push_subscriber', ['push' => 1, 'next_try' => NULL_DATE], $condition); + DBA::update('push_subscriber', ['push' => 1, 'next_try' => DBA::NULL_DATETIME], $condition); self::requeue($default_priority); } @@ -114,10 +114,10 @@ class PushSubscriber $days = round((time() - strtotime($subscriber['renewed'])) / (60 * 60 * 24)); if ($days > 60) { - DBA::update('push_subscriber', ['push' => -1, 'next_try' => NULL_DATE], ['id' => $id]); + DBA::update('push_subscriber', ['push' => -1, 'next_try' => DBA::NULL_DATETIME], ['id' => $id]); logger('Delivery error: Subscription ' . $subscriber['callback_url'] . ' for ' . $subscriber['nickname'] . ' is marked as ended.', LOGGER_DEBUG); } else { - DBA::update('push_subscriber', ['push' => 0, 'next_try' => NULL_DATE], ['id' => $id]); + DBA::update('push_subscriber', ['push' => 0, 'next_try' => DBA::NULL_DATETIME], ['id' => $id]); logger('Delivery error: Giving up ' . $subscriber['callback_url'] . ' for ' . $subscriber['nickname'] . ' for now.', LOGGER_DEBUG); } } else { @@ -146,7 +146,7 @@ class PushSubscriber } // set last_update to the 'created' date of the last item, and reset push=0 - $fields = ['push' => 0, 'next_try' => NULL_DATE, 'last_update' => $last_update]; + $fields = ['push' => 0, 'next_try' => DBA::NULL_DATETIME, 'last_update' => $last_update]; DBA::update('push_subscriber', $fields, ['id' => $id]); logger('Subscriber ' . $subscriber['callback_url'] . ' for ' . $subscriber['nickname'] . ' is marked as vital', LOGGER_DEBUG); } diff --git a/src/Model/User.php b/src/Model/User.php index 63aaa1e3de..27ed28fd4f 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -450,7 +450,7 @@ class User } catch (Exception $e) { throw new Exception(L10n::t('We encountered a problem while logging in with the OpenID you provided. Please check the correct spelling of the ID.') . EOL . EOL . L10n::t('The error message was:') . $e->getMessage(), 0, $e); } - goaway($authurl); + System::externalRedirect($authurl); // NOTREACHED } @@ -466,19 +466,30 @@ class User // collapse multiple spaces in name $username = preg_replace('/ +/', ' ', $username); - if (mb_strlen($username) > 48) { - throw new Exception(L10n::t('Please use a shorter name.')); + $username_min_length = max(1, min(64, intval(Config::get('system', 'username_min_length', 3)))); + $username_max_length = max(1, min(64, intval(Config::get('system', 'username_max_length', 48)))); + + if ($username_min_length > $username_max_length) { + logger(L10n::t('system.username_min_length (%s) and system.username_max_length (%s) are excluding each other, swapping values.', $username_min_length, $username_max_length), LOGGER_WARNING); + $tmp = $username_min_length; + $username_min_length = $username_max_length; + $username_max_length = $tmp; } - if (mb_strlen($username) < 3) { - throw new Exception(L10n::t('Name too short.')); + + if (mb_strlen($username) < $username_min_length) { + throw new Exception(L10n::tt('Username should be at least %s character.', 'Username should be at least %s characters.', $username_min_length)); + } + + if (mb_strlen($username) > $username_max_length) { + throw new Exception(L10n::tt('Username should be at most %s character.', 'Username should be at most %s characters.', $username_max_length)); } // So now we are just looking for a space in the full name. $loose_reg = Config::get('system', 'no_regfullname'); if (!$loose_reg) { $username = mb_convert_case($username, MB_CASE_TITLE, 'UTF-8'); - if (!strpos($username, ' ')) { - throw new Exception(L10n::t("That doesn't appear to be your full \x28First Last\x29 name.")); + if (strpos($username, ' ') === false) { + throw new Exception(L10n::t("That doesn't appear to be your full (First Last) name.")); } } @@ -772,6 +783,8 @@ class User return; } + $a = get_app(); + logger('Removing user: ' . $uid); $user = DBA::selectFirst('user', [], ['uid' => $uid]); @@ -796,7 +809,7 @@ class User if ($uid == local_user()) { unset($_SESSION['authenticated']); unset($_SESSION['uid']); - goaway();; + $a->internalRedirect(); } } } diff --git a/src/Module/Acctlink.php b/src/Module/Acctlink.php index 29aa99140c..692e905914 100644 --- a/src/Module/Acctlink.php +++ b/src/Module/Acctlink.php @@ -4,6 +4,7 @@ namespace Friendica\Module; use Friendica\BaseModule; use Friendica\Network\Probe; +use Friendica\Core\System; /** * Redirects to another URL based on the parameter 'addr' @@ -18,7 +19,7 @@ class Acctlink extends BaseModule $url = defaults(Probe::uri(trim($addr)), 'url', false); if ($url) { - goaway($url); + System::externalRedirect($url); exit(); } } diff --git a/src/Module/Contact.php b/src/Module/Contact.php index 0eb912e00a..fb0bf0edee 100644 --- a/src/Module/Contact.php +++ b/src/Module/Contact.php @@ -8,6 +8,7 @@ use Friendica\Content\ContactSelector; use Friendica\Content\Nav; use Friendica\Content\Text\BBCode; use Friendica\Content\Widget; +use Friendica\Core\ACL; use Friendica\Core\Addon; use Friendica\Core\L10n; use Friendica\Core\Protocol; @@ -15,11 +16,10 @@ use Friendica\Core\System; use Friendica\Core\Worker; use Friendica\Database\DBA; use Friendica\Model; +use Friendica\Module\Login; use Friendica\Network\Probe; use Friendica\Util\DateTimeFormat; use Friendica\Util\Proxy as ProxyUtils; -use Friendica\Core\ACL; -use Friendica\Module\Login; /** * Manages and show Contacts and their content @@ -66,9 +66,9 @@ class Contact extends BaseModule if (DBA::isResult($contact)) { if ($contact['self']) { if (($a->argc == 3) && intval($a->argv[1]) && in_array($a->argv[2], ['posts', 'conversations'])) { - goaway('profile/' . $contact['nick']); + $a->internalRedirect('profile/' . $contact['nick']); } else { - goaway('profile/' . $contact['nick'] . '?tab=profile'); + $a->internalRedirect('profile/' . $contact['nick'] . '?tab=profile'); } } @@ -168,7 +168,7 @@ class Contact extends BaseModule info(L10n::tt('%d contact edited.', '%d contacts edited.', $count_actions)); } - goaway('contact'); + $a->internalRedirect('contact'); } public static function post() @@ -191,7 +191,7 @@ class Contact extends BaseModule if (!DBA::exists('contact', ['id' => $contact_id, 'uid' => local_user()])) { notice(L10n::t('Could not access contact record.') . EOL); - goaway('contact'); + $a->internalRedirect('contact'); return; // NOTREACHED } @@ -374,19 +374,19 @@ class Contact extends BaseModule $orig_record = DBA::selectFirst('contact', [], ['id' => $contact_id, 'uid' => [0, local_user()], 'self' => false]); if (!DBA::isResult($orig_record)) { notice(L10n::t('Could not access contact record.') . EOL); - goaway('contact'); + $a->internalRedirect('contact'); return; // NOTREACHED } if ($cmd === 'update' && ($orig_record['uid'] != 0)) { self::updateContactFromPoll($contact_id); - goaway('contact/' . $contact_id); + $a->internalRedirect('contact/' . $contact_id); // NOTREACHED } if ($cmd === 'updateprofile' && ($orig_record['uid'] != 0)) { self::updateContactFromProbe($contact_id); - goaway('crepair/' . $contact_id); + $a->internalRedirect('crepair/' . $contact_id); // NOTREACHED } @@ -396,7 +396,7 @@ class Contact extends BaseModule $blocked = Model\Contact::isBlockedByUser($contact_id, local_user()); info(($blocked ? L10n::t('Contact has been blocked') : L10n::t('Contact has been unblocked')) . EOL); - goaway('contact/' . $contact_id); + $a->internalRedirect('contact/' . $contact_id); return; // NOTREACHED } @@ -406,7 +406,7 @@ class Contact extends BaseModule $ignored = Model\Contact::isIgnoredByUser($contact_id, local_user()); info(($ignored ? L10n::t('Contact has been ignored') : L10n::t('Contact has been unignored')) . EOL); - goaway('contact/' . $contact_id); + $a->internalRedirect('contact/' . $contact_id); return; // NOTREACHED } @@ -417,7 +417,7 @@ class Contact extends BaseModule info((($archived) ? L10n::t('Contact has been archived') : L10n::t('Contact has been unarchived')) . EOL); } - goaway('contact/' . $contact_id); + $a->internalRedirect('contact/' . $contact_id); return; // NOTREACHED } @@ -451,13 +451,13 @@ class Contact extends BaseModule } // Now check how the user responded to the confirmation query if (!empty($_REQUEST['canceled'])) { - goaway('contact'); + $a->internalRedirect('contact'); } self::dropContact($orig_record); info(L10n::t('Contact has been removed.') . EOL); - goaway('contact'); + $a->internalRedirect('contact'); return; // NOTREACHED } if ($cmd === 'posts') { @@ -468,7 +468,7 @@ class Contact extends BaseModule } } - $_SESSION['return_url'] = $a->query_string; + $_SESSION['return_path'] = $a->query_string; if (!empty($a->data['contact']) && is_array($a->data['contact'])) { $contact_id = $a->data['contact']['id']; @@ -522,9 +522,9 @@ class Contact extends BaseModule $insecure = L10n::t('Private communications are not available for this contact.'); - $last_update = (($contact['last-update'] <= NULL_DATE) ? L10n::t('Never') : DateTimeFormat::local($contact['last-update'], 'D, j M Y, g:i A')); + $last_update = (($contact['last-update'] <= DBA::NULL_DATETIME) ? L10n::t('Never') : DateTimeFormat::local($contact['last-update'], 'D, j M Y, g:i A')); - if ($contact['last-update'] > NULL_DATE) { + if ($contact['last-update'] > DBA::NULL_DATETIME) { $last_update .= ' ' . (($contact['last-update'] <= $contact['success_update']) ? L10n::t('(Update was successful)') : L10n::t('(Update was not successful)')); } $lblsuggest = (($contact['network'] === Protocol::DFRN) ? L10n::t('Suggest friends') : ''); @@ -536,7 +536,7 @@ class Contact extends BaseModule // tabs $tab_str = self::getTabsHTML($a, $contact, 3); - $lost_contact = (($contact['archive'] && $contact['term-date'] > NULL_DATE && $contact['term-date'] < DateTimeFormat::utcNow()) ? L10n::t('Communications lost with this contact!') : ''); + $lost_contact = (($contact['archive'] && $contact['term-date'] > DBA::NULL_DATETIME && $contact['term-date'] < DateTimeFormat::utcNow()) ? L10n::t('Communications lost with this contact!') : ''); $fetch_further_information = null; if ($contact['network'] == Protocol::FEED) { diff --git a/src/Module/Login.php b/src/Module/Login.php index deb6afcfbc..df918c44c8 100644 --- a/src/Module/Login.php +++ b/src/Module/Login.php @@ -10,6 +10,7 @@ use Friendica\Core\Addon; use Friendica\Core\Authentication; use Friendica\Core\Config; use Friendica\Core\L10n; +use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\Model\User; use Friendica\Util\DateTimeFormat; @@ -39,17 +40,17 @@ class Login extends BaseModule } if (local_user()) { - goaway(self::getApp()->getBaseURL()); + $a->internalRedirect(); } - return self::form($_SESSION['return_url'], intval(Config::get('config', 'register_policy')) !== REGISTER_CLOSED); + return self::form($_SESSION['return_path'], intval(Config::get('config', 'register_policy')) !== REGISTER_CLOSED); } public static function post() { - $return_url = $_SESSION['return_url']; + $return_path = $_SESSION['return_path']; session_unset(); - $_SESSION['return_url'] = $return_url; + $_SESSION['return_path'] = $return_path; // OpenId Login if ( @@ -83,22 +84,23 @@ class Login extends BaseModule { $noid = Config::get('system', 'no_openid'); + $a = self::getApp(); + // if it's an email address or doesn't resolve to a URL, fail. if ($noid || strpos($openid_url, '@') || !Network::isUrlValid($openid_url)) { notice(L10n::t('Login failed.') . EOL); - goaway(self::getApp()->getBaseURL()); + $a->internalRedirect(); // NOTREACHED } // Otherwise it's probably an openid. try { - $a = get_app(); $openid = new LightOpenID($a->getHostName()); $openid->identity = $openid_url; $_SESSION['openid'] = $openid_url; $_SESSION['remember'] = $remember; - $openid->returnUrl = self::getApp()->getBaseURL(true) . '/openid'; - goaway($openid->authUrl()); + $openid->returnUrl = $a->getBaseURL(true) . '/openid'; + System::externalRedirect($openid->authUrl()); } catch (Exception $e) { notice(L10n::t('We encountered a problem while logging in with the OpenID you provided. Please check the correct spelling of the ID.') . '

' . L10n::t('The error message was:') . ' ' . $e->getMessage()); } @@ -122,6 +124,8 @@ class Login extends BaseModule 'user_record' => null ]; + $a = self::getApp(); + /* * An addon indicates successful login by setting 'authenticated' to non-zero value and returning a user record * Addons should never set 'authenticated' except to indicate success - as hooks may be chained @@ -144,7 +148,7 @@ class Login extends BaseModule } catch (Exception $e) { logger('authenticate: failed login attempt: ' . notags($username) . ' from IP ' . $_SERVER['REMOTE_ADDR']); info('Login failed. Please check your credentials.' . EOL); - goaway('/'); + $a->internalRedirect(); } if (!$remember) { @@ -156,14 +160,14 @@ class Login extends BaseModule $_SESSION['last_login_date'] = DateTimeFormat::utcNow(); Authentication::setAuthenticatedSessionForUser($record, true, true); - if (x($_SESSION, 'return_url')) { - $return_url = $_SESSION['return_url']; - unset($_SESSION['return_url']); + if (x($_SESSION, 'return_path')) { + $return_path = $_SESSION['return_path']; + unset($_SESSION['return_path']); } else { - $return_url = ''; + $return_path = ''; } - goaway($return_url); + $a->internalRedirect($return_path); } /** @@ -173,6 +177,8 @@ class Login extends BaseModule */ public static function sessionAuth() { + $a = self::getApp(); + // When the "Friendica" cookie is set, take the value to authenticate and renew the cookie. if (isset($_COOKIE["Friendica"])) { $data = json_decode($_COOKIE["Friendica"]); @@ -191,7 +197,7 @@ class Login extends BaseModule if ($data->hash != Authentication::getCookieHashForUser($user)) { logger("Hash for user " . $data->uid . " doesn't fit."); Authentication::deleteSession(); - goaway(self::getApp()->getBaseURL()); + $a->internalRedirect(); } // Renew the cookie @@ -228,7 +234,7 @@ class Login extends BaseModule logger('Session address changed. Paranoid setting in effect, blocking session. ' . $_SESSION['addr'] . ' != ' . $_SERVER['REMOTE_ADDR']); Authentication::deleteSession(); - goaway(self::getApp()->getBaseURL()); + $a->internalRedirect(); } $user = DBA::selectFirst('user', [], @@ -242,7 +248,7 @@ class Login extends BaseModule ); if (!DBA::isResult($user)) { Authentication::deleteSession(); - goaway(self::getApp()->getBaseURL()); + $a->internalRedirect(); } // Make sure to refresh the last login time for the user if the user @@ -263,7 +269,7 @@ class Login extends BaseModule /** * @brief Wrapper for adding a login box. * - * @param string $return_url The url relative to the base the user should be sent + * @param string $return_path The path relative to the base the user should be sent * back to after login completes * @param bool $register If $register == true provide a registration link. * This will most always depend on the value of config.register_policy. @@ -273,7 +279,7 @@ class Login extends BaseModule * * @hooks 'login_hook' string $o */ - public static function form($return_url = null, $register = false, $hiddens = []) + public static function form($return_path = null, $register = false, $hiddens = []) { $a = self::getApp(); $o = ''; @@ -287,8 +293,8 @@ class Login extends BaseModule $noid = Config::get('system', 'no_openid'); - if (is_null($return_url)) { - $return_url = $a->query_string; + if (is_null($return_path)) { + $return_path = $a->query_string; } if (local_user()) { @@ -302,7 +308,7 @@ class Login extends BaseModule ); $tpl = get_markup_template('login.tpl'); - $_SESSION['return_url'] = $return_url; + $_SESSION['return_path'] = $return_path; } $o .= replace_macros( diff --git a/src/Module/Logout.php b/src/Module/Logout.php index b12ba10287..f212a89402 100644 --- a/src/Module/Logout.php +++ b/src/Module/Logout.php @@ -8,6 +8,7 @@ use Friendica\BaseModule; use Friendica\Core\Addon; use Friendica\Core\Authentication; use Friendica\Core\L10n; +use Friendica\Core\System; require_once 'boot.php'; @@ -26,6 +27,6 @@ class Logout extends BaseModule Addon::callHooks("logging_out"); Authentication::deleteSession(); info(L10n::t('Logged out.') . EOL); - goaway(self::getApp()->getBaseURL()); + self::getApp()->internalRedirect(); } } diff --git a/src/Module/Magic.php b/src/Module/Magic.php index 768fe69ebb..1d7cb715e1 100644 --- a/src/Module/Magic.php +++ b/src/Module/Magic.php @@ -7,6 +7,7 @@ namespace Friendica\Module; use Friendica\BaseModule; use Friendica\Database\DBA; use Friendica\Model\Contact; +use Friendica\Core\System; use Friendica\Util\HTTPSignature; use Friendica\Util\Network; @@ -41,9 +42,13 @@ class Magic extends BaseModule if (!$cid) { logger('No contact record found: ' . print_r($_REQUEST, true), LOGGER_DEBUG); - goaway($dest); + // @TODO Finding a more elegant possibility to redirect to either internal or external URL + if (filter_var($dest, FILTER_VALIDATE_URL)) { + System::externalRedirect($dest); + } else { + $a->internalRedirect($dest); + } } - $contact = DBA::selectFirst('contact', ['id', 'nurl', 'url'], ['id' => $cid]); // Redirect if the contact is already authenticated on this site. @@ -55,7 +60,7 @@ class Magic extends BaseModule } logger('Contact is already authenticated', LOGGER_DEBUG); - goaway($dest); + System::externalRedirect($dest); } if (local_user()) { @@ -99,10 +104,10 @@ class Magic extends BaseModule $x = strpbrk($dest, '?&'); $args = (($x) ? '&owt=' . $token : '?f=&owt=' . $token); - goaway($dest . $args); + System::externalRedirect($dest . $args); } } - goaway($dest); + System::externalRedirect($dest); } } @@ -111,6 +116,11 @@ class Magic extends BaseModule return $ret; } - goaway($dest); + // @TODO Finding a more elegant possibility to redirect to either internal or external URL + if (filter_var($dest, FILTER_VALIDATE_URL)) { + System::externalRedirect($dest); + } else { + $a->internalRedirect($dest); + } } } diff --git a/src/Module/Objects.php b/src/Module/Objects.php index ba9dace2e5..d51d5785a5 100644 --- a/src/Module/Objects.php +++ b/src/Module/Objects.php @@ -24,7 +24,7 @@ class Objects extends BaseModule } if (!ActivityPub::isRequest()) { - goaway(str_replace('objects/', 'display/', $a->query_string)); + $a->internalRedirect(str_replace('objects/', 'display/', $a->query_string)); } $item = Item::selectFirst(['id'], ['guid' => $a->argv[1], 'wall' => true, 'private' => false]); diff --git a/src/Module/Tos.php b/src/Module/Tos.php index e8a152b507..db8b55885a 100644 --- a/src/Module/Tos.php +++ b/src/Module/Tos.php @@ -49,7 +49,7 @@ class Tos extends BaseModule public static function init() { if (strlen(Config::get('system','singleuser'))) { - goaway(System::baseUrl()."/profile/" . Config::get('system','singleuser')); + self::getApp()->internalRedirect('profile/' . Config::get('system','singleuser')); } } /** diff --git a/src/Object/Post.php b/src/Object/Post.php index 34a5f8138a..85d7a3b8c1 100644 --- a/src/Object/Post.php +++ b/src/Object/Post.php @@ -209,7 +209,13 @@ class Post extends BaseObject $author = ['uid' => 0, 'id' => $item['author-id'], 'network' => $item['author-network'], 'url' => $item['author-link']]; - $profile_link = Contact::magicLinkbyContact($author); + + if (local_user() || remote_user()) { + $profile_link = Contact::magicLinkbyContact($author); + } else { + $profile_link = $item['author-link']; + } + if (strpos($profile_link, 'redir/') === 0) { $sparkle = ' sparkle'; } @@ -765,7 +771,7 @@ class Post extends BaseObject * Hmmm, code depending on the presence of a particular addon? * This should be better if done by a hook */ - if (in_array('qcomment', $a->addons)) { + if (Addon::isEnabled('qcomment')) { $qc = ((local_user()) ? PConfig::get(local_user(), 'qcomment', 'words') : null); $qcomment = (($qc) ? explode("\n", $qc) : null); } diff --git a/src/Protocol/ActivityPub/Transmitter.php b/src/Protocol/ActivityPub/Transmitter.php index 7295408d83..a0d92a571d 100644 --- a/src/Protocol/ActivityPub/Transmitter.php +++ b/src/Protocol/ActivityPub/Transmitter.php @@ -289,7 +289,7 @@ class Transmitter foreach ($activity[$element] as $receiver) { if ($receiver == $profile['followers'] && !empty($item_profile['followers'])) { - $receiver = $item_profile['followers']; + $permissions[$element][] = $item_profile['followers']; } if (!in_array($receiver, $exclude)) { $permissions[$element][] = $receiver; diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index 21a0f43944..e8cf4a631a 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -3037,7 +3037,7 @@ class DFRN logger('auto_redir: ' . $r[0]['name'] . ' ' . $sec, LOGGER_DEBUG); $dest = (($url) ? '&destination_url=' . $url : ''); - goaway($r[0]['poll'] . '?dfrn_id=' . $dfrn_id + System::externalRedirect($r[0]['poll'] . '?dfrn_id=' . $dfrn_id . '&dfrn_version=' . DFRN_PROTOCOL_VERSION . '&type=profile&sec=' . $sec . $dest); } diff --git a/src/Protocol/PortableContact.php b/src/Protocol/PortableContact.php index 0e4d58d1c1..bb7ccd564a 100644 --- a/src/Protocol/PortableContact.php +++ b/src/Protocol/PortableContact.php @@ -113,7 +113,7 @@ class PortableContact $connect_url = ''; $name = ''; $network = ''; - $updated = NULL_DATE; + $updated = DBA::NULL_DATETIME; $location = ''; $about = ''; $keywords = ''; @@ -317,7 +317,7 @@ class PortableContact $contact = ["url" => $profile]; - if ($gcontacts[0]["created"] <= NULL_DATE) { + if ($gcontacts[0]["created"] <= DBA::NULL_DATETIME) { $contact['created'] = DateTimeFormat::utcNow(); } @@ -522,7 +522,7 @@ class PortableContact // Maybe there aren't any entries. Then check if it is a valid feed if ($last_updated == "") { if ($xpath->query('/atom:feed')->length > 0) { - $last_updated = NULL_DATE; + $last_updated = DBA::NULL_DATETIME; } } @@ -931,7 +931,7 @@ class PortableContact $gserver = DBA::selectFirst('gserver', [], ['nurl' => normalise_link($server_url)]); if (DBA::isResult($gserver)) { - if ($gserver["created"] <= NULL_DATE) { + if ($gserver["created"] <= DBA::NULL_DATETIME) { $fields = ['created' => DateTimeFormat::utcNow()]; $condition = ['nurl' => normalise_link($server_url)]; DBA::update('gserver', $fields, $condition); @@ -954,12 +954,12 @@ class PortableContact // See discussion under https://forum.friendi.ca/display/0b6b25a8135aabc37a5a0f5684081633 // It can happen that a zero date is in the database, but storing it again is forbidden. - if ($last_contact < NULL_DATE) { - $last_contact = NULL_DATE; + if ($last_contact < DBA::NULL_DATETIME) { + $last_contact = DBA::NULL_DATETIME; } - if ($last_failure < NULL_DATE) { - $last_failure = NULL_DATE; + if ($last_failure < DBA::NULL_DATETIME) { + $last_failure = DBA::NULL_DATETIME; } if (!$force && !self::updateNeeded($gserver["created"], "", $last_failure, $last_contact)) { @@ -976,8 +976,8 @@ class PortableContact $register_policy = -1; $registered_users = 0; - $last_contact = NULL_DATE; - $last_failure = NULL_DATE; + $last_contact = DBA::NULL_DATETIME; + $last_failure = DBA::NULL_DATETIME; } logger("Server ".$server_url." is outdated or unknown. Start discovery. Force: ".$force." Created: ".$gserver["created"]." Failure: ".$last_failure." Contact: ".$last_contact, LOGGER_DEBUG); @@ -1794,7 +1794,7 @@ class PortableContact $connect_url = ''; $name = ''; $network = ''; - $updated = NULL_DATE; + $updated = DBA::NULL_DATETIME; $location = ''; $about = ''; $keywords = ''; diff --git a/src/Util/JsonLD.php b/src/Util/JsonLD.php index 6f4545565f..793f5e9d12 100644 --- a/src/Util/JsonLD.php +++ b/src/Util/JsonLD.php @@ -88,7 +88,7 @@ class JsonLD 'ostatus' => (object)['@id' => 'http://ostatus.org#', '@type' => '@id'], 'diaspora' => (object)['@id' => 'https://diasporafoundation.org/ns/', '@type' => '@id'], 'dc' => (object)['@id' => 'http://purl.org/dc/terms/', '@type' => '@id'], - 'uuid' => (object)['@id' => 'http://schema.org/identifier', '@type' => '@id']]; + 'ldp' => (object)['@id' => 'http://www.w3.org/ns/ldp#', '@type' => '@id']]; $jsonobj = json_decode(json_encode($json, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); diff --git a/src/Util/Temporal.php b/src/Util/Temporal.php index 696721e458..bc7639b3b7 100644 --- a/src/Util/Temporal.php +++ b/src/Util/Temporal.php @@ -11,6 +11,7 @@ use DateTimeZone; use Friendica\Core\Config; use Friendica\Core\L10n; use Friendica\Core\PConfig; +use Friendica\Database\DBA; require_once 'boot.php'; require_once 'include/text.php'; @@ -217,13 +218,13 @@ class Temporal // First day of the week (0 = Sunday) $firstDay = PConfig::get(local_user(), 'system', 'first_day_of_week', 0); - $lang = substr(L10n::getBrowserLanguage(), 0, 2); + $lang = substr(L10n::getCurrentLang(), 0, 2); // Check if the detected language is supported by the picker if (!in_array($lang, ["ar", "ro", "id", "bg", "fa", "ru", "uk", "en", "el", "de", "nl", "tr", "fr", "es", "th", "pl", "pt", "ch", "se", "kr", "it", "da", "no", "ja", "vi", "sl", "cs", "hu"])) { - $lang = Config::get('system', 'language', 'en'); + $lang = 'en'; } $o = ''; @@ -290,7 +291,7 @@ class Temporal $abs = strtotime($localtime); - if (is_null($posted_date) || $posted_date <= NULL_DATE || $abs === false) { + if (is_null($posted_date) || $posted_date <= DBA::NULL_DATETIME || $abs === false) { return L10n::t('never'); } diff --git a/src/Worker/Cron.php b/src/Worker/Cron.php index b6dd896cd7..9510063337 100644 --- a/src/Worker/Cron.php +++ b/src/Worker/Cron.php @@ -7,6 +7,7 @@ namespace Friendica\Worker; use Friendica\BaseObject; use Friendica\Core\Addon; use Friendica\Core\Config; +use Friendica\Core\Hook; use Friendica\Core\Protocol; use Friendica\Core\Worker; use Friendica\Database\DBA; @@ -45,7 +46,7 @@ class Cron logger('cron: start'); // Fork the cron jobs in separate parts to avoid problems when one of them is crashing - Addon::forkHooks($a->queue['priority'], "cron"); + Hook::fork($a->queue['priority'], "cron"); // run queue delivery process in the background Worker::add(PRIORITY_NEGLIGIBLE, "Queue"); @@ -203,7 +204,7 @@ class Cron foreach ($contacts as $contact) { if ($manual_id) { - $contact['last-update'] = NULL_DATE; + $contact['last-update'] = DBA::NULL_DATETIME; } // Friendica and OStatus are checked once a day diff --git a/src/Worker/CronJobs.php b/src/Worker/CronJobs.php index bd34449729..a564bd0b0d 100644 --- a/src/Worker/CronJobs.php +++ b/src/Worker/CronJobs.php @@ -108,7 +108,7 @@ class CronJobs private static function expireAndRemoveUsers() { // expire any expired regular accounts. Don't expire forums. - $condition = ["NOT `account_expired` AND `account_expires_on` > ? AND `account_expires_on` < UTC_TIMESTAMP() AND `page-flags` = 0", NULL_DATE]; + $condition = ["NOT `account_expired` AND `account_expires_on` > ? AND `account_expires_on` < UTC_TIMESTAMP() AND `page-flags` = 0", DBA::NULL_DATETIME]; DBA::update('user', ['account_expired' => true], $condition); // Remove any freshly expired account diff --git a/src/Worker/Expire.php b/src/Worker/Expire.php index b6096b5849..de2133bdc8 100644 --- a/src/Worker/Expire.php +++ b/src/Worker/Expire.php @@ -7,8 +7,8 @@ namespace Friendica\Worker; use Friendica\BaseObject; -use Friendica\Core\Addon; use Friendica\Core\Config; +use Friendica\Core\Hook; use Friendica\Core\Worker; use Friendica\Database\DBA; use Friendica\Model\Item; @@ -17,13 +17,13 @@ require_once 'include/dba.php'; class Expire { - public static function execute($param = '', $hook_name = '') + public static function execute($param = '', $hook_function = '') { $a = BaseObject::getApp(); require_once 'include/items.php'; - Addon::loadHooks(); + Hook::loadHooks(); if ($param == 'delete') { logger('Delete expired items', LOGGER_DEBUG); @@ -62,11 +62,11 @@ class Expire logger('Expire items for user '.$user['uid'].' ('.$user['username'].') - done ', LOGGER_DEBUG); } return; - } elseif (!empty($hook_name) && ($param == 'hook') && is_array($a->hooks) && array_key_exists("expire", $a->hooks)) { - foreach ($a->hooks["expire"] as $hook) { - if ($hook[1] == $hook_name) { + } elseif ($param == 'hook' && !empty($hook_function)) { + foreach (Hook::getByName('expire') as $hook) { + if ($hook[1] == $hook_function) { logger("Calling expire hook '" . $hook[1] . "'", LOGGER_DEBUG); - Addon::callSingleHook($a, $hook_name, $hook, $data); + Hook::callSingle($a, 'expire', $hook, $data); } } return; @@ -86,13 +86,10 @@ class Expire DBA::close($r); logger('expire: calling hooks'); - - if (is_array($a->hooks) && array_key_exists('expire', $a->hooks)) { - foreach ($a->hooks['expire'] as $hook) { - logger("Calling expire hook for '" . $hook[1] . "'", LOGGER_DEBUG); - Worker::add(['priority' => $a->queue['priority'], 'created' => $a->queue['created'], 'dont_fork' => true], - 'Expire', 'hook', $hook[1]); - } + foreach (Hook::getByName('expire') as $hook) { + logger("Calling expire hook for '" . $hook[1] . "'", LOGGER_DEBUG); + Worker::add(['priority' => $a->queue['priority'], 'created' => $a->queue['created'], 'dont_fork' => true], + 'Expire', 'hook', $hook[1]); } logger('expire: end'); diff --git a/src/Worker/ForkHook.php b/src/Worker/ForkHook.php index 3654bdd3ca..586d1496e6 100644 --- a/src/Worker/ForkHook.php +++ b/src/Worker/ForkHook.php @@ -5,7 +5,7 @@ namespace Friendica\Worker; -use Friendica\Core\Addon; +use Friendica\Core\Hook; Class ForkHook { @@ -13,6 +13,6 @@ Class ForkHook { $a = \Friendica\BaseObject::getApp(); - Addon::callSingleHook($a, $name, $hook, $data); + Hook::callSingle($a, $name, $hook, $data); } } diff --git a/src/Worker/Notifier.php b/src/Worker/Notifier.php index 3edc15c3b8..31000a26f2 100644 --- a/src/Worker/Notifier.php +++ b/src/Worker/Notifier.php @@ -7,10 +7,12 @@ namespace Friendica\Worker; use Friendica\BaseObject; use Friendica\Core\Addon; use Friendica\Core\Config; +use Friendica\Core\Hook; use Friendica\Core\Protocol; use Friendica\Core\Worker; use Friendica\Database\DBA; use Friendica\Model\Contact; +use Friendica\Model\Conversation; use Friendica\Model\Group; use Friendica\Model\Item; use Friendica\Model\PushSubscriber; @@ -20,7 +22,6 @@ use Friendica\Protocol\ActivityPub; use Friendica\Protocol\Diaspora; use Friendica\Protocol\OStatus; use Friendica\Protocol\Salmon; -use Friendica\Model\Conversation; require_once 'include/dba.php'; require_once 'include/items.php'; @@ -501,7 +502,7 @@ class Notifier logger('notifier: calling hooks for ' . $cmd . ' ' . $item_id, LOGGER_DEBUG); if ($normal_mode) { - Addon::forkHooks($a->queue['priority'], 'notifier_normal', $target_item); + Hook::fork($a->queue['priority'], 'notifier_normal', $target_item); } Addon::callHooks('notifier_end',$target_item); diff --git a/src/Worker/OnePoll.php b/src/Worker/OnePoll.php index be6d5a549e..5227c7983d 100644 --- a/src/Worker/OnePoll.php +++ b/src/Worker/OnePoll.php @@ -12,8 +12,8 @@ use Friendica\Core\Protocol; use Friendica\Database\DBA; use Friendica\Model\Contact; use Friendica\Model\Item; -use Friendica\Protocol\Email; use Friendica\Protocol\ActivityPub; +use Friendica\Protocol\Email; use Friendica\Protocol\PortableContact; use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; @@ -121,7 +121,7 @@ class OnePoll $hub_update = false; } - $last_update = (($contact['last-update'] <= NULL_DATE) + $last_update = (($contact['last-update'] <= DBA::NULL_DATETIME) ? DateTimeFormat::utc('now - 7 days', DateTimeFormat::ATOM) : DateTimeFormat::utc($contact['last-update'], DateTimeFormat::ATOM) ); @@ -252,7 +252,7 @@ class OnePoll self::updateContact($contact, $fields); Contact::markForArchival($contact); - } elseif ($contact['term-date'] > NULL_DATE) { + } elseif ($contact['term-date'] > DBA::NULL_DATETIME) { logger("$url back from the dead - removing mark for death"); Contact::unmarkForArchival($contact); } diff --git a/tests/ApiTest.php b/tests/ApiTest.php index 11c61f9fbb..c509c7d2a4 100644 --- a/tests/ApiTest.php +++ b/tests/ApiTest.php @@ -12,6 +12,8 @@ use Friendica\Core\Protocol; use Friendica\Core\System; use Friendica\Network\HTTPException; +require_once __DIR__ . '/../include/api.php'; + /** * Tests for the API functions. * @@ -20,7 +22,6 @@ use Friendica\Network\HTTPException; */ class ApiTest extends DatabaseTest { - /** * Create variables used by tests. */ @@ -28,7 +29,7 @@ class ApiTest extends DatabaseTest { parent::setUp(); - require_once __DIR__.'/../include/api.php'; + $this->app = BaseObject::getApp(); // User data that the test database is populated with $this->selfUser = [ @@ -60,6 +61,10 @@ class ApiTest extends DatabaseTest 'uid' => $this->selfUser['id'] ]; + Config::set('system', 'url', 'http://localhost'); + Config::set('system', 'hostname', 'localhost'); + Config::set('system', 'worker_dont_fork', true); + // Default config Config::set('config', 'hostname', 'localhost'); Config::set('system', 'throttle_limit_day', 100); @@ -3374,7 +3379,7 @@ class ApiTest extends DatabaseTest */ public function testApiFriendicaRemoteauthWithCorrectUrl() { - $this->markTestIncomplete("We can't use an assertion here because of goaway()."); + $this->markTestIncomplete("We can't use an assertion here because of App->redirect()."); $_GET['url'] = 'url'; $_GET['c_url'] = $this->selfUser['nurl']; api_friendica_remoteauth(); diff --git a/tests/DatabaseTest.php b/tests/DatabaseTest.php index acd0b7ac18..ec1eb290d1 100644 --- a/tests/DatabaseTest.php +++ b/tests/DatabaseTest.php @@ -14,6 +14,8 @@ use PHPUnit\DbUnit\TestCaseTrait; use PHPUnit\Framework\TestCase; use PHPUnit_Extensions_Database_DB_IDatabaseConnection; +require_once __DIR__ . '/../boot.php'; + /** * Abstract class used by tests that need a database. */ @@ -21,21 +23,6 @@ abstract class DatabaseTest extends TestCase { use TestCaseTrait; - /** - * @var App The Friendica App - */ - protected $app; - - protected function setUp() - { - // Reusable App object - $this->app = BaseObject::getApp(); - - Config::set('system', 'url', 'http://localhost'); - Config::set('system', 'hostname', 'localhost'); - Config::set('system', 'worker_dont_fork', true); - } - /** * Get database connection. * @@ -53,6 +40,11 @@ abstract class DatabaseTest extends TestCase $this->markTestSkipped('Please set the MYSQL_* environment variables to your test database credentials.'); } + DBA::connect(getenv('MYSQL_HOST'), + getenv('MYSQL_USERNAME'), + getenv('MYSQL_PASSWORD'), + getenv('MYSQL_DATABASE')); + if (!DBA::connected()) { $this->markTestSkipped('Could not connect to the database.'); } diff --git a/tests/Util/VFSTrait.php b/tests/Util/VFSTrait.php index b0e7a3a604..d51ba5b6a5 100644 --- a/tests/Util/VFSTrait.php +++ b/tests/Util/VFSTrait.php @@ -26,7 +26,7 @@ trait VFSTrait $this->setConfigFile('config.ini.php'); $this->setConfigFile('settings.ini.php'); $this->setConfigFile('local.ini.php'); - $this->setConfigFile('dbstructure.json'); + $this->setConfigFile('dbstructure.php'); } protected function setConfigFile($filename) diff --git a/tests/src/Core/Console/AutomaticInstallationConsoleTest.php b/tests/src/Core/Console/AutomaticInstallationConsoleTest.php index 290d3ed042..da009a84c1 100644 --- a/tests/src/Core/Console/AutomaticInstallationConsoleTest.php +++ b/tests/src/Core/Console/AutomaticInstallationConsoleTest.php @@ -270,9 +270,13 @@ CONF; /** * @runTestsInSeparateProcesses + * @preserveGlobalState disabled */ public function testNoDatabaseConnection() { + // TODO DBA mocking for whole console tests make this test work again + $this->markTestSkipped('DBA is already loaded, we have to mock the whole App to make it work'); + $dbaMock = \Mockery::mock('alias:Friendica\Database\DBA'); $dbaMock ->shouldReceive('connected') diff --git a/tests/src/Core/InstallTest.php b/tests/src/Core/InstallTest.php index da92a0e0fb..645ac5a957 100644 --- a/tests/src/Core/InstallTest.php +++ b/tests/src/Core/InstallTest.php @@ -6,6 +6,10 @@ namespace Friendica\Core; use Friendica\Test\Util\VFSTrait; use PHPUnit\Framework\TestCase; +/** + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled + */ class InstallTest extends TestCase { use VFSTrait; @@ -48,7 +52,6 @@ class InstallTest extends TestCase /** * @small - * @runInSeparateProcess */ public function testCheckKeys() { @@ -63,7 +66,6 @@ class InstallTest extends TestCase /** * @small - * @runInSeparateProcess */ public function testCheckFunctions() { @@ -141,7 +143,6 @@ class InstallTest extends TestCase /** * @small - * @runInSeparateProcess */ public function testCheckLocalIni() { @@ -160,7 +161,6 @@ class InstallTest extends TestCase /** * @small - * @runInSeparateProcess */ public function testCheckHtAccessFail() { @@ -201,7 +201,6 @@ class InstallTest extends TestCase /** * @small - * @runInSeparateProcess */ public function testCheckHtAccessWork() { @@ -241,7 +240,6 @@ class InstallTest extends TestCase /** * @small - * @runInSeparateProcess */ public function testImagick() { @@ -264,7 +262,6 @@ class InstallTest extends TestCase /** * @small - * @runInSeparateProcess */ public function testImagickNotFound() { diff --git a/update.php b/update.php index d889e241e2..6a0ed1af20 100644 --- a/update.php +++ b/update.php @@ -20,7 +20,7 @@ require_once 'include/dba.php'; * This function is responsible for doing post update changes to the data * (not the structure) in the database. * - * Database structure changes are done in src/Database/DBStructure.php + * Database structure changes are done in config/dbstructure.php * * If there is a need for a post process to a structure change, update this file * by adding a new function at the end with the number of the new DB_UPDATE_VERSION. @@ -31,8 +31,8 @@ require_once 'include/dba.php'; * You are currently on version 4711 and you are preparing changes that demand an update script. * * 1. Create a function "update_4712()" here in the update.php - * 2. Apply the needed structural changes in src/Database/DBStructure.php - * 3. Set DB_UPDATE_VERSION in boot.php to 4712. + * 2. Apply the needed structural changes in config/dbStructure.php + * 3. Set DB_UPDATE_VERSION in config/dbstructure.php to 4712. * * If you need to run a script before the database update, name the function "pre_update_4712()" */ diff --git a/view/theme/frio/templates/credits.tpl b/view/theme/frio/templates/credits.tpl new file mode 100644 index 0000000000..5e5aeecc25 --- /dev/null +++ b/view/theme/frio/templates/credits.tpl @@ -0,0 +1,11 @@ +
+ {{include file="section_title.tpl"}} +

{{$thanks}}

+ +
    + {{foreach $names as $name}} +
  • {{$name}}
  • + {{/foreach}} +
+
+