]> git.mxchange.org Git - friendica.git/blob - src/Module/Contact/Profile.php
Merge pull request #12707 from MrPetovan/bug/contact-page
[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                         '$baseurl' => $this->baseUrl->get(true),
240                 ]);
241
242                 switch ($localRelationship->rel) {
243                         case Contact::FRIEND:   $relation_text = $this->t('You are mutual friends with %s', $contact['name']); break;
244                         case Contact::FOLLOWER: $relation_text = $this->t('You are sharing with %s', $contact['name']); break;
245                         case Contact::SHARING:  $relation_text = $this->t('%s is sharing with you', $contact['name']); break;
246                         default:
247                                 $relation_text = '';
248                 }
249
250                 if (!in_array($contact['network'], array_merge(Protocol::FEDERATED, [Protocol::TWITTER]))) {
251                         $relation_text = '';
252                 }
253
254                 $url = Contact::magicLinkByContact($contact);
255                 if (strpos($url, 'contact/redir/') === 0) {
256                         $sparkle = ' class="sparkle" ';
257                 } else {
258                         $sparkle = '';
259                 }
260
261                 $insecure = $this->t('Private communications are not available for this contact.');
262
263                 $last_update = (($contact['last-update'] <= DBA::NULL_DATETIME) ? $this->t('Never') : DateTimeFormat::local($contact['last-update'], 'D, j M Y, g:i A'));
264
265                 if ($contact['last-update'] > DBA::NULL_DATETIME) {
266                         $last_update .= ' ' . ($contact['failed'] ? $this->t('(Update was not successful)') : $this->t('(Update was successful)'));
267                 }
268                 $lblsuggest = (($contact['network'] === Protocol::DFRN) ? $this->t('Suggest friends') : '');
269
270                 $poll_enabled = in_array($contact['network'], [Protocol::DFRN, Protocol::OSTATUS, Protocol::FEED, Protocol::MAIL]);
271
272                 $nettype = $this->t('Network type: %s', ContactSelector::networkToName($contact['network'], $contact['url'], $contact['protocol'], $contact['gsid']));
273
274                 // tabs
275                 $tab_str = Module\Contact::getTabsHTML($contact, Module\Contact::TAB_PROFILE);
276
277                 $lost_contact = (($contact['archive'] && $contact['term-date'] > DBA::NULL_DATETIME && $contact['term-date'] < DateTimeFormat::utcNow()) ? $this->t('Communications lost with this contact!') : '');
278
279                 $fetch_further_information = null;
280                 if ($contact['network'] == Protocol::FEED) {
281                         $fetch_further_information = [
282                                 'fetch_further_information',
283                                 $this->t('Fetch further information for feeds'),
284                                 $localRelationship->fetchFurtherInformation,
285                                 $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.'),
286                                 [
287                                         '0' => $this->t('Disabled'),
288                                         '1' => $this->t('Fetch information'),
289                                         '3' => $this->t('Fetch keywords'),
290                                         '2' => $this->t('Fetch information and keywords')
291                                 ]
292                         ];
293                 }
294
295                 $allow_remote_self = in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::FEED, Protocol::DFRN, Protocol::DIASPORA, Protocol::TWITTER])
296                         && $this->config->get('system', 'allow_users_remote_self');
297
298                 if ($contact['network'] == Protocol::FEED) {
299                         $remote_self_options = [
300                                 Contact::MIRROR_DEACTIVATED => $this->t('No mirroring'),
301                                 Contact::MIRROR_OWN_POST    => $this->t('Mirror as my own posting')
302                         ];
303                 } elseif ($contact['network'] == Protocol::ACTIVITYPUB) {
304                         $remote_self_options = [
305                                 Contact::MIRROR_DEACTIVATED    => $this->t('No mirroring'),
306                                 Contact::MIRROR_NATIVE_RESHARE => $this->t('Native reshare')
307                         ];
308                 } elseif ($contact['network'] == Protocol::DFRN) {
309                         $remote_self_options = [
310                                 Contact::MIRROR_DEACTIVATED    => $this->t('No mirroring'),
311                                 Contact::MIRROR_OWN_POST       => $this->t('Mirror as my own posting'),
312                                 Contact::MIRROR_NATIVE_RESHARE => $this->t('Native reshare')
313                         ];
314                 } else {
315                         $remote_self_options = [
316                                 Contact::MIRROR_DEACTIVATED => $this->t('No mirroring'),
317                                 Contact::MIRROR_OWN_POST    => $this->t('Mirror as my own posting')
318                         ];
319                 }
320
321                 $poll_interval = null;
322                 if ((($contact['network'] == Protocol::FEED) && !$this->config->get('system', 'adjust_poll_frequency')) || ($contact['network'] == Protocol::MAIL)) {
323                         $poll_interval = ContactSelector::pollInterval($localRelationship->priority, !$poll_enabled);
324                 }
325
326                 $contact_actions = $this->getContactActions($contact, $localRelationship);
327
328                 if ($localRelationship->rel !== Contact::NOTHING) {
329                         $lbl_info1              = $this->t('Contact Information / Notes');
330                         $contact_settings_label = $this->t('Contact Settings');
331                 } else {
332                         $lbl_info1              = null;
333                         $contact_settings_label = null;
334                 }
335
336                 $tpl = Renderer::getMarkupTemplate('contact_edit.tpl');
337                 $o .= Renderer::replaceMacros($tpl, [
338                         '$header'                    => $this->t('Contact'),
339                         '$tab_str'                   => $tab_str,
340                         '$submit'                    => $this->t('Submit'),
341                         '$lbl_info1'                 => $lbl_info1,
342                         '$lbl_info2'                 => $this->t('Their personal note'),
343                         '$reason'                    => trim($contact['reason'] ?? ''),
344                         '$infedit'                   => $this->t('Edit contact notes'),
345                         '$common_link'               => 'contact/' . $contact['id'] . '/contacts/common',
346                         '$relation_text'             => $relation_text,
347                         '$visit'                     => $this->t('Visit %s\'s profile [%s]', $contact['name'], $contact['url']),
348                         '$blockunblock'              => $this->t('Block/Unblock contact'),
349                         '$ignorecont'                => $this->t('Ignore contact'),
350                         '$lblrecent'                 => $this->t('View conversations'),
351                         '$lblsuggest'                => $lblsuggest,
352                         '$nettype'                   => $nettype,
353                         '$poll_interval'             => $poll_interval,
354                         '$poll_enabled'              => $poll_enabled,
355                         '$lastupdtext'               => $this->t('Last update:'),
356                         '$lost_contact'              => $lost_contact,
357                         '$updpub'                    => $this->t('Update public posts'),
358                         '$last_update'               => $last_update,
359                         '$udnow'                     => $this->t('Update now'),
360                         '$contact_id'                => $contact['id'],
361                         '$pending'                   => $localRelationship->pending   ? $this->t('Awaiting connection acknowledge') : '',
362                         '$blocked'                   => $localRelationship->blocked   ? $this->t('Currently blocked') : '',
363                         '$ignored'                   => $localRelationship->ignored   ? $this->t('Currently ignored') : '',
364                         '$collapsed'                 => $localRelationship->collapsed ? $this->t('Currently collapsed') : '',
365                         '$archived'                  => ($contact['archive'] ? $this->t('Currently archived') : ''),
366                         '$insecure'                  => (in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::MAIL, Protocol::DIASPORA]) ? '' : $insecure),
367                         '$cinfo'                     => ['info', '', $localRelationship->info, ''],
368                         '$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')],
369                         '$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')],
370                         '$fetch_further_information' => $fetch_further_information,
371                         '$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')],
372                         '$photo'                     => Contact::getPhoto($contact),
373                         '$name'                      => $contact['name'],
374                         '$sparkle'                   => $sparkle,
375                         '$url'                       => $url,
376                         '$profileurllabel'           => $this->t('Profile URL'),
377                         '$profileurl'                => $contact['url'],
378                         '$account_type'              => Contact::getAccountType($contact['contact-type']),
379                         '$location'                  => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['location']),
380                         '$location_label'            => $this->t('Location:'),
381                         '$xmpp'                      => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['xmpp']),
382                         '$xmpp_label'                => $this->t('XMPP:'),
383                         '$matrix'                    => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['matrix']),
384                         '$matrix_label'              => $this->t('Matrix:'),
385                         '$about'                     => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['about'], BBCode::EXTERNAL),
386                         '$about_label'               => $this->t('About:'),
387                         '$keywords'                  => $contact['keywords'],
388                         '$keywords_label'            => $this->t('Tags:'),
389                         '$contact_action_button'     => $this->t('Actions'),
390                         '$contact_actions'           => $contact_actions,
391                         '$contact_status'            => $this->t('Status'),
392                         '$contact_settings_label'    => $contact_settings_label,
393                         '$contact_profile_label'     => $this->t('Profile'),
394                         '$allow_remote_self'         => $allow_remote_self,
395                         '$remote_self'               => [
396                                 'remote_self',
397                                 $this->t('Mirror postings from this contact'),
398                                 $localRelationship->isRemoteSelf,
399                                 $this->t('Mark this contact as remote_self, this will cause friendica to repost new entries from this contact.'),
400                                 $remote_self_options
401                         ],
402                 ]);
403
404                 $arr = ['contact' => $contact, 'output' => $o];
405
406                 Hook::callAll('contact_edit', $arr);
407
408                 return $arr['output'];
409         }
410
411         /**
412          * Returns the list of available actions that can performed on the provided contact
413          *
414          * This includes actions like e.g. 'block', 'hide', 'delete' and others
415          *
416          * @param array                    $contact           Public contact row
417          * @param Entity\LocalRelationship $localRelationship
418          * @return array with contact related actions
419          * @throws HTTPException\InternalServerErrorException
420          */
421         private function getContactActions(array $contact, Entity\LocalRelationship $localRelationship): array
422         {
423                 $poll_enabled    = in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::OSTATUS, Protocol::FEED, Protocol::MAIL]);
424                 $contact_actions = [];
425
426                 $formSecurityToken = self::getFormSecurityToken('contact_action');
427
428                 if ($localRelationship->rel & Contact::SHARING) {
429                         $contact_actions['unfollow'] = [
430                                 'label' => $this->t('Unfollow'),
431                                 'url'   => 'contact/unfollow?url=' . urlencode($contact['url']) . '&auto=1',
432                                 'title' => '',
433                                 'sel'   => '',
434                                 'id'    => 'unfollow',
435                         ];
436                 } else {
437                         $contact_actions['follow'] = [
438                                 'label' => $this->t('Follow'),
439                                 'url'   => 'contact/follow?url=' . urlencode($contact['url']) . '&auto=1',
440                                 'title' => '',
441                                 'sel'   => '',
442                                 'id'    => 'follow',
443                         ];
444                 }
445
446                 // Provide friend suggestion only for Friendica contacts
447                 if ($contact['network'] === Protocol::DFRN) {
448                         $contact_actions['suggest'] = [
449                                 'label' => $this->t('Suggest friends'),
450                                 'url'   => 'fsuggest/' . $contact['id'],
451                                 'title' => '',
452                                 'sel'   => '',
453                                 'id'    => 'suggest',
454                         ];
455                 }
456
457                 if ($poll_enabled) {
458                         $contact_actions['update'] = [
459                                 'label' => $this->t('Update now'),
460                                 'url'   => 'contact/' . $contact['id'] . '/update?t=' . $formSecurityToken,
461                                 'title' => '',
462                                 'sel'   => '',
463                                 'id'    => 'update',
464                         ];
465                 }
466
467                 if (in_array($contact['network'], Protocol::NATIVE_SUPPORT)) {
468                         $contact_actions['updateprofile'] = [
469                                 'label' => $this->t('Refetch contact data'),
470                                 'url'   => 'contact/' . $contact['id'] . '/updateprofile?t=' . $formSecurityToken,
471                                 'title' => '',
472                                 'sel'   => '',
473                                 'id'    => 'updateprofile',
474                         ];
475                 }
476
477                 $contact_actions['block'] = [
478                         'label' => $localRelationship->blocked ? $this->t('Unblock') : $this->t('Block'),
479                         'url'   => 'contact/' . $contact['id'] . '/block?t=' . $formSecurityToken,
480                         'title' => $this->t('Toggle Blocked status'),
481                         'sel'   => $localRelationship->blocked ? 'active' : '',
482                         'id'    => 'toggle-block',
483                 ];
484
485                 $contact_actions['ignore'] = [
486                         'label' => $localRelationship->ignored ? $this->t('Unignore') : $this->t('Ignore'),
487                         'url'   => 'contact/' . $contact['id'] . '/ignore?t=' . $formSecurityToken,
488                         'title' => $this->t('Toggle Ignored status'),
489                         'sel'   => $localRelationship->ignored ? 'active' : '',
490                         'id'    => 'toggle-ignore',
491                 ];
492
493                 $contact_actions['collapse'] = [
494                         'label' => $localRelationship->collapsed ? $this->t('Uncollapse') : $this->t('Collapse'),
495                         'url'   => 'contact/' . $contact['id'] . '/collapse?t=' . $formSecurityToken,
496                         'title' => $this->t('Toggle Collapsed status'),
497                         'sel'   => $localRelationship->collapsed ? 'active' : '',
498                         'id'    => 'toggle-collapse',
499                 ];
500
501                 if (Protocol::supportsRevokeFollow($contact['network']) && in_array($localRelationship->rel, [Contact::FOLLOWER, Contact::FRIEND])) {
502                         $contact_actions['revoke_follow'] = [
503                                 'label' => $this->t('Revoke Follow'),
504                                 'url'   => 'contact/' . $contact['id'] . '/revoke',
505                                 'title' => $this->t('Revoke the follow from this contact'),
506                                 'sel'   => '',
507                                 'id'    => 'revoke_follow',
508                         ];
509                 }
510
511                 return $contact_actions;
512         }
513
514         /**
515          * Updates contact from probing
516          *
517          * @param int $contact_id Id of the contact with uid != 0
518          * @return void
519          * @throws HTTPException\InternalServerErrorException
520          * @throws \ImagickException
521          */
522         private static function updateContactFromProbe(int $contact_id)
523         {
524                 $contact = DBA::selectFirst('contact', ['url'], ['id' => $contact_id, 'uid' => [0, DI::userSession()->getLocalUserId()], 'deleted' => false]);
525                 if (!DBA::isResult($contact)) {
526                         return;
527                 }
528
529                 // Update the entry in the contact table
530                 Contact::updateFromProbe($contact_id);
531         }
532 }