mirror of
https://github.com/friendica/friendica
synced 2025-04-27 03:50:11 +00:00
Merge remote-tracking branch 'origin/2022.12-rc' into fixes
This commit is contained in:
commit
2f3f41ed9c
714 changed files with 34811 additions and 27839 deletions
|
@ -28,6 +28,7 @@ use Friendica\Core\Protocol;
|
|||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Item;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientAccept;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Network\Probe;
|
||||
|
@ -61,7 +62,7 @@ class APContact
|
|||
'addr' => $local_owner['addr'],
|
||||
'baseurl' => $local_owner['baseurl'],
|
||||
'url' => $local_owner['url'],
|
||||
'subscribe' => $local_owner['baseurl'] . '/follow?url={uri}'];
|
||||
'subscribe' => $local_owner['baseurl'] . '/contact/follow?url={uri}'];
|
||||
|
||||
if (!empty($local_owner['alias']) && ($local_owner['url'] != $local_owner['alias'])) {
|
||||
$data['alias'] = $local_owner['alias'];
|
||||
|
@ -290,22 +291,19 @@ class APContact
|
|||
return $fetched_contact;
|
||||
}
|
||||
|
||||
$parts = parse_url($apcontact['url']);
|
||||
unset($parts['scheme']);
|
||||
unset($parts['path']);
|
||||
|
||||
if (empty($apcontact['addr'])) {
|
||||
if (!empty($apcontact['nick']) && is_array($parts)) {
|
||||
$apcontact['addr'] = $apcontact['nick'] . '@' . str_replace('//', '', Network::unparseURL($parts));
|
||||
} else {
|
||||
try {
|
||||
$apcontact['addr'] = $apcontact['nick'] . '@' . (new Uri($apcontact['url']))->getAuthority();
|
||||
} catch (\Throwable $e) {
|
||||
Logger::warning('Unable to coerce APContact URL into a UriInterface object', ['url' => $apcontact['url'], 'error' => $e->getMessage()]);
|
||||
$apcontact['addr'] = '';
|
||||
}
|
||||
}
|
||||
|
||||
$apcontact['pubkey'] = null;
|
||||
if (!empty($compacted['w3id:publicKey'])) {
|
||||
$apcontact['pubkey'] = trim(JsonLD::fetchElement($compacted['w3id:publicKey'], 'w3id:publicKeyPem', '@value'));
|
||||
if (strstr($apcontact['pubkey'], 'RSA ')) {
|
||||
$apcontact['pubkey'] = trim(JsonLD::fetchElement($compacted['w3id:publicKey'], 'w3id:publicKeyPem', '@value') ?? '');
|
||||
if (strpos($apcontact['pubkey'], 'RSA ') !== false) {
|
||||
$apcontact['pubkey'] = Crypto::rsaToPem($apcontact['pubkey']);
|
||||
}
|
||||
}
|
||||
|
@ -382,7 +380,7 @@ class APContact
|
|||
// kroeg:blocks, updated
|
||||
|
||||
// When the photo is too large, try to shorten it by removing parts
|
||||
if (strlen($apcontact['photo']) > 255) {
|
||||
if (strlen($apcontact['photo'] ?? '') > 255) {
|
||||
$parts = parse_url($apcontact['photo']);
|
||||
unset($parts['fragment']);
|
||||
$apcontact['photo'] = (string)Uri::fromParts($parts);
|
||||
|
@ -495,13 +493,13 @@ class APContact
|
|||
private static function getStatusesCount(array $owner): int
|
||||
{
|
||||
$condition = [
|
||||
'private' => [Item::PUBLIC, Item::UNLISTED],
|
||||
'private' => [Item::PUBLIC, Item::UNLISTED],
|
||||
'author-id' => Contact::getIdForURL($owner['url'], 0, false),
|
||||
'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT],
|
||||
'gravity' => [Item::GRAVITY_PARENT, Item::GRAVITY_COMMENT],
|
||||
'network' => Protocol::DFRN,
|
||||
'parent-network' => Protocol::FEDERATED,
|
||||
'deleted' => false,
|
||||
'visible' => true
|
||||
'visible' => true,
|
||||
];
|
||||
|
||||
$count = Post::countPosts($condition);
|
||||
|
@ -573,7 +571,7 @@ class APContact
|
|||
*
|
||||
* @param array $apcontact
|
||||
*
|
||||
* @return bool
|
||||
* @return bool
|
||||
*/
|
||||
public static function isRelay(array $apcontact): bool
|
||||
{
|
||||
|
|
|
@ -29,7 +29,6 @@ use Friendica\Core\Hook;
|
|||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\Protocol;
|
||||
use Friendica\Core\Renderer;
|
||||
use Friendica\Core\Session;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Core\Worker;
|
||||
use Friendica\Database\Database;
|
||||
|
@ -97,17 +96,17 @@ class Contact
|
|||
* Relationship types
|
||||
* @{
|
||||
*/
|
||||
const NOTHING = 0;
|
||||
const FOLLOWER = 1;
|
||||
const SHARING = 2;
|
||||
const FRIEND = 3;
|
||||
const SELF = 4;
|
||||
const NOTHING = 0; // There is no relationship between the contact and the user
|
||||
const FOLLOWER = 1; // The contact is following this user (the contact is the subscriber)
|
||||
const SHARING = 2; // The contact shares their content with this user (the user is the subscriber)
|
||||
const FRIEND = 3; // There is a mutual relationship between the contact and the user
|
||||
const SELF = 4; // This is the user theirself
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
const MIRROR_DEACTIVATED = 0;
|
||||
const MIRROR_FORWARDED = 1;
|
||||
const MIRROR_FORWARDED = 1; // Deprecated, now does the same like MIRROR_OWN_POST
|
||||
const MIRROR_OWN_POST = 2;
|
||||
const MIRROR_NATIVE_RESHARE = 3;
|
||||
|
||||
|
@ -137,6 +136,18 @@ class Contact
|
|||
return $contact;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $fields Array of selected fields, empty for all
|
||||
* @param array $condition Array of fields for condition
|
||||
* @param array $params Array of several parameters
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function selectAccountToArray(array $fields = [], array $condition = [], array $params = []): array
|
||||
{
|
||||
return DBA::selectToArray('account-user-view', $fields, $condition, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $fields Array of selected fields, empty for all
|
||||
* @param array $condition Array of fields for condition
|
||||
|
@ -261,6 +272,32 @@ class Contact
|
|||
return DBA::selectFirst('contact', $fields, ['uri-id' => $uri_id], ['order' => ['uid']]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all remote contacts for a given contact url
|
||||
*
|
||||
* @param string $url The URL of the contact
|
||||
* @param array $fields The wanted fields
|
||||
*
|
||||
* @return array all remote contacts
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function getVisitorByUrl(string $url, array $fields = ['id', 'uid']): array
|
||||
{
|
||||
$remote = [];
|
||||
|
||||
$remote_contacts = DBA::select('contact', ['id', 'uid'], ['nurl' => Strings::normaliseLink($url), 'rel' => [Contact::FOLLOWER, Contact::FRIEND], 'self' => false]);
|
||||
while ($contact = DBA::fetch($remote_contacts)) {
|
||||
if (($contact['uid'] == 0) || Contact\User::isBlocked($contact['id'], $contact['uid'])) {
|
||||
continue;
|
||||
}
|
||||
$remote[$contact['uid']] = $contact['id'];
|
||||
}
|
||||
DBA::close($remote_contacts);
|
||||
|
||||
return $remote;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a contact by a given url
|
||||
*
|
||||
|
@ -319,7 +356,7 @@ class Contact
|
|||
|
||||
// Update the contact in the background if needed
|
||||
if (Probe::isProbable($contact['network']) && ($contact['next-update'] < DateTimeFormat::utcNow())) {
|
||||
Worker::add(['priority' => PRIORITY_LOW, 'dont_fork' => true], 'UpdateContact', $contact['id']);
|
||||
Worker::add(['priority' => Worker::PRIORITY_LOW, 'dont_fork' => true], 'UpdateContact', $contact['id']);
|
||||
}
|
||||
|
||||
// Remove the internal fields
|
||||
|
@ -704,7 +741,6 @@ class Contact
|
|||
'notify' => DI::baseUrl() . '/dfrn_notify/' . $user['nickname'],
|
||||
'poll' => DI::baseUrl() . '/dfrn_poll/' . $user['nickname'],
|
||||
'confirm' => DI::baseUrl() . '/dfrn_confirm/' . $user['nickname'],
|
||||
'poco' => DI::baseUrl() . '/poco/' . $user['nickname'],
|
||||
'name-date' => DateTimeFormat::utcNow(),
|
||||
'uri-date' => DateTimeFormat::utcNow(),
|
||||
'avatar-date' => DateTimeFormat::utcNow(),
|
||||
|
@ -786,7 +822,6 @@ class Contact
|
|||
'notify' => DI::baseUrl() . '/dfrn_notify/' . $user['nickname'],
|
||||
'poll' => DI::baseUrl() . '/dfrn_poll/'. $user['nickname'],
|
||||
'confirm' => DI::baseUrl() . '/dfrn_confirm/' . $user['nickname'],
|
||||
'poco' => DI::baseUrl() . '/poco/' . $user['nickname'],
|
||||
];
|
||||
|
||||
|
||||
|
@ -877,14 +912,14 @@ class Contact
|
|||
self::clearFollowerFollowingEndpointCache($contact['uid']);
|
||||
|
||||
// Archive the contact
|
||||
self::update(['archive' => true, 'network' => Protocol::PHANTOM, 'deleted' => true], ['id' => $id]);
|
||||
self::update(['archive' => true, 'network' => Protocol::PHANTOM, 'rel' => self::NOTHING, 'deleted' => true], ['id' => $id]);
|
||||
|
||||
if (!DBA::exists('contact', ['uri-id' => $contact['uri-id'], 'deleted' => false])) {
|
||||
Avatar::deleteCache($contact);
|
||||
}
|
||||
|
||||
// Delete it in the background
|
||||
Worker::add(PRIORITY_MEDIUM, 'Contact\Remove', $id);
|
||||
Worker::add(Worker::PRIORITY_MEDIUM, 'Contact\Remove', $id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -908,7 +943,7 @@ class Contact
|
|||
if (in_array($contact['rel'], [self::SHARING, self::FRIEND])) {
|
||||
$cdata = self::getPublicAndUserContactID($contact['id'], $contact['uid']);
|
||||
if (!empty($cdata['public'])) {
|
||||
Worker::add(PRIORITY_HIGH, 'Contact\Unfollow', $cdata['public'], $contact['uid']);
|
||||
Worker::add(Worker::PRIORITY_HIGH, 'Contact\Unfollow', $cdata['public'], $contact['uid']);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -938,7 +973,7 @@ class Contact
|
|||
if (in_array($contact['rel'], [self::FOLLOWER, self::FRIEND])) {
|
||||
$cdata = self::getPublicAndUserContactID($contact['id'], $contact['uid']);
|
||||
if (!empty($cdata['public'])) {
|
||||
Worker::add(PRIORITY_HIGH, 'Contact\RevokeFollow', $cdata['public'], $contact['uid']);
|
||||
Worker::add(Worker::PRIORITY_HIGH, 'Contact\RevokeFollow', $cdata['public'], $contact['uid']);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -966,11 +1001,11 @@ class Contact
|
|||
$cdata = self::getPublicAndUserContactID($contact['id'], $contact['uid']);
|
||||
|
||||
if (in_array($contact['rel'], [self::SHARING, self::FRIEND]) && !empty($cdata['public'])) {
|
||||
Worker::add(PRIORITY_HIGH, 'Contact\Unfollow', $cdata['public'], $contact['uid']);
|
||||
Worker::add(Worker::PRIORITY_HIGH, 'Contact\Unfollow', $cdata['public'], $contact['uid']);
|
||||
}
|
||||
|
||||
if (in_array($contact['rel'], [self::FOLLOWER, self::FRIEND]) && !empty($cdata['public'])) {
|
||||
Worker::add(PRIORITY_HIGH, 'Contact\RevokeFollow', $cdata['public'], $contact['uid']);
|
||||
Worker::add(Worker::PRIORITY_HIGH, 'Contact\RevokeFollow', $cdata['public'], $contact['uid']);
|
||||
}
|
||||
|
||||
self::remove($contact['id']);
|
||||
|
@ -1103,7 +1138,7 @@ class Contact
|
|||
$photos_link = '';
|
||||
|
||||
if ($uid == 0) {
|
||||
$uid = local_user();
|
||||
$uid = DI::userSession()->getLocalUserId();
|
||||
}
|
||||
|
||||
if (empty($contact['uid']) || ($contact['uid'] != $uid)) {
|
||||
|
@ -1124,7 +1159,7 @@ class Contact
|
|||
$sparkle = false;
|
||||
if (($contact['network'] === Protocol::DFRN) && !$contact['self'] && empty($contact['pending'])) {
|
||||
$sparkle = true;
|
||||
$profile_link = DI::baseUrl() . '/redir/' . $contact['id'];
|
||||
$profile_link = 'contact/redir/' . $contact['id'];
|
||||
} else {
|
||||
$profile_link = $contact['url'];
|
||||
}
|
||||
|
@ -1135,25 +1170,25 @@ class Contact
|
|||
|
||||
if ($sparkle) {
|
||||
$status_link = $profile_link . '/status';
|
||||
$photos_link = str_replace('/profile/', '/photos/', $profile_link);
|
||||
$photos_link = $profile_link . '/photos';
|
||||
$profile_link = $profile_link . '/profile';
|
||||
}
|
||||
|
||||
if (self::canReceivePrivateMessages($contact) && empty($contact['pending'])) {
|
||||
$pm_url = DI::baseUrl() . '/message/new/' . $contact['id'];
|
||||
$pm_url = 'message/new/' . $contact['id'];
|
||||
}
|
||||
|
||||
$contact_url = DI::baseUrl() . '/contact/' . $contact['id'];
|
||||
$contact_url = 'contact/' . $contact['id'];
|
||||
|
||||
$posts_link = DI::baseUrl() . '/contact/' . $contact['id'] . '/conversations';
|
||||
$posts_link = 'contact/' . $contact['id'] . '/conversations';
|
||||
|
||||
$follow_link = '';
|
||||
$unfollow_link = '';
|
||||
if (!$contact['self'] && Protocol::supportsFollow($contact['network'])) {
|
||||
if ($contact['uid'] && in_array($contact['rel'], [self::SHARING, self::FRIEND])) {
|
||||
$unfollow_link = 'unfollow?url=' . urlencode($contact['url']) . '&auto=1';
|
||||
$unfollow_link = 'contact/unfollow?url=' . urlencode($contact['url']) . '&auto=1';
|
||||
} elseif(!$contact['pending']) {
|
||||
$follow_link = 'follow?url=' . urlencode($contact['url']) . '&auto=1';
|
||||
$follow_link = 'contact/follow?url=' . urlencode($contact['url']) . '&auto=1';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1167,7 +1202,7 @@ class Contact
|
|||
'network' => [DI::l10n()->t('Network Posts') , $posts_link , false],
|
||||
'edit' => [DI::l10n()->t('View Contact') , $contact_url , false],
|
||||
'follow' => [DI::l10n()->t('Connect/Follow'), $follow_link , true],
|
||||
'unfollow'=> [DI::l10n()->t('UnFollow') , $unfollow_link, true],
|
||||
'unfollow'=> [DI::l10n()->t('Unfollow') , $unfollow_link, true],
|
||||
];
|
||||
} else {
|
||||
$menu = [
|
||||
|
@ -1178,7 +1213,7 @@ class Contact
|
|||
'edit' => [DI::l10n()->t('View Contact') , $contact_url , false],
|
||||
'pm' => [DI::l10n()->t('Send PM') , $pm_url , false],
|
||||
'follow' => [DI::l10n()->t('Connect/Follow'), $follow_link , true],
|
||||
'unfollow'=> [DI::l10n()->t('UnFollow') , $unfollow_link , true],
|
||||
'unfollow'=> [DI::l10n()->t('Unfollow') , $unfollow_link , true],
|
||||
];
|
||||
|
||||
if (!empty($contact['pending'])) {
|
||||
|
@ -1248,7 +1283,7 @@ class Contact
|
|||
$contact_id = $contact['id'];
|
||||
|
||||
if (Probe::isProbable($contact['network']) && ($contact['next-update'] < DateTimeFormat::utcNow())) {
|
||||
Worker::add(['priority' => PRIORITY_LOW, 'dont_fork' => true], 'UpdateContact', $contact['id']);
|
||||
Worker::add(['priority' => Worker::PRIORITY_LOW, 'dont_fork' => true], 'UpdateContact', $contact['id']);
|
||||
}
|
||||
|
||||
if (empty($update) && (!empty($contact['uri-id']) || is_bool($update))) {
|
||||
|
@ -1334,9 +1369,10 @@ class Contact
|
|||
'writable' => 1,
|
||||
'blocked' => 0,
|
||||
'readonly' => 0,
|
||||
'pending' => 0];
|
||||
'pending' => 0,
|
||||
];
|
||||
|
||||
$condition = ['nurl' => Strings::normaliseLink($data["url"]), 'uid' => $uid, 'deleted' => false];
|
||||
$condition = ['nurl' => Strings::normaliseLink($data['url']), 'uid' => $uid, 'deleted' => false];
|
||||
|
||||
// Before inserting we do check if the entry does exist now.
|
||||
$contact = DBA::selectFirst('contact', ['id'], $condition, ['order' => ['id']]);
|
||||
|
@ -1359,7 +1395,17 @@ class Contact
|
|||
}
|
||||
|
||||
if ($data['network'] == Protocol::DIASPORA) {
|
||||
FContact::updateFromProbeArray($data);
|
||||
try {
|
||||
DI::dsprContact()->updateFromProbeArray($data);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
Logger::error($e->getMessage(), ['url' => $url, 'data' => $data]);
|
||||
}
|
||||
} elseif (!empty($data['networks'][Protocol::DIASPORA])) {
|
||||
try {
|
||||
DI::dsprContact()->updateFromProbeArray($data['networks'][Protocol::DIASPORA]);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
Logger::error($e->getMessage(), ['url' => $url, 'data' => $data['networks'][Protocol::DIASPORA]]);
|
||||
}
|
||||
}
|
||||
|
||||
self::updateFromProbeArray($contact_id, $data);
|
||||
|
@ -1506,10 +1552,10 @@ class Contact
|
|||
|
||||
if ($thread_mode) {
|
||||
$condition = ["((`$contact_field` = ? AND `gravity` = ?) OR (`author-id` = ? AND `gravity` = ? AND `vid` = ? AND `thr-parent-id` = `parent-uri-id`)) AND " . $sql,
|
||||
$cid, GRAVITY_PARENT, $cid, GRAVITY_ACTIVITY, Verb::getID(Activity::ANNOUNCE), local_user()];
|
||||
$cid, Item::GRAVITY_PARENT, $cid, Item::GRAVITY_ACTIVITY, Verb::getID(Activity::ANNOUNCE), DI::userSession()->getLocalUserId()];
|
||||
} else {
|
||||
$condition = ["`$contact_field` = ? AND `gravity` IN (?, ?) AND " . $sql,
|
||||
$cid, GRAVITY_PARENT, GRAVITY_COMMENT, local_user()];
|
||||
$cid, Item::GRAVITY_PARENT, Item::GRAVITY_COMMENT, DI::userSession()->getLocalUserId()];
|
||||
}
|
||||
|
||||
if (!empty($parent)) {
|
||||
|
@ -1527,10 +1573,10 @@ class Contact
|
|||
}
|
||||
|
||||
if (DI::mode()->isMobile()) {
|
||||
$itemsPerPage = DI::pConfig()->get(local_user(), 'system', 'itemspage_mobile_network',
|
||||
$itemsPerPage = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'itemspage_mobile_network',
|
||||
DI::config()->get('system', 'itemspage_network_mobile'));
|
||||
} else {
|
||||
$itemsPerPage = DI::pConfig()->get(local_user(), 'system', 'itemspage_network',
|
||||
$itemsPerPage = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'itemspage_network',
|
||||
DI::config()->get('system', 'itemspage_network'));
|
||||
}
|
||||
|
||||
|
@ -1538,7 +1584,7 @@ class Contact
|
|||
|
||||
$params = ['order' => ['received' => true], 'limit' => [$pager->getStart(), $pager->getItemsPerPage()]];
|
||||
|
||||
if (DI::pConfig()->get(local_user(), 'system', 'infinite_scroll')) {
|
||||
if (DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'infinite_scroll')) {
|
||||
$tpl = Renderer::getMarkupTemplate('infinite_scroll_head.tpl');
|
||||
$o = Renderer::replaceMacros($tpl, ['$reload_uri' => DI::args()->getQueryString()]);
|
||||
} else {
|
||||
|
@ -1547,27 +1593,27 @@ class Contact
|
|||
|
||||
if ($thread_mode) {
|
||||
$fields = ['uri-id', 'thr-parent-id', 'gravity', 'author-id', 'commented'];
|
||||
$items = Post::toArray(Post::selectForUser(local_user(), $fields, $condition, $params));
|
||||
$items = Post::toArray(Post::selectForUser(DI::userSession()->getLocalUserId(), $fields, $condition, $params));
|
||||
|
||||
if ($pager->getStart() == 0) {
|
||||
$cdata = self::getPublicAndUserContactID($cid, local_user());
|
||||
$cdata = self::getPublicAndUserContactID($cid, DI::userSession()->getLocalUserId());
|
||||
if (!empty($cdata['public'])) {
|
||||
$pinned = Post\Collection::selectToArrayForContact($cdata['public'], Post\Collection::FEATURED, $fields);
|
||||
$items = array_merge($items, $pinned);
|
||||
}
|
||||
}
|
||||
|
||||
$o .= DI::conversation()->create($items, 'contacts', $update, false, 'pinned_commented', local_user());
|
||||
$o .= DI::conversation()->create($items, 'contacts', $update, false, 'pinned_commented', DI::userSession()->getLocalUserId());
|
||||
} else {
|
||||
$fields = array_merge(Item::DISPLAY_FIELDLIST, ['featured']);
|
||||
$items = Post::toArray(Post::selectForUser(local_user(), $fields, $condition, $params));
|
||||
$items = Post::toArray(Post::selectForUser(DI::userSession()->getLocalUserId(), $fields, $condition, $params));
|
||||
|
||||
if ($pager->getStart() == 0) {
|
||||
$cdata = self::getPublicAndUserContactID($cid, local_user());
|
||||
$cdata = self::getPublicAndUserContactID($cid, DI::userSession()->getLocalUserId());
|
||||
if (!empty($cdata['public'])) {
|
||||
$condition = ["`uri-id` IN (SELECT `uri-id` FROM `collection-view` WHERE `cid` = ? AND `type` = ?)",
|
||||
$cdata['public'], Post\Collection::FEATURED];
|
||||
$pinned = Post::toArray(Post::selectForUser(local_user(), $fields, $condition, $params));
|
||||
$pinned = Post::toArray(Post::selectForUser(DI::userSession()->getLocalUserId(), $fields, $condition, $params));
|
||||
$items = array_merge($pinned, $items);
|
||||
}
|
||||
}
|
||||
|
@ -1576,7 +1622,7 @@ class Contact
|
|||
}
|
||||
|
||||
if (!$update) {
|
||||
if (DI::pConfig()->get(local_user(), 'system', 'infinite_scroll')) {
|
||||
if (DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'infinite_scroll')) {
|
||||
$o .= HTML::scrollLoader();
|
||||
} else {
|
||||
$o .= $pager->renderMinimal(count($items));
|
||||
|
@ -1680,11 +1726,9 @@ class Contact
|
|||
/**
|
||||
* Return the photo path for a given contact array in the given size
|
||||
*
|
||||
* @param array $contact contact array
|
||||
* @param string $field Fieldname of the photo in the contact array
|
||||
* @param array $contact contact array
|
||||
* @param string $size Size of the avatar picture
|
||||
* @param string $avatar Avatar path that is displayed when no photo had been found
|
||||
* @param bool $no_update Don't perfom an update if no cached avatar was found
|
||||
* @param bool $no_update Don't perfom an update if no cached avatar was found
|
||||
* @return string photo path
|
||||
*/
|
||||
private static function getAvatarPath(array $contact, string $size, bool $no_update = false): string
|
||||
|
@ -1711,7 +1755,7 @@ class Contact
|
|||
}
|
||||
}
|
||||
|
||||
return self::getAvatarUrlForId($contact['id'], $size, $contact['updated'] ?? '');
|
||||
return self::getAvatarUrlForId($contact['id'] ?? 0, $size, $contact['updated'] ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2023,9 +2067,10 @@ class Contact
|
|||
* @param integer $cid contact id
|
||||
* @param string $size One of the Proxy::SIZE_* constants
|
||||
* @param string $updated Contact update date
|
||||
* @param bool $static If "true" a parameter is added to convert the avatar to a static one
|
||||
* @return string avatar link
|
||||
*/
|
||||
public static function getAvatarUrlForId(int $cid, string $size = '', string $updated = '', string $guid = ''): string
|
||||
public static function getAvatarUrlForId(int $cid, string $size = '', string $updated = '', string $guid = '', bool $static = false): string
|
||||
{
|
||||
// We have to fetch the "updated" variable when it wasn't provided
|
||||
// The parameter can be provided to improve performance
|
||||
|
@ -2055,7 +2100,15 @@ class Contact
|
|||
$url .= Proxy::PIXEL_LARGE . '/';
|
||||
break;
|
||||
}
|
||||
return $url . ($guid ?: $cid) . ($updated ? '?ts=' . strtotime($updated) : '');
|
||||
$query_params = [];
|
||||
if ($updated) {
|
||||
$query_params['ts'] = strtotime($updated);
|
||||
}
|
||||
if ($static) {
|
||||
$query_params['static'] = true;
|
||||
}
|
||||
|
||||
return $url . ($guid ?: $cid) . (!empty($query_params) ? '?' . http_build_query($query_params) : '');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2080,9 +2133,10 @@ class Contact
|
|||
* @param integer $cid contact id
|
||||
* @param string $size One of the Proxy::SIZE_* constants
|
||||
* @param string $updated Contact update date
|
||||
* @param bool $static If "true" a parameter is added to convert the header to a static one
|
||||
* @return string header link
|
||||
*/
|
||||
public static function getHeaderUrlForId(int $cid, string $size = '', string $updated = '', string $guid = ''): string
|
||||
public static function getHeaderUrlForId(int $cid, string $size = '', string $updated = '', string $guid = '', bool $static = false): string
|
||||
{
|
||||
// We have to fetch the "updated" variable when it wasn't provided
|
||||
// The parameter can be provided to improve performance
|
||||
|
@ -2113,7 +2167,15 @@ class Contact
|
|||
break;
|
||||
}
|
||||
|
||||
return $url . ($guid ?: $cid) . ($updated ? '?ts=' . strtotime($updated) : '');
|
||||
$query_params = [];
|
||||
if ($updated) {
|
||||
$query_params['ts'] = strtotime($updated);
|
||||
}
|
||||
if ($static) {
|
||||
$query_params['static'] = true;
|
||||
}
|
||||
|
||||
return $url . ($guid ?: $cid) . (!empty($query_params) ? '?' . http_build_query($query_params) : '');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2367,7 +2429,7 @@ class Contact
|
|||
return;
|
||||
}
|
||||
Logger::warning('account-user exists for a different contact id', ['account_user' => $account_user, 'id' => $id, 'uid' => $uid, 'uri-id' => $uri_id, 'url' => $url]);
|
||||
Worker::add(PRIORITY_HIGH, 'MergeContact', $account_user['id'], $id, $uid);
|
||||
Worker::add(Worker::PRIORITY_HIGH, 'MergeContact', $account_user['id'], $id, $uid);
|
||||
} elseif (DBA::insert('account-user', ['id' => $id, 'uri-id' => $uri_id, 'uid' => $uid], Database::INSERT_IGNORE)) {
|
||||
Logger::notice('account-user was added', ['id' => $id, 'uid' => $uid, 'uri-id' => $uri_id, 'url' => $url]);
|
||||
} else {
|
||||
|
@ -2408,7 +2470,7 @@ class Contact
|
|||
continue;
|
||||
}
|
||||
|
||||
Worker::add(PRIORITY_HIGH, 'MergeContact', $first, $duplicate['id'], $uid);
|
||||
Worker::add(Worker::PRIORITY_HIGH, 'MergeContact', $first, $duplicate['id'], $uid);
|
||||
}
|
||||
DBA::close($duplicates);
|
||||
Logger::info('Duplicates handled', ['uid' => $uid, 'nurl' => $nurl, 'callstack' => System::callstack(20)]);
|
||||
|
@ -2431,13 +2493,23 @@ class Contact
|
|||
return false;
|
||||
}
|
||||
|
||||
$ret = Probe::uri($contact['url'], $network, $contact['uid']);
|
||||
$data = Probe::uri($contact['url'], $network, $contact['uid']);
|
||||
|
||||
if ($ret['network'] == Protocol::DIASPORA) {
|
||||
FContact::updateFromProbeArray($ret);
|
||||
if ($data['network'] == Protocol::DIASPORA) {
|
||||
try {
|
||||
DI::dsprContact()->updateFromProbeArray($data);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
Logger::error($e->getMessage(), ['id' => $id, 'network' => $network, 'contact' => $contact, 'data' => $data]);
|
||||
}
|
||||
} elseif (!empty($data['networks'][Protocol::DIASPORA])) {
|
||||
try {
|
||||
DI::dsprContact()->updateFromProbeArray($data['networks'][Protocol::DIASPORA]);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
Logger::error($e->getMessage(), ['id' => $id, 'network' => $network, 'contact' => $contact, 'data' => $data]);
|
||||
}
|
||||
}
|
||||
|
||||
return self::updateFromProbeArray($id, $ret);
|
||||
return self::updateFromProbeArray($id, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2610,7 +2682,7 @@ class Contact
|
|||
if ($ret['network'] == Protocol::ACTIVITYPUB) {
|
||||
$apcontact = APContact::getByURL($ret['url'], false);
|
||||
if (!empty($apcontact['featured'])) {
|
||||
Worker::add(PRIORITY_LOW, 'FetchFeaturedPosts', $ret['url']);
|
||||
Worker::add(Worker::PRIORITY_LOW, 'FetchFeaturedPosts', $ret['url']);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2619,7 +2691,7 @@ class Contact
|
|||
}
|
||||
|
||||
$update = false;
|
||||
$guid = ($ret['guid'] ?? '') ?: Item::guidFromUri($ret['url'], parse_url($ret['url'], PHP_URL_HOST));
|
||||
$guid = ($ret['guid'] ?? '') ?: Item::guidFromUri($ret['url']);
|
||||
|
||||
// make sure to not overwrite existing values with blank entries except some technical fields
|
||||
$keep = ['batch', 'notify', 'poll', 'request', 'confirm', 'poco', 'baseurl'];
|
||||
|
@ -2651,7 +2723,7 @@ class Contact
|
|||
self::updateContact($id, $uid, $uriid, $contact['url'], ['failed' => false, 'local-data' => $has_local_data, 'last-update' => $updated, 'next-update' => $success_next_update, 'success_update' => $updated]);
|
||||
|
||||
if (Contact\Relation::isDiscoverable($ret['url'])) {
|
||||
Worker::add(PRIORITY_LOW, 'ContactDiscovery', $ret['url']);
|
||||
Worker::add(Worker::PRIORITY_LOW, 'ContactDiscovery', $ret['url']);
|
||||
}
|
||||
|
||||
// Update the public contact
|
||||
|
@ -2695,7 +2767,7 @@ class Contact
|
|||
self::updateContact($id, $uid, $ret['uri-id'], $ret['url'], $ret);
|
||||
|
||||
if (Contact\Relation::isDiscoverable($ret['url'])) {
|
||||
Worker::add(PRIORITY_LOW, 'ContactDiscovery', $ret['url']);
|
||||
Worker::add(Worker::PRIORITY_LOW, 'ContactDiscovery', $ret['url']);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -2855,30 +2927,30 @@ class Contact
|
|||
|
||||
// do we have enough information?
|
||||
if (empty($protocol) || ($protocol == Protocol::PHANTOM) || (empty($ret['url']) && empty($ret['addr']))) {
|
||||
$result['message'] .= DI::l10n()->t('The profile address specified does not provide adequate information.') . EOL;
|
||||
$result['message'] .= DI::l10n()->t('The profile address specified does not provide adequate information.') . '<br />';
|
||||
if (empty($ret['poll'])) {
|
||||
$result['message'] .= DI::l10n()->t('No compatible communication protocols or feeds were discovered.') . EOL;
|
||||
$result['message'] .= DI::l10n()->t('No compatible communication protocols or feeds were discovered.') . '<br />';
|
||||
}
|
||||
if (empty($ret['name'])) {
|
||||
$result['message'] .= DI::l10n()->t('An author or name was not found.') . EOL;
|
||||
$result['message'] .= DI::l10n()->t('An author or name was not found.') . '<br />';
|
||||
}
|
||||
if (empty($ret['url'])) {
|
||||
$result['message'] .= DI::l10n()->t('No browser URL could be matched to this address.') . EOL;
|
||||
$result['message'] .= DI::l10n()->t('No browser URL could be matched to this address.') . '<br />';
|
||||
}
|
||||
if (strpos($ret['url'], '@') !== false) {
|
||||
$result['message'] .= DI::l10n()->t('Unable to match @-style Identity Address with a known protocol or email contact.') . EOL;
|
||||
$result['message'] .= DI::l10n()->t('Use mailto: in front of address to force email check.') . EOL;
|
||||
$result['message'] .= DI::l10n()->t('Unable to match @-style Identity Address with a known protocol or email contact.') . '<br />';
|
||||
$result['message'] .= DI::l10n()->t('Use mailto: in front of address to force email check.') . '<br />';
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
if ($protocol === Protocol::OSTATUS && DI::config()->get('system', 'ostatus_disabled')) {
|
||||
$result['message'] .= DI::l10n()->t('The profile address specified belongs to a network which has been disabled on this site.') . EOL;
|
||||
$result['message'] .= DI::l10n()->t('The profile address specified belongs to a network which has been disabled on this site.') . '<br />';
|
||||
$ret['notify'] = '';
|
||||
}
|
||||
|
||||
if (!$ret['notify']) {
|
||||
$result['message'] .= DI::l10n()->t('Limited profile. This person will be unable to receive direct/personal notifications from you.') . EOL;
|
||||
$result['message'] .= DI::l10n()->t('Limited profile. This person will be unable to receive direct/personal notifications from you.') . '<br />';
|
||||
}
|
||||
|
||||
$writeable = ((($protocol === Protocol::OSTATUS) && ($ret['notify'])) ? 1 : 0);
|
||||
|
@ -2937,7 +3009,7 @@ class Contact
|
|||
|
||||
$contact = DBA::selectFirst('contact', [], ['url' => $ret['url'], 'network' => $ret['network'], 'uid' => $uid]);
|
||||
if (!DBA::isResult($contact)) {
|
||||
$result['message'] .= DI::l10n()->t('Unable to retrieve contact information.') . EOL;
|
||||
$result['message'] .= DI::l10n()->t('Unable to retrieve contact information.') . '<br />';
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
@ -2951,13 +3023,13 @@ class Contact
|
|||
|
||||
// pull feed and consume it, which should subscribe to the hub.
|
||||
if ($contact['network'] == Protocol::OSTATUS) {
|
||||
Worker::add(PRIORITY_HIGH, 'OnePoll', $contact_id, 'force');
|
||||
Worker::add(Worker::PRIORITY_HIGH, 'OnePoll', $contact_id, 'force');
|
||||
}
|
||||
|
||||
if ($probed) {
|
||||
self::updateFromProbeArray($contact_id, $ret);
|
||||
} else {
|
||||
Worker::add(PRIORITY_HIGH, 'UpdateContact', $contact_id);
|
||||
Worker::add(Worker::PRIORITY_HIGH, 'UpdateContact', $contact_id);
|
||||
}
|
||||
|
||||
$result['success'] = Protocol::follow($uid, $contact, $protocol);
|
||||
|
@ -3132,11 +3204,14 @@ class Contact
|
|||
return;
|
||||
}
|
||||
|
||||
Worker::add(Worker::PRIORITY_LOW, 'ContactDiscoveryForUser', $contact['uid']);
|
||||
|
||||
self::clearFollowerFollowingEndpointCache($contact['uid']);
|
||||
|
||||
$cdata = self::getPublicAndUserContactID($contact['id'], $contact['uid']);
|
||||
|
||||
DI::notification()->deleteForUserByVerb($contact['uid'], Activity::FOLLOW, ['actor-id' => $cdata['public']]);
|
||||
if (!empty($cdata['public'])) {
|
||||
DI::notification()->deleteForUserByVerb($contact['uid'], Activity::FOLLOW, ['actor-id' => $cdata['public']]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3155,6 +3230,8 @@ class Contact
|
|||
} else {
|
||||
self::update(['rel' => self::FOLLOWER], ['id' => $contact['id']]);
|
||||
}
|
||||
|
||||
Worker::add(Worker::PRIORITY_LOW, 'ContactDiscoveryForUser', $contact['uid']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3233,7 +3310,7 @@ class Contact
|
|||
*/
|
||||
public static function magicLink(string $contact_url, string $url = ''): string
|
||||
{
|
||||
if (!Session::isAuthenticated()) {
|
||||
if (!DI::userSession()->isAuthenticated()) {
|
||||
return $url ?: $contact_url; // Equivalent to: ($url != '') ? $url : $contact_url;
|
||||
}
|
||||
|
||||
|
@ -3279,7 +3356,7 @@ class Contact
|
|||
{
|
||||
$destination = $url ?: $contact['url']; // Equivalent to ($url != '') ? $url : $contact['url'];
|
||||
|
||||
if (!Session::isAuthenticated()) {
|
||||
if (!DI::userSession()->isAuthenticated()) {
|
||||
return $destination;
|
||||
}
|
||||
|
||||
|
@ -3288,7 +3365,7 @@ class Contact
|
|||
return $url;
|
||||
}
|
||||
|
||||
if (DI::pConfig()->get(local_user(), 'system', 'stay_local') && ($url == '')) {
|
||||
if (DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'stay_local') && ($url == '')) {
|
||||
return 'contact/' . $contact['id'] . '/conversations';
|
||||
}
|
||||
|
||||
|
@ -3300,7 +3377,7 @@ class Contact
|
|||
return $destination;
|
||||
}
|
||||
|
||||
$redirect = 'redir/' . $contact['id'];
|
||||
$redirect = 'contact/redir/' . $contact['id'];
|
||||
|
||||
if (($url != '') && !Strings::compareLink($contact['url'], $url)) {
|
||||
$redirect .= '?url=' . $url;
|
||||
|
@ -3349,11 +3426,13 @@ class Contact
|
|||
* @param string $search Name or nick
|
||||
* @param string $mode Search mode (e.g. "community")
|
||||
* @param int $uid User ID
|
||||
* @param int $limit Maximum amount of returned values
|
||||
* @param int $offset Limit offset
|
||||
*
|
||||
* @return array with search results
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public static function searchByName(string $search, string $mode = '', int $uid = 0): array
|
||||
public static function searchByName(string $search, string $mode = '', int $uid = 0, int $limit = 0, int $offset = 0): array
|
||||
{
|
||||
if (empty($search)) {
|
||||
return [];
|
||||
|
@ -3373,6 +3452,8 @@ class Contact
|
|||
|
||||
if ($uid == 0) {
|
||||
$condition['blocked'] = false;
|
||||
} else {
|
||||
$condition['rel'] = [Contact::SHARING, Contact::FRIEND];
|
||||
}
|
||||
|
||||
// check if we search only communities or every contact
|
||||
|
@ -3382,12 +3463,19 @@ class Contact
|
|||
|
||||
$search .= '%';
|
||||
|
||||
$params = [];
|
||||
|
||||
if (!empty($limit) && !empty($offset)) {
|
||||
$params['limit'] = [$offset, $limit];
|
||||
} elseif (!empty($limit)) {
|
||||
$params['limit'] = $limit;
|
||||
}
|
||||
|
||||
$condition = DBA::mergeConditions($condition,
|
||||
["(NOT `unsearchable` OR `nurl` IN (SELECT `nurl` FROM `owner-view` WHERE `publish` OR `net-publish`))
|
||||
AND (`addr` LIKE ? OR `name` LIKE ? OR `nick` LIKE ?)", $search, $search, $search]);
|
||||
|
||||
$contacts = self::selectToArray([], $condition);
|
||||
return $contacts;
|
||||
return self::selectToArray([], $condition, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3409,10 +3497,10 @@ class Contact
|
|||
}
|
||||
$contact = self::getByURL($url, false, ['id', 'network', 'next-update']);
|
||||
if (empty($contact['id']) && Network::isValidHttpUrl($url)) {
|
||||
Worker::add(PRIORITY_LOW, 'AddContact', 0, $url);
|
||||
Worker::add(Worker::PRIORITY_LOW, 'AddContact', 0, $url);
|
||||
++$added;
|
||||
} elseif (!empty($contact['network']) && Probe::isProbable($contact['network']) && ($contact['next-update'] < DateTimeFormat::utcNow())) {
|
||||
Worker::add(['priority' => PRIORITY_LOW, 'dont_fork' => true], 'UpdateContact', $contact['id']);
|
||||
Worker::add(['priority' => Worker::PRIORITY_LOW, 'dont_fork' => true], 'UpdateContact', $contact['id']);
|
||||
++$updated;
|
||||
} else {
|
||||
++$unchanged;
|
||||
|
@ -3442,4 +3530,17 @@ class Contact
|
|||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks, if contacts with the given condition exists
|
||||
*
|
||||
* @param array $condition
|
||||
*
|
||||
* @return bool
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function exists(array $condition): bool
|
||||
{
|
||||
return DBA::exists('contact', $condition);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
namespace Friendica\Model\Contact;
|
||||
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Contact;
|
||||
|
||||
/**
|
||||
|
@ -53,7 +54,7 @@ class Group
|
|||
AND NOT `contact`.`pending`
|
||||
ORDER BY `contact`.`name` ASC',
|
||||
$gid,
|
||||
local_user()
|
||||
DI::userSession()->getLocalUserId()
|
||||
);
|
||||
|
||||
if (DBA::isResult($stmt)) {
|
||||
|
@ -78,7 +79,7 @@ class Group
|
|||
{
|
||||
return Contact::selectToArray([], ["`uid` = ? AND NOT `self` AND NOT `deleted` AND NOT `blocked` AND NOT `pending` AND NOT `failed`
|
||||
AND `id` NOT IN (SELECT DISTINCT(`contact-id`) FROM `group_member` INNER JOIN `group` ON `group`.`id` = `group_member`.`gid`
|
||||
WHERE `group`.`uid` = ?)", $uid, $uid]);
|
||||
WHERE `group`.`uid` = ? AND `contact-id` = `contact`.`id`)", $uid, $uid]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -68,6 +68,26 @@ class Relation
|
|||
DBA::insert('contact-relation', ['last-interaction' => $interaction_date, 'cid' => $target, 'relation-cid' => $actor], Database::INSERT_UPDATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the followers of a given user
|
||||
*
|
||||
* @param integer $uid User ID
|
||||
* @return void
|
||||
*/
|
||||
public static function discoverByUser(int $uid)
|
||||
{
|
||||
$contact = Contact::selectFirst(['id', 'url', 'network'], ['uid' => $uid, 'self' => true]);
|
||||
if (empty($contact)) {
|
||||
Logger::warning('Self contact for user not found', ['uid' => $uid]);
|
||||
return;
|
||||
}
|
||||
|
||||
$followers = self::getContacts($uid, [Contact::FOLLOWER, Contact::FRIEND]);
|
||||
$followings = self::getContacts($uid, [Contact::SHARING, Contact::FRIEND]);
|
||||
|
||||
self::updateFollowersFollowings($contact, $followers, $followings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the followers of a given profile and adds them
|
||||
*
|
||||
|
@ -113,13 +133,27 @@ class Relation
|
|||
$followings = [];
|
||||
}
|
||||
|
||||
self::updateFollowersFollowings($contact, $followers, $followings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update followers and followings for the given contact
|
||||
*
|
||||
* @param array $contact
|
||||
* @param array $followers
|
||||
* @param array $followings
|
||||
* @return void
|
||||
*/
|
||||
private static function updateFollowersFollowings(array $contact, array $followers, array $followings)
|
||||
{
|
||||
if (empty($followers) && empty($followings)) {
|
||||
Contact::update(['last-discovery' => DateTimeFormat::utcNow()], ['id' => $contact['id']]);
|
||||
Logger::info('The contact does not offer discoverable data', ['id' => $contact['id'], 'url' => $url, 'network' => $contact['network']]);
|
||||
Logger::info('The contact does not offer discoverable data', ['id' => $contact['id'], 'url' => $contact['url'], 'network' => $contact['network']]);
|
||||
return;
|
||||
}
|
||||
|
||||
$target = $contact['id'];
|
||||
$url = $contact['url'];
|
||||
|
||||
if (!empty($followers)) {
|
||||
// Clear the follower list, since it will be recreated in the next step
|
||||
|
@ -260,6 +294,59 @@ class Relation
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the cached suggestion is outdated
|
||||
*
|
||||
* @param integer $uid
|
||||
* @return boolean
|
||||
*/
|
||||
static public function areSuggestionsOutdated(int $uid): bool
|
||||
{
|
||||
return DI::pConfig()->get($uid, 'suggestion', 'last_update') + 3600 < time();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update contact suggestions for a given user
|
||||
*
|
||||
* @param integer $uid
|
||||
* @return void
|
||||
*/
|
||||
static public function updateCachedSuggestions(int $uid)
|
||||
{
|
||||
if (!self::areSuggestionsOutdated($uid)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DBA::delete('account-suggestion', ['uid' => $uid, 'ignore' => false]);
|
||||
|
||||
foreach (self::getSuggestions($uid) as $contact) {
|
||||
DBA::insert('account-suggestion', ['uri-id' => $contact['uri-id'], 'uid' => $uid, 'level' => 1], Database::INSERT_IGNORE);
|
||||
}
|
||||
|
||||
DI::pConfig()->set($uid, 'suggestion', 'last_update', time());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a cached array of suggested contacts for given user id
|
||||
*
|
||||
* @param int $uid User id
|
||||
* @param int $start optional, default 0
|
||||
* @param int $limit optional, default 80
|
||||
* @return array
|
||||
*/
|
||||
static public function getCachedSuggestions(int $uid, int $start = 0, int $limit = 80): array
|
||||
{
|
||||
$condition = ["`uid` = ? AND `uri-id` IN (SELECT `uri-id` FROM `account-suggestion` WHERE NOT `ignore` AND `uid` = ?)", 0, $uid];
|
||||
$params = ['limit' => [$start, $limit]];
|
||||
$cached = DBA::selectToArray('contact', [], $condition, $params);
|
||||
|
||||
if (!empty($cached)) {
|
||||
return $cached;
|
||||
} else {
|
||||
return self::getSuggestions($uid, $start, $limit);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of suggested contacts for given user id
|
||||
*
|
||||
|
@ -270,6 +357,10 @@ class Relation
|
|||
*/
|
||||
static public function getSuggestions(int $uid, int $start = 0, int $limit = 80): array
|
||||
{
|
||||
if ($uid == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$cid = Contact::getPublicIdByUserId($uid);
|
||||
$totallimit = $start + $limit;
|
||||
$contacts = [];
|
||||
|
@ -284,12 +375,13 @@ class Relation
|
|||
$results = DBA::select('contact', [], ["`id` IN (SELECT `cid` FROM `contact-relation` WHERE `relation-cid` IN
|
||||
(SELECT `cid` FROM `contact-relation` WHERE `relation-cid` = ?)
|
||||
AND NOT `cid` IN (SELECT `id` FROM `contact` WHERE `uid` = ? AND `nurl` IN
|
||||
(SELECT `nurl` FROM `contact` WHERE `uid` = ? AND `rel` IN (?, ?))))
|
||||
AND NOT `hidden` AND `network` IN (?, ?, ?, ?)",
|
||||
(SELECT `nurl` FROM `contact` WHERE `uid` = ? AND `rel` IN (?, ?))) AND `id` = `cid`)
|
||||
AND NOT `hidden` AND `network` IN (?, ?, ?, ?)
|
||||
AND NOT `uri-id` IN (SELECT `uri-id` FROM `account-suggestion` WHERE `uri-id` = `contact`.`uri-id` AND `uid` = ?)",
|
||||
$cid,
|
||||
0,
|
||||
$uid, Contact::FRIEND, Contact::SHARING,
|
||||
Protocol::ACTIVITYPUB, Protocol::DFRN, $diaspora, $ostatus,
|
||||
Protocol::ACTIVITYPUB, Protocol::DFRN, $diaspora, $ostatus, $uid
|
||||
], [
|
||||
'order' => ['last-item' => true],
|
||||
'limit' => $totallimit,
|
||||
|
@ -314,10 +406,11 @@ class Relation
|
|||
["`id` IN (SELECT `cid` FROM `contact-relation` WHERE `relation-cid` IN
|
||||
(SELECT `relation-cid` FROM `contact-relation` WHERE `cid` = ?)
|
||||
AND NOT `cid` IN (SELECT `id` FROM `contact` WHERE `uid` = ? AND `nurl` IN
|
||||
(SELECT `nurl` FROM `contact` WHERE `uid` = ? AND `rel` IN (?, ?))))
|
||||
AND NOT `hidden` AND `network` IN (?, ?, ?, ?)",
|
||||
(SELECT `nurl` FROM `contact` WHERE `uid` = ? AND `rel` IN (?, ?))) AND `id` = `cid`)
|
||||
AND NOT `hidden` AND `network` IN (?, ?, ?, ?)
|
||||
AND NOT `uri-id` IN (SELECT `uri-id` FROM `account-suggestion` WHERE `uri-id` = `contact`.`uri-id` AND `uid` = ?)",
|
||||
$cid, 0, $uid, Contact::FRIEND, Contact::SHARING,
|
||||
Protocol::ACTIVITYPUB, Protocol::DFRN, $diaspora, $ostatus],
|
||||
Protocol::ACTIVITYPUB, Protocol::DFRN, $diaspora, $ostatus, $uid],
|
||||
['order' => ['last-item' => true], 'limit' => $totallimit]
|
||||
);
|
||||
|
||||
|
@ -335,9 +428,10 @@ class Relation
|
|||
// The query returns contacts that follow the given user but aren't followed by that user.
|
||||
$results = DBA::select('contact', [],
|
||||
["`nurl` IN (SELECT `nurl` FROM `contact` WHERE `uid` = ? AND `rel` = ?)
|
||||
AND NOT `hidden` AND `uid` = ? AND `network` IN (?, ?, ?, ?)",
|
||||
AND NOT `hidden` AND `uid` = ? AND `network` IN (?, ?, ?, ?)
|
||||
AND NOT `uri-id` IN (SELECT `uri-id` FROM `account-suggestion` WHERE `uri-id` = `contact`.`uri-id` AND `uid` = ?)",
|
||||
$uid, Contact::FOLLOWER, 0,
|
||||
Protocol::ACTIVITYPUB, Protocol::DFRN, $diaspora, $ostatus],
|
||||
Protocol::ACTIVITYPUB, Protocol::DFRN, $diaspora, $ostatus, $uid],
|
||||
['order' => ['last-item' => true], 'limit' => $totallimit]
|
||||
);
|
||||
|
||||
|
@ -354,10 +448,11 @@ class Relation
|
|||
|
||||
// The query returns any contact that isn't followed by that user.
|
||||
$results = DBA::select('contact', [],
|
||||
["NOT `nurl` IN (SELECT `nurl` FROM `contact` WHERE `uid` = ? AND `rel` IN (?, ?))
|
||||
AND NOT `hidden` AND `uid` = ? AND `network` IN (?, ?, ?, ?)",
|
||||
["NOT `nurl` IN (SELECT `nurl` FROM `contact` WHERE `uid` = ? AND `rel` IN (?, ?) AND `nurl` = `nurl`)
|
||||
AND NOT `hidden` AND `uid` = ? AND `network` IN (?, ?, ?, ?)
|
||||
AND NOT `uri-id` IN (SELECT `uri-id` FROM `account-suggestion` WHERE `uri-id` = `contact`.`uri-id` AND `uid` = ?)",
|
||||
$uid, Contact::FRIEND, Contact::SHARING, 0,
|
||||
Protocol::ACTIVITYPUB, Protocol::DFRN, $diaspora, $ostatus],
|
||||
Protocol::ACTIVITYPUB, Protocol::DFRN, $diaspora, $ostatus, $uid],
|
||||
['order' => ['last-item' => true], 'limit' => $totallimit]
|
||||
);
|
||||
|
||||
|
|
|
@ -21,18 +21,20 @@
|
|||
|
||||
namespace Friendica\Model;
|
||||
|
||||
use Friendica\Content\Feature;
|
||||
use Friendica\Content\Text\BBCode;
|
||||
use Friendica\Core\Hook;
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\Protocol;
|
||||
use Friendica\Core\Renderer;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Protocol\Activity;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
use Friendica\Util\Map;
|
||||
use Friendica\Util\Strings;
|
||||
use Friendica\Util\Temporal;
|
||||
use Friendica\Util\XML;
|
||||
|
||||
/**
|
||||
|
@ -279,7 +281,7 @@ class Event
|
|||
if (!DBA::isResult($existing_event)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if ($existing_event['edited'] === $event['edited']) {
|
||||
return $event['id'];
|
||||
}
|
||||
|
@ -410,7 +412,7 @@ class Event
|
|||
public static function getStrings(): array
|
||||
{
|
||||
// First day of the week (0 = Sunday).
|
||||
$firstDay = DI::pConfig()->get(local_user(), 'system', 'first_day_of_week', 0);
|
||||
$firstDay = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'first_day_of_week', 0);
|
||||
|
||||
$i18n = [
|
||||
"firstDay" => $firstDay,
|
||||
|
@ -495,157 +497,197 @@ class Event
|
|||
}
|
||||
|
||||
/**
|
||||
* Get an event by its event ID.
|
||||
* Returns the owner array of a given nickname
|
||||
* Additionally, it can check if the owner array is selectable
|
||||
*
|
||||
* @param int $owner_uid The User ID of the owner of the event
|
||||
* @param int $event_id The ID of the event in the event table
|
||||
* @param string $sql_extra
|
||||
* @param string $nickname
|
||||
*
|
||||
* @return array the owner array
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws HTTPException\NotFoundException The given nickname does not exist
|
||||
* @throws HTTPException\UnauthorizedException The access for the given nickname is restricted
|
||||
*/
|
||||
public static function getOwnerForNickname(string $nickname): array
|
||||
{
|
||||
$owner = User::getOwnerDataByNick($nickname);
|
||||
if (empty($owner) || $owner['account_removed'] || $owner['account_expired']) {
|
||||
throw new HTTPException\NotFoundException(DI::l10n()->t('User not found.'));
|
||||
}
|
||||
|
||||
if (!DI::userSession()->isAuthenticated() && $owner['hidewall']) {
|
||||
throw new HTTPException\UnauthorizedException(DI::l10n()->t('Access to this profile has been restricted.'));
|
||||
}
|
||||
|
||||
if (!DI::userSession()->isAuthenticated() && !Feature::isEnabled($owner['uid'], 'public_calendar')) {
|
||||
throw new HTTPException\UnauthorizedException(DI::l10n()->t('Permission denied.'));
|
||||
}
|
||||
|
||||
return $owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an event by its event ID. Checks permissions.
|
||||
*
|
||||
* @param int $owner_uid The User ID of the owner of the event
|
||||
* @param int $event_id The ID of the event in the event table
|
||||
* @param string|null $nickname a possible nickname to search for instead of the owner uid
|
||||
* @return array Query result
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function getListById(int $owner_uid, int $event_id, string $sql_extra = ''): array
|
||||
public static function getByIdAndUid(int $owner_uid, int $event_id): array
|
||||
{
|
||||
$return = [];
|
||||
|
||||
// Ownly allow events if there is a valid owner_id.
|
||||
// Only allow events if there is a valid owner_id.
|
||||
if ($owner_uid == 0) {
|
||||
return $return;
|
||||
return [];
|
||||
}
|
||||
|
||||
// get the permissions
|
||||
$sql_perms = Item::getPermissionsSQLByUserId($owner_uid);
|
||||
|
||||
// Query for the event by event id
|
||||
$events = DBA::toArray(DBA::p("SELECT `event`.*, `post-user`.`id` AS `itemid` FROM `event`
|
||||
LEFT JOIN `post-user` ON `post-user`.`event-id` = `event`.`id` AND `post-user`.`uid` = `event`.`uid`
|
||||
WHERE `event`.`uid` = ? AND `event`.`id` = ? $sql_extra",
|
||||
$owner_uid, $event_id));
|
||||
|
||||
if (DBA::isResult($events)) {
|
||||
$return = self::removeDuplicates($events);
|
||||
$events = DBA::toArray(DBA::p(
|
||||
"SELECT `event`.*, `post-user`.`id` AS `itemid` FROM `event`
|
||||
LEFT JOIN `post-user`
|
||||
ON `post-user`.`event-id` = `event`.`id`
|
||||
AND `post-user`.`uid` = `event`.`uid`
|
||||
WHERE `event`.`id` = ?
|
||||
AND `event`.`uid` = ?
|
||||
$sql_perms",
|
||||
$event_id, $owner_uid
|
||||
));
|
||||
if (empty($events)) {
|
||||
throw new HTTPException\NotFoundException(DI::l10n()->t('Event not found.'));
|
||||
}
|
||||
|
||||
return $return;
|
||||
return $events[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all events in a specific time frame.
|
||||
*
|
||||
* @param int $owner_uid The User ID of the owner of the events.
|
||||
* @param array $event_params An associative array with
|
||||
* int 'ignore' =>
|
||||
* string 'start' => Start time of the timeframe.
|
||||
* string 'finish' => Finish time of the timeframe.
|
||||
*
|
||||
* @param string $sql_extra Additional sql conditions (e.g. permission request).
|
||||
* @param int $owner_uid The User ID of the owner of the events.
|
||||
* @param string|null $start Start time of the timeframe.
|
||||
* @param string|null $finish Finish time of the timeframe.
|
||||
* @param bool|null $ignore Filters ignored events (false: unignored events, true: ignored events, null: all events)
|
||||
*
|
||||
* @return array Query results.
|
||||
* @throws \Exception
|
||||
* @throws HTTPException\NotFoundException
|
||||
* @throws HTTPException\UnauthorizedException
|
||||
*/
|
||||
public static function getListByDate(int $owner_uid, array $event_params, string $sql_extra = ''): array
|
||||
public static function getListByDate(int $owner_uid, string $start = null, string $finish = null, ?bool $ignore = false): array
|
||||
{
|
||||
$return = [];
|
||||
|
||||
// Only allow events if there is a valid owner_id.
|
||||
if ($owner_uid == 0) {
|
||||
return $return;
|
||||
return [];
|
||||
}
|
||||
|
||||
// get the permissions
|
||||
$sql_perms = Item::getPermissionsSQLByUserId($owner_uid);
|
||||
|
||||
if (empty($start) || empty($finish)) {
|
||||
$y = intval(DateTimeFormat::localNow('Y'));
|
||||
$m = intval(DateTimeFormat::localNow('m'));
|
||||
|
||||
if (empty($start)) {
|
||||
$start = sprintf('%d-%d-%d %d:%d:%d', $y, $m, 1, 0, 0, 0);
|
||||
} else {
|
||||
$dim = Temporal::getDaysInMonth($y, $m);
|
||||
$finish = sprintf('%d-%d-%d %d:%d:%d', $y, $m, $dim, 23, 59, 59);
|
||||
}
|
||||
}
|
||||
|
||||
if ($ignore === true) {
|
||||
$sql_ignore = " AND `event`.`ignore` = 1";
|
||||
} elseif ($ignore === false) {
|
||||
$sql_ignore = " AND `event`.`ignore` = 0";
|
||||
} else {
|
||||
$sql_ignore = "";
|
||||
}
|
||||
|
||||
// Query for the event by date.
|
||||
$events = DBA::toArray(DBA::p("SELECT `event`.*, `post-user`.`id` AS `itemid` FROM `event`
|
||||
LEFT JOIN `post-user` ON `post-user`.`event-id` = `event`.`id` AND `post-user`.`uid` = `event`.`uid`
|
||||
WHERE `event`.`uid` = ? AND `event`.`ignore` = ?
|
||||
AND (`finish` >= ? OR (`nofinish` AND `start` >= ?)) AND `start` <= ?
|
||||
" . $sql_extra,
|
||||
$owner_uid, $event_params['ignore'],
|
||||
$event_params['start'], $event_params['start'], $event_params['finish']
|
||||
$events = DBA::toArray(DBA::p(
|
||||
"SELECT `event`.*, `post-user`.`id` AS `itemid` FROM `event`
|
||||
LEFT JOIN `post-user`
|
||||
ON `post-user`.`event-id` = `event`.`id`
|
||||
AND `post-user`.`uid` = `event`.`uid`
|
||||
WHERE `event`.`uid` = ?
|
||||
$sql_ignore
|
||||
AND (`finish` >= ? OR (`nofinish` AND `start` >= ?))
|
||||
AND `start` <= ?
|
||||
$sql_perms",
|
||||
$owner_uid,
|
||||
$start, $start,
|
||||
$finish
|
||||
));
|
||||
|
||||
if (DBA::isResult($events)) {
|
||||
$return = self::removeDuplicates($events);
|
||||
}
|
||||
|
||||
return $return;
|
||||
$events = self::removeDuplicates($events);
|
||||
return self::sortByDate($events);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an array query results in an array which could be used by the events template.
|
||||
* Convert an event in an array which could be used by the event template.
|
||||
*
|
||||
* @param array $event_result Event query array.
|
||||
* @param array $event Event query array.
|
||||
* @return array Event array for the template.
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
public static function prepareListForTemplate(array $event_result): array
|
||||
public static function prepareForItem(array $event): array
|
||||
{
|
||||
$event_list = [];
|
||||
|
||||
$last_date = '';
|
||||
$fmt = DI::l10n()->t('l, F j');
|
||||
foreach ($event_result as $event) {
|
||||
$item = Post::selectFirst(['plink', 'author-name', 'author-avatar', 'author-link', 'private', 'uri-id'], ['id' => $event['itemid']]);
|
||||
if (!DBA::isResult($item)) {
|
||||
// Using default values when no item had been found
|
||||
$item = ['plink' => '', 'author-name' => '', 'author-avatar' => '', 'author-link' => '', 'private' => Item::PUBLIC, 'uri-id' => ($event['uri-id'] ?? 0)];
|
||||
}
|
||||
|
||||
$event = array_merge($event, $item);
|
||||
|
||||
$start = DateTimeFormat::local($event['start'], 'c');
|
||||
$j = DateTimeFormat::local($event['start'], 'j');
|
||||
$day = DateTimeFormat::local($event['start'], $fmt);
|
||||
$day = DI::l10n()->getDay($day);
|
||||
|
||||
if ($event['nofinish']) {
|
||||
$end = null;
|
||||
} else {
|
||||
$end = DateTimeFormat::local($event['finish'], 'c');
|
||||
}
|
||||
|
||||
$is_first = ($day !== $last_date);
|
||||
|
||||
$last_date = $day;
|
||||
|
||||
// Show edit and drop actions only if the user is the owner of the event and the event
|
||||
// is a real event (no bithdays).
|
||||
$edit = null;
|
||||
$copy = null;
|
||||
$drop = null;
|
||||
if (local_user() && local_user() == $event['uid'] && $event['type'] == 'event') {
|
||||
$edit = !$event['cid'] ? [DI::baseUrl() . '/events/event/' . $event['id'], DI::l10n()->t('Edit event') , '', ''] : null;
|
||||
$copy = !$event['cid'] ? [DI::baseUrl() . '/events/copy/' . $event['id'] , DI::l10n()->t('Duplicate event'), '', ''] : null;
|
||||
$drop = [DI::baseUrl() . '/events/drop/' . $event['id'] , DI::l10n()->t('Delete event') , '', ''];
|
||||
}
|
||||
|
||||
$title = BBCode::convertForUriId($event['uri-id'], Strings::escapeHtml($event['summary']));
|
||||
if (!$title) {
|
||||
list($title, $_trash) = explode("<br", BBCode::convertForUriId($event['uri-id'], Strings::escapeHtml($event['desc'])), BBCode::API);
|
||||
}
|
||||
|
||||
$author_link = $event['author-link'];
|
||||
|
||||
$event['author-link'] = Contact::magicLink($author_link);
|
||||
|
||||
$html = self::getHTML($event);
|
||||
$event['summary'] = BBCode::convertForUriId($event['uri-id'], Strings::escapeHtml($event['summary']));
|
||||
$event['desc'] = BBCode::convertForUriId($event['uri-id'], Strings::escapeHtml($event['desc']));
|
||||
$event['location'] = BBCode::convertForUriId($event['uri-id'], Strings::escapeHtml($event['location']));
|
||||
$event_list[] = [
|
||||
'id' => $event['id'],
|
||||
'start' => $start,
|
||||
'end' => $end,
|
||||
'allDay' => false,
|
||||
'title' => $title,
|
||||
'j' => $j,
|
||||
'd' => $day,
|
||||
'edit' => $edit,
|
||||
'drop' => $drop,
|
||||
'copy' => $copy,
|
||||
'is_first' => $is_first,
|
||||
'item' => $event,
|
||||
'html' => $html,
|
||||
'plink' => Item::getPlink($event),
|
||||
];
|
||||
$item = Post::selectFirst(['plink', 'author-name', 'author-network', 'author-id', 'author-avatar', 'author-link', 'private', 'uri-id'], ['id' => $event['itemid']]);
|
||||
if (empty($item)) {
|
||||
// Using default values when no item had been found
|
||||
$item = ['plink' => '', 'author-name' => '', 'author-avatar' => '', 'author-link' => '', 'private' => Item::PUBLIC, 'uri-id' => ($event['uri-id'] ?? 0)];
|
||||
}
|
||||
|
||||
return $event_list;
|
||||
$event = array_merge($event, $item);
|
||||
|
||||
$start = DateTimeFormat::local($event['start'], 'c');
|
||||
$j = DateTimeFormat::local($event['start'], 'j');
|
||||
$day = DateTimeFormat::local($event['start'], $fmt);
|
||||
$day = DI::l10n()->getDay($day);
|
||||
|
||||
if ($event['nofinish']) {
|
||||
$end = null;
|
||||
} else {
|
||||
$end = DateTimeFormat::local($event['finish'], 'c');
|
||||
}
|
||||
|
||||
// Show edit and drop actions only if the user is the owner of the event and the event
|
||||
// is a real event (no bithdays).
|
||||
$edit = null;
|
||||
$copy = null;
|
||||
$drop = null;
|
||||
if (DI::userSession()->getLocalUserId() && DI::userSession()->getLocalUserId() == $event['uid'] && $event['type'] == 'event') {
|
||||
$edit = !$event['cid'] ? ['calendar/event/edit/' . $event['id'], DI::l10n()->t('Edit event') , '', ''] : null;
|
||||
$copy = !$event['cid'] ? ['calendar/event/copy/' . $event['id'] , DI::l10n()->t('Duplicate event'), '', ''] : null;
|
||||
$drop = ['calendar/api/delete/' . $event['id'] , DI::l10n()->t('Delete event') , '', ''];
|
||||
}
|
||||
|
||||
$title = BBCode::convertForUriId($event['uri-id'], Strings::escapeHtml($event['summary']));
|
||||
if (!$title) {
|
||||
[$title, $_trash] = explode("<br", BBCode::convertForUriId($event['uri-id'], Strings::escapeHtml($event['desc'])), BBCode::TWITTER_API);
|
||||
}
|
||||
|
||||
$event['author-link'] = Contact::magicLink($event['author-link']);
|
||||
|
||||
return [
|
||||
'id' => $event['id'],
|
||||
'start' => $start,
|
||||
'end' => $end,
|
||||
'allDay' => false,
|
||||
'title' => $title,
|
||||
'j' => $j,
|
||||
'd' => $day,
|
||||
'edit' => $edit,
|
||||
'drop' => $drop,
|
||||
'copy' => $copy,
|
||||
'item' => $event,
|
||||
'html' => self::getHTML($event),
|
||||
'plink' => Item::getPlink($event),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -653,8 +695,6 @@ class Event
|
|||
*
|
||||
* @param array $events Query result for events.
|
||||
* @param string $format The output format (ical/csv).
|
||||
*
|
||||
* @param string $timezone Timezone (missing parameter!)
|
||||
* @return string Content according to selected export format.
|
||||
*
|
||||
* @todo Implement timezone support
|
||||
|
@ -670,14 +710,13 @@ class Event
|
|||
switch ($format) {
|
||||
// Format the exported data as a CSV file.
|
||||
case "csv":
|
||||
header("Content-type: text/csv");
|
||||
$o .= '"Subject", "Start Date", "Start Time", "Description", "End Date", "End Time", "Location"' . PHP_EOL;
|
||||
|
||||
foreach ($events as $event) {
|
||||
/// @todo The time / date entries don't include any information about the
|
||||
/// timezone the event is scheduled in :-/
|
||||
$tmp1 = strtotime($event['start']);
|
||||
$tmp2 = strtotime($event['finish']);
|
||||
$tmp1 = strtotime($event['start']);
|
||||
$tmp2 = strtotime($event['finish']);
|
||||
$time_format = "%H:%M:%S";
|
||||
$date_format = "%Y-%m-%d";
|
||||
|
||||
|
@ -691,7 +730,6 @@ class Event
|
|||
|
||||
// Format the exported data as a ics file.
|
||||
case "ical":
|
||||
header("Content-type: text/ics");
|
||||
$o = 'BEGIN:VCALENDAR' . PHP_EOL
|
||||
. 'VERSION:2.0' . PHP_EOL
|
||||
. 'PRODID:-//friendica calendar export//0.1//EN' . PHP_EOL;
|
||||
|
@ -705,6 +743,8 @@ class Event
|
|||
// also long lines SHOULD be split at 75 characters length
|
||||
foreach ($events as $event) {
|
||||
$o .= 'BEGIN:VEVENT' . PHP_EOL;
|
||||
$o .= 'UID:' . $event['id'] . PHP_EOL;
|
||||
$o .= 'DTSTAMP:' . DateTimeFormat::utc($event['created'], 'Ymd\THis\Z') . PHP_EOL;
|
||||
|
||||
if ($event['start']) {
|
||||
$o .= 'DTSTART:' . DateTimeFormat::utc($event['start'], 'Ymd\THis\Z') . PHP_EOL;
|
||||
|
@ -718,25 +758,24 @@ class Event
|
|||
$tmp = $event['summary'];
|
||||
$tmp = str_replace(PHP_EOL, PHP_EOL . ' ', $tmp);
|
||||
$tmp = addcslashes($tmp, ',;');
|
||||
$o .= 'SUMMARY:' . $tmp . PHP_EOL;
|
||||
$o .= 'SUMMARY:' . $tmp . PHP_EOL;
|
||||
}
|
||||
|
||||
if ($event['desc']) {
|
||||
$tmp = $event['desc'];
|
||||
$tmp = str_replace(PHP_EOL, PHP_EOL . ' ', $tmp);
|
||||
$tmp = addcslashes($tmp, ',;');
|
||||
$o .= 'DESCRIPTION:' . $tmp . PHP_EOL;
|
||||
$o .= 'DESCRIPTION:' . $tmp . PHP_EOL;
|
||||
}
|
||||
|
||||
if ($event['location']) {
|
||||
$tmp = $event['location'];
|
||||
$tmp = str_replace(PHP_EOL, PHP_EOL . ' ', $tmp);
|
||||
$tmp = addcslashes($tmp, ',;');
|
||||
$o .= 'LOCATION:' . $tmp . PHP_EOL;
|
||||
$o .= 'LOCATION:' . $tmp . PHP_EOL;
|
||||
}
|
||||
|
||||
$o .= 'END:VEVENT' . PHP_EOL;
|
||||
$o .= PHP_EOL;
|
||||
}
|
||||
|
||||
$o .= 'END:VCALENDAR' . PHP_EOL;
|
||||
|
@ -768,14 +807,14 @@ class Event
|
|||
return $return;
|
||||
}
|
||||
|
||||
$fields = ['start', 'finish', 'summary', 'desc', 'location', 'nofinish'];
|
||||
$fields = ['id', 'created', 'start', 'finish', 'summary', 'desc', 'location', 'nofinish'];
|
||||
|
||||
$conditions = ['uid' => $uid, 'cid' => 0];
|
||||
|
||||
// Does the user who requests happen to be the owner of the events
|
||||
// requested? then show all of your events, otherwise only those that
|
||||
// don't have limitations set in allow_cid and allow_gid.
|
||||
if (local_user() != $uid) {
|
||||
if (DI::userSession()->getLocalUserId() != $uid) {
|
||||
$conditions += ['allow_cid' => '', 'allow_gid' => ''];
|
||||
}
|
||||
|
||||
|
@ -859,42 +898,42 @@ class Event
|
|||
$tformat = DI::l10n()->t('g:i A'); // 8:01 AM.
|
||||
|
||||
// Convert the time to different formats.
|
||||
$dtstart_dt = DI::l10n()->getDay(DateTimeFormat::local($item['event-start'], $dformat));
|
||||
$dtstart_dt = DI::l10n()->getDay(DateTimeFormat::local($item['event-start'], $dformat));
|
||||
$dtstart_title = DateTimeFormat::utc($item['event-start'], DateTimeFormat::ATOM);
|
||||
// Format: Jan till Dec.
|
||||
$month_short = DI::l10n()->getDayShort(DateTimeFormat::local($item['event-start'], 'M'));
|
||||
// Format: 1 till 31.
|
||||
$date_short = DateTimeFormat::local($item['event-start'], 'j');
|
||||
$start_time = DateTimeFormat::local($item['event-start'], $tformat);
|
||||
$date_short = DateTimeFormat::local($item['event-start'], 'j');
|
||||
$start_time = DateTimeFormat::local($item['event-start'], $tformat);
|
||||
$start_short = DI::l10n()->getDayShort(DateTimeFormat::local($item['event-start'], $dformat_short));
|
||||
|
||||
// If the option 'nofinisch' isn't set, we need to format the finish date/time.
|
||||
if (!$item['event-nofinish']) {
|
||||
$finish = true;
|
||||
$dtend_dt = DI::l10n()->getDay(DateTimeFormat::local($item['event-finish'], $dformat));
|
||||
$finish = true;
|
||||
$dtend_dt = DI::l10n()->getDay(DateTimeFormat::local($item['event-finish'], $dformat));
|
||||
$dtend_title = DateTimeFormat::utc($item['event-finish'], DateTimeFormat::ATOM);
|
||||
$end_short = DI::l10n()->getDayShort(DateTimeFormat::utc($item['event-finish'], $dformat_short));
|
||||
$end_time = DateTimeFormat::local($item['event-finish'], $tformat);
|
||||
$end_short = DI::l10n()->getDayShort(DateTimeFormat::utc($item['event-finish'], $dformat_short));
|
||||
$end_time = DateTimeFormat::local($item['event-finish'], $tformat);
|
||||
// Check if start and finish time is at the same day.
|
||||
if (substr($dtstart_title, 0, 10) === substr($dtend_title, 0, 10)) {
|
||||
$same_date = true;
|
||||
}
|
||||
} else {
|
||||
$dtend_title = '';
|
||||
$dtend_dt = '';
|
||||
$end_time = '';
|
||||
$end_short = '';
|
||||
$dtend_dt = '';
|
||||
$end_time = '';
|
||||
$end_short = '';
|
||||
}
|
||||
|
||||
// Format the event location.
|
||||
$location = self::locationToArray($item['event-location']);
|
||||
|
||||
// Construct the profile link (magic-auth).
|
||||
$author = ['uid' => 0, 'id' => $item['author-id'],
|
||||
'network' => $item['author-network'], 'url' => $item['author-link']];
|
||||
$author = ['uid' => 0, 'id' => $item['author-id'],
|
||||
'network' => $item['author-network'], 'url' => $item['author-link']];
|
||||
$profile_link = Contact::magicLinkByContact($author);
|
||||
|
||||
$tpl = Renderer::getMarkupTemplate('event_stream_item.tpl');
|
||||
$tpl = Renderer::getMarkupTemplate('event_stream_item.tpl');
|
||||
$return = Renderer::replaceMacros($tpl, [
|
||||
'$id' => $item['event-id'],
|
||||
'$title' => BBCode::convertForUriId($item['uri-id'], $item['event-summary']),
|
||||
|
@ -952,15 +991,15 @@ class Event
|
|||
if (strpos($s, '[/map]') !== false) {
|
||||
$found = preg_match("/\[map\](.*?)\[\/map\]/ism", $s, $match);
|
||||
if (intval($found) > 0 && array_key_exists(1, $match)) {
|
||||
$location['address'] = $match[1];
|
||||
$location['address'] = $match[1];
|
||||
// Remove the map bbcode from the location name.
|
||||
$location['name'] = str_replace($match[0], "", $s);
|
||||
}
|
||||
// Map tag with coordinates - e.g. [map=48.864716,2.349014].
|
||||
// Map tag with coordinates - e.g. [map=48.864716,2.349014].
|
||||
} elseif (strpos($s, '[map=') !== false) {
|
||||
$found = preg_match("/\[map=(.*?)\]/ism", $s, $match);
|
||||
if (intval($found) > 0 && array_key_exists(1, $match)) {
|
||||
$location['coordinates'] = $match[1];
|
||||
$location['coordinates'] = $match[1];
|
||||
// Remove the map bbcode from the location name.
|
||||
$location['name'] = str_replace($match[0], "", $s);
|
||||
}
|
||||
|
@ -990,10 +1029,10 @@ class Event
|
|||
{
|
||||
// Check for duplicates
|
||||
$condition = [
|
||||
'uid' => $contact['uid'],
|
||||
'cid' => $contact['id'],
|
||||
'uid' => $contact['uid'],
|
||||
'cid' => $contact['id'],
|
||||
'start' => DateTimeFormat::utc($birthday),
|
||||
'type' => 'birthday'
|
||||
'type' => 'birthday'
|
||||
];
|
||||
if (DBA::exists('event', $condition)) {
|
||||
return false;
|
||||
|
@ -1019,4 +1058,9 @@ class Event
|
|||
// Check if self::store() was success
|
||||
return (self::store($values) > 0);
|
||||
}
|
||||
|
||||
public static function setIgnore(int $uid, int $eventId, bool $ignore = true)
|
||||
{
|
||||
DBA::update('event', ['ignore' => $ignore], ['id' => $eventId, 'uid' => $uid]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,160 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
*
|
||||
* @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\Core\Worker;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Network\Probe;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
use Friendica\Util\Strings;
|
||||
|
||||
class FContact
|
||||
{
|
||||
/**
|
||||
* Fetches data for a given handle
|
||||
*
|
||||
* @param string $handle The handle
|
||||
* @param boolean $update true = always update, false = never update, null = update when not found or outdated
|
||||
*
|
||||
* @return array the queried data
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
public static function getByURL(string $handle, $update = null): array
|
||||
{
|
||||
Logger::debug('Fetch fcontact', ['handle' => $handle, 'update' => $update]);
|
||||
$person = DBA::selectFirst('fcontact', [], ['network' => Protocol::DIASPORA, 'addr' => $handle]);
|
||||
if (!DBA::isResult($person)) {
|
||||
$urls = [$handle, str_replace('http://', 'https://', $handle), Strings::normaliseLink($handle)];
|
||||
$person = DBA::selectFirst('fcontact', [], ['network' => Protocol::DIASPORA, 'url' => $urls]);
|
||||
}
|
||||
|
||||
if (DBA::isResult($person)) {
|
||||
Logger::debug('In cache', ['handle' => $handle]);
|
||||
|
||||
if (is_null($update)) {
|
||||
$update = empty($person['guid']) || empty($person['uri-id']) || ($person['created'] <= DBA::NULL_DATETIME);
|
||||
if (GServer::getNextUpdateDate(true, $person['created'], $person['updated'], false) < DateTimeFormat::utcNow()) {
|
||||
Logger::debug('Start background update', ['handle' => $handle]);
|
||||
Worker::add(['priority' => PRIORITY_LOW, 'dont_fork' => true], 'UpdateFContact', $handle);
|
||||
}
|
||||
}
|
||||
} elseif (is_null($update)) {
|
||||
$update = true;
|
||||
} else {
|
||||
$person = [];
|
||||
}
|
||||
|
||||
if ($update) {
|
||||
Logger::info('create or refresh', ['handle' => $handle]);
|
||||
$data = Probe::uri($handle, Protocol::DIASPORA);
|
||||
|
||||
// Note that Friendica contacts will return a "Diaspora person"
|
||||
// if Diaspora connectivity is enabled on their server
|
||||
if ($data['network'] ?? '' === Protocol::DIASPORA) {
|
||||
self::updateFromProbeArray($data);
|
||||
|
||||
$person = self::getByURL($handle, false);
|
||||
}
|
||||
}
|
||||
|
||||
return $person;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the fcontact table
|
||||
*
|
||||
* @param array $arr The fcontact data
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function updateFromProbeArray(array $arr)
|
||||
{
|
||||
$uriid = ItemURI::insert(['uri' => $arr['url'], 'guid' => $arr['guid']]);
|
||||
|
||||
$fcontact = DBA::selectFirst('fcontact', ['created'], ['url' => $arr['url'], 'network' => $arr['network']]);
|
||||
$contact = Contact::getByUriId($uriid, ['id', 'created']);
|
||||
$apcontact = APContact::getByURL($arr['url'], false);
|
||||
if (!empty($apcontact)) {
|
||||
$interacted = $apcontact['following_count'];
|
||||
$interacting = $apcontact['followers_count'];
|
||||
$posts = $apcontact['statuses_count'];
|
||||
} elseif (!empty($contact['id'])) {
|
||||
$last_interaction = DateTimeFormat::utc('now - 180 days');
|
||||
|
||||
$interacted = DBA::count('contact-relation', ["`cid` = ? AND NOT `follows` AND `last-interaction` > ?", $contact['id'], $last_interaction]);
|
||||
$interacting = DBA::count('contact-relation', ["`relation-cid` = ? AND NOT `follows` AND `last-interaction` > ?", $contact['id'], $last_interaction]);
|
||||
$posts = DBA::count('post', ['author-id' => $contact['id'], 'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT]]);
|
||||
}
|
||||
|
||||
$fields = [
|
||||
'name' => $arr['name'],
|
||||
'photo' => $arr['photo'],
|
||||
'request' => $arr['request'],
|
||||
'nick' => $arr['nick'],
|
||||
'addr' => strtolower($arr['addr']),
|
||||
'guid' => $arr['guid'],
|
||||
'batch' => $arr['batch'],
|
||||
'notify' => $arr['notify'],
|
||||
'poll' => $arr['poll'],
|
||||
'confirm' => $arr['confirm'],
|
||||
'alias' => $arr['alias'],
|
||||
'pubkey' => $arr['pubkey'],
|
||||
'uri-id' => $uriid,
|
||||
'interacting_count' => $interacting ?? 0,
|
||||
'interacted_count' => $interacted ?? 0,
|
||||
'post_count' => $posts ?? 0,
|
||||
'updated' => DateTimeFormat::utcNow(),
|
||||
];
|
||||
|
||||
if (empty($fcontact['created'])) {
|
||||
$fields['created'] = $fields['updated'];
|
||||
} elseif (!empty($contact['created']) && ($fcontact['created'] <= DBA::NULL_DATETIME)) {
|
||||
$fields['created'] = $contact['created'];
|
||||
}
|
||||
|
||||
$fields = DI::dbaDefinition()->truncateFieldsForTable('fcontact', $fields);
|
||||
DBA::update('fcontact', $fields, ['url' => $arr['url'], 'network' => $arr['network']], true);
|
||||
}
|
||||
|
||||
/**
|
||||
* get a url (scheme://domain.tld/u/user) from a given Diaspora*
|
||||
* fcontact guid
|
||||
*
|
||||
* @param string $fcontact_guid Hexadecimal string guid
|
||||
* @return string|null the contact url or null
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function getUrlByGuid(string $fcontact_guid)
|
||||
{
|
||||
Logger::info('fcontact', ['guid' => $fcontact_guid]);
|
||||
|
||||
$fcontact = DBA::selectFirst('fcontact', ['url'], ["`url` != ? AND `network` = ? AND `guid` = ?", '', Protocol::DIASPORA, $fcontact_guid]);
|
||||
if (DBA::isResult($fcontact)) {
|
||||
return $fcontact['url'];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -70,6 +70,7 @@ class GServer
|
|||
const DETECT_UNSPECIFIC = [self::DETECT_MANUAL, self::DETECT_HEADER, self::DETECT_BODY, self::DETECT_HOST_META, self::DETECT_CONTACTS, self::DETECT_AP_ACTOR];
|
||||
|
||||
// Implementation specific endpoints
|
||||
// @todo Possibly add Lemmy detection via the endpoint /api/v3/site
|
||||
const DETECT_FRIENDIKA = 10;
|
||||
const DETECT_FRIENDICA = 11;
|
||||
const DETECT_STATUSNET = 12;
|
||||
|
@ -102,7 +103,7 @@ class GServer
|
|||
return;
|
||||
}
|
||||
|
||||
Worker::add(PRIORITY_LOW, 'UpdateGServer', $url, $only_nodeinfo);
|
||||
Worker::add(Worker::PRIORITY_LOW, 'UpdateGServer', $url, $only_nodeinfo);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -115,12 +116,12 @@ class GServer
|
|||
*/
|
||||
public static function getID(string $url, bool $no_check = false): ?int
|
||||
{
|
||||
$url = self::cleanURL($url);
|
||||
|
||||
if (empty($url)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$url = self::cleanURL($url);
|
||||
|
||||
$gserver = DBA::selectFirst('gserver', ['id'], ['nurl' => Strings::normaliseLink($url)]);
|
||||
if (DBA::isResult($gserver)) {
|
||||
Logger::debug('Got ID for URL', ['id' => $gserver['id'], 'url' => $url, 'callstack' => System::callstack(20)]);
|
||||
|
@ -323,6 +324,10 @@ class GServer
|
|||
$url = str_replace('/index.php', '', $url);
|
||||
|
||||
$urlparts = parse_url($url);
|
||||
if (empty($urlparts)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
unset($urlparts['user']);
|
||||
unset($urlparts['pass']);
|
||||
unset($urlparts['query']);
|
||||
|
@ -1209,7 +1214,7 @@ class GServer
|
|||
|
||||
if (!empty($data['url'])) {
|
||||
$serverdata['platform'] = strtolower($data['platform']);
|
||||
$serverdata['version'] = $data['version'];
|
||||
$serverdata['version'] = $data['version'] ?? 'N/A';
|
||||
}
|
||||
|
||||
if (!empty($data['plugins'])) {
|
||||
|
@ -1325,7 +1330,7 @@ class GServer
|
|||
private static function validHostMeta(string $url): bool
|
||||
{
|
||||
$xrd_timeout = DI::config()->get('system', 'xrd_timeout');
|
||||
$curlResult = DI::httpClient()->get($url . '/.well-known/host-meta', HttpClientAccept::XRD_XML, [HttpClientOptions::TIMEOUT => $xrd_timeout]);
|
||||
$curlResult = DI::httpClient()->get($url . Probe::HOST_META, HttpClientAccept::XRD_XML, [HttpClientOptions::TIMEOUT => $xrd_timeout]);
|
||||
if (!$curlResult->isSuccess()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -2108,10 +2113,10 @@ class GServer
|
|||
|
||||
while ($gserver = DBA::fetch($gservers)) {
|
||||
Logger::info('Update peer list', ['server' => $gserver['url'], 'id' => $gserver['id']]);
|
||||
Worker::add(PRIORITY_LOW, 'UpdateServerPeers', $gserver['url']);
|
||||
Worker::add(Worker::PRIORITY_LOW, 'UpdateServerPeers', $gserver['url']);
|
||||
|
||||
Logger::info('Update directory', ['server' => $gserver['url'], 'id' => $gserver['id']]);
|
||||
Worker::add(PRIORITY_LOW, 'UpdateServerDirectory', $gserver);
|
||||
Worker::add(Worker::PRIORITY_LOW, 'UpdateServerDirectory', $gserver);
|
||||
|
||||
$fields = ['last_poco_query' => DateTimeFormat::utcNow()];
|
||||
self::update($fields, ['nurl' => $gserver['nurl']]);
|
||||
|
@ -2168,7 +2173,7 @@ class GServer
|
|||
foreach ($servers['instances'] as $server) {
|
||||
$url = (is_null($server['https_score']) ? 'http' : 'https') . '://' . $server['name'];
|
||||
self::add($url);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,7 +102,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.'));
|
||||
DI::sysmsg()->addNotice(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;
|
||||
}
|
||||
|
@ -187,8 +187,8 @@ class Group
|
|||
) AS `count`
|
||||
FROM `group`
|
||||
WHERE `group`.`uid` = ?;",
|
||||
local_user(),
|
||||
local_user()
|
||||
DI::userSession()->getLocalUserId(),
|
||||
DI::userSession()->getLocalUserId()
|
||||
);
|
||||
|
||||
return DBA::toArray($stmt);
|
||||
|
@ -526,7 +526,7 @@ class Group
|
|||
*/
|
||||
public static function sidebarWidget(string $every = 'contact', string $each = 'group', string $editmode = 'standard', $group_id = '', int $cid = 0)
|
||||
{
|
||||
if (!local_user()) {
|
||||
if (!DI::userSession()->getLocalUserId()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
|
@ -544,7 +544,7 @@ class Group
|
|||
$member_of = self::getIdsByContactId($cid);
|
||||
}
|
||||
|
||||
$stmt = DBA::select('group', [], ['deleted' => false, 'uid' => local_user(), 'cid' => null], ['order' => ['name']]);
|
||||
$stmt = DBA::select('group', [], ['deleted' => false, 'uid' => DI::userSession()->getLocalUserId(), 'cid' => null], ['order' => ['name']]);
|
||||
while ($group = DBA::fetch($stmt)) {
|
||||
$selected = (($group_id == $group['id']) ? ' group-selected' : '');
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -160,7 +160,7 @@ class ParsedLogIterator implements \Iterator
|
|||
* @see Iterator::next()
|
||||
* @return void
|
||||
*/
|
||||
public function next()
|
||||
public function next(): void
|
||||
{
|
||||
$parsed = $this->read();
|
||||
|
||||
|
@ -177,7 +177,7 @@ class ParsedLogIterator implements \Iterator
|
|||
* @see Iterator::rewind()
|
||||
* @return void
|
||||
*/
|
||||
public function rewind()
|
||||
public function rewind(): void
|
||||
{
|
||||
$this->value = null;
|
||||
$this->reader->rewind();
|
||||
|
@ -200,9 +200,9 @@ class ParsedLogIterator implements \Iterator
|
|||
* Return current iterator value
|
||||
*
|
||||
* @see Iterator::current()
|
||||
* @return ?ParsedLogLing
|
||||
* @return ?ParsedLogLine
|
||||
*/
|
||||
public function current()
|
||||
public function current(): ?ParsedLogLine
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
|
|
@ -59,8 +59,7 @@ class Mail
|
|||
}
|
||||
|
||||
if (empty($msg['guid'])) {
|
||||
$host = parse_url($msg['from-url'], PHP_URL_HOST);
|
||||
$msg['guid'] = Item::guidFromUri($msg['uri'], $host);
|
||||
$msg['guid'] = Item::guidFromUri($msg['uri'], parse_url($msg['from-url'], PHP_URL_HOST));
|
||||
}
|
||||
|
||||
$msg['created'] = (!empty($msg['created']) ? DateTimeFormat::utc($msg['created']) : DateTimeFormat::utcNow());
|
||||
|
@ -137,12 +136,12 @@ class Mail
|
|||
$subject = DI::l10n()->t('[no subject]');
|
||||
}
|
||||
|
||||
$me = DBA::selectFirst('contact', [], ['uid' => local_user(), 'self' => true]);
|
||||
$me = DBA::selectFirst('contact', [], ['uid' => DI::userSession()->getLocalUserId(), 'self' => true]);
|
||||
if (!DBA::isResult($me)) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
$contacts = ACL::getValidMessageRecipientsForUser(local_user());
|
||||
$contacts = ACL::getValidMessageRecipientsForUser(DI::userSession()->getLocalUserId());
|
||||
|
||||
$contactIndex = array_search($recipient, array_column($contacts, 'id'));
|
||||
if ($contactIndex === false) {
|
||||
|
@ -151,7 +150,7 @@ class Mail
|
|||
|
||||
$contact = $contacts[$contactIndex];
|
||||
|
||||
Photo::setPermissionFromBody($body, local_user(), $me['id'], '<' . $contact['id'] . '>', '', '', '');
|
||||
Photo::setPermissionFromBody($body, DI::userSession()->getLocalUserId(), $me['id'], '<' . $contact['id'] . '>', '', '', '');
|
||||
|
||||
$guid = System::createUUID();
|
||||
$uri = Item::newURI($guid);
|
||||
|
@ -164,7 +163,7 @@ class Mail
|
|||
if (strlen($replyto)) {
|
||||
$reply = true;
|
||||
$condition = ["`uid` = ? AND (`uri` = ? OR `parent-uri` = ?)",
|
||||
local_user(), $replyto, $replyto];
|
||||
DI::userSession()->getLocalUserId(), $replyto, $replyto];
|
||||
$mail = DBA::selectFirst('mail', ['convid'], $condition);
|
||||
if (DBA::isResult($mail)) {
|
||||
$convid = $mail['convid'];
|
||||
|
@ -177,7 +176,7 @@ class Mail
|
|||
$conv_guid = System::createUUID();
|
||||
$convuri = $contact['addr'] . ':' . $conv_guid;
|
||||
|
||||
$fields = ['uid' => local_user(), 'guid' => $conv_guid, 'creator' => $me['addr'],
|
||||
$fields = ['uid' => DI::userSession()->getLocalUserId(), 'guid' => $conv_guid, 'creator' => $me['addr'],
|
||||
'created' => DateTimeFormat::utcNow(), 'updated' => DateTimeFormat::utcNow(),
|
||||
'subject' => $subject, 'recips' => $contact['addr'] . ';' . $me['addr']];
|
||||
if (DBA::insert('conv', $fields)) {
|
||||
|
@ -196,7 +195,7 @@ class Mail
|
|||
|
||||
$post_id = self::insert(
|
||||
[
|
||||
'uid' => local_user(),
|
||||
'uid' => DI::userSession()->getLocalUserId(),
|
||||
'guid' => $guid,
|
||||
'convid' => $convid,
|
||||
'from-name' => $me['name'],
|
||||
|
@ -232,14 +231,14 @@ class Mail
|
|||
foreach ($images as $image) {
|
||||
$image_rid = Photo::ridFromURI($image);
|
||||
if (!empty($image_rid)) {
|
||||
Photo::update(['allow-cid' => '<' . $recipient . '>'], ['resource-id' => $image_rid, 'album' => 'Wall Photos', 'uid' => local_user()]);
|
||||
Photo::update(['allow-cid' => '<' . $recipient . '>'], ['resource-id' => $image_rid, 'album' => 'Wall Photos', 'uid' => DI::userSession()->getLocalUserId()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($post_id) {
|
||||
Worker::add(PRIORITY_HIGH, "Notifier", Delivery::MAIL, $post_id);
|
||||
Worker::add(Worker::PRIORITY_HIGH, "Notifier", Delivery::MAIL, $post_id);
|
||||
return intval($post_id);
|
||||
} else {
|
||||
return -3;
|
||||
|
|
|
@ -25,6 +25,7 @@ use Friendica\Core\Addon;
|
|||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Item;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
|
@ -62,8 +63,8 @@ class Nodeinfo
|
|||
$logger->info('user statistics', $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`)", GRAVITY_COMMENT]);
|
||||
$config->set('nodeinfo', 'local_posts', $posts);
|
||||
$comments = DBA::count('post', ["NOT `deleted` AND `gravity` = ? AND `uri-id` IN (SELECT `uri-id` FROM `post-user` WHERE `origin`)", Item::GRAVITY_COMMENT]);
|
||||
$config->set('nodeinfo', 'local_posts', $posts);
|
||||
$config->set('nodeinfo', 'local_comments', $comments);
|
||||
|
||||
$logger->info('User actitivy', ['posts' => $posts, 'comments' => $comments]);
|
||||
|
@ -79,19 +80,17 @@ class Nodeinfo
|
|||
$config = DI::config();
|
||||
|
||||
$usage = new stdClass();
|
||||
$usage->users = [];
|
||||
$usage->users = new \stdClass;
|
||||
|
||||
if (!empty($config->get('system', 'nodeinfo'))) {
|
||||
$usage->users = [
|
||||
'total' => intval($config->get('nodeinfo', 'total_users')),
|
||||
'activeHalfyear' => intval($config->get('nodeinfo', 'active_users_halfyear')),
|
||||
'activeMonth' => intval($config->get('nodeinfo', 'active_users_monthly'))
|
||||
];
|
||||
$usage->users->total = intval($config->get('nodeinfo', 'total_users'));
|
||||
$usage->users->activeHalfyear = intval($config->get('nodeinfo', 'active_users_halfyear'));
|
||||
$usage->users->activeMonth = intval($config->get('nodeinfo', 'active_users_monthly'));
|
||||
$usage->localPosts = intval($config->get('nodeinfo', 'local_posts'));
|
||||
$usage->localComments = intval($config->get('nodeinfo', 'local_comments'));
|
||||
|
||||
if ($version2) {
|
||||
$usage->users['activeWeek'] = intval($config->get('nodeinfo', 'active_users_weekly'));
|
||||
$usage->users->activeWeek = intval($config->get('nodeinfo', 'active_users_weekly'));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -163,25 +162,16 @@ class Nodeinfo
|
|||
*
|
||||
* @param IManageConfigValues $config Configuration instance
|
||||
* @return array Organization information
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function getOrganization(IManageConfigValues $config): array
|
||||
{
|
||||
$organization = [
|
||||
'name' => null,
|
||||
'contact' => null,
|
||||
'account' => null
|
||||
$administrator = User::getFirstAdmin(['username', 'email', 'nickname']);
|
||||
|
||||
return [
|
||||
'name' => $administrator['username'] ?? null,
|
||||
'contact' => $administrator['email'] ?? null,
|
||||
'account' => $administrator['nickname'] ?? '' ? DI::baseUrl()->get() . '/profile/' . $administrator['nickname'] : null,
|
||||
];
|
||||
|
||||
if (!empty($config->get('config', 'admin_email'))) {
|
||||
$adminList = explode(',', str_replace(' ', '', $config->get('config', 'admin_email')));
|
||||
$organization['contact'] = $adminList[0];
|
||||
$administrator = User::getByEmail($adminList[0], ['username', 'nickname']);
|
||||
if (!empty($administrator)) {
|
||||
$organization['name'] = $administrator['username'];
|
||||
$organization['account'] = DI::baseUrl()->get() . '/profile/' . $administrator['nickname'];
|
||||
}
|
||||
}
|
||||
|
||||
return $organization;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@ use Friendica\Core\Cache\Enum\Duration;
|
|||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Database\DBStructure;
|
||||
use Friendica\DI;
|
||||
use Friendica\Core\Storage\Type\ExternalResource;
|
||||
use Friendica\Core\Storage\Exception\InvalidClassStorageException;
|
||||
|
@ -174,6 +173,64 @@ class Photo
|
|||
return $photo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all browsable albums for a given user
|
||||
*
|
||||
* @param int $uid The given user
|
||||
*
|
||||
* @return array An array of albums
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function getBrowsableAlbumsForUser(int $uid): array
|
||||
{
|
||||
$photos = DBA::toArray(
|
||||
DBA::p(
|
||||
"SELECT DISTINCT(`album`) AS `album` FROM `photo` WHERE `uid` = ? AND NOT `photo-type` IN (?, ?)",
|
||||
$uid,
|
||||
static::CONTACT_AVATAR,
|
||||
static::CONTACT_BANNER
|
||||
)
|
||||
);
|
||||
|
||||
return array_column($photos, 'album');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns browsable photos for a given user (optional and a given album)
|
||||
*
|
||||
* @param int $uid The given user id
|
||||
* @param string|null $album (optional) The given album
|
||||
*
|
||||
* @return array All photos of the user/album
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function getBrowsablePhotosForUser(int $uid, string $album = null): array
|
||||
{
|
||||
$values = [
|
||||
$uid,
|
||||
Photo::CONTACT_AVATAR,
|
||||
Photo::CONTACT_BANNER
|
||||
];
|
||||
|
||||
if (!empty($album)) {
|
||||
$sqlExtra = "AND `album` = ? ";
|
||||
$values[] = $album;
|
||||
$sqlExtra2 = "";
|
||||
} else {
|
||||
$sqlExtra = '';
|
||||
$sqlExtra2 = ' ORDER BY created DESC LIMIT 0, 10';
|
||||
}
|
||||
|
||||
return DBA::toArray(
|
||||
DBA::p(
|
||||
"SELECT `resource-id`, ANY_VALUE(`id`) AS `id`, ANY_VALUE(`filename`) AS `filename`, ANY_VALUE(`type`) AS `type`,
|
||||
min(`scale`) AS `hiq`, max(`scale`) AS `loq`, ANY_VALUE(`desc`) AS `desc`, ANY_VALUE(`created`) AS `created`
|
||||
FROM `photo` WHERE `uid` = ? AND NOT `photo-type` IN (?, ?) $sqlExtra
|
||||
GROUP BY `resource-id` $sqlExtra2",
|
||||
$values
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if photo with given conditions exists
|
||||
*
|
||||
|
@ -289,11 +346,14 @@ class Photo
|
|||
* @param string $url Image URL
|
||||
* @param int $uid User ID of the requesting person
|
||||
* @param string $mimetype Image mime type. Is guessed by file name when empty.
|
||||
* @param string $blurhash The blurhash that will be used to generate a picture when the original picture can't be fetched
|
||||
* @param int $width Image width
|
||||
* @param int $height Image height
|
||||
*
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function createPhotoForExternalResource(string $url, int $uid = 0, string $mimetype = ''): array
|
||||
public static function createPhotoForExternalResource(string $url, int $uid = 0, string $mimetype = '', string $blurhash = null, int $width = null, int $height = null): array
|
||||
{
|
||||
if (empty($mimetype)) {
|
||||
$mimetype = Images::guessTypeByExtension($url);
|
||||
|
@ -307,6 +367,9 @@ class Photo
|
|||
$photo['backend-ref'] = json_encode(['url' => $url, 'uid' => $uid]);
|
||||
$photo['type'] = $mimetype;
|
||||
$photo['cacheable'] = true;
|
||||
$photo['blurhash'] = $blurhash;
|
||||
$photo['width'] = $width;
|
||||
$photo['height'] = $height;
|
||||
|
||||
return $photo;
|
||||
}
|
||||
|
@ -379,6 +442,7 @@ class Photo
|
|||
'height' => $image->getHeight(),
|
||||
'width' => $image->getWidth(),
|
||||
'datasize' => strlen($image->asString()),
|
||||
'blurhash' => $image->getBlurHash(),
|
||||
'data' => $data,
|
||||
'scale' => $scale,
|
||||
'photo-type' => $type,
|
||||
|
@ -518,8 +582,9 @@ class Photo
|
|||
$image->scaleToSquare(300);
|
||||
|
||||
$filesize = strlen($image->asString());
|
||||
$maximagesize = DI::config()->get('system', 'maximagesize');
|
||||
if (!empty($maximagesize) && ($filesize > $maximagesize)) {
|
||||
$maximagesize = Strings::getBytesFromShorthand(DI::config()->get('system', 'maximagesize'));
|
||||
|
||||
if ($maximagesize && ($filesize > $maximagesize)) {
|
||||
Logger::info('Avatar exceeds image limit', ['uid' => $uid, 'cid' => $cid, 'maximagesize' => $maximagesize, 'size' => $filesize, 'type' => $image->getType()]);
|
||||
if ($image->getType() == 'image/gif') {
|
||||
$image->toStatic();
|
||||
|
@ -639,10 +704,10 @@ class Photo
|
|||
{
|
||||
$sql_extra = Security::getPermissionsSQLByUserId($uid);
|
||||
|
||||
$avatar_type = (local_user() && (local_user() == $uid)) ? self::USER_AVATAR : self::DEFAULT;
|
||||
$banner_type = (local_user() && (local_user() == $uid)) ? self::USER_BANNER : self::DEFAULT;
|
||||
$avatar_type = (DI::userSession()->getLocalUserId() && (DI::userSession()->getLocalUserId() == $uid)) ? self::USER_AVATAR : self::DEFAULT;
|
||||
$banner_type = (DI::userSession()->getLocalUserId() && (DI::userSession()->getLocalUserId() == $uid)) ? self::USER_BANNER : self::DEFAULT;
|
||||
|
||||
$key = 'photo_albums:' . $uid . ':' . local_user() . ':' . remote_user();
|
||||
$key = 'photo_albums:' . $uid . ':' . DI::userSession()->getLocalUserId() . ':' . DI::userSession()->getRemoteUserId();
|
||||
$albums = DI::cache()->get($key);
|
||||
|
||||
if (is_null($albums) || $update) {
|
||||
|
@ -681,7 +746,7 @@ class Photo
|
|||
*/
|
||||
public static function clearAlbumCache(int $uid)
|
||||
{
|
||||
$key = 'photo_albums:' . $uid . ':' . local_user() . ':' . remote_user();
|
||||
$key = 'photo_albums:' . $uid . ':' . DI::userSession()->getLocalUserId() . ':' . DI::userSession()->getRemoteUserId();
|
||||
DI::cache()->set($key, null, Duration::DAY);
|
||||
}
|
||||
|
||||
|
@ -909,9 +974,9 @@ class Photo
|
|||
$width = $image->getWidth();
|
||||
$height = $image->getHeight();
|
||||
|
||||
$maximagesize = DI::config()->get('system', 'maximagesize');
|
||||
$maximagesize = Strings::getBytesFromShorthand(DI::config()->get('system', 'maximagesize'));
|
||||
|
||||
if (!empty($maximagesize) && ($filesize > $maximagesize)) {
|
||||
if ($maximagesize && ($filesize > $maximagesize)) {
|
||||
// Scale down to multiples of 640 until the maximum size isn't exceeded anymore
|
||||
foreach ([5120, 2560, 1280, 640] as $pixels) {
|
||||
if (($filesize > $maximagesize) && (max($width, $height) > $pixels)) {
|
||||
|
@ -1131,8 +1196,8 @@ class Photo
|
|||
$picture['height'] = $photo['height'];
|
||||
$picture['type'] = $photo['type'];
|
||||
$picture['albumpage'] = DI::baseUrl() . '/photos/' . $user['nickname'] . '/image/' . $resource_id;
|
||||
$picture['picture'] = DI::baseUrl() . '/photo/{$resource_id}-0.' . $image->getExt();
|
||||
$picture['preview'] = DI::baseUrl() . '/photo/{$resource_id}-{$smallest}.' . $image->getExt();
|
||||
$picture['picture'] = DI::baseUrl() . '/photo/' . $resource_id . '-0.' . $image->getExt();
|
||||
$picture['preview'] = DI::baseUrl() . '/photo/' . $resource_id . '-' . $smallest . '.' . $image->getExt();
|
||||
|
||||
Logger::info('upload done', ['picture' => $picture]);
|
||||
return $picture;
|
||||
|
@ -1260,7 +1325,7 @@ class Photo
|
|||
logger::warning('profile banner upload with scale 3 (960) failed');
|
||||
}
|
||||
|
||||
logger::info('new profile banner upload ended');
|
||||
logger::info('new profile banner upload ended', ['uid' => $uid, 'resource_id' => $resource_id, 'filename' => $filename]);
|
||||
|
||||
$condition = ["`photo-type` = ? AND `resource-id` != ? AND `uid` = ?", self::USER_BANNER, $resource_id, $uid];
|
||||
self::update(['photo-type' => self::DEFAULT], $condition);
|
||||
|
@ -1273,4 +1338,3 @@ class Photo
|
|||
return $resource_id;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ use Friendica\Core\Logger;
|
|||
use Friendica\Core\System;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Database\DBStructure;
|
||||
use Friendica\DI;
|
||||
use Friendica\Protocol\Activity;
|
||||
|
||||
|
@ -103,26 +102,25 @@ class Post
|
|||
}
|
||||
|
||||
/**
|
||||
* Fills an array with data from an post query
|
||||
* Fills an array with data from a post query
|
||||
*
|
||||
* @param object $stmt statement object
|
||||
* @param bool $do_close
|
||||
* @param object|bool $stmt Return value from Database->select
|
||||
* @return array Data array
|
||||
* @todo Find proper type-hint for $stmt and maybe avoid boolean
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function toArray($stmt, bool $do_close = true)
|
||||
public static function toArray($stmt): array
|
||||
{
|
||||
if (is_bool($stmt)) {
|
||||
return $stmt;
|
||||
return [];
|
||||
}
|
||||
|
||||
$data = [];
|
||||
while ($row = self::fetch($stmt)) {
|
||||
$data[] = $row;
|
||||
}
|
||||
if ($do_close) {
|
||||
DBA::close($stmt);
|
||||
}
|
||||
|
||||
DBA::close($stmt);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
@ -376,6 +374,21 @@ class Post
|
|||
return self::selectView('post-thread-user-view', $selected, $condition, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select rows from the post-thread-view view
|
||||
*
|
||||
* @param array $selected Array of selected fields, empty for all
|
||||
* @param array $condition Array of fields for condition
|
||||
* @param array $params Array of several parameters
|
||||
*
|
||||
* @return boolean|object
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function selectPostThread(array $selected = [], array $condition = [], array $params = [])
|
||||
{
|
||||
return self::selectView('post-thread-view', $selected, $condition, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select rows from the given view for a given user
|
||||
*
|
||||
|
@ -405,12 +418,12 @@ class Post
|
|||
AND NOT `owner-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND `blocked` AND `cid` = `owner-id`)
|
||||
AND NOT (`gravity` = ? AND `author-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND `ignored` AND `cid` = `author-id`))
|
||||
AND NOT (`gravity` = ? AND `owner-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND `ignored` AND `cid` = `owner-id`))",
|
||||
0, Contact::SHARING, Contact::FRIEND, GRAVITY_PARENT, 0, $uid, $uid, $uid, GRAVITY_PARENT, $uid, GRAVITY_PARENT, $uid]);
|
||||
0, Contact::SHARING, Contact::FRIEND, Item::GRAVITY_PARENT, 0, $uid, $uid, $uid, Item::GRAVITY_PARENT, $uid, Item::GRAVITY_PARENT, $uid]);
|
||||
|
||||
$select_string = implode(', ', array_map([DBA::class, 'quoteIdentifier'], $selected));
|
||||
|
||||
$condition_string = DBA::buildCondition($condition);
|
||||
$param_string = DBA::buildParameter($params);
|
||||
$param_string = DBA::buildParameter($params);
|
||||
|
||||
$sql = "SELECT " . $select_string . " FROM `" . $view . "` " . $condition_string . $param_string;
|
||||
$sql = DBA::cleanQuery($sql);
|
||||
|
@ -507,7 +520,7 @@ class Post
|
|||
{
|
||||
$affected = 0;
|
||||
|
||||
Logger::info('Start Update', ['fields' => $fields, 'condition' => $condition, 'uid' => local_user(),'callstack' => System::callstack(10)]);
|
||||
Logger::info('Start Update', ['fields' => $fields, 'condition' => $condition, 'uid' => DI::userSession()->getLocalUserId(),'callstack' => System::callstack(10)]);
|
||||
|
||||
// Don't allow changes to fields that are responsible for the relation between the records
|
||||
unset($fields['id']);
|
||||
|
@ -520,7 +533,7 @@ class Post
|
|||
unset($fields['parent-uri']);
|
||||
unset($fields['parent-uri-id']);
|
||||
|
||||
$thread_condition = DBA::mergeConditions($condition, ['gravity' => GRAVITY_PARENT]);
|
||||
$thread_condition = DBA::mergeConditions($condition, ['gravity' => Item::GRAVITY_PARENT]);
|
||||
|
||||
// To ensure the data integrity we do it in an transaction
|
||||
DBA::transaction();
|
||||
|
@ -528,7 +541,7 @@ class Post
|
|||
$update_fields = DI::dbaDefinition()->truncateFieldsForTable('post-user', $fields);
|
||||
if (!empty($update_fields)) {
|
||||
$affected_count = 0;
|
||||
$posts = DBA::select('post-user-view', ['post-user-id'], $condition);
|
||||
$posts = DBA::select('post-user-view', ['post-user-id'], $condition);
|
||||
while ($rows = DBA::toArray($posts, false, 100)) {
|
||||
$puids = array_column($rows, 'post-user-id');
|
||||
if (!DBA::update('post-user', $update_fields, ['id' => $puids])) {
|
||||
|
@ -545,7 +558,7 @@ class Post
|
|||
$update_fields = DI::dbaDefinition()->truncateFieldsForTable('post-content', $fields);
|
||||
if (!empty($update_fields)) {
|
||||
$affected_count = 0;
|
||||
$posts = DBA::select('post-user-view', ['uri-id'], $condition, ['group_by' => ['uri-id']]);
|
||||
$posts = DBA::select('post-user-view', ['uri-id'], $condition, ['group_by' => ['uri-id']]);
|
||||
while ($rows = DBA::toArray($posts, false, 100)) {
|
||||
$uriids = array_column($rows, 'uri-id');
|
||||
if (!DBA::update('post-content', $update_fields, ['uri-id' => $uriids])) {
|
||||
|
@ -562,7 +575,7 @@ class Post
|
|||
$update_fields = DI::dbaDefinition()->truncateFieldsForTable('post', $fields);
|
||||
if (!empty($update_fields)) {
|
||||
$affected_count = 0;
|
||||
$posts = DBA::select('post-user-view', ['uri-id'], $condition, ['group_by' => ['uri-id']]);
|
||||
$posts = DBA::select('post-user-view', ['uri-id'], $condition, ['group_by' => ['uri-id']]);
|
||||
while ($rows = DBA::toArray($posts, false, 100)) {
|
||||
$uriids = array_column($rows, 'uri-id');
|
||||
|
||||
|
@ -585,7 +598,7 @@ class Post
|
|||
$update_fields = Post\DeliveryData::extractFields($fields);
|
||||
if (!empty($update_fields)) {
|
||||
$affected_count = 0;
|
||||
$posts = DBA::select('post-user-view', ['uri-id'], $condition, ['group_by' => ['uri-id']]);
|
||||
$posts = DBA::select('post-user-view', ['uri-id'], $condition, ['group_by' => ['uri-id']]);
|
||||
while ($rows = DBA::toArray($posts, false, 100)) {
|
||||
$uriids = array_column($rows, 'uri-id');
|
||||
if (!DBA::update('post-delivery-data', $update_fields, ['uri-id' => $uriids])) {
|
||||
|
@ -602,7 +615,7 @@ class Post
|
|||
$update_fields = DI::dbaDefinition()->truncateFieldsForTable('post-thread', $fields);
|
||||
if (!empty($update_fields)) {
|
||||
$affected_count = 0;
|
||||
$posts = DBA::select('post-user-view', ['uri-id'], $thread_condition, ['group_by' => ['uri-id']]);
|
||||
$posts = DBA::select('post-user-view', ['uri-id'], $thread_condition, ['group_by' => ['uri-id']]);
|
||||
while ($rows = DBA::toArray($posts, false, 100)) {
|
||||
$uriids = array_column($rows, 'uri-id');
|
||||
if (!DBA::update('post-thread', $update_fields, ['uri-id' => $uriids])) {
|
||||
|
@ -619,7 +632,7 @@ class Post
|
|||
$update_fields = DI::dbaDefinition()->truncateFieldsForTable('post-thread-user', $fields);
|
||||
if (!empty($update_fields)) {
|
||||
$affected_count = 0;
|
||||
$posts = DBA::select('post-user-view', ['post-user-id'], $thread_condition);
|
||||
$posts = DBA::select('post-user-view', ['post-user-id'], $thread_condition);
|
||||
while ($rows = DBA::toArray($posts, false, 100)) {
|
||||
$thread_puids = array_column($rows, 'post-user-id');
|
||||
if (!DBA::update('post-thread-user', $update_fields, ['post-user-id' => $thread_puids])) {
|
||||
|
|
|
@ -38,12 +38,6 @@ class Delayed
|
|||
* This is used for automated scheduled posts via feeds or from the API.
|
||||
*/
|
||||
const PREPARED = 0;
|
||||
/**
|
||||
* The content is posted like a manual post. Means some processing of body will be done.
|
||||
* Also it is posted with default permissions and default connector settings.
|
||||
* This is used for mirrored connector posts.
|
||||
*/
|
||||
const UNPREPARED = 1;
|
||||
/**
|
||||
* Like PREPARED, but additionally the connector settings can differ.
|
||||
* This is used when manually publishing scheduled posts.
|
||||
|
@ -80,7 +74,7 @@ class Delayed
|
|||
|
||||
Logger::notice('Adding post for delayed publishing', ['uid' => $item['uid'], 'delayed' => $delayed, 'uri' => $uri]);
|
||||
|
||||
$wid = Worker::add(['priority' => PRIORITY_HIGH, 'delayed' => $delayed], 'DelayedPublish', $item, $notify, $taglist, $attachments, $preparation_mode, $uri);
|
||||
$wid = Worker::add(['priority' => Worker::PRIORITY_HIGH, 'delayed' => $delayed], 'DelayedPublish', $item, $notify, $taglist, $attachments, $preparation_mode, $uri);
|
||||
if (!$wid) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -199,37 +193,9 @@ class Delayed
|
|||
$item['attachments'] = $attachments;
|
||||
}
|
||||
|
||||
if ($preparation_mode == self::UNPREPARED) {
|
||||
$_SESSION['authenticated'] = true;
|
||||
$_SESSION['uid'] = $item['uid'];
|
||||
|
||||
$_REQUEST = $item;
|
||||
$_REQUEST['api_source'] = true;
|
||||
$_REQUEST['profile_uid'] = $item['uid'];
|
||||
$_REQUEST['title'] = $item['title'] ?? '';
|
||||
|
||||
if (!empty($item['app'])) {
|
||||
$_REQUEST['source'] = $item['app'];
|
||||
}
|
||||
|
||||
require_once 'mod/item.php';
|
||||
$id = item_post(DI::app());
|
||||
|
||||
if (empty($uri) && !empty($item['extid'])) {
|
||||
$uri = $item['extid'];
|
||||
}
|
||||
|
||||
Logger::notice('Unprepared post stored', ['id' => $id, 'uid' => $item['uid'], 'uri' => $uri]);
|
||||
if (self::exists($uri, $item['uid'])) {
|
||||
self::delete($uri, $item['uid']);
|
||||
}
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
$id = Item::insert($item, $notify, $preparation_mode == self::PREPARED);
|
||||
|
||||
Logger::notice('Post stored', ['id' => $id, 'uid' => $item['uid'], 'cid' => $item['contact-id']]);
|
||||
Logger::notice('Post stored', ['id' => $id, 'uid' => $item['uid'], 'cid' => $item['contact-id'] ?? 'N/A']);
|
||||
|
||||
if (empty($uri) && !empty($item['uri'])) {
|
||||
$uri = $item['uri'];
|
||||
|
|
|
@ -23,10 +23,12 @@ namespace Friendica\Model\Post;
|
|||
|
||||
use Friendica\Content\Text\BBCode;
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\Protocol;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Item;
|
||||
use Friendica\Model\Photo;
|
||||
use Friendica\Model\Post;
|
||||
|
@ -56,12 +58,15 @@ class Media
|
|||
const HTML = 17;
|
||||
const XML = 18;
|
||||
const PLAIN = 19;
|
||||
const ACTIVITY = 20;
|
||||
const ACCOUNT = 21;
|
||||
const DOCUMENT = 128;
|
||||
|
||||
/**
|
||||
* Insert a post-media record
|
||||
*
|
||||
* @param array $media
|
||||
* @param bool $force
|
||||
* @return void
|
||||
*/
|
||||
public static function insert(array $media, bool $force = false)
|
||||
|
@ -113,7 +118,7 @@ class Media
|
|||
*/
|
||||
private static function unsetEmptyFields(array $media): array
|
||||
{
|
||||
$fields = ['mimetype', 'height', 'width', 'size', 'preview', 'preview-height', 'preview-width', 'description'];
|
||||
$fields = ['mimetype', 'height', 'width', 'size', 'preview', 'preview-height', 'preview-width', 'blurhash', 'description'];
|
||||
foreach ($fields as $field) {
|
||||
if (empty($media[$field])) {
|
||||
unset($media[$field]);
|
||||
|
@ -199,6 +204,7 @@ class Media
|
|||
$media['size'] = $imagedata['size'];
|
||||
$media['width'] = $imagedata[0];
|
||||
$media['height'] = $imagedata[1];
|
||||
$media['blurhash'] = $imagedata['blurhash'] ?? null;
|
||||
} else {
|
||||
Logger::notice('No image data', ['media' => $media]);
|
||||
}
|
||||
|
@ -215,20 +221,142 @@ class Media
|
|||
$media = self::addType($media);
|
||||
}
|
||||
|
||||
if ($media['type'] == self::HTML) {
|
||||
$data = ParseUrl::getSiteinfoCached($media['url'], false);
|
||||
$media['preview'] = $data['images'][0]['src'] ?? null;
|
||||
$media['preview-height'] = $data['images'][0]['height'] ?? null;
|
||||
$media['preview-width'] = $data['images'][0]['width'] ?? null;
|
||||
$media['description'] = $data['text'] ?? null;
|
||||
$media['name'] = $data['title'] ?? null;
|
||||
$media['author-url'] = $data['author_url'] ?? null;
|
||||
$media['author-name'] = $data['author_name'] ?? null;
|
||||
$media['author-image'] = $data['author_img'] ?? null;
|
||||
$media['publisher-url'] = $data['publisher_url'] ?? null;
|
||||
$media['publisher-name'] = $data['publisher_name'] ?? null;
|
||||
$media['publisher-image'] = $data['publisher_img'] ?? null;
|
||||
if (in_array($media['type'], [self::TEXT, self::APPLICATION, self::HTML, self::XML, self::PLAIN])) {
|
||||
$media = self::addActivity($media);
|
||||
}
|
||||
|
||||
if (in_array($media['type'], [self::TEXT, self::APPLICATION, self::HTML, self::XML, self::PLAIN])) {
|
||||
$media = self::addAccount($media);
|
||||
}
|
||||
|
||||
if ($media['type'] == self::HTML) {
|
||||
$media = self::addPage($media);
|
||||
}
|
||||
|
||||
return $media;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the activity type if the media entry is linked to an activity
|
||||
*
|
||||
* @param array $media
|
||||
* @return array
|
||||
*/
|
||||
private static function addActivity(array $media): array
|
||||
{
|
||||
$id = Item::fetchByLink($media['url']);
|
||||
if (empty($id)) {
|
||||
return $media;
|
||||
}
|
||||
|
||||
$item = Post::selectFirst([], ['id' => $id, 'network' => Protocol::FEDERATED]);
|
||||
if (empty($item['id'])) {
|
||||
Logger::debug('Not a federated activity', ['id' => $id, 'uri-id' => $media['uri-id'], 'url' => $media['url']]);
|
||||
return $media;
|
||||
}
|
||||
|
||||
if (!empty($item['plink']) && Strings::compareLink($item['plink'], $media['url']) &&
|
||||
parse_url($item['plink'], PHP_URL_HOST) != parse_url($item['uri'], PHP_URL_HOST)) {
|
||||
Logger::debug('Not a link to an activity', ['uri-id' => $media['uri-id'], 'url' => $media['url'], 'plink' => $item['plink'], 'uri' => $item['uri']]);
|
||||
return $media;
|
||||
}
|
||||
|
||||
if (in_array($item['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN])) {
|
||||
$media['mimetype'] = 'application/activity+json';
|
||||
} elseif ($item['network'] == Protocol::DIASPORA) {
|
||||
$media['mimetype'] = 'application/xml';
|
||||
}
|
||||
|
||||
$contact = Contact::getById($item['author-id'], ['avatar', 'gsid']);
|
||||
if (!empty($contact['gsid'])) {
|
||||
$gserver = DBA::selectFirst('gserver', ['url', 'site_name'], ['id' => $contact['gsid']]);
|
||||
}
|
||||
|
||||
$media['type'] = self::ACTIVITY;
|
||||
$media['media-uri-id'] = $item['uri-id'];
|
||||
$media['height'] = null;
|
||||
$media['width'] = null;
|
||||
$media['preview'] = null;
|
||||
$media['preview-height'] = null;
|
||||
$media['preview-width'] = null;
|
||||
$media['blurhash'] = null;
|
||||
$media['description'] = $item['body'];
|
||||
$media['name'] = $item['title'];
|
||||
$media['author-url'] = $item['author-link'];
|
||||
$media['author-name'] = $item['author-name'];
|
||||
$media['author-image'] = $contact['avatar'] ?? $item['author-avatar'];
|
||||
$media['publisher-url'] = $gserver['url'] ?? null;
|
||||
$media['publisher-name'] = $gserver['site_name'] ?? null;
|
||||
$media['publisher-image'] = null;
|
||||
|
||||
Logger::debug('Activity detected', ['uri-id' => $media['uri-id'], 'url' => $media['url'], 'plink' => $item['plink'], 'uri' => $item['uri']]);
|
||||
return $media;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the account type if the media entry is linked to an account
|
||||
*
|
||||
* @param array $media
|
||||
* @return array
|
||||
*/
|
||||
private static function addAccount(array $media): array
|
||||
{
|
||||
$contact = Contact::getByURL($media['url'], false);
|
||||
if (empty($contact) || ($contact['network'] == Protocol::PHANTOM)) {
|
||||
return $media;
|
||||
}
|
||||
|
||||
if (in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN])) {
|
||||
$media['mimetype'] = 'application/activity+json';
|
||||
}
|
||||
|
||||
if (!empty($contact['gsid'])) {
|
||||
$gserver = DBA::selectFirst('gserver', ['url', 'site_name'], ['id' => $contact['gsid']]);
|
||||
}
|
||||
|
||||
$media['type'] = self::ACCOUNT;
|
||||
$media['media-uri-id'] = $contact['uri-id'];
|
||||
$media['height'] = null;
|
||||
$media['width'] = null;
|
||||
$media['preview'] = null;
|
||||
$media['preview-height'] = null;
|
||||
$media['preview-width'] = null;
|
||||
$media['blurhash'] = null;
|
||||
$media['description'] = $contact['about'];
|
||||
$media['name'] = $contact['name'];
|
||||
$media['author-url'] = $contact['url'];
|
||||
$media['author-name'] = $contact['name'];
|
||||
$media['author-image'] = $contact['avatar'];
|
||||
$media['publisher-url'] = $gserver['url'] ?? null;
|
||||
$media['publisher-name'] = $gserver['site_name'] ?? null;
|
||||
$media['publisher-image'] = null;
|
||||
|
||||
Logger::debug('Account detected', ['uri-id' => $media['uri-id'], 'url' => $media['url'], 'uri' => $contact['url']]);
|
||||
return $media;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add page infos for HTML entries
|
||||
*
|
||||
* @param array $media
|
||||
* @return array
|
||||
*/
|
||||
private static function addPage(array $media): array
|
||||
{
|
||||
$data = ParseUrl::getSiteinfoCached($media['url'], false);
|
||||
$media['preview'] = $data['images'][0]['src'] ?? null;
|
||||
$media['preview-height'] = $data['images'][0]['height'] ?? null;
|
||||
$media['preview-width'] = $data['images'][0]['width'] ?? null;
|
||||
$media['blurhash'] = $data['images'][0]['blurhash'] ?? null;
|
||||
$media['description'] = $data['text'] ?? null;
|
||||
$media['name'] = $data['title'] ?? null;
|
||||
$media['author-url'] = $data['author_url'] ?? null;
|
||||
$media['author-name'] = $data['author_name'] ?? null;
|
||||
$media['author-image'] = $data['author_img'] ?? null;
|
||||
$media['publisher-url'] = $data['publisher_url'] ?? null;
|
||||
$media['publisher-name'] = $data['publisher_name'] ?? null;
|
||||
$media['publisher-image'] = $data['publisher_img'] ?? null;
|
||||
|
||||
return $media;
|
||||
}
|
||||
|
||||
|
@ -248,6 +376,7 @@ class Media
|
|||
$media['size'] = $photo['datasize'];
|
||||
$media['width'] = $photo['width'];
|
||||
$media['height'] = $photo['height'];
|
||||
$media['blurhash'] = $photo['blurhash'];
|
||||
}
|
||||
|
||||
if (!preg_match('|.*?/photo/(.*[a-fA-F0-9])\-(.*[0-9])\..*[\w]|', $media['preview'] ?? '', $matches)) {
|
||||
|
@ -332,19 +461,14 @@ class Media
|
|||
* @param string $body
|
||||
* @return string Body without media links
|
||||
*/
|
||||
public static function insertFromBody(int $uriid, string $body): string
|
||||
public static function insertFromBody(int $uriid, string $body, bool $endmatch = false): string
|
||||
{
|
||||
$endmatchpattern = $endmatch ? '\z' : '';
|
||||
// Simplify image codes
|
||||
$unshared_body = $body = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $body);
|
||||
|
||||
// Only remove the shared data from "real" reshares
|
||||
$shared = BBCode::fetchShareAttributes($body);
|
||||
if (!empty($shared['guid'])) {
|
||||
$unshared_body = preg_replace("/\s*\[share .*?\].*?\[\/share\]\s*/ism", '', $body);
|
||||
}
|
||||
$unshared_body = $body = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]$endmatchpattern/ism", '[img]$3[/img]', $body);
|
||||
|
||||
$attachments = [];
|
||||
if (preg_match_all("#\[url=([^\]]+?)\]\s*\[img=([^\[\]]*)\]([^\[\]]*)\[\/img\]\s*\[/url\]#ism", $body, $pictures, PREG_SET_ORDER)) {
|
||||
if (preg_match_all("#\[url=([^\]]+?)\]\s*\[img=([^\[\]]*)\]([^\[\]]*)\[\/img\]\s*\[/url\]$endmatchpattern#ism", $body, $pictures, PREG_SET_ORDER)) {
|
||||
foreach ($pictures as $picture) {
|
||||
if (!self::isPictureLink($picture[1], $picture[2])) {
|
||||
continue;
|
||||
|
@ -356,14 +480,14 @@ class Media
|
|||
}
|
||||
}
|
||||
|
||||
if (preg_match_all("/\[img=([^\[\]]*)\]([^\[\]]*)\[\/img\]/Usi", $body, $pictures, PREG_SET_ORDER)) {
|
||||
if (preg_match_all("/\[img=([^\[\]]*)\]([^\[\]]*)\[\/img\]$endmatchpattern/Usi", $body, $pictures, PREG_SET_ORDER)) {
|
||||
foreach ($pictures as $picture) {
|
||||
$body = str_replace($picture[0], '', $body);
|
||||
$attachments[$picture[1]] = ['uri-id' => $uriid, 'type' => self::IMAGE, 'url' => $picture[1], 'description' => $picture[2]];
|
||||
}
|
||||
}
|
||||
|
||||
if (preg_match_all("#\[url=([^\]]+?)\]\s*\[img\]([^\[]+?)\[/img\]\s*\[/url\]#ism", $body, $pictures, PREG_SET_ORDER)) {
|
||||
if (preg_match_all("#\[url=([^\]]+?)\]\s*\[img\]([^\[]+?)\[/img\]\s*\[/url\]$endmatchpattern#ism", $body, $pictures, PREG_SET_ORDER)) {
|
||||
foreach ($pictures as $picture) {
|
||||
if (!self::isPictureLink($picture[1], $picture[2])) {
|
||||
continue;
|
||||
|
@ -375,41 +499,58 @@ class Media
|
|||
}
|
||||
}
|
||||
|
||||
if (preg_match_all("/\[img\]([^\[\]]*)\[\/img\]/ism", $body, $pictures, PREG_SET_ORDER)) {
|
||||
if (preg_match_all("/\[img\]([^\[\]]*)\[\/img\]$endmatchpattern/ism", $body, $pictures, PREG_SET_ORDER)) {
|
||||
foreach ($pictures as $picture) {
|
||||
$body = str_replace($picture[0], '', $body);
|
||||
$attachments[$picture[1]] = ['uri-id' => $uriid, 'type' => self::IMAGE, 'url' => $picture[1]];
|
||||
}
|
||||
}
|
||||
|
||||
if (preg_match_all("/\[audio\]([^\[\]]*)\[\/audio\]/ism", $body, $audios, PREG_SET_ORDER)) {
|
||||
if (preg_match_all("/\[audio\]([^\[\]]*)\[\/audio\]$endmatchpattern/ism", $body, $audios, PREG_SET_ORDER)) {
|
||||
foreach ($audios as $audio) {
|
||||
$body = str_replace($audio[0], '', $body);
|
||||
$attachments[$audio[1]] = ['uri-id' => $uriid, 'type' => self::AUDIO, 'url' => $audio[1]];
|
||||
}
|
||||
}
|
||||
|
||||
if (preg_match_all("/\[video\]([^\[\]]*)\[\/video\]/ism", $body, $videos, PREG_SET_ORDER)) {
|
||||
if (preg_match_all("/\[video\]([^\[\]]*)\[\/video\]$endmatchpattern/ism", $body, $videos, PREG_SET_ORDER)) {
|
||||
foreach ($videos as $video) {
|
||||
$body = str_replace($video[0], '', $body);
|
||||
$attachments[$video[1]] = ['uri-id' => $uriid, 'type' => self::VIDEO, 'url' => $video[1]];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($attachments as $attachment) {
|
||||
if (Post\Link::exists($uriid, $attachment['preview'] ?? $attachment['url'])) {
|
||||
continue;
|
||||
}
|
||||
if ($uriid != 0) {
|
||||
foreach ($attachments as $attachment) {
|
||||
if (Post\Link::exists($uriid, $attachment['preview'] ?? $attachment['url'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only store attachments that are part of the unshared body
|
||||
if (Item::containsLink($unshared_body, $attachment['preview'] ?? $attachment['url'], $attachment['type'])) {
|
||||
self::insert($attachment);
|
||||
// Only store attachments that are part of the unshared body
|
||||
if (Item::containsLink($unshared_body, $attachment['preview'] ?? $attachment['url'], $attachment['type'])) {
|
||||
self::insert($attachment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return trim($body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove media that is at the end of the body
|
||||
*
|
||||
* @param string $body
|
||||
* @return string
|
||||
*/
|
||||
public static function removeFromEndOfBody(string $body): string
|
||||
{
|
||||
do {
|
||||
$prebody = $body;
|
||||
$body = self::insertFromBody(0, $body, true);
|
||||
} while ($prebody != $body);
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add media links from a relevant url in the body
|
||||
*
|
||||
|
@ -417,15 +558,8 @@ class Media
|
|||
* @param string $body
|
||||
* @return void
|
||||
*/
|
||||
public static function insertFromRelevantUrl(int $uriid, string $body)
|
||||
public static function insertFromRelevantUrl(int $uriid, string $body, string $fullbody, string $network)
|
||||
{
|
||||
// Only remove the shared data from "real" reshares
|
||||
$shared = BBCode::fetchShareAttributes($body);
|
||||
if (!empty($shared['guid'])) {
|
||||
// Don't look at the shared content
|
||||
$body = preg_replace("/\s*\[share .*?\].*?\[\/share\]\s*/ism", '', $body);
|
||||
}
|
||||
|
||||
// Remove all hashtags and mentions
|
||||
$body = preg_replace("/([#@!])\[url\=(.*?)\](.*?)\[\/url\]/ism", '', $body);
|
||||
|
||||
|
@ -433,7 +567,10 @@ class Media
|
|||
if (preg_match_all("/\[url\](https?:.*?)\[\/url\]/ism", $body, $matches)) {
|
||||
foreach ($matches[1] as $url) {
|
||||
Logger::info('Got page url (link without description)', ['uri-id' => $uriid, 'url' => $url]);
|
||||
self::insert(['uri-id' => $uriid, 'type' => self::UNKNOWN, 'url' => $url]);
|
||||
self::insert(['uri-id' => $uriid, 'type' => self::UNKNOWN, 'url' => $url], false, $network);
|
||||
if ($network == Protocol::DFRN) {
|
||||
self::revertHTMLType($uriid, $url, $fullbody);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -441,11 +578,31 @@ class Media
|
|||
if (preg_match_all("/\[url\=(https?:.*?)\].*?\[\/url\]/ism", $body, $matches)) {
|
||||
foreach ($matches[1] as $url) {
|
||||
Logger::info('Got page url (link with description)', ['uri-id' => $uriid, 'url' => $url]);
|
||||
self::insert(['uri-id' => $uriid, 'type' => self::UNKNOWN, 'url' => $url]);
|
||||
self::insert(['uri-id' => $uriid, 'type' => self::UNKNOWN, 'url' => $url], false, $network);
|
||||
if ($network == Protocol::DFRN) {
|
||||
self::revertHTMLType($uriid, $url, $fullbody);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Revert the media type of links to UNKNOWN for DFRN posts when they aren't attached
|
||||
*
|
||||
* @param integer $uriid
|
||||
* @param string $url
|
||||
* @param string $body
|
||||
* @return void
|
||||
*/
|
||||
private static function revertHTMLType(int $uriid, string $url, string $body)
|
||||
{
|
||||
$attachment = BBCode::getAttachmentData($body);
|
||||
if (!empty($attachment['url']) && Network::getUrlMatch($attachment['url'], $url)) {
|
||||
return;
|
||||
}
|
||||
DBA::update('post-media', ['type' => self::UNKNOWN], ['uri-id' => $uriid, 'type' => self::HTML, 'url' => $url]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add media links from the attachment field
|
||||
*
|
||||
|
@ -455,9 +612,6 @@ class Media
|
|||
*/
|
||||
public static function insertFromAttachmentData(int $uriid, string $body)
|
||||
{
|
||||
// Don't look at the shared content
|
||||
$body = preg_replace("/\s*\[share .*?\].*?\[\/share\]\s*/ism", '', $body);
|
||||
|
||||
$data = BBCode::getAttachmentData($body);
|
||||
if (empty($data)) {
|
||||
return;
|
||||
|
@ -517,7 +671,7 @@ class Media
|
|||
*/
|
||||
public static function getByURIId(int $uri_id, array $types = [])
|
||||
{
|
||||
$condition = ['uri-id' => $uri_id];
|
||||
$condition = ["`uri-id` = ? AND `type` != ?", $uri_id, self::UNKNOWN];
|
||||
|
||||
if (!empty($types)) {
|
||||
$condition = DBA::mergeConditions($condition, ['type' => $types]);
|
||||
|
@ -536,7 +690,7 @@ class Media
|
|||
*/
|
||||
public static function existsByURIId(int $uri_id, array $types = []): bool
|
||||
{
|
||||
$condition = ['uri-id' => $uri_id];
|
||||
$condition = ["`uri-id` = ? AND `type` != ?", $uri_id, self::UNKNOWN];
|
||||
|
||||
if (!empty($types)) {
|
||||
$condition = DBA::mergeConditions($condition, ['type' => $types]);
|
||||
|
@ -549,12 +703,11 @@ class Media
|
|||
* Split the attachment media in the three segments "visual", "link" and "additional"
|
||||
*
|
||||
* @param int $uri_id URI id
|
||||
* @param string $guid GUID
|
||||
* @param array $links list of links that shouldn't be added
|
||||
* @param bool $has_media
|
||||
* @return array attachments
|
||||
*/
|
||||
public static function splitAttachments(int $uri_id, string $guid = '', array $links = [], bool $has_media = true): array
|
||||
public static function splitAttachments(int $uri_id, array $links = [], bool $has_media = true): array
|
||||
{
|
||||
$attachments = ['visual' => [], 'link' => [], 'additional' => []];
|
||||
|
||||
|
@ -585,11 +738,17 @@ class Media
|
|||
}
|
||||
}
|
||||
|
||||
// Currently these two types are ignored here.
|
||||
// Posts are added differently and contacts are not displayed as attachments.
|
||||
if (in_array($medium['type'], [self::ACCOUNT, self::ACTIVITY])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!empty($medium['preview'])) {
|
||||
$previews[] = $medium['preview'];
|
||||
}
|
||||
|
||||
$type = explode('/', current(explode(';', $medium['mimetype'])));
|
||||
$type = explode('/', explode(';', $medium['mimetype'] ?? '')[0]);
|
||||
if (count($type) < 2) {
|
||||
Logger::info('Unknown MimeType', ['type' => $type, 'media' => $medium]);
|
||||
$filetype = 'unkn';
|
||||
|
@ -648,11 +807,13 @@ class Media
|
|||
/**
|
||||
* Add media attachments to the body
|
||||
*
|
||||
* @param int $uriid
|
||||
* @param int $uriid
|
||||
* @param string $body
|
||||
* @param array $types
|
||||
*
|
||||
* @return string body
|
||||
*/
|
||||
public static function addAttachmentsToBody(int $uriid, string $body = ''): string
|
||||
public static function addAttachmentsToBody(int $uriid, string $body = '', array $types = [self::IMAGE, self::AUDIO, self::VIDEO]): string
|
||||
{
|
||||
if (empty($body)) {
|
||||
$item = Post::selectFirst(['body'], ['uri-id' => $uriid]);
|
||||
|
@ -665,7 +826,7 @@ class Media
|
|||
|
||||
$body = preg_replace("/\s*\[attachment .*?\].*?\[\/attachment\]\s*/ism", '', $body);
|
||||
|
||||
foreach (self::getByURIId($uriid, [self::IMAGE, self::AUDIO, self::VIDEO]) as $media) {
|
||||
foreach (self::getByURIId($uriid, $types) as $media) {
|
||||
if (Item::containsLink($body, $media['preview'] ?? $media['url'], $media['type'])) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ use Friendica\Database\DBA;
|
|||
use Friendica\Database\DBStructure;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Item;
|
||||
use Friendica\Model\Post;
|
||||
use Friendica\Model\Subscription;
|
||||
use Friendica\Model\Tag;
|
||||
|
@ -177,11 +178,15 @@ class UserNotification
|
|||
return;
|
||||
}
|
||||
|
||||
$user = User::getById($uid, ['account-type']);
|
||||
$user = User::getById($uid, ['account-type', 'account_removed', 'account_expired']);
|
||||
if (in_array($user['account-type'], [User::ACCOUNT_TYPE_COMMUNITY, User::ACCOUNT_TYPE_RELAY])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($user['account_removed'] || $user['account_expired']) {
|
||||
return;
|
||||
}
|
||||
|
||||
$author = Contact::getById($item['author-id'], ['contact-type']);
|
||||
if (empty($author)) {
|
||||
return;
|
||||
|
@ -288,7 +293,7 @@ class UserNotification
|
|||
}
|
||||
|
||||
// Only create notifications for posts and comments, not for activities
|
||||
if (($item['gravity'] == GRAVITY_ACTIVITY) && ($item['verb'] != Activity::ANNOUNCE)) {
|
||||
if (($item['gravity'] == Item::GRAVITY_ACTIVITY) && ($item['verb'] != Activity::ANNOUNCE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -310,7 +315,7 @@ class UserNotification
|
|||
*/
|
||||
private static function insertNotificationByItem(int $type, int $uid, array $item): void
|
||||
{
|
||||
if (($item['verb'] != Activity::ANNOUNCE) && ($item['gravity'] == GRAVITY_ACTIVITY) &&
|
||||
if (($item['verb'] != Activity::ANNOUNCE) && ($item['gravity'] == Item::GRAVITY_ACTIVITY) &&
|
||||
!in_array($type, [self::TYPE_DIRECT_COMMENT, self::TYPE_DIRECT_THREAD_COMMENT])) {
|
||||
// Activities are only stored when performed on the user's post or comment
|
||||
return;
|
||||
|
@ -321,7 +326,7 @@ class UserNotification
|
|||
$item['vid'],
|
||||
$type,
|
||||
$item['author-id'],
|
||||
$item['gravity'] == GRAVITY_ACTIVITY ? $item['thr-parent-id'] : $item['uri-id'],
|
||||
$item['gravity'] == Item::GRAVITY_ACTIVITY ? $item['thr-parent-id'] : $item['uri-id'],
|
||||
$item['parent-uri-id']
|
||||
);
|
||||
|
||||
|
@ -423,14 +428,14 @@ class UserNotification
|
|||
private static function checkShared(array $item, int $uid): bool
|
||||
{
|
||||
// Only check on original posts and reshare ("announce") activities, otherwise return
|
||||
if (($item['gravity'] != GRAVITY_PARENT) && ($item['verb'] != Activity::ANNOUNCE)) {
|
||||
if (($item['gravity'] != Item::GRAVITY_PARENT) && ($item['verb'] != Activity::ANNOUNCE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't notify about reshares by communities of our own posts or each time someone comments
|
||||
if (($item['verb'] == Activity::ANNOUNCE) && DBA::exists('contact', ['id' => $item['contact-id'], 'contact-type' => Contact::TYPE_COMMUNITY])) {
|
||||
$post = Post::selectFirst(['origin', 'gravity'], ['uri-id' => $item['thr-parent-id'], 'uid' => $uid]);
|
||||
if ($post['origin'] || ($post['gravity'] != GRAVITY_PARENT)) {
|
||||
if (!$post || $post['origin'] || ($post['gravity'] != Item::GRAVITY_PARENT)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -497,7 +502,7 @@ class UserNotification
|
|||
*/
|
||||
private static function checkCommentedThread(array $item, array $contacts): bool
|
||||
{
|
||||
$condition = ['parent' => $item['parent'], 'author-id' => $contacts, 'deleted' => false, 'gravity' => GRAVITY_PARENT];
|
||||
$condition = ['parent' => $item['parent'], 'author-id' => $contacts, 'deleted' => false, 'gravity' => Item::GRAVITY_PARENT];
|
||||
return Post::exists($condition);
|
||||
}
|
||||
|
||||
|
@ -511,7 +516,7 @@ class UserNotification
|
|||
*/
|
||||
private static function checkDirectComment(array $item, array $contacts): bool
|
||||
{
|
||||
$condition = ['uri' => $item['thr-parent'], 'uid' => $item['uid'], 'author-id' => $contacts, 'deleted' => false, 'gravity' => GRAVITY_COMMENT];
|
||||
$condition = ['uri' => $item['thr-parent'], 'uid' => $item['uid'], 'author-id' => $contacts, 'deleted' => false, 'gravity' => Item::GRAVITY_COMMENT];
|
||||
return Post::exists($condition);
|
||||
}
|
||||
|
||||
|
@ -525,7 +530,7 @@ class UserNotification
|
|||
*/
|
||||
private static function checkDirectCommentedThread(array $item, array $contacts): bool
|
||||
{
|
||||
$condition = ['uri' => $item['thr-parent'], 'uid' => $item['uid'], 'author-id' => $contacts, 'deleted' => false, 'gravity' => GRAVITY_PARENT];
|
||||
$condition = ['uri' => $item['thr-parent'], 'uid' => $item['uid'], 'author-id' => $contacts, 'deleted' => false, 'gravity' => Item::GRAVITY_PARENT];
|
||||
return Post::exists($condition);
|
||||
}
|
||||
|
||||
|
@ -539,7 +544,7 @@ class UserNotification
|
|||
*/
|
||||
private static function checkCommentedParticipation(array $item, array $contacts): bool
|
||||
{
|
||||
$condition = ['parent' => $item['parent'], 'author-id' => $contacts, 'deleted' => false, 'gravity' => GRAVITY_COMMENT];
|
||||
$condition = ['parent' => $item['parent'], 'author-id' => $contacts, 'deleted' => false, 'gravity' => Item::GRAVITY_COMMENT];
|
||||
return Post::exists($condition);
|
||||
}
|
||||
|
||||
|
@ -553,7 +558,7 @@ class UserNotification
|
|||
*/
|
||||
private static function checkFollowParticipation(array $item, array $contacts): bool
|
||||
{
|
||||
$condition = ['parent' => $item['parent'], 'author-id' => $contacts, 'deleted' => false, 'gravity' => GRAVITY_ACTIVITY, 'verb' => Activity::FOLLOW];
|
||||
$condition = ['parent' => $item['parent'], 'author-id' => $contacts, 'deleted' => false, 'gravity' => Item::GRAVITY_ACTIVITY, 'verb' => Activity::FOLLOW];
|
||||
return Post::exists($condition);
|
||||
}
|
||||
|
||||
|
@ -567,7 +572,7 @@ class UserNotification
|
|||
*/
|
||||
private static function checkActivityParticipation(array $item, array $contacts): bool
|
||||
{
|
||||
$condition = ['parent' => $item['parent'], 'author-id' => $contacts, 'deleted' => false, 'gravity' => GRAVITY_ACTIVITY];
|
||||
$condition = ['parent' => $item['parent'], 'author-id' => $contacts, 'deleted' => false, 'gravity' => Item::GRAVITY_ACTIVITY];
|
||||
return Post::exists($condition);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@ use Friendica\Core\Logger;
|
|||
use Friendica\Core\Protocol;
|
||||
use Friendica\Core\Renderer;
|
||||
use Friendica\Core\Search;
|
||||
use Friendica\Core\Session;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Core\Worker;
|
||||
use Friendica\Database\DBA;
|
||||
|
@ -153,11 +152,11 @@ class Profile
|
|||
if ($owner['net-publish'] || $force) {
|
||||
// Update global directory in background
|
||||
if (Search::getGlobalDirectory()) {
|
||||
Worker::add(PRIORITY_LOW, 'Directory', $owner['url']);
|
||||
Worker::add(Worker::PRIORITY_LOW, 'Directory', $owner['url']);
|
||||
}
|
||||
}
|
||||
|
||||
Worker::add(PRIORITY_LOW, 'ProfileUpdate', $uid);
|
||||
Worker::add(Worker::PRIORITY_LOW, 'ProfileUpdate', $uid);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -239,7 +238,7 @@ class Profile
|
|||
|
||||
DI::page()['title'] = $profile['name'] . ' @ ' . DI::config()->get('config', 'sitename');
|
||||
|
||||
if (!local_user()) {
|
||||
if (!DI::userSession()->getLocalUserId()) {
|
||||
$a->setCurrentTheme($profile['theme']);
|
||||
$a->setCurrentMobileTheme(DI::pConfig()->get($a->getProfileOwner(), 'system', 'mobile_theme') ?? '');
|
||||
}
|
||||
|
@ -255,7 +254,7 @@ class Profile
|
|||
require_once $theme_info_file;
|
||||
}
|
||||
|
||||
$block = (DI::config()->get('system', 'block_public') && !Session::isAuthenticated());
|
||||
$block = (DI::config()->get('system', 'block_public') && !DI::userSession()->isAuthenticated());
|
||||
|
||||
/**
|
||||
* @todo
|
||||
|
@ -295,8 +294,8 @@ class Profile
|
|||
|
||||
$profile_contact = [];
|
||||
|
||||
if (local_user() && ($profile['uid'] ?? 0) != local_user()) {
|
||||
$profile_contact = Contact::getByURL($profile['nurl'], null, [], local_user());
|
||||
if (DI::userSession()->getLocalUserId() && ($profile['uid'] ?? 0) != DI::userSession()->getLocalUserId()) {
|
||||
$profile_contact = Contact::getByURL($profile['nurl'], null, [], DI::userSession()->getLocalUserId());
|
||||
}
|
||||
if (!empty($profile['cid']) && self::getMyURL()) {
|
||||
$profile_contact = Contact::selectFirst([], ['id' => $profile['cid']]);
|
||||
|
@ -336,13 +335,13 @@ class Profile
|
|||
if (!$visitor_is_authenticated) {
|
||||
// Remote follow is only available for local profiles
|
||||
if (!empty($profile['nickname']) && strpos($profile_url, DI::baseUrl()->get()) === 0) {
|
||||
$follow_link = 'remote_follow/' . $profile['nickname'];
|
||||
$follow_link = 'profile/' . $profile['nickname'] . '/remote_follow';
|
||||
}
|
||||
} else {
|
||||
if ($visitor_is_following) {
|
||||
$unfollow_link = $visitor_base_path . '/unfollow?url=' . urlencode($profile_url) . '&auto=1';
|
||||
$unfollow_link = $visitor_base_path . '/contact/unfollow?url=' . urlencode($profile_url) . '&auto=1';
|
||||
} else {
|
||||
$follow_link = $visitor_base_path .'/follow?url=' . urlencode($profile_url) . '&auto=1';
|
||||
$follow_link = $visitor_base_path . '/contact/follow?url=' . urlencode($profile_url) . '&auto=1';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -350,7 +349,7 @@ class Profile
|
|||
if ($visitor_is_followed || $visitor_is_following) {
|
||||
$wallmessage_link = $visitor_base_path . '/message/new/' . $profile_contact['id'];
|
||||
} elseif ($visitor_is_authenticated && !empty($profile['unkmail'])) {
|
||||
$wallmessage_link = 'wallmessage/' . $profile['nickname'];
|
||||
$wallmessage_link = 'profile/' . $profile['nickname'] . '/unkmail';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -379,7 +378,7 @@ class Profile
|
|||
$xmpp = !empty($profile['xmpp']) ? DI::l10n()->t('XMPP:') : false;
|
||||
$matrix = !empty($profile['matrix']) ? DI::l10n()->t('Matrix:') : false;
|
||||
|
||||
if ((!empty($profile['hidewall']) || $block) && !Session::isAuthenticated()) {
|
||||
if ((!empty($profile['hidewall']) || $block) && !DI::userSession()->isAuthenticated()) {
|
||||
$location = $homepage = $about = false;
|
||||
}
|
||||
|
||||
|
@ -413,7 +412,7 @@ class Profile
|
|||
}
|
||||
|
||||
if (!$block && $show_contacts) {
|
||||
$contact_block = ContactBlock::getHTML($profile, local_user());
|
||||
$contact_block = ContactBlock::getHTML($profile, DI::userSession()->getLocalUserId());
|
||||
|
||||
if (is_array($profile) && !$profile['hide-friends']) {
|
||||
$contact_count = DBA::count('contact', [
|
||||
|
@ -452,6 +451,10 @@ class Profile
|
|||
|
||||
$p['url'] = Contact::magicLinkById($cid, $profile['url']);
|
||||
|
||||
if (!isset($profile['hidewall'])) {
|
||||
Logger::warning('Missing hidewall key in profile array', ['profile' => $profile, 'callstack' => System::callstack(10)]);
|
||||
}
|
||||
|
||||
$tpl = Renderer::getMarkupTemplate('profile/vcard.tpl');
|
||||
$o .= Renderer::replaceMacros($tpl, [
|
||||
'$profile' => $p,
|
||||
|
@ -462,12 +465,13 @@ class Profile
|
|||
'$unfollow' => DI::l10n()->t('Unfollow'),
|
||||
'$unfollow_link' => $unfollow_link,
|
||||
'$subscribe_feed' => DI::l10n()->t('Atom feed'),
|
||||
'$subscribe_feed_link' => $profile['poll'],
|
||||
'$subscribe_feed_link' => $profile['hidewall'] ?? 0 ? '' : $profile['poll'],
|
||||
'$wallmessage' => DI::l10n()->t('Message'),
|
||||
'$wallmessage_link' => $wallmessage_link,
|
||||
'$account_type' => $account_type,
|
||||
'$location' => $location,
|
||||
'$homepage' => $homepage,
|
||||
'$homepage_verified' => DI::l10n()->t('This website has been verified to belong to the same person.'),
|
||||
'$about' => $about,
|
||||
'$network' => DI::l10n()->t('Network:'),
|
||||
'$contacts' => $contact_count,
|
||||
|
@ -493,7 +497,7 @@ class Profile
|
|||
*/
|
||||
public static function getBirthdays(): string
|
||||
{
|
||||
if (!local_user() || DI::mode()->isMobile() || DI::mode()->isMobile()) {
|
||||
if (!DI::userSession()->getLocalUserId() || DI::mode()->isMobile() || DI::mode()->isMobile()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
|
@ -506,7 +510,7 @@ class Profile
|
|||
|
||||
$bd_short = DI::l10n()->t('F d');
|
||||
|
||||
$cacheKey = 'get_birthdays:' . local_user();
|
||||
$cacheKey = 'get_birthdays:' . DI::userSession()->getLocalUserId();
|
||||
$events = DI::cache()->get($cacheKey);
|
||||
if (is_null($events)) {
|
||||
$result = DBA::p(
|
||||
|
@ -523,7 +527,7 @@ class Profile
|
|||
ORDER BY `start`",
|
||||
Contact::SHARING,
|
||||
Contact::FRIEND,
|
||||
local_user(),
|
||||
DI::userSession()->getLocalUserId(),
|
||||
DateTimeFormat::utc('now + 6 days'),
|
||||
DateTimeFormat::utcNow()
|
||||
);
|
||||
|
@ -595,7 +599,7 @@ class Profile
|
|||
$a = DI::app();
|
||||
$o = '';
|
||||
|
||||
if (!local_user() || DI::mode()->isMobile() || DI::mode()->isMobile()) {
|
||||
if (!DI::userSession()->getLocalUserId() || DI::mode()->isMobile() || DI::mode()->isMobile()) {
|
||||
return $o;
|
||||
}
|
||||
|
||||
|
@ -610,7 +614,7 @@ class Profile
|
|||
$classtoday = '';
|
||||
|
||||
$condition = ["`uid` = ? AND `type` != 'birthday' AND `start` < ? AND `start` >= ?",
|
||||
local_user(), DateTimeFormat::utc('now + 7 days'), DateTimeFormat::utc('now - 1 days')];
|
||||
DI::userSession()->getLocalUserId(), DateTimeFormat::utc('now + 7 days'), DateTimeFormat::utc('now - 1 days')];
|
||||
$s = DBA::select('event', [], $condition, ['order' => ['start']]);
|
||||
|
||||
$r = [];
|
||||
|
@ -620,7 +624,7 @@ class Profile
|
|||
$total = 0;
|
||||
|
||||
while ($rr = DBA::fetch($s)) {
|
||||
$condition = ['parent-uri' => $rr['uri'], 'uid' => $rr['uid'], 'author-id' => public_contact(),
|
||||
$condition = ['parent-uri' => $rr['uri'], 'uid' => $rr['uid'], 'author-id' => DI::userSession()->getPublicContactId(),
|
||||
'vid' => [Verb::getID(Activity::ATTEND), Verb::getID(Activity::ATTENDMAYBE)],
|
||||
'visible' => true, 'deleted' => false];
|
||||
if (!Post::exists($condition)) {
|
||||
|
@ -680,10 +684,11 @@ class Profile
|
|||
* Retrieves the my_url session variable
|
||||
*
|
||||
* @return string
|
||||
* @deprecated since version 2022.12, please use UserSession->getMyUrl instead
|
||||
*/
|
||||
public static function getMyURL(): string
|
||||
{
|
||||
return Session::get('my_url') ?? '';
|
||||
return DI::userSession()->getMyUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -712,7 +717,7 @@ class Profile
|
|||
$my_url = self::getMyURL();
|
||||
$my_url = Network::isUrlValid($my_url);
|
||||
|
||||
if (empty($my_url) || local_user()) {
|
||||
if (empty($my_url) || DI::userSession()->getLocalUserId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -730,7 +735,7 @@ class Profile
|
|||
|
||||
$contact = DBA::selectFirst('contact',['id', 'url'], ['id' => $cid]);
|
||||
|
||||
if (DBA::isResult($contact) && remote_user() && remote_user() == $contact['id']) {
|
||||
if (DBA::isResult($contact) && DI::userSession()->getRemoteUserId() && DI::userSession()->getRemoteUserId() == $contact['id']) {
|
||||
Logger::info('The visitor ' . $my_url . ' is already authenticated');
|
||||
return;
|
||||
}
|
||||
|
@ -797,7 +802,7 @@ class Profile
|
|||
$_SESSION['my_url'] = $visitor['url'];
|
||||
$_SESSION['remote_comment'] = $visitor['subscribe'];
|
||||
|
||||
Session::setVisitorsContacts();
|
||||
DI::userSession()->setVisitorsContacts();
|
||||
|
||||
$a->setContactId($visitor['id']);
|
||||
|
||||
|
@ -865,7 +870,7 @@ class Profile
|
|||
|
||||
$a->setContactId($arr['visitor']['id']);
|
||||
|
||||
info(DI::l10n()->t('OpenWebAuth: %1$s welcomes %2$s', DI::baseUrl()->getHostname(), $visitor['name']));
|
||||
DI::sysmsg()->addInfo(DI::l10n()->t('OpenWebAuth: %1$s welcomes %2$s', DI::baseUrl()->getHostname(), $visitor['name']));
|
||||
|
||||
Logger::info('OpenWebAuth: auth success from ' . $visitor['addr']);
|
||||
}
|
||||
|
@ -916,7 +921,7 @@ class Profile
|
|||
*/
|
||||
public static function getThemeUid(App $a): int
|
||||
{
|
||||
return local_user() ?: $a->getProfileOwner();
|
||||
return DI::userSession()->getLocalUserId() ?: $a->getProfileOwner();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -37,7 +37,7 @@ class PushSubscriber
|
|||
* @return void
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public static function publishFeed(int $uid, int $default_priority = PRIORITY_HIGH)
|
||||
public static function publishFeed(int $uid, int $default_priority = Worker::PRIORITY_HIGH)
|
||||
{
|
||||
$condition = ['push' => 0, 'uid' => $uid];
|
||||
DBA::update('push_subscriber', ['push' => 1, 'next_try' => DBA::NULL_DATETIME], $condition);
|
||||
|
@ -52,7 +52,7 @@ class PushSubscriber
|
|||
* @return void
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public static function requeue(int $default_priority = PRIORITY_HIGH)
|
||||
public static function requeue(int $default_priority = Worker::PRIORITY_HIGH)
|
||||
{
|
||||
// We'll push to each subscriber that has push > 0,
|
||||
// i.e. there has been an update (set in notifier.php).
|
||||
|
@ -61,7 +61,7 @@ class PushSubscriber
|
|||
while ($subscriber = DBA::fetch($subscribers)) {
|
||||
// We always handle retries with low priority
|
||||
if ($subscriber['push'] > 1) {
|
||||
$priority = PRIORITY_LOW;
|
||||
$priority = Worker::PRIORITY_LOW;
|
||||
} else {
|
||||
$priority = $default_priority;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ namespace Friendica\Model;
|
|||
|
||||
use Friendica\Content\Pager;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
use Friendica\Util\Strings;
|
||||
|
||||
|
@ -113,21 +114,27 @@ class Register
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a register record for approval and returns the success of the database insert
|
||||
* Creates a register record for approval
|
||||
* Checks for the existence of the provided user id
|
||||
*
|
||||
* @param integer $uid The ID of the user needing approval
|
||||
* @param string $language The registration language
|
||||
* @param string $note An additional message from the user
|
||||
* @return boolean
|
||||
* @throws \Exception
|
||||
* @param integer $uid The ID of the user needing approval
|
||||
* @param string $language The registration language
|
||||
* @param string $note An additional message from the user
|
||||
* @return void
|
||||
* @throws \OutOfBoundsException
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws HTTPException\NotFoundException
|
||||
*/
|
||||
public static function createForApproval(int $uid, string $language, string $note = ''): bool
|
||||
public static function createForApproval(int $uid, string $language, string $note = ''): void
|
||||
{
|
||||
$hash = Strings::getRandomHex();
|
||||
|
||||
if (!$uid) {
|
||||
throw new \OutOfBoundsException("User ID can't be empty");
|
||||
}
|
||||
|
||||
if (!User::exists($uid)) {
|
||||
return false;
|
||||
throw new HTTPException\NotFoundException("User ID doesn't exist");
|
||||
}
|
||||
|
||||
$fields = [
|
||||
|
@ -139,7 +146,9 @@ class Register
|
|||
'note' => $note
|
||||
];
|
||||
|
||||
return DBA::insert('register', $fields);
|
||||
if (!DBA::insert('register', $fields)) {
|
||||
throw new HTTPException\InternalServerErrorException('Unable to insert a `register` record');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -141,7 +141,7 @@ class Subscription
|
|||
{
|
||||
$type = NotificationFactory::getType($notification);
|
||||
|
||||
if (DI::notify()->NotifyOnDesktop($notification, $type)) {
|
||||
if (DI::notify()->shouldShowOnDesktop($notification, $type)) {
|
||||
DI::notify()->createFromNotification($notification);
|
||||
}
|
||||
|
||||
|
@ -152,7 +152,7 @@ class Subscription
|
|||
$subscriptions = DBA::select('subscription', [], ['uid' => $notification->uid, $type => true]);
|
||||
while ($subscription = DBA::fetch($subscriptions)) {
|
||||
Logger::info('Push notification', ['id' => $subscription['id'], 'uid' => $subscription['uid'], 'type' => $type]);
|
||||
Worker::add(PRIORITY_HIGH, 'PushSubscription', $subscription['id'], $notification->id);
|
||||
Worker::add(Worker::PRIORITY_HIGH, 'PushSubscription', $subscription['id'], $notification->id);
|
||||
}
|
||||
DBA::close($subscriptions);
|
||||
}
|
||||
|
|
|
@ -257,17 +257,16 @@ class Tag
|
|||
* @param string $hash
|
||||
* @param string $name
|
||||
* @param string $url
|
||||
* @param boolean $probing Whether probing is active
|
||||
* @return void
|
||||
*/
|
||||
public static function storeByHash(int $uriId, string $hash, string $name, string $url = '', bool $probing = true)
|
||||
public static function storeByHash(int $uriId, string $hash, string $name, string $url = '')
|
||||
{
|
||||
$type = self::getTypeForHash($hash);
|
||||
if ($type == self::UNKNOWN) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::store($uriId, $type, $name, $url, $probing);
|
||||
self::store($uriId, $type, $name, $url);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -297,34 +296,39 @@ class Tag
|
|||
* @param integer $uriId URI-Id
|
||||
* @param string $body Body of the post
|
||||
* @param string $tags Accepted tags
|
||||
* @param boolean $probing Perform a probing for contacts, adding them if needed
|
||||
* @return void
|
||||
*/
|
||||
public static function storeFromBody(int $uriId, string $body, string $tags = null, bool $probing = true)
|
||||
public static function storeFromBody(int $uriId, string $body, string $tags = null)
|
||||
{
|
||||
Logger::info('Check for tags', ['uri-id' => $uriId, 'hash' => $tags, 'callstack' => System::callstack()]);
|
||||
$item = ['uri-id' => $uriId, 'body' => $body, 'quote-uri-id' => null];
|
||||
self::storeFromArray($item, $tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store tags and mentions from the item array
|
||||
*
|
||||
* @param array $item Item array
|
||||
* @param string $tags Accepted tags
|
||||
* @return void
|
||||
*/
|
||||
public static function storeFromArray(array $item, string $tags = null)
|
||||
{
|
||||
Logger::info('Check for tags', ['uri-id' => $item['uri-id'], 'hash' => $tags, 'callstack' => System::callstack()]);
|
||||
|
||||
if (is_null($tags)) {
|
||||
$tags = self::TAG_CHARACTER[self::HASHTAG] . self::TAG_CHARACTER[self::MENTION] . self::TAG_CHARACTER[self::EXCLUSIVE_MENTION];
|
||||
}
|
||||
|
||||
// Only remove the shared data from "real" reshares
|
||||
$shared = BBCode::fetchShareAttributes($body);
|
||||
if (!empty($shared['guid'])) {
|
||||
if (preg_match("/\s*\[share .*?\](.*?)\[\/share\]\s*/ism", $body, $matches)) {
|
||||
$share_body = $matches[1];
|
||||
}
|
||||
$body = preg_replace("/\s*\[share .*?\].*?\[\/share\]\s*/ism", '', $body);
|
||||
foreach (self::getFromBody($item['body'], $tags) as $tag) {
|
||||
self::storeByHash($item['uri-id'], $tag[1], $tag[3], $tag[2]);
|
||||
}
|
||||
|
||||
foreach (self::getFromBody($body, $tags) as $tag) {
|
||||
self::storeByHash($uriId, $tag[1], $tag[3], $tag[2], $probing);
|
||||
}
|
||||
$shared = DI::contentItem()->getSharedPost($item, ['uri-id']);
|
||||
|
||||
// Search for hashtags in the shared body (but only if hashtags are wanted)
|
||||
if (!empty($share_body) && (strpos($tags, self::TAG_CHARACTER[self::HASHTAG]) !== false)) {
|
||||
foreach (self::getFromBody($share_body, self::TAG_CHARACTER[self::HASHTAG]) as $tag) {
|
||||
self::storeByHash($uriId, $tag[1], $tag[3], $tag[2], $probing);
|
||||
if (!empty($shared) && (strpos($tags, self::TAG_CHARACTER[self::HASHTAG]) !== false)) {
|
||||
foreach (self::getByURIId($shared['post']['uri-id'], [self::HASHTAG]) as $tag) {
|
||||
self::store($item['uri-id'], $tag['type'], $tag['name'], $tag['url']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -158,6 +158,7 @@ class User
|
|||
$system['publish'] = false;
|
||||
$system['net-publish'] = false;
|
||||
$system['hide-friends'] = true;
|
||||
$system['hidewall'] = true;
|
||||
$system['prv_keywords'] = '';
|
||||
$system['pub_keywords'] = '';
|
||||
$system['address'] = '';
|
||||
|
@ -265,7 +266,7 @@ class User
|
|||
// List of possible actor names
|
||||
$possible_accounts = ['friendica', 'actor', 'system', 'internal'];
|
||||
foreach ($possible_accounts as $name) {
|
||||
if (!DBA::exists('user', ['nickname' => $name, 'account_removed' => false, 'expire' => false]) &&
|
||||
if (!DBA::exists('user', ['nickname' => $name, 'account_removed' => false, 'account_expired' => false]) &&
|
||||
!DBA::exists('userd', ['username' => $name])) {
|
||||
DI::config()->set('system', 'actor_name', $name);
|
||||
return $name;
|
||||
|
@ -381,17 +382,15 @@ class User
|
|||
*
|
||||
* @param array $fields
|
||||
* @return array user
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function getFirstAdmin(array $fields = []) : array
|
||||
{
|
||||
if (!empty(DI::config()->get('config', 'admin_nickname'))) {
|
||||
return self::getByNickname(DI::config()->get('config', 'admin_nickname'), $fields);
|
||||
} elseif (!empty(DI::config()->get('config', 'admin_email'))) {
|
||||
$adminList = explode(',', str_replace(' ', '', DI::config()->get('config', 'admin_email')));
|
||||
return self::getByEmail($adminList[0], $fields);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
|
||||
return self::getAdminList()[0] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -667,6 +666,28 @@ class User
|
|||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the day of the last activity of the given user
|
||||
*
|
||||
* @param integer $uid
|
||||
* @return void
|
||||
*/
|
||||
public static function updateLastActivity(int $uid)
|
||||
{
|
||||
$user = User::getById($uid, ['last-activity']);
|
||||
if (empty($user)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$current_day = DateTimeFormat::utcNow('Y-m-d');
|
||||
|
||||
if ($user['last-activity'] != $current_day) {
|
||||
User::update(['last-activity' => $current_day], $uid);
|
||||
// Set the last actitivy for all identities of the user
|
||||
DBA::update('user', ['last-activity' => $current_day], ['parent-uid' => $uid, 'account_removed' => false]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a human-readable random password
|
||||
*
|
||||
|
@ -994,7 +1015,7 @@ class User
|
|||
try {
|
||||
$authurl = $openid->authUrl();
|
||||
} catch (Exception $e) {
|
||||
throw new Exception(DI::l10n()->t('We encountered a problem while logging in with the OpenID you provided. Please check the correct spelling of the ID.') . EOL . EOL . DI::l10n()->t('The error message was:') . $e->getMessage(), 0, $e);
|
||||
throw new Exception(DI::l10n()->t('We encountered a problem while logging in with the OpenID you provided. Please check the correct spelling of the ID.') . '<br />' . DI::l10n()->t('The error message was:') . $e->getMessage(), 0, $e);
|
||||
}
|
||||
System::externalRedirect($authurl);
|
||||
// NOTREACHED
|
||||
|
@ -1054,11 +1075,8 @@ class User
|
|||
|
||||
// Disallow somebody creating an account using openid that uses the admin email address,
|
||||
// since openid bypasses email verification. We'll allow it if there is not yet an admin account.
|
||||
if (DI::config()->get('config', 'admin_email') && strlen($openid_url)) {
|
||||
$adminlist = explode(',', str_replace(' ', '', strtolower(DI::config()->get('config', 'admin_email'))));
|
||||
if (in_array(strtolower($email), $adminlist)) {
|
||||
throw new Exception(DI::l10n()->t('Cannot use that email.'));
|
||||
}
|
||||
if (strlen($openid_url) && in_array(strtolower($email), self::getAdminEmailList())) {
|
||||
throw new Exception(DI::l10n()->t('Cannot use that email.'));
|
||||
}
|
||||
|
||||
$nickname = $data['nickname'] = strtolower($nickname);
|
||||
|
@ -1317,7 +1335,7 @@ class User
|
|||
|
||||
if (DBA::isResult($profile) && $profile['net-publish'] && Search::getGlobalDirectory()) {
|
||||
$url = DI::baseUrl() . '/profile/' . $user['nickname'];
|
||||
Worker::add(PRIORITY_LOW, "Directory", $url);
|
||||
Worker::add(Worker::PRIORITY_LOW, "Directory", $url);
|
||||
}
|
||||
|
||||
$l10n = DI::l10n()->withLang($register['language']);
|
||||
|
@ -1418,7 +1436,7 @@ class User
|
|||
If you are new and do not know anybody here, they may help
|
||||
you to make some new and interesting friends.
|
||||
|
||||
If you ever want to delete your account, you can do so at %1$s/removeme
|
||||
If you ever want to delete your account, you can do so at %1$s/settings/removeme
|
||||
|
||||
Thank you and welcome to %4$s.'));
|
||||
|
||||
|
@ -1522,7 +1540,7 @@ class User
|
|||
If you are new and do not know anybody here, they may help
|
||||
you to make some new and interesting friends.
|
||||
|
||||
If you ever want to delete your account, you can do so at %3$s/removeme
|
||||
If you ever want to delete your account, you can do so at %3$s/settings/removeme
|
||||
|
||||
Thank you and welcome to %2$s.',
|
||||
$user['nickname'],
|
||||
|
@ -1567,14 +1585,14 @@ class User
|
|||
|
||||
// The user and related data will be deleted in Friendica\Worker\ExpireAndRemoveUsers
|
||||
DBA::update('user', ['account_removed' => true, 'account_expires_on' => DateTimeFormat::utc('now + 7 day')], ['uid' => $uid]);
|
||||
Worker::add(PRIORITY_HIGH, 'Notifier', Delivery::REMOVAL, $uid);
|
||||
Worker::add(Worker::PRIORITY_HIGH, 'Notifier', Delivery::REMOVAL, $uid);
|
||||
|
||||
// Send an update to the directory
|
||||
$self = DBA::selectFirst('contact', ['url'], ['uid' => $uid, 'self' => true]);
|
||||
Worker::add(PRIORITY_LOW, 'Directory', $self['url']);
|
||||
Worker::add(Worker::PRIORITY_LOW, 'Directory', $self['url']);
|
||||
|
||||
// Remove the user relevant data
|
||||
Worker::add(PRIORITY_NEGLIGIBLE, 'RemoveUser', $uid);
|
||||
Worker::add(Worker::PRIORITY_NEGLIGIBLE, 'RemoveUser', $uid);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1714,8 +1732,8 @@ class User
|
|||
'active_users_weekly' => 0,
|
||||
];
|
||||
|
||||
$userStmt = DBA::select('owner-view', ['uid', 'login_date', 'last-item'],
|
||||
["`verified` AND `login_date` > ? AND NOT `blocked`
|
||||
$userStmt = DBA::select('owner-view', ['uid', 'last-activity', 'last-item'],
|
||||
["`verified` AND `last-activity` > ? AND NOT `blocked`
|
||||
AND NOT `account_removed` AND NOT `account_expired`",
|
||||
DBA::NULL_DATETIME]);
|
||||
if (!DBA::isResult($userStmt)) {
|
||||
|
@ -1729,17 +1747,17 @@ class User
|
|||
while ($user = DBA::fetch($userStmt)) {
|
||||
$statistics['total_users']++;
|
||||
|
||||
if ((strtotime($user['login_date']) > $halfyear) || (strtotime($user['last-item']) > $halfyear)
|
||||
if ((strtotime($user['last-activity']) > $halfyear) || (strtotime($user['last-item']) > $halfyear)
|
||||
) {
|
||||
$statistics['active_users_halfyear']++;
|
||||
}
|
||||
|
||||
if ((strtotime($user['login_date']) > $month) || (strtotime($user['last-item']) > $month)
|
||||
if ((strtotime($user['last-activity']) > $month) || (strtotime($user['last-item']) > $month)
|
||||
) {
|
||||
$statistics['active_users_monthly']++;
|
||||
}
|
||||
|
||||
if ((strtotime($user['login_date']) > $week) || (strtotime($user['last-item']) > $week)
|
||||
if ((strtotime($user['last-activity']) > $week) || (strtotime($user['last-item']) > $week)
|
||||
) {
|
||||
$statistics['active_users_weekly']++;
|
||||
}
|
||||
|
@ -1783,4 +1801,64 @@ class User
|
|||
|
||||
return DBA::selectToArray('owner-view', [], $condition, $param);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of lowercase admin email addresses from the comma-separated list in the config
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getAdminEmailList(): array
|
||||
{
|
||||
$adminEmails = strtolower(str_replace(' ', '', DI::config()->get('config', 'admin_email')));
|
||||
if (!$adminEmails) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return explode(',', $adminEmails);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the complete list of admin user accounts
|
||||
*
|
||||
* @param array $fields
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function getAdminList(array $fields = []): array
|
||||
{
|
||||
$condition = [
|
||||
'email' => self::getAdminEmailList(),
|
||||
'parent-uid' => 0,
|
||||
'blocked' => 0,
|
||||
'verified' => true,
|
||||
'account_removed' => false,
|
||||
'account_expired' => false,
|
||||
];
|
||||
|
||||
return DBA::selectToArray('user', $fields, $condition, ['order' => ['uid']]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of admin user accounts where each unique email address appears only once.
|
||||
*
|
||||
* This method is meant for admin notifications that do not need to be sent multiple times to the same email address.
|
||||
*
|
||||
* @param array $fields
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function getAdminListForEmailing(array $fields = []): array
|
||||
{
|
||||
return array_filter(self::getAdminList($fields), function ($user) {
|
||||
static $emails = [];
|
||||
|
||||
if (in_array($user['email'], $emails)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$emails[] = $user['email'];
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue