From 1d7154a7d17c6034ba257b3e17609a7da9e981bc Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 2 Jul 2019 09:06:48 +0000 Subject: [PATCH] Update the gcontact entry when the public contact entry has changed --- config/dbstructure.config.php | 4 +- database.sql | 4 +- src/Model/Contact.php | 11 ++- src/Model/GContact.php | 129 +++++++++++++++++++++++----------- 4 files changed, 103 insertions(+), 45 deletions(-) diff --git a/config/dbstructure.config.php b/config/dbstructure.config.php index 5cf9d8597..415e389b6 100755 --- a/config/dbstructure.config.php +++ b/config/dbstructure.config.php @@ -34,7 +34,7 @@ use Friendica\Database\DBA; if (!defined('DB_UPDATE_VERSION')) { - define('DB_UPDATE_VERSION', 1315); + define('DB_UPDATE_VERSION', 1316); } return [ @@ -423,6 +423,8 @@ return [ "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" => ""], + "archive_date" => ["type" => "datetime", "default" => DBA::NULL_DATETIME, "comment" => ""], + "archived" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], "location" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], "about" => ["type" => "text", "comment" => ""], "keywords" => ["type" => "text", "comment" => "puplic keywords (interests)"], diff --git a/database.sql b/database.sql index 67ae8b4c2..07d4e2f28 100644 --- a/database.sql +++ b/database.sql @@ -1,6 +1,6 @@ -- ------------------------------------------ -- Friendica 2019.09-dev (Dalmatian Bellflower) --- DB_UPDATE_VERSION 1314 +-- DB_UPDATE_VERSION 1316 -- ------------------------------------------ @@ -372,6 +372,8 @@ CREATE TABLE IF NOT EXISTS `gcontact` ( `updated` datetime DEFAULT '0001-01-01 00:00:00' COMMENT '', `last_contact` datetime DEFAULT '0001-01-01 00:00:00' COMMENT '', `last_failure` datetime DEFAULT '0001-01-01 00:00:00' COMMENT '', + `archive_date` datetime DEFAULT '0001-01-01 00:00:00' COMMENT '', + `archived` boolean NOT NULL DEFAULT '0' COMMENT '', `location` varchar(255) NOT NULL DEFAULT '' COMMENT '', `about` text COMMENT '', `keywords` text COMMENT 'puplic keywords (interests)', diff --git a/src/Model/Contact.php b/src/Model/Contact.php index a10c0d05e..77726e6d4 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -1516,6 +1516,11 @@ class Contact extends BaseObject DBA::update('contact', $updated, ['id' => $contact_id], $contact); + if (!$background_update && ($uid == 0)) { + // Update the gcontact entry + GContact::updateFromPublicContact($contact_id); + } + return $contact_id; } @@ -1770,6 +1775,9 @@ class Contact extends BaseObject return; } + // Update the corresponding gcontact entry + GContact::updateFromPublicContact($id); + // Archive or unarchive the contact. We only need to do this for the public contact. // The archive/unarchive function will update the personal contacts by themselves. $contact = DBA::selectFirst('contact', [], ['id' => $id]); @@ -1876,9 +1884,6 @@ class Contact extends BaseObject self::updateContact($id, $uid, $ret['url'], $ret); - // Update the corresponding gcontact entry - GContact::updateFromProbe($ret['url']); - return true; } diff --git a/src/Model/GContact.php b/src/Model/GContact.php index 8c6471281..dd1e4285c 100644 --- a/src/Model/GContact.php +++ b/src/Model/GContact.php @@ -140,7 +140,7 @@ class GContact } // Assure that there are no parameter fragments in the profile url - if (in_array($gcontact['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::DIASPORA, Protocol::OSTATUS, ""])) { + if (empty($gcontact["network"]) || in_array($gcontact["network"], Protocol::FEDERATED)) { $gcontact['url'] = self::cleanContactUrl($gcontact['url']); } @@ -216,7 +216,7 @@ class GContact throw new Exception('No name and photo for URL '.$gcontact['url']); } - if (!in_array($gcontact['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::OSTATUS, Protocol::DIASPORA])) { + if (!in_array($gcontact['network'], Protocol::FEDERATED)) { throw new Exception('No federated network ('.$gcontact['network'].') detected for URL '.$gcontact['url']); } @@ -664,7 +664,7 @@ class GContact self::fixAlternateContactAddress($contact); // Remove unwanted parts from the contact url (e.g. "?zrl=...") - if (in_array($contact["network"], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::DIASPORA, Protocol::OSTATUS])) { + if (in_array($contact["network"], Protocol::FEDERATED)) { $contact["url"] = self::cleanContactUrl($contact["url"]); } @@ -851,55 +851,104 @@ class GContact 'server_url' => $contact['server_url'], 'connect' => $contact['connect']]; DBA::update('gcontact', $updated, $condition, $fields); - - // Now update the contact entry with the user id "0" as well. - // This is used for the shadow copies of public items. - /// @todo Check if we really should do this. - // The quality of the gcontact table is mostly lower than the public contact - $public_contact = DBA::selectFirst('contact', ['id'], ['nurl' => Strings::normaliseLink($contact["url"]), 'uid' => 0]); - if (DBA::isResult($public_contact)) { - Logger::log("Update public contact ".$public_contact["id"], Logger::DEBUG); - - Contact::updateAvatar($contact["photo"], 0, $public_contact["id"]); - - $fields = ['name', 'nick', 'addr', - 'network', 'bd', 'gender', - 'keywords', 'alias', 'contact-type', - 'url', 'location', 'about']; - $old_contact = DBA::selectFirst('contact', $fields, ['id' => $public_contact["id"]]); - - // Update it with the current values - $fields = ['name' => $contact['name'], 'nick' => $contact['nick'], - 'addr' => $contact['addr'], 'network' => $contact['network'], - 'bd' => $contact['birthday'], 'gender' => $contact['gender'], - 'keywords' => $contact['keywords'], 'alias' => $contact['alias'], - 'contact-type' => $contact['contact-type'], 'url' => $contact['url'], - 'location' => $contact['location'], 'about' => $contact['about']]; - - // Don't update the birthday field if not set or invalid - if (empty($contact['birthday']) || ($contact['birthday'] <= DBA::NULL_DATE)) { - unset($fields['bd']); - } - - - DBA::update('contact', $fields, ['id' => $public_contact["id"]], $old_contact); - } } return $gcontact_id; } /** - * @brief Updates the gcontact entry from probe + * @brief Updates the gcontact entry from a given public contact id * - * @param string $url profile link + * @param integer $cid contact id * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function updateFromProbe($url) + public static function updateFromPublicContact($cid) { - $data = Probe::uri($url); + $fields = ['name', 'nick', 'url', 'nurl', 'location', 'about', 'keywords', 'gender', + 'bd', 'contact-type', 'network', 'addr', 'notify', 'alias', 'archive', + 'created', 'updated', 'avatar', 'success_update', 'failure_update', 'forum', 'prv']; + $contact = DBA::selectFirst('contact', $fields, ['id' => $cid, 'uid' => 0, 'network' => Protocol::FEDERATED]); + if (!DBA::isResult($contact)) { + return; + } + + // These fields cannot be updated, since they don't exist in the contact table + // hide, nsfw, server_url + // "connect" does exist, but seems to contain the same as "addr" + + $fields = ['name', 'nick', 'url', 'nurl', 'location', 'about', 'keywords', 'gender', 'generation', + 'birthday', 'contact-type', 'network', 'addr', 'notify', 'alias', 'archived', 'archive_date', + 'created', 'updated', 'photo', 'last_contact', 'last_failure', 'community', 'connect']; + + $old_gcontact = DBA::selectFirst('gcontact', $fields, ['nurl' => $contact['nurl']]); + $do_insert = !DBA::isResult($old_gcontact); + if ($do_insert) { + $old_gcontact = []; + } + + $gcontact = $contact; + + // These fields are having different names but the same content + $gcontact['archived'] = $gcontact['archive']; + unset($gcontact['archive']); + $gcontact['birthday'] = $gcontact['bd']; + unset($gcontact['bd']); + $gcontact['photo'] = $gcontact['avatar']; + unset($gcontact['avatar']); + $gcontact['last_contact'] = $gcontact['success_update']; + unset($gcontact['success_update']); + $gcontact['last_failure'] = $gcontact['failure_update']; + unset($gcontact['failure_update']); + $gcontact['community'] = ($gcontact['forum'] || $gcontact['prv']); + unset($gcontact['forum']); + unset($gcontact['prv']); + + foreach (['last_contact', 'last_failure', 'updated'] as $field) { + if (!empty($old_gcontact[$field]) && ($old_gcontact[$field] >= $gcontact[$field])) { + unset($gcontact[$field]); + } + } + + if ($gcontact['archived'] && (empty($old_gcontact['archive_date']) || ($old_gcontact['archive_date'] <= DBA::NULL_DATETIME))) { + $gcontact['archive_date'] = DateTimeFormat::utcNow(); + } elseif (!$gcontact['archived']) { + $gcontact['archive_date'] = DBA::NULL_DATETIME; + } + + if (!empty($old_gcontact['created']) && ($old_gcontact['created'] > DBA::NULL_DATETIME) + && ($old_gcontact['created'] <= $gcontact['created'])) { + unset($gcontact['created']); + } + + if (empty($gcontact['birthday']) && ($gcontact['birthday'] <= DBA::NULL_DATETIME)) { + unset($gcontact['birthday']); + } + + if (empty($old_gcontact['generation']) || ($old_gcontact['generation'] > 2)) { + $gcontact['generation'] = 2; // We fetched the data directly from the other server + } + + if (!$do_insert) { + DBA::update('gcontact', $gcontact, ['nurl' => $contact['nurl']], $old_gcontact); + } elseif (!$gcontact['archived']) { + DBA::insert('gcontact', $gcontact); + } + } + + /** + * @brief Updates the gcontact entry from probe + * + * @param string $url profile link + * @param boolean $force Optional forcing of network probing (otherwise we use the cached data) + * @return void + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException + */ + public static function updateFromProbe($url, $force = false) + { + $data = Probe::uri($url, $force); if (in_array($data["network"], [Protocol::PHANTOM])) { Logger::log("Invalid network for contact url ".$data["url"]." - Called by: ".System::callstack(), Logger::DEBUG);