]> git.mxchange.org Git - friendica.git/blob - src/Module/Contact/Profile.php
Issue 13052: The limit parameter now behaves like the Mastodon counterpart
[friendica.git] / src / Module / Contact / Profile.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2023, the Friendica project
4  *
5  * @license GNU AGPL version 3 or any later version
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  *
20  */
21
22 namespace Friendica\Module\Contact;
23
24 use Friendica\App;
25 use Friendica\BaseModule;
26 use Friendica\Contact\LocalRelationship\Entity;
27 use Friendica\Contact\LocalRelationship\Repository;
28 use Friendica\Content\ContactSelector;
29 use Friendica\Content\Nav;
30 use Friendica\Content\Text\BBCode;
31 use Friendica\Content\Widget;
32 use Friendica\Core\Config\Capability\IManageConfigValues;
33 use Friendica\Core\Hook;
34 use Friendica\Core\L10n;
35 use Friendica\Core\Protocol;
36 use Friendica\Core\Renderer;
37 use Friendica\Database\DBA;
38 use Friendica\DI;
39 use Friendica\Model\Contact;
40 use Friendica\Model\Group;
41 use Friendica\Module;
42 use Friendica\Module\Response;
43 use Friendica\Network\HTTPException;
44 use Friendica\Util\DateTimeFormat;
45 use Friendica\Util\Profiler;
46 use Psr\Log\LoggerInterface;
47
48 /**
49  *  Show a contact profile
50  */
51 class Profile extends BaseModule
52 {
53         /**
54          * @var Repository\LocalRelationship
55          */
56         private $localRelationship;
57         /**
58          * @var App\Page
59          */
60         private $page;
61         /**
62          * @var IManageConfigValues
63          */
64         private $config;
65
66         public function __construct(L10n $l10n, Repository\LocalRelationship $localRelationship, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, App\Page $page, IManageConfigValues $config, array $server, array $parameters = [])
67         {
68                 parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
69
70                 $this->localRelationship = $localRelationship;
71                 $this->page              = $page;
72                 $this->config            = $config;
73         }
74
75         protected function post(array $request = [])
76         {
77                 if (!DI::userSession()->getLocalUserId()) {
78                         return;
79                 }
80
81                 $contact_id = $this->parameters['id'];
82
83                 // Backward compatibility: The update still needs a user-specific contact ID
84                 // Change to user-contact table check by version 2022.03
85                 $cdata = Contact::getPublicAndUserContactID($contact_id, DI::userSession()->getLocalUserId());
86                 if (empty($cdata['user']) || !DBA::exists('contact', ['id' => $cdata['user'], 'deleted' => false])) {
87                         return;
88                 }
89
90                 Hook::callAll('contact_edit_post', $_POST);
91
92                 $fields = [];
93
94                 if (isset($_POST['hidden'])) {
95                         $fields['hidden'] = !empty($_POST['hidden']);
96                 }
97
98                 if (isset($_POST['notify_new_posts'])) {
99                         $fields['notify_new_posts'] = !empty($_POST['notify_new_posts']);
100                 }
101
102                 if (isset($_POST['fetch_further_information'])) {
103                         $fields['fetch_further_information'] = intval($_POST['fetch_further_information']);
104                 }
105
106                 if (isset($_POST['remote_self'])) {
107                         $fields['remote_self'] = intval($_POST['remote_self']);
108                 }
109
110                 if (isset($_POST['ffi_keyword_denylist'])) {
111                         $fields['ffi_keyword_denylist'] = $_POST['ffi_keyword_denylist'];
112                 }
113
114                 if (isset($_POST['poll'])) {
115                         $priority = intval($_POST['poll']);
116                         if ($priority > 5 || $priority < 0) {
117                                 $priority = 0;
118                         }
119
120                         $fields['priority'] = $priority;
121                 }
122
123                 if (isset($_POST['info'])) {
124                         $fields['info'] = $_POST['info'];
125                 }
126
127                 if (!Contact::update($fields, ['id' => $cdata['user'], 'uid' => DI::userSession()->getLocalUserId()])) {
128                         DI::sysmsg()->addNotice($this->t('Failed to update contact record.'));
129                 }
130         }
131
132         protected function content(array $request = []): string
133         {
134                 if (!DI::userSession()->getLocalUserId()) {
135                         return Module\Security\Login::form($_SERVER['REQUEST_URI']);
136                 }
137
138                 // Backward compatibility: Ensure to use the public contact when the user contact is provided
139                 // Remove by version 2022.03
140                 $data = Contact::getPublicAndUserContactID(intval($this->parameters['id']), DI::userSession()->getLocalUserId());
141                 if (empty($data)) {
142                         throw new HTTPException\NotFoundException($this->t('Contact not found.'));
143                 }
144
145                 $contact = Contact::getById($data['public']);
146                 if (!DBA::isResult($contact)) {
147                         throw new HTTPException\NotFoundException($this->t('Contact not found.'));
148                 }
149
150                 // Don't display contacts that are about to be deleted
151                 if (DBA::isResult($contact) && (!empty($contact['deleted']) || !empty($contact['network']) && $contact['network'] == Protocol::PHANTOM)) {
152                         throw new HTTPException\NotFoundException($this->t('Contact not found.'));
153                 }
154
155                 $localRelationship = $this->localRelationship->getForUserContact(DI::userSession()->getLocalUserId(), $contact['id']);
156
157                 if ($localRelationship->rel === Contact::SELF) {
158                         $this->baseUrl->redirect('profile/' . $contact['nick'] . '/profile');
159                 }
160
161                 if (isset($this->parameters['action'])) {
162                         self::checkFormSecurityTokenRedirectOnError('contact/' . $contact['id'], 'contact_action', 't');
163
164                         $cmd = $this->parameters['action'];
165                         if ($cmd === 'update' && $localRelationship->rel !== Contact::NOTHING) {
166                                 Module\Contact::updateContactFromPoll($contact['id']);
167                         }
168
169                         if ($cmd === 'updateprofile') {
170                                 self::updateContactFromProbe($contact['id']);
171                         }
172
173                         if ($cmd === 'block') {
174                                 if ($localRelationship->blocked) {
175                                         // @TODO Backward compatibility, replace with $localRelationship->unblock()
176                                         Contact\User::setBlocked($contact['id'], DI::userSession()->getLocalUserId(), false);
177
178                                         $message = $this->t('Contact has been unblocked');
179                                 } else {
180                                         // @TODO Backward compatibility, replace with $localRelationship->block()
181                                         Contact\User::setBlocked($contact['id'], DI::userSession()->getLocalUserId(), true);
182                                         $message = $this->t('Contact has been blocked');
183                                 }
184
185                                 // @TODO: add $this->localRelationship->save($localRelationship);
186                                 DI::sysmsg()->addInfo($message);
187                         }
188
189                         if ($cmd === 'ignore') {
190                                 if ($localRelationship->ignored) {
191                                         // @TODO Backward compatibility, replace with $localRelationship->unblock()
192                                         Contact\User::setIgnored($contact['id'], DI::userSession()->getLocalUserId(), false);
193
194                                         $message = $this->t('Contact has been unignored');
195                                 } else {
196                                         // @TODO Backward compatibility, replace with $localRelationship->block()
197                                         Contact\User::setIgnored($contact['id'], DI::userSession()->getLocalUserId(), true);
198                                         $message = $this->t('Contact has been ignored');
199                                 }
200
201                                 // @TODO: add $this->localRelationship->save($localRelationship);
202                                 DI::sysmsg()->addInfo($message);
203                         }
204
205                         if ($cmd === 'collapse') {
206                                 if ($localRelationship->collapsed) {
207                                         // @TODO Backward compatibility, replace with $localRelationship->unblock()
208                                         Contact\User::setCollapsed($contact['id'], DI::userSession()->getLocalUserId(), false);
209
210                                         $message = $this->t('Contact has been uncollapsed');
211                                 } else {
212                                         // @TODO Backward compatibility, replace with $localRelationship->block()
213                                         Contact\User::setCollapsed($contact['id'], DI::userSession()->getLocalUserId(), true);
214                                         $message = $this->t('Contact has been collapsed');
215                                 }
216
217                                 // @TODO: add $this->localRelationship->save($localRelationship);
218                                 DI::sysmsg()->addInfo($message);
219                         }
220
221                         $this->baseUrl->redirect('contact/' . $contact['id']);
222                 }
223
224                 $vcard_widget  = Widget\VCard::getHTML($contact);
225                 $groups_widget = '';
226
227                 if (!in_array($localRelationship->rel, [Contact::NOTHING, Contact::SELF])) {
228                         $groups_widget = Group::sidebarWidget('contact', 'group', 'full', 'everyone', $data['user']);
229                 }
230
231                 $this->page['aside'] .= $vcard_widget . $groups_widget;
232
233                 $o = '';
234                 Nav::setSelected('contact');
235
236                 $_SESSION['return_path'] = $this->args->getQueryString();
237
238                 $this->page['htmlhead'] .= Renderer::replaceMacros(Renderer::getMarkupTemplate('contact_head.tpl'), [
239                 ]);
240
241                 switch ($localRelationship->rel) {
242                         case Contact::FRIEND:   $relation_text = $this->t('You are mutual friends with %s', $contact['name']); break;
243                         case Contact::FOLLOWER: $relation_text = $this->t('You are sharing with %s', $contact['name']); break;
244                         case Contact::SHARING:  $relation_text = $this->t('%s is sharing with you', $contact['name']); break;
245                         default:
246                                 $relation_text = '';
247                 }
248
249                 if (!in_array($contact['network'], array_merge(Protocol::FEDERATED, [Protocol::TWITTER]))) {
250                         $relation_text = '';
251                 }
252
253                 $url = Contact::magicLinkByContact($contact);
254                 if (strpos($url, 'contact/redir/') === 0) {
255                         $sparkle = ' class="sparkle" ';
256                 } else {
257                         $sparkle = '';
258                 }
259
260                 $insecure = $this->t('Private communications are not available for this contact.');
261
262                 $last_update = (($contact['last-update'] <= DBA::NULL_DATETIME) ? $this->t('Never') : DateTimeFormat::local($contact['last-update'], 'D, j M Y, g:i A'));
263
264                 if ($contact['last-update'] > DBA::NULL_DATETIME) {
265                         $last_update .= ' ' . ($contact['failed'] ? $this->t('(Update was not successful)') : $this->t('(Update was successful)'));
266                 }
267                 $lblsuggest = (($contact['network'] === Protocol::DFRN) ? $this->t('Suggest friends') : '');
268
269                 $poll_enabled = in_array($contact['network'], [Protocol::DFRN, Protocol::OSTATUS, Protocol::FEED, Protocol::MAIL]);
270
271                 $nettype = $this->t('Network type: %s', ContactSelector::networkToName($contact['network'], $contact['url'], $contact['protocol'], $contact['gsid']));
272
273                 // tabs
274                 $tab_str = Module\Contact::getTabsHTML($contact, Module\Contact::TAB_PROFILE);
275
276                 $lost_contact = (($contact['archive'] && $contact['term-date'] > DBA::NULL_DATETIME && $contact['term-date'] < DateTimeFormat::utcNow()) ? $this->t('Communications lost with this contact!') : '');
277
278                 $fetch_further_information = null;
279                 if ($contact['network'] == Protocol::FEED) {
280                         $fetch_further_information = [
281                                 'fetch_further_information',
282                                 $this->t('Fetch further information for feeds'),
283                                 $localRelationship->fetchFurtherInformation,
284                                 $this->t('Fetch information like preview pictures, title and teaser from the feed item. You can activate this if the feed doesn\'t contain much text. Keywords are taken from the meta header in the feed item and are posted as hash tags.'),
285                                 [
286                                         '0' => $this->t('Disabled'),
287                                         '1' => $this->t('Fetch information'),
288                                         '3' => $this->t('Fetch keywords'),
289                                         '2' => $this->t('Fetch information and keywords')
290                                 ]
291                         ];
292                 }
293
294                 $allow_remote_self = in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::FEED, Protocol::DFRN, Protocol::DIASPORA, Protocol::TWITTER])
295                         && $this->config->get('system', 'allow_users_remote_self');
296
297                 if ($contact['network'] == Protocol::FEED) {
298                         $remote_self_options = [
299                                 Contact::MIRROR_DEACTIVATED => $this->t('No mirroring'),
300                                 Contact::MIRROR_OWN_POST    => $this->t('Mirror as my own posting')
301                         ];
302                 } elseif ($contact['network'] == Protocol::ACTIVITYPUB) {
303                         $remote_self_options = [
304                                 Contact::MIRROR_DEACTIVATED    => $this->t('No mirroring'),
305                                 Contact::MIRROR_NATIVE_RESHARE => $this->t('Native reshare')
306                         ];
307                 } elseif ($contact['network'] == Protocol::DFRN) {
308                         $remote_self_options = [
309                                 Contact::MIRROR_DEACTIVATED    => $this->t('No mirroring'),
310                                 Contact::MIRROR_OWN_POST       => $this->t('Mirror as my own posting'),
311                                 Contact::MIRROR_NATIVE_RESHARE => $this->t('Native reshare')
312                         ];
313                 } else {
314                         $remote_self_options = [
315                                 Contact::MIRROR_DEACTIVATED => $this->t('No mirroring'),
316                                 Contact::MIRROR_OWN_POST    => $this->t('Mirror as my own posting')
317                         ];
318                 }
319
320                 $poll_interval = null;
321                 if ((($contact['network'] == Protocol::FEED) && !$this->config->get('system', 'adjust_poll_frequency')) || ($contact['network'] == Protocol::MAIL)) {
322                         $poll_interval = ContactSelector::pollInterval($localRelationship->priority, !$poll_enabled);
323                 }
324
325                 $contact_actions = $this->getContactActions($contact, $localRelationship);
326
327                 if ($localRelationship->rel !== Contact::NOTHING) {
328                         $lbl_info1              = $this->t('Contact Information / Notes');
329                         $contact_settings_label = $this->t('Contact Settings');
330                 } else {
331                         $lbl_info1              = null;
332                         $contact_settings_label = null;
333                 }
334
335                 $tpl = Renderer::getMarkupTemplate('contact_edit.tpl');
336                 $o .= Renderer::replaceMacros($tpl, [
337                         '$header'                    => $this->t('Contact'),
338                         '$tab_str'                   => $tab_str,
339                         '$submit'                    => $this->t('Submit'),
340                         '$lbl_info1'                 => $lbl_info1,
341                         '$lbl_info2'                 => $this->t('Their personal note'),
342                         '$reason'                    => trim($contact['reason'] ?? ''),
343                         '$infedit'                   => $this->t('Edit contact notes'),
344                         '$common_link'               => 'contact/' . $contact['id'] . '/contacts/common',
345                         '$relation_text'             => $relation_text,
346                         '$visit'                     => $this->t('Visit %s\'s profile [%s]', $contact['name'], $contact['url']),
347                         '$blockunblock'              => $this->t('Block/Unblock contact'),
348                         '$ignorecont'                => $this->t('Ignore contact'),
349                         '$lblrecent'                 => $this->t('View conversations'),
350                         '$lblsuggest'                => $lblsuggest,
351                         '$nettype'                   => $nettype,
352                         '$poll_interval'             => $poll_interval,
353                         '$poll_enabled'              => $poll_enabled,
354                         '$lastupdtext'               => $this->t('Last update:'),
355                         '$lost_contact'              => $lost_contact,
356                         '$updpub'                    => $this->t('Update public posts'),
357                         '$last_update'               => $last_update,
358                         '$udnow'                     => $this->t('Update now'),
359                         '$contact_id'                => $contact['id'],
360                         '$pending'                   => $localRelationship->pending   ? $this->t('Awaiting connection acknowledge') : '',
361                         '$blocked'                   => $localRelationship->blocked   ? $this->t('Currently blocked') : '',
362                         '$ignored'                   => $localRelationship->ignored   ? $this->t('Currently ignored') : '',
363                         '$collapsed'                 => $localRelationship->collapsed ? $this->t('Currently collapsed') : '',
364                         '$archived'                  => ($contact['archive'] ? $this->t('Currently archived') : ''),
365                         '$insecure'                  => (in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::MAIL, Protocol::DIASPORA]) ? '' : $insecure),
366                         '$cinfo'                     => ['info', '', $localRelationship->info, ''],
367                         '$hidden'                    => ['hidden', $this->t('Hide this contact from others'), $localRelationship->hidden, $this->t('Replies/likes to your public posts <strong>may</strong> still be visible')],
368                         '$notify_new_posts'          => ['notify_new_posts', $this->t('Notification for new posts'), ($localRelationship->notifyNewPosts), $this->t('Send a notification of every new post of this contact')],
369                         '$fetch_further_information' => $fetch_further_information,
370                         '$ffi_keyword_denylist'      => ['ffi_keyword_denylist', $this->t('Keyword Deny List'), $localRelationship->ffiKeywordDenylist, $this->t('Comma separated list of keywords that should not be converted to hashtags, when "Fetch information and keywords" is selected')],
371                         '$photo'                     => Contact::getPhoto($contact),
372                         '$name'                      => $contact['name'],
373                         '$sparkle'                   => $sparkle,
374                         '$url'                       => $url,
375                         '$profileurllabel'           => $this->t('Profile URL'),
376                         '$profileurl'                => $contact['url'],
377                         '$account_type'              => Contact::getAccountType($contact['contact-type']),
378                         '$location'                  => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['location']),
379                         '$location_label'            => $this->t('Location:'),
380                         '$xmpp'                      => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['xmpp']),
381                         '$xmpp_label'                => $this->t('XMPP:'),
382                         '$matrix'                    => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['matrix']),
383                         '$matrix_label'              => $this->t('Matrix:'),
384                         '$about'                     => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['about'], BBCode::EXTERNAL),
385                         '$about_label'               => $this->t('About:'),
386                         '$keywords'                  => $contact['keywords'],
387                         '$keywords_label'            => $this->t('Tags:'),
388                         '$contact_action_button'     => $this->t('Actions'),
389                         '$contact_actions'           => $contact_actions,
390                         '$contact_status'            => $this->t('Status'),
391                         '$contact_settings_label'    => $contact_settings_label,
392                         '$contact_profile_label'     => $this->t('Profile'),
393                         '$allow_remote_self'         => $allow_remote_self,
394                         '$remote_self'               => [
395                                 'remote_self',
396                                 $this->t('Mirror postings from this contact'),
397                                 $localRelationship->isRemoteSelf,
398                                 $this->t('Mark this contact as remote_self, this will cause friendica to repost new entries from this contact.'),
399                                 $remote_self_options
400                         ],
401                 ]);
402
403                 $arr = ['contact' => $contact, 'output' => $o];
404
405                 Hook::callAll('contact_edit', $arr);
406
407                 return $arr['output'];
408         }
409
410         /**
411          * Returns the list of available actions that can performed on the provided contact
412          *
413          * This includes actions like e.g. 'block', 'hide', 'delete' and others
414          *
415          * @param array                    $contact           Public contact row
416          * @param Entity\LocalRelationship $localRelationship
417          * @return array with contact related actions
418          * @throws HTTPException\InternalServerErrorException
419          */
420         private function getContactActions(array $contact, Entity\LocalRelationship $localRelationship): array
421         {
422                 $poll_enabled    = in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::OSTATUS, Protocol::FEED, Protocol::MAIL]);
423                 $contact_actions = [];
424
425                 $formSecurityToken = self::getFormSecurityToken('contact_action');
426
427                 if ($localRelationship->rel & Contact::SHARING) {
428                         $contact_actions['unfollow'] = [
429                                 'label' => $this->t('Unfollow'),
430                                 'url'   => 'contact/unfollow?url=' . urlencode($contact['url']) . '&auto=1',
431                                 'title' => '',
432                                 'sel'   => '',
433                                 'id'    => 'unfollow',
434                         ];
435                 } else {
436                         $contact_actions['follow'] = [
437                                 'label' => $this->t('Follow'),
438                                 'url'   => 'contact/follow?url=' . urlencode($contact['url']) . '&auto=1',
439                                 'title' => '',
440                                 'sel'   => '',
441                                 'id'    => 'follow',
442                         ];
443                 }
444
445                 // Provide friend suggestion only for Friendica contacts
446                 if ($contact['network'] === Protocol::DFRN) {
447                         $contact_actions['suggest'] = [
448                                 'label' => $this->t('Suggest friends'),
449                                 'url'   => 'fsuggest/' . $contact['id'],
450                                 'title' => '',
451                                 'sel'   => '',
452                                 'id'    => 'suggest',
453                         ];
454                 }
455
456                 if ($poll_enabled) {
457                         $contact_actions['update'] = [
458                                 'label' => $this->t('Update now'),
459                                 'url'   => 'contact/' . $contact['id'] . '/update?t=' . $formSecurityToken,
460                                 'title' => '',
461                                 'sel'   => '',
462                                 'id'    => 'update',
463                         ];
464                 }
465
466                 if (Protocol::supportsProbe($contact['network'])) {
467                         $contact_actions['updateprofile'] = [
468                                 'label' => $this->t('Refetch contact data'),
469                                 'url'   => 'contact/' . $contact['id'] . '/updateprofile?t=' . $formSecurityToken,
470                                 'title' => '',
471                                 'sel'   => '',
472                                 'id'    => 'updateprofile',
473                         ];
474                 }
475
476                 $contact_actions['block'] = [
477                         'label' => $localRelationship->blocked ? $this->t('Unblock') : $this->t('Block'),
478                         'url'   => 'contact/' . $contact['id'] . '/block?t=' . $formSecurityToken,
479                         'title' => $this->t('Toggle Blocked status'),
480                         'sel'   => $localRelationship->blocked ? 'active' : '',
481                         'id'    => 'toggle-block',
482                 ];
483
484                 $contact_actions['ignore'] = [
485                         'label' => $localRelationship->ignored ? $this->t('Unignore') : $this->t('Ignore'),
486                         'url'   => 'contact/' . $contact['id'] . '/ignore?t=' . $formSecurityToken,
487                         'title' => $this->t('Toggle Ignored status'),
488                         'sel'   => $localRelationship->ignored ? 'active' : '',
489                         'id'    => 'toggle-ignore',
490                 ];
491
492                 $contact_actions['collapse'] = [
493                         'label' => $localRelationship->collapsed ? $this->t('Uncollapse') : $this->t('Collapse'),
494                         'url'   => 'contact/' . $contact['id'] . '/collapse?t=' . $formSecurityToken,
495                         'title' => $this->t('Toggle Collapsed status'),
496                         'sel'   => $localRelationship->collapsed ? 'active' : '',
497                         'id'    => 'toggle-collapse',
498                 ];
499
500                 if (Protocol::supportsRevokeFollow($contact['network']) && in_array($localRelationship->rel, [Contact::FOLLOWER, Contact::FRIEND])) {
501                         $contact_actions['revoke_follow'] = [
502                                 'label' => $this->t('Revoke Follow'),
503                                 'url'   => 'contact/' . $contact['id'] . '/revoke',
504                                 'title' => $this->t('Revoke the follow from this contact'),
505                                 'sel'   => '',
506                                 'id'    => 'revoke_follow',
507                         ];
508                 }
509
510                 return $contact_actions;
511         }
512
513         /**
514          * Updates contact from probing
515          *
516          * @param int $contact_id Id of the contact with uid != 0
517          * @return void
518          * @throws HTTPException\InternalServerErrorException
519          * @throws \ImagickException
520          */
521         private static function updateContactFromProbe(int $contact_id)
522         {
523                 $contact = DBA::selectFirst('contact', ['url'], ['id' => $contact_id, 'uid' => [0, DI::userSession()->getLocalUserId()], 'deleted' => false]);
524                 if (!DBA::isResult($contact)) {
525                         return;
526                 }
527
528                 // Update the entry in the contact table
529                 Contact::updateFromProbe($contact_id);
530         }
531 }