mirror of
https://github.com/friendica/friendica
synced 2025-04-28 13:04:23 +02:00
Merge branch 'stable' into develop
This commit is contained in:
commit
95229140f8
194 changed files with 11224 additions and 9691 deletions
|
@ -287,6 +287,7 @@ class APContact
|
|||
} elseif ($apcontact['type'] == 'Tombstone') {
|
||||
// The "inbox" field must have a content
|
||||
$apcontact['inbox'] = '';
|
||||
$apcontact['addr'] = '';
|
||||
}
|
||||
|
||||
// Quit if this doesn't seem to be an account at all
|
||||
|
@ -294,7 +295,7 @@ class APContact
|
|||
return $fetched_contact;
|
||||
}
|
||||
|
||||
if (empty($apcontact['addr'])) {
|
||||
if (empty($apcontact['addr']) && ($apcontact['type'] != 'Tombstone')) {
|
||||
try {
|
||||
$apcontact['addr'] = $apcontact['nick'] . '@' . (new Uri($apcontact['url']))->getAuthority();
|
||||
} catch (\Throwable $e) {
|
||||
|
|
|
@ -245,6 +245,7 @@ class Attach
|
|||
* @param string $src Source file name
|
||||
* @param int $uid User id
|
||||
* @param string $filename Optional file name
|
||||
* @param string $filetype Optional file type
|
||||
* @param string $allow_cid
|
||||
* @param string $allow_gid
|
||||
* @param string $deny_cid
|
||||
|
@ -252,7 +253,7 @@ class Attach
|
|||
* @return boolean|int Insert id or false on failure
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public static function storeFile(string $src, int $uid, string $filename = '', string $allow_cid = '', string $allow_gid = '', string $deny_cid = '', string $deny_gid = '')
|
||||
public static function storeFile(string $src, int $uid, string $filename = '', string $filetype = '', string $allow_cid = '', string $allow_gid = '', string $deny_cid = '', string $deny_gid = '')
|
||||
{
|
||||
if ($filename === '') {
|
||||
$filename = basename($src);
|
||||
|
@ -260,7 +261,7 @@ class Attach
|
|||
|
||||
$data = @file_get_contents($src);
|
||||
|
||||
return self::store($data, $uid, $filename, '', null, $allow_cid, $allow_gid, $deny_cid, $deny_gid);
|
||||
return self::store($data, $uid, $filename, $filetype, null, $allow_cid, $allow_gid, $deny_cid, $deny_gid);
|
||||
}
|
||||
|
||||
|
||||
|
@ -345,6 +346,16 @@ class Attach
|
|||
}
|
||||
}
|
||||
|
||||
public static function setPermissionForId(int $id, int $uid, string $str_contact_allow, string $str_circle_allow, string $str_contact_deny, string $str_circle_deny)
|
||||
{
|
||||
$fields = [
|
||||
'allow_cid' => $str_contact_allow, 'allow_gid' => $str_circle_allow,
|
||||
'deny_cid' => $str_contact_deny, 'deny_gid' => $str_circle_deny,
|
||||
];
|
||||
|
||||
self::update($fields, ['id' => $id, 'uid' => $uid]);
|
||||
}
|
||||
|
||||
public static function addAttachmentToBody(string $body, int $uid): string
|
||||
{
|
||||
preg_match_all("/\[attachment\](.*?)\[\/attachment\]/ism", $body, $matches, PREG_SET_ORDER);
|
||||
|
|
|
@ -290,12 +290,12 @@ class Circle
|
|||
throw new HTTPException\NotFoundException('Circle not found.');
|
||||
}
|
||||
|
||||
$cdata = Contact::getPublicAndUserContactID($cid, $circle['uid']);
|
||||
if (empty($cdata['user'])) {
|
||||
$ucid = Contact::getUserContactId($cid, $circle['uid']);
|
||||
if (!$ucid) {
|
||||
throw new HTTPException\NotFoundException('Invalid contact.');
|
||||
}
|
||||
|
||||
return DBA::insert('group_member', ['gid' => $gid, 'contact-id' => $cdata['user']], Database::INSERT_IGNORE);
|
||||
return DBA::insert('group_member', ['gid' => $gid, 'contact-id' => $ucid], Database::INSERT_IGNORE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -318,12 +318,12 @@ class Circle
|
|||
throw new HTTPException\NotFoundException('Circle not found.');
|
||||
}
|
||||
|
||||
$cdata = Contact::getPublicAndUserContactID($cid, $circle['uid']);
|
||||
if (empty($cdata['user'])) {
|
||||
$ucid = Contact::getUserContactId($cid, $circle['uid']);
|
||||
if (!$ucid) {
|
||||
throw new HTTPException\NotFoundException('Invalid contact.');
|
||||
}
|
||||
|
||||
return DBA::delete('group_member', ['gid' => $gid, 'contact-id' => $cid]);
|
||||
return DBA::delete('group_member', ['gid' => $gid, 'contact-id' => $ucid]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -347,12 +347,12 @@ class Circle
|
|||
}
|
||||
|
||||
foreach ($contacts as $cid) {
|
||||
$cdata = Contact::getPublicAndUserContactID($cid, $circle['uid']);
|
||||
if (empty($cdata['user'])) {
|
||||
$ucid = Contact::getUserContactId($cid, $circle['uid']);
|
||||
if (!$ucid) {
|
||||
throw new HTTPException\NotFoundException('Invalid contact.');
|
||||
}
|
||||
|
||||
DBA::insert('group_member', ['gid' => $gid, 'contact-id' => $cdata['user']], Database::INSERT_IGNORE);
|
||||
DBA::insert('group_member', ['gid' => $gid, 'contact-id' => $ucid], Database::INSERT_IGNORE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -379,12 +379,12 @@ class Circle
|
|||
$contactIds = [];
|
||||
|
||||
foreach ($contacts as $cid) {
|
||||
$cdata = Contact::getPublicAndUserContactID($cid, $circle['uid']);
|
||||
if (empty($cdata['user'])) {
|
||||
$ucid = Contact::getUserContactId($cid, $circle['uid']);
|
||||
if (!$ucid) {
|
||||
throw new HTTPException\NotFoundException('Invalid contact.');
|
||||
}
|
||||
|
||||
$contactIds[] = $cdata['user'];
|
||||
$contactIds[] = $ucid;
|
||||
}
|
||||
|
||||
// Return status of deletion
|
||||
|
|
|
@ -444,12 +444,12 @@ class Contact
|
|||
return false;
|
||||
}
|
||||
|
||||
$cdata = self::getPublicAndUserContactID($cid, $uid);
|
||||
if (empty($cdata['user'])) {
|
||||
$ucid = self::getUserContactId($cid, $uid);
|
||||
if (!$ucid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$condition = ['id' => $cdata['user'], 'rel' => [self::FOLLOWER, self::FRIEND]];
|
||||
$condition = ['id' => $ucid, 'rel' => [self::FOLLOWER, self::FRIEND]];
|
||||
if ($strict) {
|
||||
$condition = array_merge($condition, ['pending' => false, 'readonly' => false, 'blocked' => false]);
|
||||
}
|
||||
|
@ -495,12 +495,12 @@ class Contact
|
|||
return false;
|
||||
}
|
||||
|
||||
$cdata = self::getPublicAndUserContactID($cid, $uid);
|
||||
if (empty($cdata['user'])) {
|
||||
$ucid = self::getUserContactId($cid, $uid);
|
||||
if (!$ucid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$condition = ['id' => $cdata['user'], 'rel' => [self::SHARING, self::FRIEND]];
|
||||
$condition = ['id' => $ucid, 'rel' => [self::SHARING, self::FRIEND]];
|
||||
if ($strict) {
|
||||
$condition = array_merge($condition, ['pending' => false, 'readonly' => false, 'blocked' => false]);
|
||||
}
|
||||
|
@ -671,6 +671,32 @@ class Contact
|
|||
return ['public' => $pcid, 'user' => $ucid];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the public contact id of a provided contact id
|
||||
*
|
||||
* @param integer $cid
|
||||
* @param integer $uid
|
||||
* @return integer
|
||||
*/
|
||||
public static function getPublicContactId(int $cid, int $uid): int
|
||||
{
|
||||
$contact = DBA::selectFirst('account-user-view', ['pid'], ['id' => $cid, 'uid' => [0, $uid]]);
|
||||
return $contact['pid'] ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user contact id of a provided contact id
|
||||
*
|
||||
* @param integer $cid
|
||||
* @param integer $uid
|
||||
* @return integer
|
||||
*/
|
||||
public static function getUserContactId(int $cid, int $uid): int
|
||||
{
|
||||
$data = self::getPublicAndUserContactID($cid, $uid);
|
||||
return $data['user'] ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for "getPublicAndUserContactID"
|
||||
*
|
||||
|
@ -968,13 +994,13 @@ class Contact
|
|||
}
|
||||
|
||||
if (in_array($contact['rel'], [self::SHARING, self::FRIEND])) {
|
||||
$cdata = self::getPublicAndUserContactID($contact['id'], $contact['uid']);
|
||||
if (!empty($cdata['public'])) {
|
||||
Worker::add(Worker::PRIORITY_HIGH, 'Contact\Unfollow', $cdata['public'], $contact['uid']);
|
||||
$pcid = self::getPublicContactId($contact['id'], $contact['uid']);
|
||||
if ($pcid) {
|
||||
Worker::add(Worker::PRIORITY_HIGH, 'Contact\Unfollow', $pcid, $contact['uid']);
|
||||
}
|
||||
}
|
||||
|
||||
self::removeSharer($contact);
|
||||
self::removeSharer($contact, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -998,13 +1024,13 @@ class Contact
|
|||
}
|
||||
|
||||
if (in_array($contact['rel'], [self::FOLLOWER, self::FRIEND])) {
|
||||
$cdata = self::getPublicAndUserContactID($contact['id'], $contact['uid']);
|
||||
if (!empty($cdata['public'])) {
|
||||
Worker::add(Worker::PRIORITY_HIGH, 'Contact\RevokeFollow', $cdata['public'], $contact['uid']);
|
||||
$pcid = self::getPublicContactId($contact['id'], $contact['uid']);
|
||||
if ($pcid) {
|
||||
Worker::add(Worker::PRIORITY_HIGH, 'Contact\RevokeFollow', $pcid, $contact['uid']);
|
||||
}
|
||||
}
|
||||
|
||||
self::removeFollower($contact);
|
||||
self::removeFollower($contact, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1025,14 +1051,14 @@ class Contact
|
|||
throw new \InvalidArgumentException('Unexpected public contact record');
|
||||
}
|
||||
|
||||
$cdata = self::getPublicAndUserContactID($contact['id'], $contact['uid']);
|
||||
$pcid = self::getPublicContactId($contact['id'], $contact['uid']);
|
||||
|
||||
if (in_array($contact['rel'], [self::SHARING, self::FRIEND]) && !empty($cdata['public'])) {
|
||||
Worker::add(Worker::PRIORITY_HIGH, 'Contact\Unfollow', $cdata['public'], $contact['uid']);
|
||||
if (in_array($contact['rel'], [self::SHARING, self::FRIEND]) && $pcid) {
|
||||
Worker::add(Worker::PRIORITY_HIGH, 'Contact\Unfollow', $pcid, $contact['uid']);
|
||||
}
|
||||
|
||||
if (in_array($contact['rel'], [self::FOLLOWER, self::FRIEND]) && !empty($cdata['public'])) {
|
||||
Worker::add(Worker::PRIORITY_HIGH, 'Contact\RevokeFollow', $cdata['public'], $contact['uid']);
|
||||
if (in_array($contact['rel'], [self::FOLLOWER, self::FRIEND]) && $pcid) {
|
||||
Worker::add(Worker::PRIORITY_HIGH, 'Contact\RevokeFollow', $pcid, $contact['uid']);
|
||||
}
|
||||
|
||||
self::remove($contact['id']);
|
||||
|
@ -1547,24 +1573,25 @@ class Contact
|
|||
/**
|
||||
* Returns posts from a given contact url
|
||||
*
|
||||
* @param string $contact_url Contact URL
|
||||
* @param bool $thread_mode
|
||||
* @param int $update Update mode
|
||||
* @param int $parent Item parent ID for the update mode
|
||||
* @param bool $only_media Only display media content
|
||||
* @param string $contact_url Contact URL
|
||||
* @param int $uid User ID
|
||||
* @param bool $only_media Only display media content
|
||||
* @param string $last_created Newest creation date, used for paging
|
||||
* @return string posts in HTML
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function getPostsFromUrl(string $contact_url, int $uid, bool $only_media = false): string
|
||||
public static function getPostsFromUrl(string $contact_url, int $uid, bool $only_media = false, string $last_created = null): string
|
||||
{
|
||||
return self::getPostsFromId(self::getIdForURL($contact_url), $uid, $only_media);
|
||||
return self::getPostsFromId(self::getIdForURL($contact_url), $uid, $only_media, $last_created);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns posts from a given contact id
|
||||
*
|
||||
* @param int $cid Contact ID
|
||||
* @param bool $only_media Only display media content
|
||||
* @param int $cid Contact ID
|
||||
* @param int $uid User ID
|
||||
* @param bool $only_media Only display media content
|
||||
* @param string $last_created Newest creation date, used for paging
|
||||
* @return string posts in HTML
|
||||
* @throws \Exception
|
||||
*/
|
||||
|
@ -2666,6 +2693,14 @@ class Contact
|
|||
|
||||
$data = Probe::uri($contact['url'], $network, $contact['uid']);
|
||||
|
||||
if (in_array($data['network'], Protocol::FEDERATED) && (parse_url($data['url'], PHP_URL_SCHEME) == 'http')) {
|
||||
$ssl_url = str_replace('http://', 'https://', $contact['url']);
|
||||
$ssl_data = Probe::uri($ssl_url, $network, $contact['uid']);
|
||||
if (($ssl_data['network'] == $data['network']) && (parse_url($ssl_data['url'], PHP_URL_SCHEME) != 'http')) {
|
||||
$data = $ssl_data;
|
||||
}
|
||||
}
|
||||
|
||||
if ($data['network'] == Protocol::DIASPORA) {
|
||||
try {
|
||||
DI::dsprContact()->updateFromProbeArray($data);
|
||||
|
@ -2824,7 +2859,7 @@ class Contact
|
|||
// We must not try to update relay contacts via probe. They are no real contacts.
|
||||
// See Relay::updateContact() for more details.
|
||||
// We check after the probing to be able to correct falsely detected contact types.
|
||||
if (($contact['contact-type'] == self::TYPE_RELAY) && Strings::compareLink($contact['url'], $contact['baseurl']) &&
|
||||
if (($contact['contact-type'] == self::TYPE_RELAY) && Strings::compareLink($contact['url'], $contact['baseurl'] ?? '') &&
|
||||
(!Strings::compareLink($ret['url'], $contact['url']) || in_array($ret['network'], [Protocol::FEED, Protocol::PHANTOM]))
|
||||
) {
|
||||
if (GServer::reachable($contact)) {
|
||||
|
@ -3013,6 +3048,10 @@ class Contact
|
|||
*/
|
||||
public static function getProtocol(string $url, string $network): string
|
||||
{
|
||||
if (self::isLocal($url)) {
|
||||
return Protocol::ACTIVITYPUB;
|
||||
}
|
||||
|
||||
if ($network != Protocol::DFRN) {
|
||||
return $network;
|
||||
}
|
||||
|
@ -3404,16 +3443,21 @@ class Contact
|
|||
* Update the local relationship when a local user loses a follower
|
||||
*
|
||||
* @param array $contact User-specific contact (uid != 0) array
|
||||
* @param bool $delete Delete if set, otherwise set relation to "nothing" when contact had been a follower
|
||||
* @return void
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
public static function removeFollower(array $contact)
|
||||
public static function removeFollower(array $contact, bool $delete = true)
|
||||
{
|
||||
if (in_array($contact['rel'] ?? [], [self::FRIEND, self::SHARING])) {
|
||||
self::update(['rel' => self::SHARING], ['id' => $contact['id']]);
|
||||
} elseif (!empty($contact['id'])) {
|
||||
self::remove($contact['id']);
|
||||
if ($delete) {
|
||||
self::remove($contact['id']);
|
||||
} else {
|
||||
self::update(['rel' => self::NOTHING, 'pending' => false], ['id' => $contact['id']]);
|
||||
}
|
||||
} else {
|
||||
DI::logger()->info('Couldn\'t remove follower because of invalid contact array', ['contact' => $contact]);
|
||||
return;
|
||||
|
@ -3423,9 +3467,9 @@ class Contact
|
|||
|
||||
self::clearFollowerFollowingEndpointCache($contact['uid']);
|
||||
|
||||
$cdata = self::getPublicAndUserContactID($contact['id'], $contact['uid']);
|
||||
if (!empty($cdata['public'])) {
|
||||
DI::notification()->deleteForUserByVerb($contact['uid'], Activity::FOLLOW, ['actor-id' => $cdata['public']]);
|
||||
$pcid = self::getPublicContactId($contact['id'], $contact['uid']);
|
||||
if ($pcid) {
|
||||
DI::notification()->deleteForUserByVerb($contact['uid'], Activity::FOLLOW, ['actor-id' => $pcid]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3434,14 +3478,19 @@ class Contact
|
|||
* Removes the contact for sharing-only protocols (feed and mail).
|
||||
*
|
||||
* @param array $contact User-specific contact (uid != 0) array
|
||||
* @param bool $delete Delete if set, otherwise set relation to "nothing" when contact had been a sharer
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public static function removeSharer(array $contact)
|
||||
public static function removeSharer(array $contact, bool $delete = true)
|
||||
{
|
||||
self::clearFollowerFollowingEndpointCache($contact['uid']);
|
||||
|
||||
if ($contact['rel'] == self::SHARING || in_array($contact['network'], [Protocol::FEED, Protocol::MAIL])) {
|
||||
self::remove($contact['id']);
|
||||
if (in_array($contact['rel'], [self::SHARING, self::NOTHING]) || in_array($contact['network'], [Protocol::FEED, Protocol::MAIL])) {
|
||||
if ($delete) {
|
||||
self::remove($contact['id']);
|
||||
} else {
|
||||
self::update(['rel' => self::NOTHING, 'pending' => false], ['id' => $contact['id']]);
|
||||
}
|
||||
} else {
|
||||
self::update(['rel' => self::FOLLOWER, 'pending' => false], ['id' => $contact['id']]);
|
||||
}
|
||||
|
@ -3572,6 +3621,9 @@ class Contact
|
|||
}
|
||||
|
||||
$contact = DBA::selectFirst('contact', ['id', 'network', 'url', 'alias', 'uid'], ['id' => $cid]);
|
||||
if (empty($contact)) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
return self::magicLinkByContact($contact, $url);
|
||||
}
|
||||
|
|
|
@ -281,12 +281,12 @@ class User
|
|||
*/
|
||||
public static function setCollapsed(int $cid, int $uid, bool $collapsed)
|
||||
{
|
||||
$cdata = Contact::getPublicAndUserContactID($cid, $uid);
|
||||
if (empty($cdata)) {
|
||||
$pcid = Contact::getPublicContactId($cid, $uid);
|
||||
if (!$pcid) {
|
||||
return;
|
||||
}
|
||||
|
||||
DBA::update('user-contact', ['collapsed' => $collapsed], ['cid' => $cdata['public'], 'uid' => $uid], true);
|
||||
DBA::update('user-contact', ['collapsed' => $collapsed], ['cid' => $pcid, 'uid' => $uid], true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -300,21 +300,13 @@ class User
|
|||
*/
|
||||
public static function isCollapsed(int $cid, int $uid): bool
|
||||
{
|
||||
$cdata = Contact::getPublicAndUserContactID($cid, $uid);
|
||||
if (empty($cdata)) {
|
||||
$pcid = Contact::getPublicContactId($cid, $uid);
|
||||
if (!$pcid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$collapsed = false;
|
||||
|
||||
if (!empty($cdata['public'])) {
|
||||
$public_contact = DBA::selectFirst('user-contact', ['collapsed'], ['cid' => $cdata['public'], 'uid' => $uid]);
|
||||
if (DBA::isResult($public_contact)) {
|
||||
$collapsed = (bool) $public_contact['collapsed'];
|
||||
}
|
||||
}
|
||||
|
||||
return $collapsed;
|
||||
$public_contact = DBA::selectFirst('user-contact', ['collapsed'], ['cid' => $pcid, 'uid' => $uid]);
|
||||
return $public_contact['collapsed'] ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -328,12 +320,12 @@ class User
|
|||
*/
|
||||
public static function setChannelFrequency(int $cid, int $uid, int $frequency)
|
||||
{
|
||||
$cdata = Contact::getPublicAndUserContactID($cid, $uid);
|
||||
if (empty($cdata)) {
|
||||
$pcid = Contact::getPublicContactId($cid, $uid);
|
||||
if (!$pcid) {
|
||||
return;
|
||||
}
|
||||
|
||||
DBA::update('user-contact', ['channel-frequency' => $frequency], ['cid' => $cdata['public'], 'uid' => $uid], true);
|
||||
DBA::update('user-contact', ['channel-frequency' => $frequency], ['cid' => $pcid, 'uid' => $uid], true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -347,21 +339,13 @@ class User
|
|||
*/
|
||||
public static function getChannelFrequency(int $cid, int $uid): int
|
||||
{
|
||||
$cdata = Contact::getPublicAndUserContactID($cid, $uid);
|
||||
if (empty($cdata)) {
|
||||
$pcid = Contact::getPublicContactId($cid, $uid);
|
||||
if (!$pcid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$frequency = self::FREQUENCY_DEFAULT;
|
||||
|
||||
if (!empty($cdata['public'])) {
|
||||
$public_contact = DBA::selectFirst('user-contact', ['channel-frequency'], ['cid' => $cdata['public'], 'uid' => $uid]);
|
||||
if (DBA::isResult($public_contact)) {
|
||||
$frequency = $public_contact['channel-frequency'] ?? self::FREQUENCY_DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
return $frequency;
|
||||
$public_contact = DBA::selectFirst('user-contact', ['channel-frequency'], ['cid' => $pcid, 'uid' => $uid]);
|
||||
return $public_contact['channel-frequency'] ?? self::FREQUENCY_DEFAULT;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -375,12 +359,12 @@ class User
|
|||
*/
|
||||
public static function setChannelOnly(int $cid, int $uid, bool $isChannelOnly)
|
||||
{
|
||||
$cdata = Contact::getPublicAndUserContactID($cid, $uid);
|
||||
if (empty($cdata)) {
|
||||
$pcid = Contact::getPublicContactId($cid, $uid);
|
||||
if (!$pcid) {
|
||||
return;
|
||||
}
|
||||
|
||||
DBA::update('user-contact', ['channel-only' => $isChannelOnly], ['cid' => $cdata['public'], 'uid' => $uid], true);
|
||||
DBA::update('user-contact', ['channel-only' => $isChannelOnly], ['cid' => $pcid, 'uid' => $uid], true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -394,21 +378,13 @@ class User
|
|||
*/
|
||||
public static function getChannelOnly(int $cid, int $uid): bool
|
||||
{
|
||||
$cdata = Contact::getPublicAndUserContactID($cid, $uid);
|
||||
if (empty($cdata)) {
|
||||
$pcid = Contact::getPublicContactId($cid, $uid);
|
||||
if (!$pcid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$isChannelOnly = false;
|
||||
|
||||
if (!empty($cdata['public'])) {
|
||||
$public_contact = DBA::selectFirst('user-contact', ['channel-only'], ['cid' => $cdata['public'], 'uid' => $uid]);
|
||||
if (DBA::isResult($public_contact)) {
|
||||
$isChannelOnly = $public_contact['channel-only'] ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
return $isChannelOnly;
|
||||
$public_contact = DBA::selectFirst('user-contact', ['channel-only'], ['cid' => $pcid, 'uid' => $uid]);
|
||||
return $public_contact['channel-only'] ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -422,12 +398,12 @@ class User
|
|||
*/
|
||||
public static function setIsBlocked(int $cid, int $uid, bool $blocked)
|
||||
{
|
||||
$cdata = Contact::getPublicAndUserContactID($cid, $uid);
|
||||
if (empty($cdata)) {
|
||||
$pcid = Contact::getPublicContactId($cid, $uid);
|
||||
if (!$pcid) {
|
||||
return;
|
||||
}
|
||||
|
||||
DBA::update('user-contact', ['is-blocked' => $blocked], ['cid' => $cdata['public'], 'uid' => $uid], true);
|
||||
DBA::update('user-contact', ['is-blocked' => $blocked], ['cid' => $pcid, 'uid' => $uid], true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -440,18 +416,12 @@ class User
|
|||
*/
|
||||
public static function isIsBlocked(int $cid, int $uid): bool
|
||||
{
|
||||
$cdata = Contact::getPublicAndUserContactID($cid, $uid);
|
||||
if (empty($cdata)) {
|
||||
$pcid = Contact::getPublicContactId($cid, $uid);
|
||||
if (!$pcid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty($cdata['public'])) {
|
||||
$public_contact = DBA::selectFirst('user-contact', ['is-blocked'], ['cid' => $cdata['public'], 'uid' => $uid]);
|
||||
if (DBA::isResult($public_contact)) {
|
||||
return $public_contact['is-blocked'];
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
$public_contact = DBA::selectFirst('user-contact', ['is-blocked'], ['cid' => $pcid, 'uid' => $uid]);
|
||||
return $public_contact['is-blocked'] ?? false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,9 +87,11 @@ class GServer
|
|||
|
||||
// Standardized endpoints
|
||||
const DETECT_STATISTICS_JSON = 100;
|
||||
const DETECT_NODEINFO_1 = 101;
|
||||
const DETECT_NODEINFO_2 = 102;
|
||||
const DETECT_NODEINFO_210 = 103;
|
||||
const DETECT_NODEINFO_10 = 101; // Nodeinfo Version 1.0
|
||||
const DETECT_NODEINFO_20 = 102; // Nodeinfo Version 2.0
|
||||
const DETECT_NODEINFO2_10 = 103; // Nodeinfo2 Version 1.0
|
||||
const DETECT_NODEINFO_21 = 104; // Nodeinfo Version 2.1
|
||||
const DETECT_NODEINFO_22 = 105; // Nodeinfo Version 2.2
|
||||
|
||||
/**
|
||||
* Check for the existence of a server and adds it in the background if not existant
|
||||
|
@ -612,7 +614,7 @@ class GServer
|
|||
$in_webroot = empty(parse_url($url, PHP_URL_PATH));
|
||||
|
||||
// When a nodeinfo is present, we don't need to dig further
|
||||
$curlResult = DI::httpClient()->get($url . '/.well-known/x-nodeinfo2', HttpClientAccept::JSON, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
$curlResult = DI::httpClient()->get($url . '/.well-known/nodeinfo', HttpClientAccept::JSON, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
if ($curlResult->isTimeout()) {
|
||||
self::setFailureByUrl($url);
|
||||
return false;
|
||||
|
@ -621,10 +623,11 @@ class GServer
|
|||
if (!empty($network) && !in_array($network, Protocol::NATIVE_SUPPORT)) {
|
||||
$serverdata = ['detection-method' => self::DETECT_MANUAL, 'network' => $network, 'platform' => '', 'version' => '', 'site_name' => '', 'info' => ''];
|
||||
} else {
|
||||
$serverdata = self::parseNodeinfo210($curlResult);
|
||||
if (empty($serverdata)) {
|
||||
$curlResult = DI::httpClient()->get($url . '/.well-known/nodeinfo', HttpClientAccept::JSON, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
$serverdata = self::fetchNodeinfo($url, $curlResult);
|
||||
$serverdata = self::parseNodeinfo($url, $curlResult);
|
||||
|
||||
if (empty($serverdata) || !in_array($serverdata['detection-method'], [self::DETECT_NODEINFO_20, self::DETECT_NODEINFO_21, self::DETECT_NODEINFO_22])) {
|
||||
$curlResult = DI::httpClient()->get($url . '/.well-known/x-nodeinfo2', HttpClientAccept::JSON, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
$serverdata = self::parseNodeinfo2($curlResult) ?: $serverdata;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1049,7 +1052,9 @@ class GServer
|
|||
}
|
||||
|
||||
/**
|
||||
* Detect server type by using the nodeinfo data
|
||||
* Parses Nodeinfo
|
||||
*
|
||||
* @see https://github.com/jhass/nodeinfo
|
||||
*
|
||||
* @param string $url address of the server
|
||||
* @param ICanHandleHttpResponses $httpResult
|
||||
|
@ -1058,7 +1063,7 @@ class GServer
|
|||
*
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
private static function fetchNodeinfo(string $url, ICanHandleHttpResponses $httpResult): array
|
||||
private static function parseNodeinfo(string $url, ICanHandleHttpResponses $httpResult): array
|
||||
{
|
||||
if (!$httpResult->isSuccess()) {
|
||||
return [];
|
||||
|
@ -1072,6 +1077,7 @@ class GServer
|
|||
|
||||
$nodeinfo1_url = '';
|
||||
$nodeinfo2_url = '';
|
||||
$detection_method = self::DETECT_MANUAL;
|
||||
|
||||
foreach ($nodeinfo['links'] as $link) {
|
||||
if (!is_array($link) || empty($link['rel']) || empty($link['href'])) {
|
||||
|
@ -1081,8 +1087,15 @@ class GServer
|
|||
|
||||
if ($link['rel'] == 'http://nodeinfo.diaspora.software/ns/schema/1.0') {
|
||||
$nodeinfo1_url = Network::addBasePath($link['href'], $httpResult->getUrl());
|
||||
} elseif ($link['rel'] == 'http://nodeinfo.diaspora.software/ns/schema/2.0') {
|
||||
} elseif (($detection_method < self::DETECT_NODEINFO_20) && ($link['rel'] == 'http://nodeinfo.diaspora.software/ns/schema/2.0')) {
|
||||
$nodeinfo2_url = Network::addBasePath($link['href'], $httpResult->getUrl());
|
||||
$detection_method = self::DETECT_NODEINFO_20;
|
||||
} elseif (($detection_method < self::DETECT_NODEINFO_21) && ($link['rel'] == 'http://nodeinfo.diaspora.software/ns/schema/2.1')) {
|
||||
$nodeinfo2_url = Network::addBasePath($link['href'], $httpResult->getUrl());
|
||||
$detection_method = self::DETECT_NODEINFO_21;
|
||||
} elseif (($detection_method < self::DETECT_NODEINFO_22) && ($link['rel'] == 'http://nodeinfo.diaspora.software/ns/schema/2.2')) {
|
||||
$nodeinfo2_url = Network::addBasePath($link['href'], $httpResult->getUrl());
|
||||
$detection_method = self::DETECT_NODEINFO_22;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1093,18 +1106,20 @@ class GServer
|
|||
$server = [];
|
||||
|
||||
if (!empty($nodeinfo2_url)) {
|
||||
$server = self::parseNodeinfo2($nodeinfo2_url);
|
||||
$server = self::parseNodeinfo_2($nodeinfo2_url, $detection_method);
|
||||
}
|
||||
|
||||
if (empty($server) && !empty($nodeinfo1_url)) {
|
||||
$server = self::parseNodeinfo1($nodeinfo1_url);
|
||||
$server = self::parseNodeinfo_1($nodeinfo1_url);
|
||||
}
|
||||
|
||||
return $server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses Nodeinfo 1
|
||||
* Parses Nodeinfo with the version 1.0
|
||||
*
|
||||
* @see https://github.com/jhass/nodeinfo/tree/main/schemas/1.0
|
||||
*
|
||||
* @param string $nodeinfo_url address of the nodeinfo path
|
||||
*
|
||||
|
@ -1112,7 +1127,7 @@ class GServer
|
|||
*
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
private static function parseNodeinfo1(string $nodeinfo_url): array
|
||||
private static function parseNodeinfo_1(string $nodeinfo_url): array
|
||||
{
|
||||
$curlResult = DI::httpClient()->get($nodeinfo_url, HttpClientAccept::JSON, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
if (!$curlResult->isSuccess()) {
|
||||
|
@ -1125,8 +1140,10 @@ class GServer
|
|||
return [];
|
||||
}
|
||||
|
||||
$server = ['detection-method' => self::DETECT_NODEINFO_1,
|
||||
'register_policy' => Register::CLOSED];
|
||||
$server = [
|
||||
'detection-method' => self::DETECT_NODEINFO_10,
|
||||
'register_policy' => Register::CLOSED
|
||||
];
|
||||
|
||||
if (!empty($nodeinfo['openRegistrations'])) {
|
||||
$server['register_policy'] = Register::OPEN;
|
||||
|
@ -1202,17 +1219,20 @@ class GServer
|
|||
}
|
||||
|
||||
/**
|
||||
* Parses Nodeinfo 2
|
||||
* Parses Nodeinfo with the versions 2.0, 2.1 and 2.2
|
||||
*
|
||||
* @see https://git.feneas.org/jaywink/nodeinfo2
|
||||
* @see https://github.com/jhass/nodeinfo/tree/main/schemas/2.0
|
||||
* @see https://github.com/jhass/nodeinfo/tree/main/schemas/2.1
|
||||
* @see https://github.com/jhass/nodeinfo/tree/main/schemas/2.2
|
||||
*
|
||||
* @param string $nodeinfo_url address of the nodeinfo path
|
||||
* @param string $nodeinfo_url address of the nodeinfo path
|
||||
* @param int $detection_method nodeinfo version
|
||||
*
|
||||
* @return array Server data
|
||||
*
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
private static function parseNodeinfo2(string $nodeinfo_url): array
|
||||
private static function parseNodeinfo_2(string $nodeinfo_url, int $detection_method): array
|
||||
{
|
||||
$curlResult = DI::httpClient()->get($nodeinfo_url, HttpClientAccept::JSON, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
if (!$curlResult->isSuccess()) {
|
||||
|
@ -1225,7 +1245,7 @@ class GServer
|
|||
}
|
||||
|
||||
$server = [
|
||||
'detection-method' => self::DETECT_NODEINFO_2,
|
||||
'detection-method' => $detection_method,
|
||||
'register_policy' => Register::CLOSED,
|
||||
'platform' => 'unknown',
|
||||
];
|
||||
|
@ -1234,6 +1254,15 @@ class GServer
|
|||
$server['register_policy'] = Register::OPEN;
|
||||
}
|
||||
|
||||
if (!empty($nodeinfo['instance'])) {
|
||||
if (!empty($nodeinfo['instance']['name'])) {
|
||||
$server['site_name'] = $nodeinfo['instance']['name'];
|
||||
}
|
||||
if (!empty($nodeinfo['instance']['description'])) {
|
||||
$server['info'] = $nodeinfo['instance']['description'];
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($nodeinfo['software'])) {
|
||||
if (isset($nodeinfo['software']['name'])) {
|
||||
$server['platform'] = strtolower($nodeinfo['software']['name']);
|
||||
|
@ -1249,6 +1278,13 @@ class GServer
|
|||
if (($server['platform'] == 'mastodon') && substr($nodeinfo['software']['version'], -5) == '-qoto') {
|
||||
$server['platform'] = 'qoto';
|
||||
}
|
||||
|
||||
if (isset($nodeinfo['software']['repository'])) {
|
||||
$server['repository'] = strtolower($nodeinfo['software']['repository']);
|
||||
}
|
||||
if (isset($nodeinfo['software']['homepage'])) {
|
||||
$server['homepage'] = strtolower($nodeinfo['software']['homepage']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1260,6 +1296,9 @@ class GServer
|
|||
if (!empty($nodeinfo['metadata']['nodeName'])) {
|
||||
$server['site_name'] = $nodeinfo['metadata']['nodeName'];
|
||||
}
|
||||
if (!empty($nodeinfo['metadata']['nodeDescription'])) {
|
||||
$server['info'] = $nodeinfo['metadata']['nodeDescription'];
|
||||
}
|
||||
|
||||
if (!empty($nodeinfo['usage']['users']['total'])) {
|
||||
$server['registered-users'] = max($nodeinfo['usage']['users']['total'], 1);
|
||||
|
@ -1320,9 +1359,9 @@ class GServer
|
|||
}
|
||||
|
||||
/**
|
||||
* Parses NodeInfo2 protocol 1.0
|
||||
* Parses NodeInfo2
|
||||
*
|
||||
* @see https://github.com/jaywink/nodeinfo2/blob/master/PROTOCOL.md
|
||||
* @see https://github.com/jaywink/nodeinfo2
|
||||
*
|
||||
* @param string $nodeinfo_url address of the nodeinfo path
|
||||
*
|
||||
|
@ -1330,7 +1369,7 @@ class GServer
|
|||
*
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
private static function parseNodeinfo210(ICanHandleHttpResponses $httpResult): array
|
||||
private static function parseNodeinfo2(ICanHandleHttpResponses $httpResult): array
|
||||
{
|
||||
if (!$httpResult->isSuccess()) {
|
||||
return [];
|
||||
|
@ -1342,8 +1381,10 @@ class GServer
|
|||
return [];
|
||||
}
|
||||
|
||||
$server = ['detection-method' => self::DETECT_NODEINFO_210,
|
||||
'register_policy' => Register::CLOSED];
|
||||
$server = [
|
||||
'detection-method' => self::DETECT_NODEINFO2_10,
|
||||
'register_policy' => Register::CLOSED
|
||||
];
|
||||
|
||||
if (!empty($nodeinfo['openRegistrations'])) {
|
||||
$server['register_policy'] = Register::OPEN;
|
||||
|
@ -2570,6 +2611,10 @@ class GServer
|
|||
return;
|
||||
}
|
||||
|
||||
if ($data['openwebauth'] == $gserver['openwebauth']) {
|
||||
return;
|
||||
}
|
||||
|
||||
$serverdata = self::getZotData($gserver['url'], []);
|
||||
if (empty($serverdata)) {
|
||||
$serverdata = ['openwebauth' => $data['openwebauth']];
|
||||
|
|
|
@ -198,6 +198,10 @@ class Item
|
|||
$fields['external-id'] = ItemURI::getIdByURI($fields['extid']);
|
||||
}
|
||||
|
||||
if (!empty($fields['replies'])) {
|
||||
$fields['replies-id'] = ItemURI::getIdByURI($fields['replies']);
|
||||
}
|
||||
|
||||
if (!empty($fields['verb'])) {
|
||||
$fields['vid'] = Verb::getID($fields['verb']);
|
||||
}
|
||||
|
@ -415,8 +419,24 @@ class Item
|
|||
self::markForDeletion(['parent' => $item['parent'], 'deleted' => false], $priority);
|
||||
}
|
||||
|
||||
if ($item['uid'] == 0 && $item['gravity'] == self::GRAVITY_PARENT) {
|
||||
$posts = DI::keyValue()->get('nodeinfo_total_posts') ?? 0;
|
||||
DI::keyValue()->set('nodeinfo_total_posts', $posts - 1);
|
||||
} elseif ($item['uid'] == 0 && $item['gravity'] == self::GRAVITY_COMMENT) {
|
||||
$comments = DI::keyValue()->get('nodeinfo_total_comments') ?? 0;
|
||||
DI::keyValue()->set('nodeinfo_total_comments', $comments - 1);
|
||||
}
|
||||
|
||||
// Is it our comment and/or our thread?
|
||||
if (($item['origin'] || $parent['origin']) && ($item['uid'] != 0)) {
|
||||
if ($item['origin'] && $item['gravity'] == self::GRAVITY_PARENT) {
|
||||
$posts = DI::keyValue()->get('nodeinfo_local_posts') ?? 0;
|
||||
DI::keyValue()->set('nodeinfo_local_posts', $posts - 1);
|
||||
} elseif ($item['origin'] && $item['gravity'] == self::GRAVITY_COMMENT) {
|
||||
$comments = DI::keyValue()->get('nodeinfo_local_comments') ?? 0;
|
||||
DI::keyValue()->set('nodeinfo_local_comments', $comments - 1);
|
||||
}
|
||||
|
||||
// When we delete the original post we will delete all existing copies on the server as well
|
||||
self::markForDeletion(['uri-id' => $item['uri-id'], 'deleted' => false], $priority);
|
||||
|
||||
|
@ -536,9 +556,9 @@ class Item
|
|||
}
|
||||
|
||||
if (!empty($item['causer-id']) && Contact::isSharing($item['causer-id'], $item['uid'], true)) {
|
||||
$cdata = Contact::getPublicAndUserContactID($item['causer-id'], $item['uid']);
|
||||
if (!empty($cdata['user'])) {
|
||||
return $cdata['user'];
|
||||
$ucid = Contact::getUserContactId($item['causer-id'], $item['uid']);
|
||||
if ($ucid) {
|
||||
return $ucid;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1077,6 +1097,10 @@ class Item
|
|||
$parent_id = 0;
|
||||
$parent_origin = $item['origin'];
|
||||
|
||||
if ($item['wall'] && empty($item['context'])) {
|
||||
$item['context'] = $item['parent-uri'] . '#context';
|
||||
}
|
||||
|
||||
if ($item['wall'] && empty($item['conversation'])) {
|
||||
$item['conversation'] = $item['parent-uri'] . '#context';
|
||||
}
|
||||
|
@ -1098,6 +1122,10 @@ class Item
|
|||
$item['conversation-id'] = ItemURI::getIdByURI($item['conversation']);
|
||||
}
|
||||
|
||||
if (!empty($item['context']) && empty($item['context-id'])) {
|
||||
$item['context-id'] = ItemURI::getIdByURI($item['context']);
|
||||
}
|
||||
|
||||
// Is this item available in the global items (with uid=0)?
|
||||
if ($item['uid'] == 0) {
|
||||
$item['global'] = true;
|
||||
|
@ -1165,6 +1193,10 @@ class Item
|
|||
$item['external-id'] = ItemURI::getIdByURI($item['extid']);
|
||||
}
|
||||
|
||||
if (!empty($item['replies'])) {
|
||||
$item['replies-id'] = ItemURI::getIdByURI($item['replies']);
|
||||
}
|
||||
|
||||
if ($item['verb'] == Activity::ANNOUNCE) {
|
||||
self::setOwnerforResharedItem($item);
|
||||
}
|
||||
|
@ -1334,6 +1366,14 @@ class Item
|
|||
return 0;
|
||||
}
|
||||
|
||||
if ($posted_item['origin'] && $posted_item['gravity'] == self::GRAVITY_PARENT) {
|
||||
$posts = (int)(DI::keyValue()->get('nodeinfo_local_posts') ?? 0);
|
||||
DI::keyValue()->set('nodeinfo_local_posts', $posts + 1);
|
||||
} elseif ($posted_item['origin'] && $posted_item['gravity'] == self::GRAVITY_COMMENT) {
|
||||
$comments = (int)(DI::keyValue()->get('nodeinfo_local_comments') ?? 0);
|
||||
DI::keyValue()->set('nodeinfo_local_comments', $comments + 1);
|
||||
}
|
||||
|
||||
Post\Origin::insert($posted_item);
|
||||
|
||||
// update the commented timestamp on the parent
|
||||
|
@ -1423,6 +1463,14 @@ class Item
|
|||
}
|
||||
|
||||
if ($inserted) {
|
||||
if ($posted_item['gravity'] == self::GRAVITY_PARENT) {
|
||||
$posts = (int)(DI::keyValue()->get('nodeinfo_total_posts') ?? 0);
|
||||
DI::keyValue()->set('nodeinfo_total_posts', $posts + 1);
|
||||
} elseif ($posted_item['gravity'] == self::GRAVITY_COMMENT) {
|
||||
$comments = (int)(DI::keyValue()->get('nodeinfo_total_comments') ?? 0);
|
||||
DI::keyValue()->set('nodeinfo_total_comments', $comments + 1);
|
||||
}
|
||||
|
||||
// Fill the cache with the rendered content.
|
||||
if (in_array($posted_item['gravity'], [self::GRAVITY_PARENT, self::GRAVITY_COMMENT])) {
|
||||
self::updateDisplayCache($posted_item['uri-id']);
|
||||
|
@ -2584,12 +2632,12 @@ class Item
|
|||
return;
|
||||
}
|
||||
|
||||
$cdata = Contact::getPublicAndUserContactID($item['author-id'], $item['uid']);
|
||||
if (empty($cdata['user']) || ($cdata['user'] != $item['contact-id'])) {
|
||||
$ucid = Contact::getUserContactId($item['author-id'], $item['uid']);
|
||||
if (!$ucid || ($ucid != $item['contact-id'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!DBA::exists('contact', ['id' => $cdata['user'], 'remote_self' => LocalRelationship::MIRROR_NATIVE_RESHARE])) {
|
||||
if (!DBA::exists('contact', ['id' => $ucid, 'remote_self' => LocalRelationship::MIRROR_NATIVE_RESHARE])) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4118,6 +4166,10 @@ class Item
|
|||
return $item_id;
|
||||
}
|
||||
|
||||
if (ActivityPub\Processor::alreadyKnown($uri, '')) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$hookData = [
|
||||
'uri' => $uri,
|
||||
'uid' => $uid,
|
||||
|
@ -4213,4 +4265,22 @@ class Item
|
|||
Logger::warning('Post does not exist although it was supposed to had been fetched.', ['id' => $id, 'url' => $url, 'uid' => $uid]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static function incrementInbound(string $network)
|
||||
{
|
||||
$packets = (int)(DI::keyValue()->get('stats_packets_inbound_' . $network) ?? 0);
|
||||
if ($packets >= PHP_INT_MAX) {
|
||||
$packets = 0;
|
||||
}
|
||||
DI::keyValue()->set('stats_packets_inbound_' . $network, $packets + 1);
|
||||
}
|
||||
|
||||
public static function incrementOutbound(string $network)
|
||||
{
|
||||
$packets = (int)(DI::keyValue()->get('stats_packets_outbound_' . $network) ?? 0);
|
||||
if ($packets >= PHP_INT_MAX) {
|
||||
$packets = 0;
|
||||
}
|
||||
DI::keyValue()->set('stats_packets_outbound_' . $network, $packets + 1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,8 @@ class Nodeinfo
|
|||
return;
|
||||
}
|
||||
|
||||
$logger->info('User statistics - start');
|
||||
|
||||
$userStats = User::getStatistics();
|
||||
|
||||
DI::keyValue()->set('nodeinfo_total_users', $userStats['total_users']);
|
||||
|
@ -60,21 +62,26 @@ class Nodeinfo
|
|||
DI::keyValue()->set('nodeinfo_active_users_monthly', $userStats['active_users_monthly']);
|
||||
DI::keyValue()->set('nodeinfo_active_users_weekly', $userStats['active_users_weekly']);
|
||||
|
||||
$logger->info('user statistics', $userStats);
|
||||
$logger->info('user statistics - done', $userStats);
|
||||
|
||||
$posts = DBA::count('post-thread', ["`uri-id` IN (SELECT `uri-id` FROM `post-user` WHERE NOT `deleted` AND `origin`)"]);
|
||||
$comments = DBA::count('post', ["NOT `deleted` AND `gravity` = ? AND `uri-id` IN (SELECT `uri-id` FROM `post-user` WHERE `origin`)", Item::GRAVITY_COMMENT]);
|
||||
DI::keyValue()->set('nodeinfo_local_posts', $posts);
|
||||
DI::keyValue()->set('nodeinfo_local_comments', $comments);
|
||||
|
||||
$logger->info('User activity', ['posts' => $posts, 'comments' => $comments]);
|
||||
$posts = DBA::count('post', ['deleted' => false, 'gravity' => Item::GRAVITY_COMMENT]);
|
||||
$comments = DBA::count('post', ['deleted' => false, 'gravity' => Item::GRAVITY_COMMENT]);
|
||||
DI::keyValue()->set('nodeinfo_total_posts', $posts);
|
||||
DI::keyValue()->set('nodeinfo_total_comments', $comments);
|
||||
|
||||
$logger->info('Post statistics - done', ['posts' => $posts, 'comments' => $comments]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the supported services
|
||||
*
|
||||
* @return Object with supported services
|
||||
*/
|
||||
*/
|
||||
public static function getUsage(bool $version2 = false)
|
||||
{
|
||||
$config = DI::config();
|
||||
|
@ -101,7 +108,7 @@ class Nodeinfo
|
|||
* Return the supported services
|
||||
*
|
||||
* @return array with supported services
|
||||
*/
|
||||
*/
|
||||
public static function getServices(): array
|
||||
{
|
||||
$services = [
|
||||
|
|
|
@ -141,7 +141,7 @@ class Content
|
|||
if ($uid != 0) {
|
||||
$condition = ["MATCH (`searchtext`) AGAINST (? IN BOOLEAN MODE) AND (NOT `restricted` OR `uri-id` IN (SELECT `uri-id` FROM `post-user` WHERE `uid` = ?))", $search, $uid];
|
||||
} else {
|
||||
$condition = ["MATCH (`searchtext`) AGAINST (? IN BOOLEAN MODE) AND NOT `restricted", $search];
|
||||
$condition = ["MATCH (`searchtext`) AGAINST (? IN BOOLEAN MODE) AND NOT `restricted`", $search];
|
||||
}
|
||||
return DBA::count(SearchIndex::getSearchTable(), $condition);
|
||||
}
|
||||
|
|
|
@ -88,8 +88,8 @@ class Media
|
|||
// "document" has got the lowest priority. So when the same file is both attached as document
|
||||
// and embedded as picture then we only store the picture or replace the document
|
||||
$found = DBA::selectFirst('post-media', ['type'], ['uri-id' => $media['uri-id'], 'url' => $media['url']]);
|
||||
if (!$force && !empty($found) && (($found['type'] != self::DOCUMENT) || ($media['type'] == self::DOCUMENT))) {
|
||||
Logger::info('Media already exists', ['uri-id' => $media['uri-id'], 'url' => $media['url']]);
|
||||
if (!$force && !empty($found) && (!in_array($found['type'], [self::UNKNOWN, self::DOCUMENT]) || ($media['type'] == self::DOCUMENT))) {
|
||||
Logger::info('Media already exists', ['uri-id' => $media['uri-id'], 'url' => $media['url'], 'found' => $found['type'], 'new' => $media['type']]);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -444,42 +444,46 @@ class Media
|
|||
return $data;
|
||||
}
|
||||
|
||||
$type = explode('/', current(explode(';', $data['mimetype'])));
|
||||
$data['type'] = self::getType($data['mimetype']);
|
||||
return $data;
|
||||
}
|
||||
|
||||
public static function getType(string $mimeType): int
|
||||
{
|
||||
$type = explode('/', current(explode(';', $mimeType)));
|
||||
if (count($type) < 2) {
|
||||
Logger::info('Unknown MimeType', ['type' => $type, 'media' => $data]);
|
||||
$data['type'] = self::UNKNOWN;
|
||||
return $data;
|
||||
Logger::info('Unknown MimeType', ['type' => $type, 'media' => $mimeType]);
|
||||
return self::UNKNOWN;
|
||||
}
|
||||
|
||||
$filetype = strtolower($type[0]);
|
||||
$subtype = strtolower($type[1]);
|
||||
|
||||
if ($filetype == 'image') {
|
||||
$data['type'] = self::IMAGE;
|
||||
$type = self::IMAGE;
|
||||
} elseif ($filetype == 'video') {
|
||||
$data['type'] = self::VIDEO;
|
||||
$type = self::VIDEO;
|
||||
} elseif ($filetype == 'audio') {
|
||||
$data['type'] = self::AUDIO;
|
||||
$type = self::AUDIO;
|
||||
} elseif (($filetype == 'text') && ($subtype == 'html')) {
|
||||
$data['type'] = self::HTML;
|
||||
$type = self::HTML;
|
||||
} elseif (($filetype == 'text') && ($subtype == 'xml')) {
|
||||
$data['type'] = self::XML;
|
||||
$type = self::XML;
|
||||
} elseif (($filetype == 'text') && ($subtype == 'plain')) {
|
||||
$data['type'] = self::PLAIN;
|
||||
$type = self::PLAIN;
|
||||
} elseif ($filetype == 'text') {
|
||||
$data['type'] = self::TEXT;
|
||||
$type = self::TEXT;
|
||||
} elseif (($filetype == 'application') && ($subtype == 'x-bittorrent')) {
|
||||
$data['type'] = self::TORRENT;
|
||||
$type = self::TORRENT;
|
||||
} elseif ($filetype == 'application') {
|
||||
$data['type'] = self::APPLICATION;
|
||||
$type = self::APPLICATION;
|
||||
} else {
|
||||
$data['type'] = self::UNKNOWN;
|
||||
Logger::info('Unknown type', ['filetype' => $filetype, 'subtype' => $subtype, 'media' => $data]);
|
||||
return $data;
|
||||
$type = self::UNKNOWN;
|
||||
Logger::info('Unknown type', ['filetype' => $filetype, 'subtype' => $subtype, 'media' => $mimeType]);
|
||||
}
|
||||
|
||||
Logger::debug('Detected type', ['filetype' => $filetype, 'subtype' => $subtype, 'media' => $data]);
|
||||
return $data;
|
||||
Logger::debug('Detected type', ['filetype' => $filetype, 'subtype' => $subtype, 'media' => $mimeType]);
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -622,8 +622,10 @@ class Profile
|
|||
$bd_format = DI::l10n()->t('g A l F d'); // 8 AM Friday January 18
|
||||
$classtoday = '';
|
||||
|
||||
$condition = ["`uid` = ? AND `type` != 'birthday' AND `start` < ? AND `start` >= ?",
|
||||
$uid, DateTimeFormat::utc('now + 7 days'), DateTimeFormat::utc('now - 1 days')];
|
||||
$condition = [
|
||||
"`uid` = ? AND `type` != 'birthday' AND `start` < ? AND `start` >= ?",
|
||||
$uid, DateTimeFormat::utc('now + 7 days'), DateTimeFormat::utc('now - 1 days')
|
||||
];
|
||||
$s = DBA::select('event', [], $condition, ['order' => ['start']]);
|
||||
|
||||
$r = [];
|
||||
|
@ -633,9 +635,11 @@ class Profile
|
|||
$total = 0;
|
||||
|
||||
while ($rr = DBA::fetch($s)) {
|
||||
$condition = ['parent-uri' => $rr['uri'], 'uid' => $rr['uid'], 'author-id' => $pcid,
|
||||
$condition = [
|
||||
'parent-uri' => $rr['uri'], 'uid' => $rr['uid'], 'author-id' => $pcid,
|
||||
'vid' => [Verb::getID(Activity::ATTEND), Verb::getID(Activity::ATTENDMAYBE)],
|
||||
'visible' => true, 'deleted' => false];
|
||||
'visible' => true, 'deleted' => false
|
||||
];
|
||||
if (!Post::exists($condition)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -724,7 +728,8 @@ class Profile
|
|||
if (!empty($search)) {
|
||||
$publish = (DI::config()->get('system', 'publish_all') ? '' : "AND `publish` ");
|
||||
$searchTerm = '%' . $search . '%';
|
||||
$condition = ["`verified` AND NOT `blocked` AND NOT `account_removed` AND NOT `account_expired`
|
||||
$condition = [
|
||||
"`verified` AND NOT `blocked` AND NOT `account_removed` AND NOT `account_expired`
|
||||
$publish
|
||||
AND ((`name` LIKE ?) OR
|
||||
(`nickname` LIKE ?) OR
|
||||
|
@ -735,7 +740,8 @@ class Profile
|
|||
(`pub_keywords` LIKE ?) OR
|
||||
(`prv_keywords` LIKE ?))",
|
||||
$searchTerm, $searchTerm, $searchTerm, $searchTerm,
|
||||
$searchTerm, $searchTerm, $searchTerm, $searchTerm];
|
||||
$searchTerm, $searchTerm, $searchTerm, $searchTerm
|
||||
];
|
||||
} else {
|
||||
$condition = ['verified' => true, 'blocked' => false, 'account_removed' => false, 'account_expired' => false];
|
||||
if (!DI::config()->get('system', 'publish_all')) {
|
||||
|
@ -838,4 +844,44 @@ class Profile
|
|||
DBA::delete('profile', ['id' => $profile['id']]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get "about" field with the added responsible relay contact if appropriate.
|
||||
*
|
||||
* @param string $about
|
||||
* @param integer|null $parent_uid
|
||||
* @param integer $account_type
|
||||
* @param string $language
|
||||
* @return string
|
||||
*/
|
||||
public static function addResponsibleRelayContact(string $about = null, int $parent_uid = null, int $account_type, string $language): ?string
|
||||
{
|
||||
if (($account_type != User::ACCOUNT_TYPE_RELAY) || empty($parent_uid)) {
|
||||
return $about;
|
||||
}
|
||||
|
||||
$parent = User::getOwnerDataById($parent_uid);
|
||||
if (strpos($about, $parent['addr']) || strpos($about, $parent['url'])) {
|
||||
return $about;
|
||||
}
|
||||
|
||||
$l10n = DI::l10n()->withLang($language);
|
||||
|
||||
return $about .= "\n" . $l10n->t('Responsible account: %s', $parent['addr']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set "about" field with the added responsible relay contact if appropriate.
|
||||
*
|
||||
* @param integer $uid
|
||||
* @return void
|
||||
*/
|
||||
public static function setResponsibleRelayContact(int $uid)
|
||||
{
|
||||
$owner = User::getOwnerDataById($uid);
|
||||
$about = self::addResponsibleRelayContact($owner['about'], $owner['parent-uid'], $owner['account-type'], $owner['language']);
|
||||
if ($about != $owner['about']) {
|
||||
self::update(['about' => $about], $uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -412,6 +412,29 @@ class User
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user id of a given contact id
|
||||
*
|
||||
* @param int $cid
|
||||
*
|
||||
* @return integer user id
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function getIdForContactId(int $cid): int
|
||||
{
|
||||
$account = Contact::selectFirstAccountUser(['pid', 'self', 'uid'], ['id' => $cid]);
|
||||
if (empty($account['pid'])) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($account['self']) {
|
||||
return $account['uid'];
|
||||
}
|
||||
|
||||
$self = Contact::selectFirstAccountUser(['uid'], ['pid' => $cid, 'self' => true]);
|
||||
return $self['uid'] ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a user based on its email
|
||||
*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue