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