X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FProtocol%2FDiaspora.php;h=7c4e19d923a7dda098576c1f9ffb350bef954200;hb=dbad46c37847f894312c0f1318a21f5ce3606cb0;hp=2dd3eba1e2c940befa788381589710c6f0b5cda9;hpb=2ec3a97393959e42d450e074271d2d622d25701f;p=friendica.git diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index 2dd3eba1e2..7c4e19d923 100644 --- a/src/Protocol/Diaspora.php +++ b/src/Protocol/Diaspora.php @@ -35,9 +35,12 @@ use Friendica\Model\Contact; use Friendica\Model\Conversation; use Friendica\Model\GContact; use Friendica\Model\Item; +use Friendica\Model\ItemURI; use Friendica\Model\ItemDeliveryData; use Friendica\Model\Mail; use Friendica\Model\Profile; +use Friendica\Model\Tag; +use Friendica\Model\Term; use Friendica\Model\User; use Friendica\Network\Probe; use Friendica\Util\Crypto; @@ -123,7 +126,7 @@ class Diaspora } // All tags of the current post - $condition = ['otype' => TERM_OBJ_POST, 'type' => TERM_HASHTAG, 'oid' => $parent['parent']]; + $condition = ['otype' => Term::OBJECT_TYPE_POST, 'type' => Term::HASHTAG, 'oid' => $parent['parent']]; $tags = DBA::select('term', ['term'], $condition); $taglist = []; while ($tag = DBA::fetch($tags)) { @@ -256,27 +259,13 @@ class Diaspora */ public static function participantsForThread($thread, array $contacts) { - $r = DBA::p("SELECT `contact`.`batch`, `contact`.`id`, `contact`.`url`, `contact`.`name`, `contact`.`network`, `contact`.`protocol`, - `fcontact`.`batch` AS `fbatch`, `fcontact`.`network` AS `fnetwork` FROM `participation` - INNER JOIN `contact` ON `contact`.`id` = `participation`.`cid` - INNER JOIN `fcontact` ON `fcontact`.`id` = `participation`.`fid` - WHERE `participation`.`iid` = ? AND NOT `contact`.`archive`", $thread); - - while ($contact = DBA::fetch($r)) { - if (!empty($contact['fnetwork'])) { - $contact['network'] = $contact['fnetwork']; - } - unset($contact['fnetwork']); + $participation = DBA::select('participation-view', [], ['iid' => $thread]); + while ($contact = DBA::fetch($participation)) { if (empty($contact['protocol'])) { $contact['protocol'] = $contact['network']; } - if (empty($contact['batch']) && !empty($contact['fbatch'])) { - $contact['batch'] = $contact['fbatch']; - } - unset($contact['fbatch']); - $exists = false; foreach ($contacts as $entry) { if ($entry['batch'] == $contact['batch']) { @@ -288,7 +277,8 @@ class Diaspora $contacts[] = $contact; } } - DBA::close($r); + + DBA::close($participation); return $contacts; } @@ -335,7 +325,7 @@ class Diaspora */ private static function verifyMagicEnvelope($envelope) { - $basedom = XML::parseString($envelope); + $basedom = XML::parseString($envelope, true); if (!is_object($basedom)) { Logger::log("Envelope is no XML file"); @@ -461,7 +451,7 @@ class Diaspora $xml = $raw; } - $basedom = XML::parseString($xml); + $basedom = XML::parseString($xml, true); if (!is_object($basedom)) { Logger::log('Received data does not seem to be an XML. Discarding. '.$xml); @@ -1476,7 +1466,8 @@ class Diaspora public static function fetchByURL($url, $uid = 0) { // Check for Diaspora (and Friendica) typical paths - if (!preg_match("=(https?://.+)/(?:posts|display)/([a-zA-Z0-9-_@.:%]+[a-zA-Z0-9])=i", $url, $matches)) { + if (!preg_match("=(https?://.+)/(?:posts|display|objects)/([a-zA-Z0-9-_@.:%]+[a-zA-Z0-9])=i", $url, $matches)) { + Logger::info('Invalid url', ['url' => $url]); return false; } @@ -1484,15 +1475,20 @@ class Diaspora $item = Item::selectFirst(['id'], ['guid' => $guid, 'uid' => $uid]); if (DBA::isResult($item)) { + Logger::info('Found', ['id' => $item['id']]); return $item['id']; } - self::storeByGuid($guid, $matches[1], $uid); + Logger::info('Fetch GUID from origin', ['guid' => $guid, 'server' => $matches[1]]); + $ret = self::storeByGuid($guid, $matches[1], $uid); + Logger::info('Result', ['ret' => $ret]); $item = Item::selectFirst(['id'], ['guid' => $guid, 'uid' => $uid]); if (DBA::isResult($item)) { + Logger::info('Found', ['id' => $item['id']]); return $item['id']; } else { + Logger::info('Not found', ['guid' => $guid, 'uid' => $uid]); return false; } } @@ -1575,9 +1571,9 @@ class Diaspora * * @return bool is it a hubzilla server? */ - public static function isRedmatrix($url) + private static function isHubzilla($url) { - return(strstr($url, "/channel/")); + return(strstr($url, '/channel/')); } /** @@ -1594,28 +1590,54 @@ class Diaspora private static function plink($addr, $guid, $parent_guid = '') { $contact = Contact::getDetailsByAddr($addr); + if (empty($contact)) { + Logger::info('No contact data for address', ['addr' => $addr]); + return ''; + } - // Fallback - if (!$contact) { - if ($parent_guid != '') { - return "https://" . substr($addr, strpos($addr, "@") + 1) . "/posts/" . $parent_guid . "#" . $guid; - } else { - return "https://" . substr($addr, strpos($addr, "@") + 1) . "/posts/" . $guid; + if (empty($contact['baseurl'])) { + $contact['baseurl'] = 'https://' . substr($addr, strpos($addr, '@') + 1); + Logger::info('Create baseurl from address', ['baseurl' => $contact['baseurl'], 'url' => $contact['url']]); + } + + $platform = ''; + $gserver = DBA::selectFirst('gserver', ['platform'], ['nurl' => Strings::normaliseLink($contact['baseurl'])]); + if (!empty($gserver['platform'])) { + $platform = strtolower($gserver['platform']); + Logger::info('Detected platform', ['platform' => $platform, 'url' => $contact['url']]); + } + + if (!in_array($platform, ['diaspora', 'friendica', 'hubzilla', 'socialhome'])) { + if (self::isHubzilla($contact['url'])) { + Logger::info('Detected unknown platform as Hubzilla', ['platform' => $platform, 'url' => $contact['url']]); + $platform = 'hubzilla'; + } elseif ($contact['network'] == Protocol::DFRN) { + Logger::info('Detected unknown platform as Friendica', ['platform' => $platform, 'url' => $contact['url']]); + $platform = 'friendica'; } } - if ($contact["network"] == Protocol::DFRN) { - return str_replace("/profile/" . $contact["nick"] . "/", "/display/" . $guid, $contact["url"] . "/"); + if ($platform == 'friendica') { + return str_replace('/profile/' . $contact['nick'] . '/', '/display/' . $guid, $contact['url'] . '/'); + } + + if ($platform == 'hubzilla') { + return $contact['baseurl'] . '/item/' . $guid; + } + + if ($platform == 'socialhome') { + return $contact['baseurl'] . '/content/' . $guid; } - if (self::isRedmatrix($contact["url"])) { - return $contact["url"] . "/?mid=" . $guid; + if ($platform != 'diaspora') { + Logger::info('Unknown platform', ['platform' => $platform, 'url' => $contact['url']]); + return ''; } if ($parent_guid != '') { - return "https://" . substr($addr, strpos($addr, "@") + 1) . "/posts/" . $parent_guid . "#" . $guid; + return $contact['baseurl'] . '/posts/' . $parent_guid . '#' . $guid; } else { - return "https://" . substr($addr, strpos($addr, "@") + 1) . "/posts/" . $guid; + return $contact['baseurl'] . '/posts/' . $guid; } } @@ -1775,6 +1797,40 @@ class Diaspora return false; } + /** + * Store the mentions in the tag table + * + * @param integer $uriid + * @param string $text + */ + private static function storeMentions(int $uriid, string $text) + { + preg_match_all('/([@!]){(?:([^}]+?); ?)?([^} ]+)}/', $text, $matches, PREG_SET_ORDER); + if (empty($matches)) { + return; + } + + /* + * Matching values for the preg match + * [1] = mention type (@ or !) + * [2] = name (optional) + * [3] = profile URL + */ + + foreach ($matches as $match) { + if (empty($match)) { + continue; + } + + $person = self::personByHandle($match[3]); + if (empty($person)) { + continue; + } + + Tag::storeByHash($uriid, $match[1], $person['name'] ?: $person['nick'], $person['url']); + } + } + /** * Processes an incoming comment * @@ -1845,6 +1901,7 @@ class Diaspora $datarray["guid"] = $guid; $datarray["uri"] = self::getUriFromGuid($author, $guid); + $datarray['uri-id'] = ItemURI::insert(['uri' => $datarray['uri'], 'guid' => $datarray['guid']]); $datarray["verb"] = Activity::POST; $datarray["gravity"] = GRAVITY_COMMENT; @@ -1863,11 +1920,13 @@ class Diaspora $datarray["changed"] = $datarray["created"] = $datarray["edited"] = $created_at; $datarray["plink"] = self::plink($author, $guid, $parent_item['guid']); - $body = Markdown::toBBCode($text); $datarray["body"] = self::replacePeopleGuid($body, $person["url"]); + self::storeMentions($datarray['uri-id'], $text); + Tag::storeRawTagsFromBody($datarray['uri-id'], $datarray["body"]); + self::fetchGuid($datarray); // If we are the origin of the parent we store the original data. @@ -2211,7 +2270,7 @@ class Diaspora return false; } - $item = Item::selectFirst(['id'], ['guid' => $parent_guid, 'origin' => true, 'private' => false]); + $item = Item::selectFirst(['id'], ['guid' => $parent_guid, 'origin' => true, 'private' => [Item::PUBLIC, Item::UNLISTED]]); if (!DBA::isResult($item)) { Logger::log('Item not found, no origin or private: '.$parent_guid); return false; @@ -2299,7 +2358,6 @@ class Diaspora $name = XML::unescape($data->first_name).((strlen($data->last_name)) ? " ".XML::unescape($data->last_name) : ""); $image_url = XML::unescape($data->image_url); $birthday = XML::unescape($data->birthday); - $gender = XML::unescape($data->gender); $about = Markdown::toBBCode(XML::unescape($data->bio)); $location = Markdown::toBBCode(XML::unescape($data->location)); $searchable = (XML::unescape($data->searchable) == "true"); @@ -2347,8 +2405,7 @@ class Diaspora } $fields = ['name' => $name, 'location' => $location, - 'name-date' => DateTimeFormat::utcNow(), - 'about' => $about, 'gender' => $gender, + 'name-date' => DateTimeFormat::utcNow(), 'about' => $about, 'addr' => $author, 'nick' => $nick, 'keywords' => $keywords, 'unsearchable' => !$searchable, 'sensitive' => $nsfw]; @@ -2362,7 +2419,7 @@ class Diaspora $gcontact = ["url" => $contact["url"], "network" => Protocol::DIASPORA, "generation" => 2, "photo" => $image_url, "name" => $name, "location" => $location, - "about" => $about, "birthday" => $birthday, "gender" => $gender, + "about" => $about, "birthday" => $birthday, "addr" => $author, "nick" => $nick, "keywords" => $keywords, "hide" => !$searchable, "nsfw" => $nsfw]; @@ -2525,7 +2582,7 @@ class Diaspora // Do we already have this item? $fields = ['body', 'title', 'attach', 'tag', 'app', 'created', 'object-type', 'uri', 'guid', 'author-name', 'author-link', 'author-avatar']; - $condition = ['guid' => $guid, 'visible' => true, 'deleted' => false, 'private' => false]; + $condition = ['guid' => $guid, 'visible' => true, 'deleted' => false, 'private' => [Item::PUBLIC, Item::UNLISTED]]; $item = Item::selectFirst($fields, $condition); if (DBA::isResult($item)) { @@ -2569,7 +2626,7 @@ class Diaspora if ($stored) { $fields = ['body', 'title', 'attach', 'tag', 'app', 'created', 'object-type', 'uri', 'guid', 'author-name', 'author-link', 'author-avatar']; - $condition = ['guid' => $guid, 'visible' => true, 'deleted' => false, 'private' => false]; + $condition = ['guid' => $guid, 'visible' => true, 'deleted' => false, 'private' => [Item::PUBLIC, Item::UNLISTED]]; $item = Item::selectFirst($fields, $condition); if (DBA::isResult($item)) { @@ -2686,6 +2743,7 @@ class Diaspora $datarray["guid"] = $guid; $datarray["uri"] = $datarray["parent-uri"] = self::getUriFromGuid($author, $guid); + $datarray['uri-id'] = ItemURI::insert(['uri' => $datarray['uri'], 'guid' => $datarray['guid']]); $datarray["verb"] = Activity::POST; $datarray["gravity"] = GRAVITY_PARENT; @@ -2693,6 +2751,8 @@ class Diaspora $datarray["protocol"] = Conversation::PARCEL_DIASPORA; $datarray["source"] = $xml; + /// @todo Copy tag data from original post + $prefix = share_header( $original_item["author-name"], $original_item["author-link"], @@ -2708,12 +2768,14 @@ class Diaspora $datarray["body"] = $prefix.$original_item["body"]."[/share]"; + Tag::storeFromBody($datarray['uri-id'], $datarray["body"]); + $datarray["tag"] = $original_item["tag"]; $datarray["attach"] = $original_item["attach"]; $datarray["app"] = $original_item["app"]; $datarray["plink"] = self::plink($author, $guid); - $datarray["private"] = (($public == "false") ? 1 : 0); + $datarray["private"] = (($public == "false") ? Item::PRIVATE : Item::PUBLIC); $datarray["changed"] = $datarray["created"] = $datarray["edited"] = $created_at; $datarray["object-type"] = $original_item["object-type"]; @@ -2796,7 +2858,7 @@ class Diaspora continue; } - Item::delete(['id' => $item['id']]); + Item::markForDeletion(['id' => $item['id']]); Logger::log("Deleted target ".$target_guid." (".$item["id"].") from user ".$item["uid"]." parent: ".$item["parent"], Logger::DEBUG); } @@ -2903,7 +2965,7 @@ class Diaspora $datarray["object-type"] = Activity\ObjectType::NOTE; // Add OEmbed and other information to the body - if (!self::isRedmatrix($contact["url"])) { + if (!self::isHubzilla($contact["url"])) { $body = add_page_info_to_body($body, false, true); } } @@ -2929,6 +2991,7 @@ class Diaspora $datarray["guid"] = $guid; $datarray["uri"] = $datarray["parent-uri"] = self::getUriFromGuid($author, $guid); + $datarray['uri-id'] = ItemURI::insert(['uri' => $datarray['uri'], 'guid' => $datarray['guid']]); $datarray["verb"] = Activity::POST; $datarray["gravity"] = GRAVITY_PARENT; @@ -2938,12 +3001,15 @@ class Diaspora $datarray["body"] = self::replacePeopleGuid($body, $contact["url"]); + self::storeMentions($datarray['uri-id'], $text); + Tag::storeRawTagsFromBody($datarray['uri-id'], $datarray["body"]); + if ($provider_display_name != "") { $datarray["app"] = $provider_display_name; } $datarray["plink"] = self::plink($author, $guid); - $datarray["private"] = (($public == "false") ? 1 : 0); + $datarray["private"] = (($public == "false") ? Item::PRIVATE : Item::PUBLIC); $datarray["changed"] = $datarray["created"] = $datarray["edited"] = $created_at; if (isset($address["address"])) { @@ -3247,7 +3313,7 @@ class Diaspora private static function sendParticipation(array $contact, array $item) { // Don't send notifications for private postings - if ($item['private']) { + if ($item['private'] == Item::PRIVATE) { return; } @@ -3538,12 +3604,12 @@ class Diaspora $myaddr = self::myHandle($owner); - $public = ($item["private"] ? "false" : "true"); + $public = ($item["private"] == Item::PRIVATE ? "false" : "true"); $created = DateTimeFormat::utc($item['received'], DateTimeFormat::ATOM); $edited = DateTimeFormat::utc($item["edited"] ?? $item["created"], DateTimeFormat::ATOM); // Detect a share element and do a reshare - if (!$item['private'] && ($ret = self::isReshare($item["body"]))) { + if (($item['private'] != Item::PRIVATE) && ($ret = self::isReshare($item["body"]))) { $message = ["author" => $myaddr, "guid" => $item["guid"], "created_at" => $created, @@ -3912,30 +3978,24 @@ class Diaspora Logger::log("Got relayable data ".$type." for item ".$item["guid"]." (".$item["id"].")", Logger::DEBUG); - // Old way - is used by the internal Friendica functions - /// @todo Change all signatur storing functions to the new format - if ($item['signed_text'] && $item['signature'] && $item['signer']) { - $message = self::messageFromSignature($item); - } else {// New way - $msg = json_decode($item['signed_text'], true); - - $message = []; - if (is_array($msg)) { - foreach ($msg as $field => $data) { - if (!$item["deleted"]) { - if ($field == "diaspora_handle") { - $field = "author"; - } - if ($field == "target_type") { - $field = "parent_type"; - } - } + $msg = json_decode($item['signed_text'], true); - $message[$field] = $data; + $message = []; + if (is_array($msg)) { + foreach ($msg as $field => $data) { + if (!$item["deleted"]) { + if ($field == "diaspora_handle") { + $field = "author"; + } + if ($field == "target_type") { + $field = "parent_type"; + } } - } else { - Logger::log("Signature text for item ".$item["guid"]." (".$item["id"].") couldn't be extracted: ".$item['signed_text'], Logger::DEBUG); + + $message[$field] = $data; } + } else { + Logger::log("Signature text for item ".$item["guid"]." (".$item["id"].") couldn't be extracted: ".$item['signed_text'], Logger::DEBUG); } $message["parent_author_signature"] = self::signature($owner, $message); @@ -4097,20 +4157,11 @@ class Diaspora */ private static function createProfileData($uid) { - $r = q( - "SELECT `profile`.`uid` AS `profile_uid`, `profile`.* , `user`.*, `user`.`prvkey` AS `uprvkey`, `contact`.`addr` - FROM `profile` - INNER JOIN `user` ON `profile`.`uid` = `user`.`uid` - INNER JOIN `contact` ON `profile`.`uid` = `contact`.`uid` - WHERE `user`.`uid` = %d AND `contact`.`self` LIMIT 1", - intval($uid) - ); - - if (!$r) { + $profile = DBA::selectFirst('owner-view', ['uid', 'addr', 'name', 'location', 'net-publish', 'dob', 'about', 'pub_keywords'], ['uid' => $uid]); + if (!DBA::isResult($profile)) { return []; } - $profile = $r[0]; $handle = $profile["addr"]; $split_name = self::splitName($profile['name']); @@ -4120,7 +4171,7 @@ class Diaspora $large = DI::baseUrl().'/photo/custom/300/'.$profile['uid'].'.jpg'; $medium = DI::baseUrl().'/photo/custom/100/'.$profile['uid'].'.jpg'; $small = DI::baseUrl().'/photo/custom/50/' .$profile['uid'].'.jpg'; - $searchable = (($profile['publish'] && $profile['net-publish']) ? 'true' : 'false'); + $searchable = ($profile['net-publish'] ? 'true' : 'false'); $dob = null; $about = null; @@ -4137,10 +4188,9 @@ class Diaspora $dob = DateTimeFormat::utc($year . '-' . $month . '-'. $day, 'Y-m-d'); } - $about = $profile['about']; - $about = strip_tags(BBCode::convert($about)); + $about = BBCode::toMarkdown($profile['about']); - $location = Profile::formatLocation($profile); + $location = $profile['location']; $tags = ''; if ($profile['pub_keywords']) { $kw = str_replace(',', ' ', $profile['pub_keywords']); @@ -4164,7 +4214,6 @@ class Diaspora "image_url_medium" => $medium, "image_url_small" => $small, "birthday" => $dob, - "gender" => $profile['gender'], "bio" => $about, "location" => $location, "searchable" => $searchable,