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