From c0784f730106494f7a37b8d4ae2db63eb6d595fd Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 22 Apr 2017 20:46:40 +0000 Subject: [PATCH 1/9] New tables for conversations --- boot.php | 14 ++++++++++++++ include/dbstructure.php | 13 +++++++++++++ 2 files changed, 27 insertions(+) diff --git a/boot.php b/boot.php index 2ef5853e0..480001475 100644 --- a/boot.php +++ b/boot.php @@ -218,6 +218,20 @@ define ( 'CP_USERS_ON_SERVER', 0 ); define ( 'CP_GLOBAL_COMMUNITY', 1 ); /** @}*/ +/** + * @name Protocols + * + * Different protocols that we are storing + * @{ + */ +define('PROTOCOL_UNKNOWN', 0); +define('PROTOCOL_DFRN', 1); +define('PROTOCOL_DIASPORA', 2); +define('PROTOCOL_OSTATUS_SALMON', 3); +define('PROTOCOL_OSTATUS_FEED', 4); +define('PROTOCOL_GS_CONVERSATION', 5); +/** @}*/ + /** * @name Network * diff --git a/include/dbstructure.php b/include/dbstructure.php index 0d5c10f98..9842b9754 100644 --- a/include/dbstructure.php +++ b/include/dbstructure.php @@ -788,6 +788,19 @@ function db_definition() { "uid" => array("uid"), ) ); + $database["conversation"] = array( + "fields" => array( + "item-uri" => array("type" => "varbinary(255)", "not null" => "1", "primary" => "1"), + "reply-to-uri" => array("type" => "varbinary(255)", "not null" => "1", "default" => ""), + "conversation-uri" => array("type" => "varbinary(255)", "not null" => "1", "default" => ""), + "protocol" => array("type" => "tinyint(1) unsigned", "not null" => "1", "default" => "0"), + "source" => array("type" => "mediumtext"), + ), + "indexes" => array( + "PRIMARY" => array("item-uri"), + "conversation-uri" => array("conversation-uri"), + ) + ); $database["event"] = array( "fields" => array( "id" => array("type" => "int(11)", "not null" => "1", "extra" => "auto_increment", "primary" => "1"), From 45d73b106bbebdea17c56c00235c0dcebc471536 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 26 Apr 2017 21:16:25 +0000 Subject: [PATCH 2/9] Conversation data is now stored in another table --- database.sql | 45 ++++++++++++++++++++++++++--------------- include/dba.php | 24 ++++++++++++++++++++++ include/dbstructure.php | 1 + include/items.php | 36 +++++++++++++++++++++++++++++++++ include/ostatus.php | 8 ++++++-- 5 files changed, 96 insertions(+), 18 deletions(-) diff --git a/database.sql b/database.sql index 69da511b0..e9a4ee2e4 100644 --- a/database.sql +++ b/database.sql @@ -1,6 +1,6 @@ -- ------------------------------------------ -- Friendica 3.5.2-dev (Asparagus) --- DB_UPDATE_VERSION 1219 +-- DB_UPDATE_VERSION 1220 -- ------------------------------------------ @@ -174,13 +174,13 @@ CREATE TABLE IF NOT EXISTS `contact` ( `fetch_further_information` tinyint(1) NOT NULL DEFAULT 0, `ffi_keyword_blacklist` text, PRIMARY KEY(`id`), - INDEX `uid_name` (`uid`,`name`), + INDEX `uid_name` (`uid`,`name`(190)), INDEX `self_uid` (`self`,`uid`), INDEX `alias_uid` (`alias`(32),`uid`), INDEX `pending_uid` (`pending`,`uid`), INDEX `blocked_uid` (`blocked`,`uid`), - INDEX `uid_rel_network_poll` (`uid`,`rel`,`network`,`poll`(64),`archive`), - INDEX `uid_network_batch` (`uid`,`network`,`batch`(64)), + INDEX `uid_rel_network_poll` (`uid`,`rel`,`network`(4),`poll`(64),`archive`), + INDEX `uid_network_batch` (`uid`,`network`(4),`batch`(64)), INDEX `addr_uid` (`addr`(32),`uid`), INDEX `nurl_uid` (`nurl`(32),`uid`), INDEX `nick_uid` (`nick`(32),`uid`), @@ -204,6 +204,19 @@ CREATE TABLE IF NOT EXISTS `conv` ( INDEX `uid` (`uid`) ) DEFAULT COLLATE utf8mb4_general_ci; +-- +-- TABLE conversation +-- +CREATE TABLE IF NOT EXISTS `conversation` ( + `item-uri` varbinary(255) NOT NULL, + `reply-to-uri` varbinary(255) NOT NULL DEFAULT '', + `conversation-uri` varbinary(255) NOT NULL DEFAULT '', + `protocol` tinyint(1) unsigned NOT NULL DEFAULT 0, + `source` mediumtext, + PRIMARY KEY(`item-uri`), + INDEX `conversation-uri` (`conversation-uri`) +) DEFAULT COLLATE utf8mb4_general_ci; + -- -- TABLE event -- @@ -344,7 +357,7 @@ CREATE TABLE IF NOT EXISTS `gcontact` ( INDEX `name` (`name`(64)), INDEX `nick` (`nick`(32)), INDEX `addr` (`addr`(64)), - INDEX `hide_network_updated` (`hide`,`network`,`updated`), + INDEX `hide_network_updated` (`hide`,`network`(4),`updated`), INDEX `updated` (`updated`) ) DEFAULT COLLATE utf8mb4_general_ci; @@ -523,22 +536,22 @@ CREATE TABLE IF NOT EXISTS `item` ( INDEX `uid_contactid_id` (`uid`,`contact-id`,`id`), INDEX `uid_created` (`uid`,`created`), INDEX `uid_unseen_contactid` (`uid`,`unseen`,`contact-id`), - INDEX `uid_network_received` (`uid`,`network`,`received`), - INDEX `uid_network_commented` (`uid`,`network`,`commented`), - INDEX `uid_thrparent` (`uid`,`thr-parent`), - INDEX `uid_parenturi` (`uid`,`parent-uri`), + INDEX `uid_network_received` (`uid`,`network`(4),`received`), + INDEX `uid_network_commented` (`uid`,`network`(4),`commented`), + INDEX `uid_thrparent` (`uid`,`thr-parent`(190)), + INDEX `uid_parenturi` (`uid`,`parent-uri`(190)), INDEX `uid_contactid_created` (`uid`,`contact-id`,`created`), INDEX `authorid_created` (`author-id`,`created`), - INDEX `uid_uri` (`uid`,`uri`), + INDEX `uid_uri` (`uid`,`uri`(190)), INDEX `resource-id` (`resource-id`), INDEX `contactid_allowcid_allowpid_denycid_denygid` (`contact-id`,`allow_cid`(10),`allow_gid`(10),`deny_cid`(10),`deny_gid`(10)), - INDEX `uid_type_changed` (`uid`,`type`,`changed`), - INDEX `contactid_verb` (`contact-id`,`verb`), + INDEX `uid_type_changed` (`uid`,`type`(190),`changed`), + INDEX `contactid_verb` (`contact-id`,`verb`(190)), INDEX `deleted_changed` (`deleted`,`changed`), INDEX `uid_wall_changed` (`uid`,`wall`,`changed`), INDEX `uid_eventid` (`uid`,`event-id`), - INDEX `uid_authorlink` (`uid`,`author-link`), - INDEX `uid_ownerlink` (`uid`,`owner-link`) + INDEX `uid_authorlink` (`uid`,`author-link`(190)), + INDEX `uid_ownerlink` (`uid`,`owner-link`(190)) ) DEFAULT COLLATE utf8mb4_general_ci; -- @@ -652,7 +665,7 @@ CREATE TABLE IF NOT EXISTS `notify` ( INDEX `hash_uid` (`hash`,`uid`), INDEX `seen_uid_date` (`seen`,`uid`,`date`), INDEX `uid_date` (`uid`,`date`), - INDEX `uid_type_link` (`uid`,`type`,`link`) + INDEX `uid_type_link` (`uid`,`type`,`link`(190)) ) DEFAULT COLLATE utf8mb4_general_ci; -- @@ -963,7 +976,7 @@ CREATE TABLE IF NOT EXISTS `term` ( `aid` int(10) unsigned NOT NULL DEFAULT 0, `uid` int(10) unsigned NOT NULL DEFAULT 0, PRIMARY KEY(`tid`), - INDEX `oid_otype_type_term` (`oid`,`otype`,`type`,`term`), + INDEX `oid_otype_type_term` (`oid`,`otype`,`type`,`term`(32)), INDEX `uid_otype_type_term_global_created` (`uid`,`otype`,`type`,`term`(32),`global`,`created`), INDEX `uid_otype_type_url` (`uid`,`otype`,`type`,`url`(64)), INDEX `guid` (`guid`(64)) diff --git a/include/dba.php b/include/dba.php index 76791911a..5846d4948 100644 --- a/include/dba.php +++ b/include/dba.php @@ -492,6 +492,9 @@ class dba { $sql = "/*".$a->callstack()." */ ".$sql; } + self::$dbo->error = ''; + self::$dbo->errorno = 0; + switch (self::$dbo->driver) { case 'pdo': if (!$stmt = self::$dbo->db->prepare($sql)) { @@ -563,6 +566,10 @@ class dba { break; } + if (self::$dbo->errorno != 0) { + logger('DB Error '.self::$dbo->errorno.': '.self::$dbo->error); + } + $a->save_timestamp($stamp1, 'database'); if (x($a->config,'system') && x($a->config['system'], 'db_log')) { @@ -700,6 +707,23 @@ class dba { } } + /** + * @brief Insert a row into a table + * + * @param string $table Table name + * @param array $param parameter array + * + * @return boolean was the insert successfull? + */ + static public function insert($table, $param) { + $sql = "INSERT INTO `".$table."` (`".implode("`, `", array_keys($param))."`) VALUES (". + substr(str_repeat("?, ", count($param)), 0, -2).");"; + + $sql = self::replace_parameters($sql, $param); + + return self::e($sql); + } + /** * @brief Closes the current statement * diff --git a/include/dbstructure.php b/include/dbstructure.php index a9d364a15..5260a87a3 100644 --- a/include/dbstructure.php +++ b/include/dbstructure.php @@ -816,6 +816,7 @@ function db_definition() { "conversation-uri" => array("type" => "varbinary(255)", "not null" => "1", "default" => ""), "protocol" => array("type" => "tinyint(1) unsigned", "not null" => "1", "default" => "0"), "source" => array("type" => "mediumtext"), + "received" => array("type" => "datetime", "not null" => "1", "default" => NULL_DATE), ), "indexes" => array( "PRIMARY" => array("item-uri"), diff --git a/include/items.php b/include/items.php index 2500e08d5..3bf0a001c 100644 --- a/include/items.php +++ b/include/items.php @@ -690,6 +690,42 @@ function item_store($arr, $force_parent = false, $notify = false, $dontcache = f item_body_set_hashtags($arr); $arr['thr-parent'] = $arr['parent-uri']; + + if (in_array($arr['network'], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS))) { + $conversation = array('item-uri' => $arr['uri'], 'received' => dbm::date()); + if (isset($arr['thr-parent'])) { + if ($arr['thr-parent'] != $arr['uri']) { + $conversation['reply-to-uri'] = $arr['thr-parent']; + } + } + if (isset($arr['conversation-uri'])) { + $conversation['conversation-uri'] = $arr['conversation-uri']; + unset($arr['conversation-uri']); + } + + if ($arr['network'] == NETWORK_DFRN) { + $conversation['protocol'] = PROTOCOL_DFRN; + } elseif ($arr['network'] == NETWORK_DIASPORA) { + $conversation['protocol'] = PROTOCOL_DIASPORA; + } + + if (isset($arr['protocol'])) { + $conversation['protocol'] = $arr['protocol']; + unset($arr['protocol']); + } + if (isset($arr['object'])) { + $conversation['source'] = $arr['object']; + if (in_array($arr['network'], array(NETWORK_DIASPORA, NETWORK_OSTATUS))) { + unset($arr['object']); + } + } + if (isset($arr['source'])) { + $conversation['source'] = $arr['source']; + unset($arr['source']); + } + dba::insert('conversation', $conversation); + } + if ($arr['parent-uri'] === $arr['uri']) { $parent_id = 0; $parent_deleted = 0; diff --git a/include/ostatus.php b/include/ostatus.php index c1d730eb1..54d67d66e 100644 --- a/include/ostatus.php +++ b/include/ostatus.php @@ -312,8 +312,10 @@ class ostatus { if ($first_child == "feed") { $entries = $xpath->query('/atom:feed/atom:entry'); + $header["protocol"] = PROTOCOL_OSTATUS_FEED; } else { $entries = $xpath->query('/atom:entry'); + $header["protocol"] = PROTOCOL_OSTATUS_SALMON; } $conversation = ""; $conversationlist = array(); @@ -370,7 +372,7 @@ class ostatus { } elseif ($item["object-type"] == ACTIVITY_OBJ_QUESTION) { $item["title"] = $xpath->query('atom:title/text()', $entry)->item(0)->nodeValue; } - $item["object"] = $xml; + $item["source"] = $xml; /// @TODO /// Delete a message @@ -1172,7 +1174,9 @@ class ostatus { $arr["app"] = "OStatus"; - $arr["object"] = json_encode($single_conv); + $arr["source"] = json_encode($single_conv); + $arr["protocol"] = PROTOCOL_GS_CONVERSATION; + $arr["verb"] = $parent["verb"]; $arr["visible"] = $parent["visible"]; $arr["location"] = $single_conv->location->displayName; From 35dc56c9c25f30823ff1cfbefe8ea9eab47cc6ee Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 27 Apr 2017 20:38:46 +0000 Subject: [PATCH 3/9] Salmons with Mastodon seem to work now --- boot.php | 1 + database.sql | 2 + include/dba.php | 24 ++++++++++- include/dbstructure.php | 3 +- include/dfrn.php | 46 +++++++++++++++++++-- include/diaspora.php | 10 +++-- include/items.php | 24 +++++------ include/ostatus.php | 90 ++++++++++++++++++++++++++++++----------- 8 files changed, 156 insertions(+), 44 deletions(-) diff --git a/boot.php b/boot.php index 480001475..1851f8457 100644 --- a/boot.php +++ b/boot.php @@ -368,6 +368,7 @@ define ( 'NAMESPACE_FEED', 'http://schemas.google.com/g/2010#updates- define ( 'NAMESPACE_OSTATUS', 'http://ostatus.org/schema/1.0' ); define ( 'NAMESPACE_STATUSNET', 'http://status.net/schema/api/1/' ); define ( 'NAMESPACE_ATOM1', 'http://www.w3.org/2005/Atom' ); +define ( 'NAMESPACE_MASTODON', 'http://mastodon.social/schema/1.0' ); /* @}*/ /** diff --git a/database.sql b/database.sql index e9a4ee2e4..c8010e1e2 100644 --- a/database.sql +++ b/database.sql @@ -211,8 +211,10 @@ CREATE TABLE IF NOT EXISTS `conversation` ( `item-uri` varbinary(255) NOT NULL, `reply-to-uri` varbinary(255) NOT NULL DEFAULT '', `conversation-uri` varbinary(255) NOT NULL DEFAULT '', + `conversation-href` varbinary(255) NOT NULL DEFAULT '', `protocol` tinyint(1) unsigned NOT NULL DEFAULT 0, `source` mediumtext, + `received` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', PRIMARY KEY(`item-uri`), INDEX `conversation-uri` (`conversation-uri`) ) DEFAULT COLLATE utf8mb4_general_ci; diff --git a/include/dba.php b/include/dba.php index 5846d4948..7e9979cf9 100644 --- a/include/dba.php +++ b/include/dba.php @@ -634,7 +634,29 @@ class dba { if (is_bool($stmt)) { $retval = $stmt; } else { - $retval = (self::rows($stmt) > 0); + $retval = (self::num_rows($stmt) > 0); + } + + self::close($stmt); + + return $retval; + } + + /** + * @brief Fetches the first row + * + * @param string $sql SQL statement + * @return array first row of query + */ + static public function fetch_first($sql) { + $args = func_get_args(); + + $stmt = call_user_func_array('self::p', $args); + + if (is_bool($stmt)) { + $retval = $stmt; + } else { + $retval = self::fetch($stmt); } self::close($stmt); diff --git a/include/dbstructure.php b/include/dbstructure.php index 5260a87a3..156d3eb64 100644 --- a/include/dbstructure.php +++ b/include/dbstructure.php @@ -814,12 +814,13 @@ function db_definition() { "item-uri" => array("type" => "varbinary(255)", "not null" => "1", "primary" => "1"), "reply-to-uri" => array("type" => "varbinary(255)", "not null" => "1", "default" => ""), "conversation-uri" => array("type" => "varbinary(255)", "not null" => "1", "default" => ""), + "conversation-href" => array("type" => "varbinary(255)", "not null" => "1", "default" => ""), "protocol" => array("type" => "tinyint(1) unsigned", "not null" => "1", "default" => "0"), "source" => array("type" => "mediumtext"), "received" => array("type" => "datetime", "not null" => "1", "default" => NULL_DATE), ), "indexes" => array( - "PRIMARY" => array("item-uri"), + "PRIMARY" => array("item-uri", "protocol"), "conversation-uri" => array("conversation-uri"), ) ); diff --git a/include/dfrn.php b/include/dfrn.php index ddebf1e9b..5977ed9a0 100644 --- a/include/dfrn.php +++ b/include/dfrn.php @@ -817,6 +817,28 @@ class dfrn { xml::add_element($doc, $entry, "thr:in-reply-to", "", $attributes); } + // Add conversation data. This is used for OStatus + $conversation_href = App::get_baseurl()."/display/".$owner["nick"]."/".$item["parent"]; + $conversation_uri = $conversation_href; + + if (isset($parent_item)) { + $r = dba::fetch_first("SELECT `conversation-uri`, `conversation-href` FROM `conversation` WHERE `item-uri` = ?", $item['parent-uri']); + if (dbm::is_result($r)) { + if ($r['conversation-uri'] != '') { + $conversation_uri = $r['conversation-uri']; + } + if ($r['conversation-href'] != '') { + $conversation_href = $r['conversation-href']; + } + } + } + + $attributes = array( + "href" => $conversation_href, + "ref" => $conversation_uri); + + xml::add_element($doc, $entry, "ostatus:conversation", $conversation_uri, $attributes); + xml::add_element($doc, $entry, "id", $item["uri"]); xml::add_element($doc, $entry, "title", $item["title"]); @@ -2209,12 +2231,16 @@ class dfrn { * @param array $importer Record of the importer user mixed with contact of the content * @todo Add type-hints */ - private static function process_entry($header, $xpath, $entry, $importer) { + private static function process_entry($header, $xpath, $entry, $importer, $xml) { logger("Processing entries"); $item = $header; + $item["protocol"] = PROTOCOL_DFRN; + + $item["source"] = $xml; + // Get the uri $item["uri"] = $xpath->query("atom:id/text()", $entry)->item(0)->nodeValue; @@ -2373,6 +2399,20 @@ class dfrn { self::parse_links($links, $item); } + $item['conversation-uri'] = $xpath->query('ostatus:conversation/text()', $entry)->item(0)->nodeValue; + + $conv = $xpath->query('ostatus:conversation', $entry); + if (is_object($conv->item(0))) { + foreach ($conv->item(0)->attributes AS $attributes) { + if ($attributes->name == "ref") { + $item['conversation-uri'] = $attributes->textContent; + } + if ($attributes->name == "href") { + $item['conversation-href'] = $attributes->textContent; + } + } + } + // Is it a reply or a top level posting? $item["parent-uri"] = $item["uri"]; @@ -2801,7 +2841,7 @@ class dfrn { if (!$sort_by_date) { $entries = $xpath->query("/atom:feed/atom:entry"); foreach ($entries AS $entry) { - self::process_entry($header, $xpath, $entry, $importer); + self::process_entry($header, $xpath, $entry, $importer, $xml); } } else { $newentries = array(); @@ -2815,7 +2855,7 @@ class dfrn { ksort($newentries); foreach ($newentries AS $entry) { - self::process_entry($header, $xpath, $entry, $importer); + self::process_entry($header, $xpath, $entry, $importer, $xml); } } logger("Import done for user " . $importer["uid"] . " from contact " . $importer["id"], LOGGER_DEBUG); diff --git a/include/diaspora.php b/include/diaspora.php index b8eff62b1..b926f21da 100644 --- a/include/diaspora.php +++ b/include/diaspora.php @@ -1308,7 +1308,9 @@ class Diaspora { } $datarray["object-type"] = ACTIVITY_OBJ_COMMENT; - $datarray["object"] = $xml; + + $datarray["protocol"] = PROTOCOL_DIASPORA; + $datarray["source"] = $xml; $datarray["changed"] = $datarray["created"] = $datarray["edited"] = $created_at; @@ -2278,7 +2280,8 @@ class Diaspora { $datarray["verb"] = ACTIVITY_POST; $datarray["gravity"] = GRAVITY_PARENT; - $datarray["object"] = $xml; + $datarray["protocol"] = PROTOCOL_DIASPORA; + $datarray["source"] = $xml; $prefix = share_header($original_item["author-name"], $original_item["author-link"], $original_item["author-avatar"], $original_item["guid"], $original_item["created"], $orig_url); @@ -2481,7 +2484,8 @@ class Diaspora { $datarray["verb"] = ACTIVITY_POST; $datarray["gravity"] = GRAVITY_PARENT; - $datarray["object"] = $xml; + $datarray["protocol"] = PROTOCOL_DIASPORA; + $datarray["source"] = $xml; $datarray["body"] = self::replace_people_guid($body, $contact["url"]); diff --git a/include/items.php b/include/items.php index 3bf0a001c..dcc99e8bd 100644 --- a/include/items.php +++ b/include/items.php @@ -693,39 +693,37 @@ function item_store($arr, $force_parent = false, $notify = false, $dontcache = f if (in_array($arr['network'], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS))) { $conversation = array('item-uri' => $arr['uri'], 'received' => dbm::date()); + if (isset($arr['thr-parent'])) { if ($arr['thr-parent'] != $arr['uri']) { $conversation['reply-to-uri'] = $arr['thr-parent']; } } + if (isset($arr['conversation-uri'])) { $conversation['conversation-uri'] = $arr['conversation-uri']; - unset($arr['conversation-uri']); } - if ($arr['network'] == NETWORK_DFRN) { - $conversation['protocol'] = PROTOCOL_DFRN; - } elseif ($arr['network'] == NETWORK_DIASPORA) { - $conversation['protocol'] = PROTOCOL_DIASPORA; + if (isset($arr['conversation-href'])) { + $conversation['conversation-href'] = $arr['conversation-href']; } if (isset($arr['protocol'])) { $conversation['protocol'] = $arr['protocol']; - unset($arr['protocol']); - } - if (isset($arr['object'])) { - $conversation['source'] = $arr['object']; - if (in_array($arr['network'], array(NETWORK_DIASPORA, NETWORK_OSTATUS))) { - unset($arr['object']); - } } + if (isset($arr['source'])) { $conversation['source'] = $arr['source']; - unset($arr['source']); } + dba::insert('conversation', $conversation); } + unset($arr['conversation-uri']); + unset($arr['conversation-href']); + unset($arr['protocol']); + unset($arr['source']); + if ($arr['parent-uri'] === $arr['uri']) { $parent_id = 0; $parent_deleted = 0; diff --git a/include/ostatus.php b/include/ostatus.php index 54d67d66e..1800a9cc8 100644 --- a/include/ostatus.php +++ b/include/ostatus.php @@ -420,6 +420,19 @@ class ostatus { $item["created"] = $xpath->query('atom:published/text()', $entry)->item(0)->nodeValue; $item["edited"] = $xpath->query('atom:updated/text()', $entry)->item(0)->nodeValue; $conversation = $xpath->query('ostatus:conversation/text()', $entry)->item(0)->nodeValue; + $item['conversation-uri'] = $conversation; + + $conv = $xpath->query('ostatus:conversation', $entry); + if (is_object($conv->item(0))) { + foreach ($conv->item(0)->attributes AS $attributes) { + if ($attributes->name == "ref") { + $item['conversation-uri'] = $attributes->textContent; + } + if ($attributes->name == "href") { + $item['conversation-href'] = $attributes->textContent; + } + } + } $related = ""; @@ -473,6 +486,10 @@ class ostatus { break; case "ostatus:conversation": $conversation = $attribute['href']; + $item['conversation-href'] = $conversation; + if (!isset($item['conversation-uri'])) { + $item['conversation-uri'] = $item['conversation-href']; + } break; case "enclosure": $enclosure = $attribute['href']; @@ -1162,6 +1179,10 @@ class ostatus { $arr["author-avatar"] = $arr["owner-avatar"]; $arr["body"] = add_page_info_to_body(html2bbcode($single_conv->content)); + if (isset($single_conv->status_net->conversation)) { + $arr['conversation-uri'] = $single_conv->status_net->conversation; + } + if (isset($single_conv->status_net->notice_info->source)) $arr["app"] = strip_tags($single_conv->status_net->notice_info->source); elseif (isset($single_conv->statusnet->notice_info->source)) @@ -1408,6 +1429,7 @@ class ostatus { $root->setAttribute("xmlns:poco", NAMESPACE_POCO); $root->setAttribute("xmlns:ostatus", NAMESPACE_OSTATUS); $root->setAttribute("xmlns:statusnet", NAMESPACE_STATUSNET); + $root->setAttribute("xmlns:mastodon", NAMESPACE_MASTODON); $attributes = array("uri" => "https://friendi.ca", "version" => FRIENDICA_VERSION."-".DB_UPDATE_VERSION); xml::add_element($doc, $root, "generator", FRIENDICA_PLATFORM, $attributes); @@ -1546,14 +1568,16 @@ class ostatus { */ private function add_author($doc, $owner) { - $r = q("SELECT `homepage` FROM `profile` WHERE `uid` = %d AND `is-default` LIMIT 1", intval($owner["uid"])); + $r = q("SELECT `homepage`, `publish` FROM `profile` WHERE `uid` = %d AND `is-default` LIMIT 1", intval($owner["uid"])); if ($r) $profile = $r[0]; $author = $doc->createElement("author"); + xml::add_element($doc, $author, "id", $owner["url"]); xml::add_element($doc, $author, "activity:object-type", ACTIVITY_OBJ_PERSON); xml::add_element($doc, $author, "uri", $owner["url"]); - xml::add_element($doc, $author, "name", $owner["name"]); + xml::add_element($doc, $author, "name", $owner["nick"]); + xml::add_element($doc, $author, "email", $owner["addr"]); xml::add_element($doc, $author, "summary", bbcode($owner["about"], false, false, 7)); $attributes = array("rel" => "alternate", "type" => "text/html", "href" => $owner["url"]); @@ -1600,6 +1624,9 @@ class ostatus { xml::add_element($doc, $author, "statusnet:profile_info", "", array("local_id" => $owner["uid"])); } + if ($profile["publish"]) { + xml::add_element($doc, $author, "mastodon:scope", "public"); + } return $author; } @@ -1773,7 +1800,7 @@ class ostatus { self::entry_content($doc, $as_object, $repeated_item, $owner, "", "", false); $author = self::add_author($doc, $contact); - $as_object->appendChild($author); + $as_object->appendChild($author); $as_object2 = $doc->createElement("activity:object"); @@ -1995,6 +2022,7 @@ class ostatus { $entry->setAttribute("xmlns:poco", NAMESPACE_POCO); $entry->setAttribute("xmlns:ostatus", NAMESPACE_OSTATUS); $entry->setAttribute("xmlns:statusnet", NAMESPACE_STATUSNET); + $entry->setAttribute("xmlns:mastodon", NAMESPACE_MASTODON); $author = self::add_author($doc, $owner); $entry->appendChild($author); @@ -2061,39 +2089,54 @@ class ostatus { $parent = q("SELECT `guid`, `author-link`, `owner-link` FROM `item` WHERE `id` = %d", intval($item["parent"])); $parent_item = (($item['thr-parent']) ? $item['thr-parent'] : $item['parent-uri']); - $attributes = array( - "ref" => $parent_item, - "type" => "text/html", - "href" => App::get_baseurl()."/display/".$parent[0]["guid"]); - xml::add_element($doc, $entry, "thr:in-reply-to", "", $attributes); - - $attributes = array( - "rel" => "related", - "href" => App::get_baseurl()."/display/".$parent[0]["guid"]); - xml::add_element($doc, $entry, "link", "", $attributes); - - $mentioned[$parent[0]["author-link"]] = $parent[0]["author-link"]; - $mentioned[$parent[0]["owner-link"]] = $parent[0]["owner-link"]; - - $thrparent = q("SELECT `guid`, `author-link`, `owner-link` FROM `item` WHERE `uid` = %d AND `uri` = '%s'", + $thrparent = q("SELECT `guid`, `author-link`, `owner-link`, `plink` FROM `item` WHERE `uid` = %d AND `uri` = '%s'", intval($owner["uid"]), dbesc($parent_item)); if ($thrparent) { $mentioned[$thrparent[0]["author-link"]] = $thrparent[0]["author-link"]; $mentioned[$thrparent[0]["owner-link"]] = $thrparent[0]["owner-link"]; + $parent_plink = $thrparent[0]["plink"]; + } else { + $mentioned[$parent[0]["author-link"]] = $parent[0]["author-link"]; + $mentioned[$parent[0]["owner-link"]] = $parent[0]["owner-link"]; + $parent_plink = App::get_baseurl()."/display/".$parent[0]["guid"]; } + + $attributes = array( + "ref" => $parent_item, + "href" => $parent_plink); + xml::add_element($doc, $entry, "thr:in-reply-to", "", $attributes); + + $attributes = array( + "rel" => "related", + "href" => $parent_plink); + xml::add_element($doc, $entry, "link", "", $attributes); } if (intval($item["parent"]) > 0) { - $conversation = App::get_baseurl()."/display/".$owner["nick"]."/".$item["parent"]; - xml::add_element($doc, $entry, "link", "", array("rel" => "ostatus:conversation", "href" => $conversation)); + $conversation_href = App::get_baseurl()."/display/".$owner["nick"]."/".$item["parent"]; + $conversation_uri = $conversation_href; + + if (isset($parent_item)) { + $r = dba::fetch_first("SELECT `conversation-uri`, `conversation-href` FROM `conversation` WHERE `item-uri` = ?", $parent_item); + if (dbm::is_result($r)) { + if ($r['conversation-uri'] != '') { + $conversation_uri = $r['conversation-uri']; + } + if ($r['conversation-href'] != '') { + $conversation_href = $r['conversation-href']; + } + } + } + + xml::add_element($doc, $entry, "link", "", array("rel" => "ostatus:conversation", "href" => $conversation_href)); $attributes = array( - "href" => $conversation, + "href" => $conversation_href, "local_id" => $item["parent"], - "ref" => $conversation); + "ref" => $conversation_uri); - xml::add_element($doc, $entry, "ostatus:conversation", $conversation, $attributes); + xml::add_element($doc, $entry, "ostatus:conversation", $conversation_uri, $attributes); } $tags = item_getfeedtags($item); @@ -2131,6 +2174,7 @@ class ostatus { xml::add_element($doc, $entry, "link", "", array("rel" => "mentioned", "ostatus:object-type" => "http://activitystrea.ms/schema/1.0/collection", "href" => "http://activityschema.org/collection/public")); + xml::add_element($doc, $entry, "mastodon:scope", "public"); } if(count($tags)) From 15355850f7bc0d88766129191a870271b96f1a95 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 27 Apr 2017 20:47:52 +0000 Subject: [PATCH 4/9] Set the database version --- boot.php | 2 +- update.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/boot.php b/boot.php index 1851f8457..d5972484b 100644 --- a/boot.php +++ b/boot.php @@ -38,7 +38,7 @@ define ( 'FRIENDICA_PLATFORM', 'Friendica'); define ( 'FRIENDICA_CODENAME', 'Asparagus'); define ( 'FRIENDICA_VERSION', '3.5.2-dev' ); define ( 'DFRN_PROTOCOL_VERSION', '2.23' ); -define ( 'DB_UPDATE_VERSION', 1220 ); +define ( 'DB_UPDATE_VERSION', 1221 ); /** * @brief Constant with a HTML line break. diff --git a/update.php b/update.php index 8da76336f..704f2ac06 100644 --- a/update.php +++ b/update.php @@ -1,6 +1,6 @@ Date: Fri, 28 Apr 2017 04:05:50 +0000 Subject: [PATCH 5/9] We should escape the table name as well. --- include/dba.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/dba.php b/include/dba.php index 7e9979cf9..5a93338a1 100644 --- a/include/dba.php +++ b/include/dba.php @@ -456,7 +456,7 @@ class dba { if (is_int($args[$param]) OR is_float($args[$param])) { $replace = intval($args[$param]); } else { - $replace = "'".dbesc($args[$param])."'"; + $replace = "'".self::$dbo->escape($args[$param])."'"; } $pos = strpos($sql, '?', $offset); @@ -738,7 +738,7 @@ class dba { * @return boolean was the insert successfull? */ static public function insert($table, $param) { - $sql = "INSERT INTO `".$table."` (`".implode("`, `", array_keys($param))."`) VALUES (". + $sql = "INSERT INTO `".self::$dbo->escape($table)."` (`".implode("`, `", array_keys($param))."`) VALUES (". substr(str_repeat("?, ", count($param)), 0, -2).");"; $sql = self::replace_parameters($sql, $param); From 3b5e1bbfc3f19dbe5199abdcbf598d69c2bdc234 Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 28 Apr 2017 04:47:28 +0000 Subject: [PATCH 6/9] dba:p and dba:e can now be called with a parameter array as well. --- include/dba.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/include/dba.php b/include/dba.php index 5a93338a1..8686760ea 100644 --- a/include/dba.php +++ b/include/dba.php @@ -482,6 +482,15 @@ class dba { $args = func_get_args(); unset($args[0]); + // When the second function parameter is an array then use this as the parameter array + if ((count($args) == 1) AND (is_array($args[1]))) { + $params = $args[1]; + $i = 0; + foreach ($params AS $param) { + $args[++$i] = $param; + } + } + if (!self::$dbo OR !self::$dbo->connected) { return false; } @@ -741,9 +750,7 @@ class dba { $sql = "INSERT INTO `".self::$dbo->escape($table)."` (`".implode("`, `", array_keys($param))."`) VALUES (". substr(str_repeat("?, ", count($param)), 0, -2).");"; - $sql = self::replace_parameters($sql, $param); - - return self::e($sql); + return self::e($sql, $param); } /** From 782783aa52f504811aa13b7495880e1d6f758fd2 Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 28 Apr 2017 05:50:27 +0000 Subject: [PATCH 7/9] New function "dba::update" and changed unique index for the conversations --- database.sql | 2 +- include/dba.php | 26 ++++++++++++++++++++++++++ include/dbstructure.php | 2 +- include/items.php | 10 +++++++++- 4 files changed, 37 insertions(+), 3 deletions(-) diff --git a/database.sql b/database.sql index c8010e1e2..73547b305 100644 --- a/database.sql +++ b/database.sql @@ -1,6 +1,6 @@ -- ------------------------------------------ -- Friendica 3.5.2-dev (Asparagus) --- DB_UPDATE_VERSION 1220 +-- DB_UPDATE_VERSION 1221 -- ------------------------------------------ diff --git a/include/dba.php b/include/dba.php index 8686760ea..93df40b40 100644 --- a/include/dba.php +++ b/include/dba.php @@ -753,6 +753,32 @@ class dba { return self::e($sql, $param); } + /** + * @brief Updates rows + * + * @param string $table Table name + * @param array $fields contains the fields that are updated + * @param array $condition condition array with the key values + * + * @return boolean was the update successfull? + */ + static public function update($table, $fields, $condition) { + + $sql = "UPDATE `".self::$dbo->escape($table)."` SET `". + implode("` = ?, `", array_keys($fields))."` = ? WHERE `". + implode("` = ? AND `", array_keys($condition))."` = ?"; + + $params = array(); + foreach ($fields AS $value) { + $params[] = $value; + } + foreach ($condition AS $value) { + $params[] = $value; + } + + self::e($sql, $params); + } + /** * @brief Closes the current statement * diff --git a/include/dbstructure.php b/include/dbstructure.php index 156d3eb64..98a4a9c30 100644 --- a/include/dbstructure.php +++ b/include/dbstructure.php @@ -820,7 +820,7 @@ function db_definition() { "received" => array("type" => "datetime", "not null" => "1", "default" => NULL_DATE), ), "indexes" => array( - "PRIMARY" => array("item-uri", "protocol"), + "PRIMARY" => array("item-uri"), "conversation-uri" => array("conversation-uri"), ) ); diff --git a/include/items.php b/include/items.php index dcc99e8bd..98b40f1ee 100644 --- a/include/items.php +++ b/include/items.php @@ -716,7 +716,15 @@ function item_store($arr, $force_parent = false, $notify = false, $dontcache = f $conversation['source'] = $arr['source']; } - dba::insert('conversation', $conversation); + $conv = dba::fetch_first("SELECT `protocol` FROM `conversation` WHERE `item-uri` = ?", $conversation['item-uri']); + if (dbm::is_result($conv)) { + // Replace the conversation entry when the new one is better + if (($conv['protocol'] == 0) OR ($conv['protocol'] > $conversation['protocol'])) { + dba::update('conversation', $conversation, array('item-uri' => $conversation['item-uri'])); + } + } else { + dba::insert('conversation', $conversation); + } } unset($arr['conversation-uri']); From 7240b2198bb6623dad2d19e406c140757001f2f1 Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 28 Apr 2017 06:03:04 +0000 Subject: [PATCH 8/9] Missed protocol ... --- include/diaspora.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/diaspora.php b/include/diaspora.php index b926f21da..b3af9cc64 100644 --- a/include/diaspora.php +++ b/include/diaspora.php @@ -1630,6 +1630,8 @@ class Diaspora { $datarray = array(); + $datarray["protocol"] = PROTOCOL_DIASPORA; + $datarray["uid"] = $importer["uid"]; $datarray["contact-id"] = $author_contact["cid"]; $datarray["network"] = $author_contact["network"]; @@ -1921,6 +1923,7 @@ class Diaspora { if ($self && $contact["rel"] == CONTACT_IS_FOLLOWER) { $arr = array(); + $arr["protocol"] = PROTOCOL_DIASPORA; $arr["uri"] = $arr["parent-uri"] = item_new_uri($a->get_hostname(), $importer["uid"]); $arr["uid"] = $importer["uid"]; $arr["contact-id"] = $self[0]["id"]; From 9900d28c4b09fe5de730ed295f5e34021e2d39ca Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 28 Apr 2017 06:21:12 +0000 Subject: [PATCH 9/9] We should return a return value when we say that we have a return value. --- include/dba.php | 2 +- include/items.php | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/include/dba.php b/include/dba.php index 93df40b40..3f4d81482 100644 --- a/include/dba.php +++ b/include/dba.php @@ -776,7 +776,7 @@ class dba { $params[] = $value; } - self::e($sql, $params); + return self::e($sql, $params); } /** diff --git a/include/items.php b/include/items.php index 98b40f1ee..285a5745a 100644 --- a/include/items.php +++ b/include/items.php @@ -719,11 +719,15 @@ function item_store($arr, $force_parent = false, $notify = false, $dontcache = f $conv = dba::fetch_first("SELECT `protocol` FROM `conversation` WHERE `item-uri` = ?", $conversation['item-uri']); if (dbm::is_result($conv)) { // Replace the conversation entry when the new one is better - if (($conv['protocol'] == 0) OR ($conv['protocol'] > $conversation['protocol'])) { - dba::update('conversation', $conversation, array('item-uri' => $conversation['item-uri'])); + if ((($conv['protocol'] == 0) OR ($conv['protocol'] > $conversation['protocol'])) AND ($conversation['protocol'] > 0)) { + if (!dba::update('conversation', $conversation, array('item-uri' => $conversation['item-uri']))) { + logger('Conversation: update for '.$conversation['item-uri'].' from '.$conv['protocol'].' to '.$conversation['protocol'].' failed', LOGGER_DEBUG); + } } } else { - dba::insert('conversation', $conversation); + if (!dba::insert('conversation', $conversation)) { + logger('Conversation: insert for '.$conversation['item-uri'].' (protocol '.$conversation['protocol'].') failed', LOGGER_DEBUG); + } } }