]> git.mxchange.org Git - friendica.git/blob - src/Module/Contact/Follow.php
Move Follow to `/contact` namespace
[friendica.git] / src / Module / Contact / Follow.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2022, 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\Content\Widget\VCard;
27 use Friendica\Core\Config\Capability\IManageConfigValues;
28 use Friendica\Core\L10n;
29 use Friendica\Core\Protocol;
30 use Friendica\Core\Renderer;
31 use Friendica\Core\Session\Capability\IHandleUserSessions;
32 use Friendica\Model\Contact;
33 use Friendica\Model\Item;
34 use Friendica\Model\Post;
35 use Friendica\Model\Profile;
36 use Friendica\Model\User;
37 use Friendica\Module\Response;
38 use Friendica\Navigation\SystemMessages;
39 use Friendica\Network\HTTPException\ForbiddenException;
40 use Friendica\Network\Probe;
41 use Friendica\Util\Profiler;
42 use Friendica\Util\Strings;
43 use Psr\Log\LoggerInterface;
44
45 class Follow extends BaseModule
46 {
47         /** @var IHandleUserSessions */
48         protected $session;
49         /** @var SystemMessages */
50         protected $sysMessages;
51         /** @var App */
52         protected $app;
53         /** @var IManageConfigValues */
54         protected $config;
55         /** @var App\Page */
56         protected $page;
57
58         public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, IHandleUserSessions $session, SystemMessages $sysMessages, App $app, IManageConfigValues $config, App\Page $page, array $server, array $parameters = [])
59         {
60                 parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
61
62                 $this->session     = $session;
63                 $this->sysMessages = $sysMessages;
64                 $this->app         = $app;
65                 $this->config      = $config;
66                 $this->page        = $page;
67         }
68
69         protected function post(array $request = [])
70         {
71                 if (!$this->session->getLocalUserId()) {
72                         throw new ForbiddenException($this->t('Access denied.'));
73                 }
74
75                 if (!empty($request['url'])) {
76                         $this->baseUrl->redirect($request['url']);
77                 }
78
79                 $url = Probe::cleanURI($this->session->get('url'));
80
81                 $this->process($url);
82         }
83
84         protected function content(array $request = []): string
85         {
86                 $returnPath = 'contact';
87
88                 if (!$this->session->getLocalUserId()) {
89                         $this->sysMessages->addNotice($this->t('Permission denied.'));
90                         $this->baseUrl->redirect($returnPath);
91                 }
92
93                 $uid = $this->session->getLocalUserId();
94                 $url = Probe::cleanURI(trim($request['url'] ?? ''));
95
96                 // Issue 6874: Allow remote following from Peertube
97                 if (strpos($url, 'acct:') === 0) {
98                         $url = str_replace('acct:', '', $url);
99                 }
100
101                 if (empty($url)) {
102                         $this->baseUrl->redirect($returnPath);
103                 }
104
105                 $submit = $this->t('Submit Request');
106
107                 // Don't try to add a pending contact
108                 $userContact = Contact::selectFirst(['pending'], [
109                         "`uid` = ? AND ((`rel` != ?) OR (`network` = ?)) AND (`nurl` = ? OR `alias` = ? OR `alias` = ?) AND `network` != ?",
110                         $uid, Contact::FOLLOWER, Protocol::DFRN,
111                         Strings::normaliseLink($url),
112                         Strings::normaliseLink($url), $url,
113                         Protocol::STATUSNET]);
114
115                 if (!empty($userContact['pending'])) {
116                         $this->sysMessages->addNotice($this->t('You already added this contact.'));
117                         $submit = '';
118                 }
119
120                 $contact = Contact::getByURL($url, true);
121
122                 // Possibly it is a mail contact
123                 if (empty($contact)) {
124                         $contact = Probe::uri($url, Protocol::MAIL, $uid);
125                 }
126
127                 if (empty($contact) || ($contact['network'] == Protocol::PHANTOM)) {
128                         // Possibly it is a remote item and not an account
129                         $this->followRemoteItem($url);
130
131                         $this->sysMessages->addNotice($this->t('The network type couldn\'t be detected. Contact can\'t be added.'));
132                         $submit  = '';
133                         $contact = ['url' => $url, 'network' => Protocol::PHANTOM, 'name' => $url, 'keywords' => ''];
134                 }
135
136                 $protocol = Contact::getProtocol($contact['url'], $contact['network']);
137
138                 if (($protocol == Protocol::DIASPORA) && !$this->config->get('system', 'diaspora_enabled')) {
139                         $this->sysMessages->addNotice($this->t('Diaspora support isn\'t enabled. Contact can\'t be added.'));
140                         $submit = '';
141                 }
142
143                 if (($protocol == Protocol::OSTATUS) && $this->config->get('system', 'ostatus_disabled')) {
144                         $this->sysMessages->addNotice($this->t("OStatus support is disabled. Contact can't be added."));
145                         $submit = '';
146                 }
147
148                 if ($protocol == Protocol::MAIL) {
149                         $contact['url'] = $contact['addr'];
150                 }
151
152                 if (!empty($request['auto'])) {
153                         $this->process($contact['url']);
154                 }
155
156                 $request = $this->baseUrl . '/follow';
157                 $tpl     = Renderer::getMarkupTemplate('auto_request.tpl');
158
159                 $owner = User::getOwnerDataById($uid);
160                 if (empty($owner)) {
161                         $this->sysMessages->addNotice($this->t('Permission denied.'));
162                         $this->baseUrl->redirect($returnPath);
163                 }
164
165                 $myaddr = $owner['url'];
166
167                 $output = Renderer::replaceMacros($tpl, [
168                         '$header'         => $this->t('Connect/Follow'),
169                         '$pls_answer'     => $this->t('Please answer the following:'),
170                         '$your_address'   => $this->t('Your Identity Address:'),
171                         '$url_label'      => $this->t('Profile URL'),
172                         '$keywords_label' => $this->t('Tags:'),
173                         '$submit'         => $submit,
174                         '$cancel'         => $this->t('Cancel'),
175
176                         '$request'  => $request,
177                         '$name'     => $contact['name'],
178                         '$url'      => $contact['url'],
179                         '$zrl'      => Profile::zrl($contact['url']),
180                         '$myaddr'   => $myaddr,
181                         '$keywords' => $contact['keywords'],
182
183                         '$does_know_you' => ['knowyou', $this->t('%s knows you', $contact['name'])],
184                         '$addnote_field' => ['dfrn-request-message', $this->t('Add a personal note:')],
185                 ]);
186
187                 $this['aside'] = '';
188
189                 if (!in_array($protocol, [Protocol::PHANTOM, Protocol::MAIL])) {
190                         $this['aside'] = VCard::getHTML($contact);
191
192                         $output .= Renderer::replaceMacros(Renderer::getMarkupTemplate('section_title.tpl'),
193                                 ['$title' => $this->t('Status Messages and Posts')]
194                         );
195
196                         // Show last public posts
197                         $output .= Contact::getPostsFromUrl($contact['url']);
198                 }
199
200                 return $output;
201         }
202
203         protected function process(string $url)
204         {
205                 $returnPath = 'follow?url=' . urlencode($url);
206
207                 $result = Contact::createFromProbeForUser($this->app->getLoggedInUserId(), $url);
208
209                 if (!$result['success']) {
210                         // Possibly it is a remote item and not an account
211                         $this->followRemoteItem($url);
212
213                         if (!empty($result['message'])) {
214                                 $this->sysMessages->addNotice($result['message']);
215                         }
216
217                         $this->baseUrl->redirect($returnPath);
218                 } elseif (!empty($result['cid'])) {
219                         $this->baseUrl->redirect('contact/' . $result['cid']);
220                 }
221
222                 $this->sysMessages->addNotice($this->t('The contact could not be added.'));
223                 $this->baseUrl->redirect($returnPath);
224         }
225
226         protected function followRemoteItem(string $url)
227         {
228                 $itemId = Item::fetchByLink($url, $this->session->getLocalUserId());
229                 if (!$itemId) {
230                         // If the user-specific search failed, we search and probe a public post
231                         $itemId = Item::fetchByLink($url);
232                 }
233
234                 if (!empty($itemId)) {
235                         $item = Post::selectFirst(['guid'], ['id' => $itemId]);
236                         if (!empty($item['guid'])) {
237                                 $this->baseUrl->redirect('display/' . $item['guid']);
238                         }
239                 }
240         }
241 }