Merge remote-tracking branch 'upstream/develop' into personal-copy
This commit is contained in:
commit
e6cd5a4d66
165 changed files with 1879 additions and 3326 deletions
|
@ -24,15 +24,13 @@ namespace Friendica\Model;
|
|||
use Friendica\Content\Text\HTML;
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Network\Probe;
|
||||
use Friendica\Protocol\ActivityNamespace;
|
||||
use Friendica\Protocol\ActivityPub;
|
||||
use Friendica\Util\Crypto;
|
||||
use Friendica\Util\Network;
|
||||
use Friendica\Util\JsonLD;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
use Friendica\Util\Strings;
|
||||
use Friendica\Util\JsonLD;
|
||||
use Friendica\Util\Network;
|
||||
|
||||
class APContact
|
||||
{
|
||||
|
|
|
@ -1418,7 +1418,6 @@ class Contact
|
|||
'poll' => $data['poll'] ?? '',
|
||||
'name' => $data['name'] ?? '',
|
||||
'nick' => $data['nick'] ?? '',
|
||||
'photo' => $data['photo'] ?? '',
|
||||
'keywords' => $data['keywords'] ?? '',
|
||||
'location' => $data['location'] ?? '',
|
||||
'about' => $data['about'] ?? '',
|
||||
|
@ -1464,7 +1463,7 @@ class Contact
|
|||
}
|
||||
|
||||
if (!empty($data['photo']) && ($data['network'] != Protocol::FEED)) {
|
||||
self::updateAvatar($data['photo'], $uid, $contact_id);
|
||||
self::updateAvatar($contact_id, $data['photo']);
|
||||
}
|
||||
|
||||
if (in_array($data["network"], array_merge(Protocol::NATIVE_SUPPORT, [Protocol::PUMPIO]))) {
|
||||
|
@ -1474,14 +1473,6 @@ class Contact
|
|||
} else {
|
||||
// Else do a direct update
|
||||
self::updateFromProbe($contact_id, '', false);
|
||||
|
||||
// Update the gcontact entry
|
||||
if ($uid == 0) {
|
||||
GContact::updateFromPublicContactID($contact_id);
|
||||
if (($data['network'] == Protocol::ACTIVITYPUB) && in_array(DI::config()->get('system', 'gcontact_discovery'), [GContact::DISCOVERY_DIRECT, GContact::DISCOVERY_RECURSIVE])) {
|
||||
GContact::discoverFollowers($data['url']);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$fields = ['url', 'nurl', 'addr', 'alias', 'name', 'nick', 'keywords', 'location', 'about', 'avatar-date', 'baseurl', 'gsid'];
|
||||
|
@ -1775,12 +1766,80 @@ class Contact
|
|||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that cached avatar exist
|
||||
*
|
||||
* @param integer $cid
|
||||
*/
|
||||
public static function checkAvatarCache(int $cid)
|
||||
{
|
||||
$contact = DBA::selectFirst('contact', ['url', 'avatar', 'photo', 'thumb', 'micro'], ['id' => $cid, 'uid' => 0, 'self' => false]);
|
||||
if (!DBA::isResult($contact)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($contact['avatar']) || (!empty($contact['photo']) && !empty($contact['thumb']) && !empty($contact['micro']))) {
|
||||
return;
|
||||
}
|
||||
|
||||
Logger::info('Adding avatar cache', ['id' => $cid, 'contact' => $contact]);
|
||||
|
||||
self::updateAvatar($cid, $contact['avatar'], true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the given contact array for avatar cache fields
|
||||
*
|
||||
* @param array $contact
|
||||
* @return array contact array with avatar cache fields
|
||||
*/
|
||||
public static function checkAvatarCacheByArray(array $contact)
|
||||
{
|
||||
$update = false;
|
||||
$contact_fields = [];
|
||||
$fields = ['photo', 'thumb', 'micro'];
|
||||
foreach ($fields as $field) {
|
||||
if (isset($contact[$field])) {
|
||||
$contact_fields[] = $field;
|
||||
}
|
||||
if (isset($contact[$field]) && empty($contact[$field])) {
|
||||
$update = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$update) {
|
||||
return $contact;
|
||||
}
|
||||
|
||||
if (!empty($contact['id']) && !empty($contact['avatar'])) {
|
||||
self::updateAvatar($contact['id'], $contact['avatar'], true);
|
||||
|
||||
$new_contact = self::getById($contact['id'], $contact_fields);
|
||||
if (DBA::isResult($new_contact)) {
|
||||
// We only update the cache fields
|
||||
$contact = array_merge($contact, $new_contact);
|
||||
}
|
||||
}
|
||||
|
||||
/// add the default avatars if the fields aren't filled
|
||||
if (isset($contact['photo']) && empty($contact['photo'])) {
|
||||
$contact['photo'] = DI::baseUrl() . '/images/person-300.jpg';
|
||||
}
|
||||
if (isset($contact['thumb']) && empty($contact['thumb'])) {
|
||||
$contact['thumb'] = DI::baseUrl() . '/images/person-80.jpg';
|
||||
}
|
||||
if (isset($contact['micro']) && empty($contact['micro'])) {
|
||||
$contact['micro'] = DI::baseUrl() . '/images/person-48.jpg';
|
||||
}
|
||||
|
||||
return $contact;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the avatar links in a contact only if needed
|
||||
*
|
||||
* @param string $avatar Link to avatar picture
|
||||
* @param int $uid User id of contact owner
|
||||
* @param int $cid Contact id
|
||||
* @param string $avatar Link to avatar picture
|
||||
* @param bool $force force picture update
|
||||
*
|
||||
* @return void
|
||||
|
@ -1788,41 +1847,51 @@ class Contact
|
|||
* @throws HTTPException\NotFoundException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
public static function updateAvatar($avatar, $uid, $cid, $force = false)
|
||||
public static function updateAvatar(int $cid, string $avatar, bool $force = false)
|
||||
{
|
||||
$contact = DBA::selectFirst('contact', ['avatar', 'photo', 'thumb', 'micro', 'nurl'], ['id' => $cid, 'self' => false]);
|
||||
$contact = DBA::selectFirst('contact', ['uid', 'avatar', 'photo', 'thumb', 'micro', 'nurl'], ['id' => $cid, 'self' => false]);
|
||||
if (!DBA::isResult($contact)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$uid = $contact['uid'];
|
||||
|
||||
// Only update the cached photo links of public contacts when they already are cached
|
||||
if (($uid == 0) && !$force && empty($contact['thumb']) && empty($contact['micro'])) {
|
||||
if ($contact['avatar'] != $avatar) {
|
||||
DBA::update('contact', ['avatar' => $avatar], ['id' => $cid]);
|
||||
Logger::info('Only update the avatar', ['id' => $cid, 'avatar' => $avatar, 'contact' => $contact]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$data = [
|
||||
$contact['photo'] ?? '',
|
||||
$contact['thumb'] ?? '',
|
||||
$contact['micro'] ?? '',
|
||||
];
|
||||
|
||||
foreach ($data as $image_uri) {
|
||||
$image_rid = Photo::ridFromURI($image_uri);
|
||||
if ($image_rid && !Photo::exists(['resource-id' => $image_rid, 'uid' => $uid])) {
|
||||
Logger::info('Regenerating avatar', ['contact uid' => $uid, 'cid' => $cid, 'missing photo' => $image_rid, 'avatar' => $contact['avatar']]);
|
||||
$force = true;
|
||||
$update = ($contact['avatar'] != $avatar) || $force;
|
||||
|
||||
if (!$update) {
|
||||
foreach ($data as $image_uri) {
|
||||
$image_rid = Photo::ridFromURI($image_uri);
|
||||
if ($image_rid && !Photo::exists(['resource-id' => $image_rid, 'uid' => $uid])) {
|
||||
Logger::info('Regenerating avatar', ['contact uid' => $uid, 'cid' => $cid, 'missing photo' => $image_rid, 'avatar' => $contact['avatar']]);
|
||||
$update = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (($contact["avatar"] != $avatar) || $force) {
|
||||
if ($update) {
|
||||
$photos = Photo::importProfilePhoto($avatar, $uid, $cid, true);
|
||||
|
||||
if ($photos) {
|
||||
$fields = ['avatar' => $avatar, 'photo' => $photos[0], 'thumb' => $photos[1], 'micro' => $photos[2], 'avatar-date' => DateTimeFormat::utcNow()];
|
||||
DBA::update('contact', $fields, ['id' => $cid]);
|
||||
|
||||
// Update the public contact (contact id = 0)
|
||||
if ($uid != 0) {
|
||||
$pcontact = DBA::selectFirst('contact', ['id'], ['nurl' => $contact['nurl'], 'uid' => 0]);
|
||||
if (DBA::isResult($pcontact)) {
|
||||
DBA::update('contact', $fields, ['id' => $pcontact['id']]);
|
||||
}
|
||||
}
|
||||
} elseif (empty($contact['avatar'])) {
|
||||
// Ensure that the avatar field is set
|
||||
DBA::update('contact', ['avatar' => $avatar], ['id' => $cid]);
|
||||
Logger::info('Failed profile import', ['id' => $cid, 'force' => $force, 'avatar' => $avatar, 'contact' => $contact]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2006,6 +2075,13 @@ class Contact
|
|||
|
||||
$new_pubkey = $ret['pubkey'];
|
||||
|
||||
// Update the gcontact entry
|
||||
if ($uid == 0) {
|
||||
GContact::updateFromPublicContactID($id);
|
||||
}
|
||||
|
||||
ContactRelation::discoverByUrl($ret['url']);
|
||||
|
||||
$update = false;
|
||||
|
||||
// make sure to not overwrite existing values with blank entries except some technical fields
|
||||
|
@ -2021,7 +2097,7 @@ class Contact
|
|||
}
|
||||
|
||||
if (!empty($ret['photo']) && ($ret['network'] != Protocol::FEED)) {
|
||||
self::updateAvatar($ret['photo'], $uid, $id, $update || $force);
|
||||
self::updateAvatar($id, $ret['photo'], $update || $force);
|
||||
}
|
||||
|
||||
if (!$update) {
|
||||
|
@ -2311,7 +2387,7 @@ class Contact
|
|||
Group::addMember(User::getDefaultGroup($user['uid'], $contact["network"]), $contact_id);
|
||||
|
||||
// Update the avatar
|
||||
self::updateAvatar($ret['photo'], $user['uid'], $contact_id);
|
||||
self::updateAvatar($contact_id, $ret['photo']);
|
||||
|
||||
// pull feed and consume it, which should subscribe to the hub.
|
||||
|
||||
|
@ -2479,7 +2555,6 @@ class Contact
|
|||
'nurl' => Strings::normaliseLink($url),
|
||||
'name' => $name,
|
||||
'nick' => $nick,
|
||||
'photo' => $photo,
|
||||
'network' => $network,
|
||||
'rel' => self::FOLLOWER,
|
||||
'blocked' => 0,
|
||||
|
@ -2493,7 +2568,7 @@ class Contact
|
|||
// Ensure to always have the correct network type, independent from the connection request method
|
||||
self::updateFromProbe($contact_id, '', true);
|
||||
|
||||
Contact::updateAvatar($photo, $importer["uid"], $contact_id, true);
|
||||
self::updateAvatar($contact_id, $photo, true);
|
||||
|
||||
$contact_record = DBA::selectFirst('contact', ['id', 'network', 'name', 'url', 'photo'], ['id' => $contact_id]);
|
||||
|
||||
|
|
171
src/Model/ContactRelation.php
Normal file
171
src/Model/ContactRelation.php
Normal file
|
@ -0,0 +1,171 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2020, Friendica
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Friendica\Model;
|
||||
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\Protocol;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Protocol\ActivityPub;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
use Friendica\Util\Strings;
|
||||
|
||||
class ContactRelation
|
||||
{
|
||||
/**
|
||||
* No discovery of followers/followings
|
||||
*/
|
||||
const DISCOVERY_NONE = 0;
|
||||
/**
|
||||
* Discover followers/followings of local contacts
|
||||
*/
|
||||
const DISCOVERY_LOCAL = 1;
|
||||
/**
|
||||
* Discover followers/followings of local contacts and contacts that visibly interacted on the system
|
||||
*/
|
||||
const DISCOVERY_INTERACTOR = 2;
|
||||
/**
|
||||
* Discover followers/followings of all contacts
|
||||
*/
|
||||
const DISCOVERY_ALL = 3;
|
||||
|
||||
public static function store(int $target, int $actor, string $interaction_date)
|
||||
{
|
||||
if ($actor == $target) {
|
||||
return;
|
||||
}
|
||||
|
||||
DBA::update('contact-relation', ['last-interaction' => $interaction_date], ['cid' => $target, 'relation-cid' => $actor], true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the followers of a given profile and adds them
|
||||
*
|
||||
* @param string $url URL of a profile
|
||||
* @return void
|
||||
*/
|
||||
public static function discoverByUrl(string $url)
|
||||
{
|
||||
$contact_discovery = DI::config()->get('system', 'contact_discovery');
|
||||
|
||||
if ($contact_discovery == self::DISCOVERY_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
$contact = Contact::getByURL($url);
|
||||
if (empty($contact)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($contact['last-discovery'] > DateTimeFormat::utc('now - 1 month')) {
|
||||
Logger::info('No discovery - Last was less than a month ago.', ['id' => $contact['id'], 'url' => $url, 'discovery' => $contact['last-discovery']]);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($contact_discovery != self::DISCOVERY_ALL) {
|
||||
$local = DBA::exists('contact', ["`nurl` = ? AND `uid` != ?", Strings::normaliseLink($url), 0]);
|
||||
if (($contact_discovery == self::DISCOVERY_LOCAL) && !$local) {
|
||||
Logger::info('No discovery - This contact is not followed/following locally.', ['id' => $contact['id'], 'url' => $url]);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($contact_discovery == self::DISCOVERY_INTERACTOR) {
|
||||
$interactor = DBA::exists('contact-relation', ["`relation-cid` = ? AND `last-interaction` > ?", $contact['id'], DBA::NULL_DATETIME]);
|
||||
if (!$local && !$interactor) {
|
||||
Logger::info('No discovery - This contact is not interacting locally.', ['id' => $contact['id'], 'url' => $url]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} elseif ($contact['created'] > DateTimeFormat::utc('now - 1 day')) {
|
||||
// Newly created contacts are not discovered to avoid DDoS attacks
|
||||
Logger::info('No discovery - Contact record is less than a day old.', ['id' => $contact['id'], 'url' => $url, 'discovery' => $contact['created']]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::OSTATUS])) {
|
||||
// The contact is (most likely) speaking AP, so updating is allowed
|
||||
$apcontact = APContact::getByURL($url);
|
||||
} else {
|
||||
// The contact isn't obviously speaking AP, so we don't allow updating
|
||||
$apcontact = APContact::getByURL($url, false);
|
||||
}
|
||||
|
||||
if (!empty($apcontact['followers']) && is_string($apcontact['followers'])) {
|
||||
$followers = ActivityPub::fetchItems($apcontact['followers']);
|
||||
} else {
|
||||
$followers = [];
|
||||
}
|
||||
|
||||
if (!empty($apcontact['following']) && is_string($apcontact['following'])) {
|
||||
$followings = ActivityPub::fetchItems($apcontact['following']);
|
||||
} else {
|
||||
$followings = [];
|
||||
}
|
||||
|
||||
if (empty($followers) && empty($followings)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$target = $contact['id'];
|
||||
|
||||
if (!empty($followers)) {
|
||||
// Clear the follower list, since it will be recreated in the next step
|
||||
DBA::update('contact-relation', ['follows' => false], ['cid' => $target]);
|
||||
}
|
||||
|
||||
$contacts = [];
|
||||
foreach (array_merge($followers, $followings) as $contact) {
|
||||
if (is_string($contact)) {
|
||||
$contacts[] = $contact;
|
||||
} elseif (!empty($contact['url']) && is_string($contact['url'])) {
|
||||
$contacts[] = $contact['url'];
|
||||
}
|
||||
}
|
||||
$contacts = array_unique($contacts);
|
||||
|
||||
Logger::info('Discover contacts', ['id' => $target, 'url' => $url, 'contacts' => count($contacts)]);
|
||||
foreach ($contacts as $contact) {
|
||||
$actor = Contact::getIdForURL($contact);
|
||||
if (!empty($actor)) {
|
||||
$fields = [];
|
||||
if (in_array($contact, $followers)) {
|
||||
$fields = ['cid' => $target, 'relation-cid' => $actor];
|
||||
} elseif (in_array($contact, $followings)) {
|
||||
$fields = ['cid' => $actor, 'relation-cid' => $target];
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
DBA::update('contact-relation', ['follows' => true, 'follow-updated' => DateTimeFormat::utcNow()], $fields, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($followers)) {
|
||||
// Delete all followers that aren't followers anymore (and aren't interacting)
|
||||
DBA::delete('contact-relation', ['cid' => $target, 'follows' => false, 'last-interaction' => DBA::NULL_DATETIME]);
|
||||
}
|
||||
|
||||
DBA::update('contact', ['last-discovery' => DateTimeFormat::utcNow()], ['id' => $target]);
|
||||
Logger::info('Contacts discovery finished, "last-discovery" set', ['id' => $target, 'url' => $url]);
|
||||
return;
|
||||
}
|
||||
}
|
|
@ -271,8 +271,6 @@ class FileTag
|
|||
if (!strlen($saved) || !stristr($saved, '[' . self::encode($file) . ']')) {
|
||||
DI::pConfig()->set($uid, 'system', 'filetags', $saved . '[' . self::encode($file) . ']');
|
||||
}
|
||||
|
||||
info(DI::l10n()->t('Item filed'));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -26,8 +26,8 @@ use DOMXPath;
|
|||
use Exception;
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\Protocol;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Core\Search;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Core\Worker;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
|
@ -43,19 +43,6 @@ use Friendica\Util\Strings;
|
|||
*/
|
||||
class GContact
|
||||
{
|
||||
/**
|
||||
* No discovery of followers/followings
|
||||
*/
|
||||
const DISCOVERY_NONE = 0;
|
||||
/**
|
||||
* Only discover followers/followings from direct contacts
|
||||
*/
|
||||
const DISCOVERY_DIRECT = 1;
|
||||
/**
|
||||
* Recursive discovery of followers/followings
|
||||
*/
|
||||
const DISCOVERY_RECURSIVE = 2;
|
||||
|
||||
/**
|
||||
* Search global contact table by nick or name
|
||||
*
|
||||
|
@ -537,7 +524,7 @@ class GContact
|
|||
$done[] = DI::baseUrl() . '/poco';
|
||||
|
||||
if (strlen(DI::config()->get('system', 'directory'))) {
|
||||
$x = Network::fetchUrl(Search::getGlobalDirectory() . '/pubsites');
|
||||
$x = DI::httpRequest()->fetch(Search::getGlobalDirectory() . '/pubsites');
|
||||
if (!empty($x)) {
|
||||
$j = json_decode($x);
|
||||
if (!empty($j->entries)) {
|
||||
|
@ -845,7 +832,7 @@ class GContact
|
|||
return false;
|
||||
}
|
||||
|
||||
$curlResult = Network::curl($gserver['noscrape'] . '/' . $data['nick']);
|
||||
$curlResult = DI::httpRequest()->get($gserver['noscrape'] . '/' . $data['nick']);
|
||||
|
||||
if ($curlResult->isSuccess() && !empty($curlResult->getBody())) {
|
||||
$noscrape = json_decode($curlResult->getBody(), true);
|
||||
|
@ -927,7 +914,7 @@ class GContact
|
|||
private static function updateFromFeed(array $data)
|
||||
{
|
||||
// Search for the newest entry in the feed
|
||||
$curlResult = Network::curl($data['poll']);
|
||||
$curlResult = DI::httpRequest()->get($data['poll']);
|
||||
if (!$curlResult->isSuccess()) {
|
||||
$fields = ['failed' => true, 'last_failure' => DateTimeFormat::utcNow()];
|
||||
DBA::update('gcontact', $fields, ['nurl' => Strings::normaliseLink($data['url'])]);
|
||||
|
@ -1205,7 +1192,7 @@ class GContact
|
|||
|
||||
$url = $server . '/main/statistics';
|
||||
|
||||
$curlResult = Network::curl($url);
|
||||
$curlResult = DI::httpRequest()->get($url);
|
||||
if (!$curlResult->isSuccess()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1288,129 +1275,6 @@ class GContact
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the followers of a given profile and adds them
|
||||
*
|
||||
* @param string $url URL of a profile
|
||||
* @return void
|
||||
*/
|
||||
public static function discoverFollowers(string $url)
|
||||
{
|
||||
$gcontact = DBA::selectFirst('gcontact', ['id', 'last_discovery'], ['nurl' => Strings::normaliseLink(($url))]);
|
||||
if (!DBA::isResult($gcontact)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($gcontact['last_discovery'] > DateTimeFormat::utc('now - 1 month')) {
|
||||
Logger::info('Last discovery was less then a month before.', ['url' => $url, 'discovery' => $gcontact['last_discovery']]);
|
||||
return;
|
||||
}
|
||||
|
||||
$gcid = $gcontact['id'];
|
||||
|
||||
$apcontact = APContact::getByURL($url);
|
||||
|
||||
if (!empty($apcontact['followers']) && is_string($apcontact['followers'])) {
|
||||
$followers = ActivityPub::fetchItems($apcontact['followers']);
|
||||
} else {
|
||||
$followers = [];
|
||||
}
|
||||
|
||||
if (!empty($apcontact['following']) && is_string($apcontact['following'])) {
|
||||
$followings = ActivityPub::fetchItems($apcontact['following']);
|
||||
} else {
|
||||
$followings = [];
|
||||
}
|
||||
|
||||
if (!empty($followers) || !empty($followings)) {
|
||||
if (!empty($followers)) {
|
||||
// Clear the follower list, since it will be recreated in the next step
|
||||
DBA::update('gfollower', ['deleted' => true], ['gcid' => $gcid]);
|
||||
}
|
||||
|
||||
$contacts = [];
|
||||
foreach (array_merge($followers, $followings) as $contact) {
|
||||
if (is_string($contact)) {
|
||||
$contacts[] = $contact;
|
||||
} elseif (!empty($contact['url']) && is_string($contact['url'])) {
|
||||
$contacts[] = $contact['url'];
|
||||
}
|
||||
}
|
||||
$contacts = array_unique($contacts);
|
||||
|
||||
Logger::info('Discover AP contacts', ['url' => $url, 'contacts' => count($contacts)]);
|
||||
foreach ($contacts as $contact) {
|
||||
$gcontact = DBA::selectFirst('gcontact', ['id'], ['nurl' => Strings::normaliseLink(($contact))]);
|
||||
if (DBA::isResult($gcontact)) {
|
||||
$fields = [];
|
||||
if (in_array($contact, $followers)) {
|
||||
$fields = ['gcid' => $gcid, 'follower-gcid' => $gcontact['id']];
|
||||
} elseif (in_array($contact, $followings)) {
|
||||
$fields = ['gcid' => $gcontact['id'], 'follower-gcid' => $gcid];
|
||||
}
|
||||
|
||||
if (!empty($fields)) {
|
||||
Logger::info('Set relation between contacts', $fields);
|
||||
DBA::update('gfollower', ['deleted' => false], $fields, true);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Network::isUrlBlocked($contact)) {
|
||||
Logger::info('Discover new AP contact', ['url' => $contact]);
|
||||
Worker::add(PRIORITY_LOW, 'UpdateGContact', $contact, 'nodiscover');
|
||||
} else {
|
||||
Logger::info('No discovery, the URL is blocked.', ['url' => $contact]);
|
||||
}
|
||||
}
|
||||
if (!empty($followers)) {
|
||||
// Delete all followers that aren't undeleted
|
||||
DBA::delete('gfollower', ['gcid' => $gcid, 'deleted' => true]);
|
||||
}
|
||||
|
||||
DBA::update('gcontact', ['last_discovery' => DateTimeFormat::utcNow()], ['id' => $gcid]);
|
||||
Logger::info('AP contacts discovery finished, last discovery set', ['url' => $url]);
|
||||
return;
|
||||
}
|
||||
|
||||
$data = Probe::uri($url);
|
||||
if (empty($data['poco'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$curlResult = Network::curl($data['poco']);
|
||||
if (!$curlResult->isSuccess()) {
|
||||
return;
|
||||
}
|
||||
$poco = json_decode($curlResult->getBody(), true);
|
||||
if (empty($poco['entry'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
Logger::info('PoCo Discovery started', ['url' => $url, 'contacts' => count($poco['entry'])]);
|
||||
|
||||
foreach ($poco['entry'] as $entries) {
|
||||
if (!empty($entries['urls'])) {
|
||||
foreach ($entries['urls'] as $entry) {
|
||||
if ($entry['type'] == 'profile') {
|
||||
if (DBA::exists('gcontact', ['nurl' => Strings::normaliseLink(($entry['value']))])) {
|
||||
continue;
|
||||
}
|
||||
if (!Network::isUrlBlocked($entry['value'])) {
|
||||
Logger::info('Discover new PoCo contact', ['url' => $entry['value']]);
|
||||
Worker::add(PRIORITY_LOW, 'UpdateGContact', $entry['value'], 'nodiscover');
|
||||
} else {
|
||||
Logger::info('No discovery, the URL is blocked.', ['url' => $entry['value']]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DBA::update('gcontact', ['last_discovery' => DateTimeFormat::utcNow()], ['id' => $gcid]);
|
||||
Logger::info('PoCo Discovery finished', ['url' => $url]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a random, global contact of the current node
|
||||
*
|
||||
|
|
|
@ -23,20 +23,20 @@ namespace Friendica\Model;
|
|||
|
||||
use DOMDocument;
|
||||
use DOMXPath;
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\Protocol;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Core\Worker;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Module\Register;
|
||||
use Friendica\Network\CurlResult;
|
||||
use Friendica\Util\Network;
|
||||
use Friendica\Protocol\Diaspora;
|
||||
use Friendica\Protocol\PortableContact;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
use Friendica\Util\Network;
|
||||
use Friendica\Util\Strings;
|
||||
use Friendica\Util\XML;
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Protocol\PortableContact;
|
||||
use Friendica\Protocol\Diaspora;
|
||||
|
||||
/**
|
||||
* This class handles GServer related functions
|
||||
|
@ -309,7 +309,7 @@ class GServer
|
|||
|
||||
// When a nodeinfo is present, we don't need to dig further
|
||||
$xrd_timeout = DI::config()->get('system', 'xrd_timeout');
|
||||
$curlResult = Network::curl($url . '/.well-known/nodeinfo', false, ['timeout' => $xrd_timeout]);
|
||||
$curlResult = DI::httpRequest()->get($url . '/.well-known/nodeinfo', false, ['timeout' => $xrd_timeout]);
|
||||
if ($curlResult->isTimeout()) {
|
||||
self::setFailure($url);
|
||||
return false;
|
||||
|
@ -342,7 +342,7 @@ class GServer
|
|||
$basedata = ['detection-method' => self::DETECT_MANUAL];
|
||||
}
|
||||
|
||||
$curlResult = Network::curl($baseurl, false, ['timeout' => $xrd_timeout]);
|
||||
$curlResult = DI::httpRequest()->get($baseurl, false, ['timeout' => $xrd_timeout]);
|
||||
if ($curlResult->isSuccess()) {
|
||||
$basedata = self::analyseRootHeader($curlResult, $basedata);
|
||||
$basedata = self::analyseRootBody($curlResult, $basedata, $baseurl);
|
||||
|
@ -359,7 +359,7 @@ class GServer
|
|||
// When the base path doesn't seem to contain a social network we try the complete path.
|
||||
// Most detectable system have to be installed in the root directory.
|
||||
// We checked the base to avoid false positives.
|
||||
$curlResult = Network::curl($url, false, ['timeout' => $xrd_timeout]);
|
||||
$curlResult = DI::httpRequest()->get($url, false, ['timeout' => $xrd_timeout]);
|
||||
if ($curlResult->isSuccess()) {
|
||||
$urldata = self::analyseRootHeader($curlResult, $serverdata);
|
||||
$urldata = self::analyseRootBody($curlResult, $urldata, $url);
|
||||
|
@ -498,7 +498,7 @@ class GServer
|
|||
{
|
||||
Logger::info('Discover relay data', ['server' => $server_url]);
|
||||
|
||||
$curlResult = Network::curl($server_url . '/.well-known/x-social-relay');
|
||||
$curlResult = DI::httpRequest()->get($server_url . '/.well-known/x-social-relay');
|
||||
if (!$curlResult->isSuccess()) {
|
||||
return;
|
||||
}
|
||||
|
@ -579,7 +579,7 @@ class GServer
|
|||
*/
|
||||
private static function fetchStatistics(string $url)
|
||||
{
|
||||
$curlResult = Network::curl($url . '/statistics.json');
|
||||
$curlResult = DI::httpRequest()->get($url . '/statistics.json');
|
||||
if (!$curlResult->isSuccess()) {
|
||||
return [];
|
||||
}
|
||||
|
@ -689,7 +689,8 @@ class GServer
|
|||
*/
|
||||
private static function parseNodeinfo1(string $nodeinfo_url)
|
||||
{
|
||||
$curlResult = Network::curl($nodeinfo_url);
|
||||
$curlResult = DI::httpRequest()->get($nodeinfo_url);
|
||||
|
||||
if (!$curlResult->isSuccess()) {
|
||||
return [];
|
||||
}
|
||||
|
@ -765,7 +766,7 @@ class GServer
|
|||
*/
|
||||
private static function parseNodeinfo2(string $nodeinfo_url)
|
||||
{
|
||||
$curlResult = Network::curl($nodeinfo_url);
|
||||
$curlResult = DI::httpRequest()->get($nodeinfo_url);
|
||||
if (!$curlResult->isSuccess()) {
|
||||
return [];
|
||||
}
|
||||
|
@ -842,7 +843,7 @@ class GServer
|
|||
*/
|
||||
private static function fetchSiteinfo(string $url, array $serverdata)
|
||||
{
|
||||
$curlResult = Network::curl($url . '/siteinfo.json');
|
||||
$curlResult = DI::httpRequest()->get($url . '/siteinfo.json');
|
||||
if (!$curlResult->isSuccess()) {
|
||||
return $serverdata;
|
||||
}
|
||||
|
@ -911,7 +912,7 @@ class GServer
|
|||
private static function validHostMeta(string $url)
|
||||
{
|
||||
$xrd_timeout = DI::config()->get('system', 'xrd_timeout');
|
||||
$curlResult = Network::curl($url . '/.well-known/host-meta', false, ['timeout' => $xrd_timeout]);
|
||||
$curlResult = DI::httpRequest()->get($url . '/.well-known/host-meta', false, ['timeout' => $xrd_timeout]);
|
||||
if (!$curlResult->isSuccess()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1007,7 +1008,7 @@ class GServer
|
|||
{
|
||||
$serverdata['poco'] = '';
|
||||
|
||||
$curlResult = Network::curl($url. '/poco');
|
||||
$curlResult = DI::httpRequest()->get($url . '/poco');
|
||||
if (!$curlResult->isSuccess()) {
|
||||
return $serverdata;
|
||||
}
|
||||
|
@ -1037,7 +1038,7 @@ class GServer
|
|||
*/
|
||||
public static function checkMastodonDirectory(string $url, array $serverdata)
|
||||
{
|
||||
$curlResult = Network::curl($url . '/api/v1/directory?limit=1');
|
||||
$curlResult = DI::httpRequest()->get($url . '/api/v1/directory?limit=1');
|
||||
if (!$curlResult->isSuccess()) {
|
||||
return $serverdata;
|
||||
}
|
||||
|
@ -1064,7 +1065,8 @@ class GServer
|
|||
*/
|
||||
private static function detectNextcloud(string $url, array $serverdata)
|
||||
{
|
||||
$curlResult = Network::curl($url . '/status.php');
|
||||
$curlResult = DI::httpRequest()->get($url . '/status.php');
|
||||
|
||||
if (!$curlResult->isSuccess() || ($curlResult->getBody() == '')) {
|
||||
return $serverdata;
|
||||
}
|
||||
|
@ -1097,7 +1099,8 @@ class GServer
|
|||
*/
|
||||
private static function detectMastodonAlikes(string $url, array $serverdata)
|
||||
{
|
||||
$curlResult = Network::curl($url . '/api/v1/instance');
|
||||
$curlResult = DI::httpRequest()->get($url . '/api/v1/instance');
|
||||
|
||||
if (!$curlResult->isSuccess() || ($curlResult->getBody() == '')) {
|
||||
return $serverdata;
|
||||
}
|
||||
|
@ -1162,7 +1165,7 @@ class GServer
|
|||
*/
|
||||
private static function detectHubzilla(string $url, array $serverdata)
|
||||
{
|
||||
$curlResult = Network::curl($url . '/api/statusnet/config.json');
|
||||
$curlResult = DI::httpRequest()->get($url . '/api/statusnet/config.json');
|
||||
if (!$curlResult->isSuccess() || ($curlResult->getBody() == '')) {
|
||||
return $serverdata;
|
||||
}
|
||||
|
@ -1260,7 +1263,7 @@ class GServer
|
|||
private static function detectGNUSocial(string $url, array $serverdata)
|
||||
{
|
||||
// Test for GNU Social
|
||||
$curlResult = Network::curl($url . '/api/gnusocial/version.json');
|
||||
$curlResult = DI::httpRequest()->get($url . '/api/gnusocial/version.json');
|
||||
if ($curlResult->isSuccess() && ($curlResult->getBody() != '{"error":"not implemented"}') &&
|
||||
($curlResult->getBody() != '') && (strlen($curlResult->getBody()) < 30)) {
|
||||
$serverdata['platform'] = 'gnusocial';
|
||||
|
@ -1278,7 +1281,7 @@ class GServer
|
|||
}
|
||||
|
||||
// Test for Statusnet
|
||||
$curlResult = Network::curl($url . '/api/statusnet/version.json');
|
||||
$curlResult = DI::httpRequest()->get($url . '/api/statusnet/version.json');
|
||||
if ($curlResult->isSuccess() && ($curlResult->getBody() != '{"error":"not implemented"}') &&
|
||||
($curlResult->getBody() != '') && (strlen($curlResult->getBody()) < 30)) {
|
||||
|
||||
|
@ -1314,9 +1317,9 @@ class GServer
|
|||
*/
|
||||
private static function detectFriendica(string $url, array $serverdata)
|
||||
{
|
||||
$curlResult = Network::curl($url . '/friendica/json');
|
||||
$curlResult = DI::httpRequest()->get($url . '/friendica/json');
|
||||
if (!$curlResult->isSuccess()) {
|
||||
$curlResult = Network::curl($url . '/friendika/json');
|
||||
$curlResult = DI::httpRequest()->get($url . '/friendika/json');
|
||||
$friendika = true;
|
||||
$platform = 'Friendika';
|
||||
} else {
|
||||
|
@ -1631,7 +1634,7 @@ class GServer
|
|||
$protocols = ['activitypub', 'diaspora', 'dfrn', 'ostatus'];
|
||||
foreach ($protocols as $protocol) {
|
||||
$query = '{nodes(protocol:"' . $protocol . '"){host}}';
|
||||
$curlResult = Network::fetchUrl('https://the-federation.info/graphql?query=' . urlencode($query));
|
||||
$curlResult = DI::httpRequest()->fetch('https://the-federation.info/graphql?query=' . urlencode($query));
|
||||
if (!empty($curlResult)) {
|
||||
$data = json_decode($curlResult, true);
|
||||
if (!empty($data['data']['nodes'])) {
|
||||
|
@ -1649,7 +1652,8 @@ class GServer
|
|||
if (!empty($accesstoken)) {
|
||||
$api = 'https://instances.social/api/1.0/instances/list?count=0';
|
||||
$header = ['Authorization: Bearer '.$accesstoken];
|
||||
$curlResult = Network::curl($api, false, ['headers' => $header]);
|
||||
$curlResult = DI::httpRequest()->get($api, false, ['headers' => $header]);
|
||||
|
||||
if ($curlResult->isSuccess()) {
|
||||
$servers = json_decode($curlResult->getBody(), true);
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@ class Group
|
|||
$group = DBA::selectFirst('group', ['deleted'], ['id' => $gid]);
|
||||
if (DBA::isResult($group) && $group['deleted']) {
|
||||
DBA::update('group', ['deleted' => 0], ['id' => $gid]);
|
||||
notice(DI::l10n()->t('A deleted group with this name was revived. Existing item permissions <strong>may</strong> apply to this group and any future members. If this is not what you intended, please create another group with a different name.') . EOL);
|
||||
notice(DI::l10n()->t('A deleted group with this name was revived. Existing item permissions <strong>may</strong> apply to this group and any future members. If this is not what you intended, please create another group with a different name.'));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1554,9 +1554,7 @@ class Item
|
|||
}
|
||||
|
||||
// Update the contact relations
|
||||
if ($item['author-id'] != $parent['author-id']) {
|
||||
DBA::update('contact-relation', ['last-interaction' => $item['created']], ['cid' => $parent['author-id'], 'relation-cid' => $item['author-id']], true);
|
||||
}
|
||||
ContactRelation::store($parent['author-id'], $item['author-id'], $item['created']);
|
||||
}
|
||||
|
||||
return $item;
|
||||
|
@ -1703,6 +1701,10 @@ class Item
|
|||
'photo' => $item['owner-avatar'], 'network' => $item['network']];
|
||||
$item['owner-id'] = ($item['owner-id'] ?? 0) ?: Contact::getIdForURL($item['owner-link'], 0, null, $default);
|
||||
|
||||
// Ensure that there is an avatar cache
|
||||
Contact::checkAvatarCache($item['author-id']);
|
||||
Contact::checkAvatarCache($item['owner-id']);
|
||||
|
||||
// The contact-id should be set before "self::insert" was called - but there seems to be issues sometimes
|
||||
$item["contact-id"] = self::contactId($item);
|
||||
|
||||
|
@ -3696,7 +3698,7 @@ class Item
|
|||
*
|
||||
* @return integer item id
|
||||
*/
|
||||
public static function fetchByLink($uri, $uid = 0)
|
||||
public static function fetchByLink(string $uri, int $uid = 0)
|
||||
{
|
||||
$item_id = self::searchByLink($uri, $uid);
|
||||
if (!empty($item_id)) {
|
||||
|
@ -3749,7 +3751,7 @@ class Item
|
|||
*
|
||||
* @return array item array with data from the original item
|
||||
*/
|
||||
public static function addShareDataFromOriginal($item)
|
||||
public static function addShareDataFromOriginal(array $item)
|
||||
{
|
||||
$shared = self::getShareArray($item);
|
||||
if (empty($shared)) {
|
||||
|
@ -3771,9 +3773,9 @@ class Item
|
|||
}
|
||||
|
||||
// Otherwhise try to find (and possibly fetch) the item via the link. This should work for Diaspora and ActivityPub posts
|
||||
$id = self::fetchByLink($shared['link'], $uid);
|
||||
$id = self::fetchByLink($shared['link'] ?? '', $uid);
|
||||
if (empty($id)) {
|
||||
Logger::info('Original item not found', ['url' => $shared['link'], 'callstack' => System::callstack()]);
|
||||
Logger::info('Original item not found', ['url' => $shared['link'] ?? '', 'callstack' => System::callstack()]);
|
||||
return $item;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,6 @@ use Friendica\Model\Storage\SystemResource;
|
|||
use Friendica\Object\Image;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
use Friendica\Util\Images;
|
||||
use Friendica\Util\Network;
|
||||
use Friendica\Util\Security;
|
||||
use Friendica\Util\Strings;
|
||||
|
||||
|
@ -421,7 +420,7 @@ class Photo
|
|||
|
||||
$filename = basename($image_url);
|
||||
if (!empty($image_url)) {
|
||||
$ret = Network::curl($image_url, true);
|
||||
$ret = DI::httpRequest()->get($image_url, true);
|
||||
$img_str = $ret->getBody();
|
||||
$type = $ret->getContentType();
|
||||
} else {
|
||||
|
|
|
@ -737,7 +737,7 @@ class Profile
|
|||
$magic_path = $basepath . '/magic' . '?owa=1&dest=' . $dest . '&' . $addr_request;
|
||||
|
||||
// We have to check if the remote server does understand /magic without invoking something
|
||||
$serverret = Network::curl($basepath . '/magic');
|
||||
$serverret = DI::httpRequest()->get($basepath . '/magic');
|
||||
if ($serverret->isSuccess()) {
|
||||
Logger::log('Doing magic auth for visitor ' . $my_url . ' to ' . $magic_path, Logger::DEBUG);
|
||||
System::externalRedirect($magic_path);
|
||||
|
|
|
@ -823,7 +823,7 @@ class User
|
|||
$photo_failure = false;
|
||||
|
||||
$filename = basename($photo);
|
||||
$curlResult = Network::curl($photo, true);
|
||||
$curlResult = DI::httpRequest()->get($photo, true);
|
||||
if ($curlResult->isSuccess()) {
|
||||
$img_str = $curlResult->getBody();
|
||||
$type = $curlResult->getContentType();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue