]> git.mxchange.org Git - friendica.git/blob - src/Console/Contact.php
Allow adding local contacts via console
[friendica.git] / src / Console / Contact.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\Console;
23
24 use Console_Table;
25 use Friendica\App;
26 use Friendica\DI;
27 use Friendica\Model\Contact as ContactModel;
28 use Friendica\Model\User as UserModel;
29 use Friendica\Network\Probe;
30 use Friendica\Util\Temporal;
31 use RuntimeException;
32 use Seld\CliPrompt\CliPrompt;
33
34 /**
35  * tool to manage contacts of users of the current node
36  */
37 class Contact extends \Asika\SimpleConsole\Console
38 {
39         protected $helpOptions = ['h', 'help', '?'];
40
41         /**
42          * @var App\Mode
43          */
44         private $appMode;
45         /**
46          * @var IPConfig
47          */
48         private $pConfig;
49
50         protected function getHelp()
51         {
52                 $help = <<<HELP
53 console contact - Modify contact settings per console commands.
54 Usage
55         bin/console contact add <user nick> <URL> [<network>] [-h|--help|-?] [-v]
56         bin/console contact remove <CID> [-h|--help|-?] [-v]
57         bin/console contact search id <CID> [-h|--help|-?] [-v]
58         bin/console contact search url <user nick> <URL> [-h|--help|-?] [-v]
59         bin/console contact terminate <CID> [-h|--help|-?] [-v]
60
61 Description
62         Modify contact settings per console commands.
63
64 Options
65     -h|--help|-? Show help information
66     -v           Show more debug information
67     -y           Non-interactive mode, assume "yes" as answer to the user deletion prompt
68 HELP;
69                 return $help;
70         }
71
72         public function __construct(App\Mode $appMode, array $argv = null)
73         {
74                 parent::__construct($argv);
75
76                 $this->appMode = $appMode;
77         }
78
79         protected function doExecute(): int
80         {
81                 if ($this->getOption('v')) {
82                         $this->out('Class: ' . __CLASS__);
83                         $this->out('Arguments: ' . var_export($this->args, true));
84                         $this->out('Options: ' . var_export($this->options, true));
85                 }
86
87                 if (count($this->args) == 0) {
88                         $this->out($this->getHelp());
89                         return 0;
90                 }
91
92                 if ($this->appMode->isInstall()) {
93                         throw new RuntimeException('Database isn\'t ready or populated yet');
94                 }
95
96                 $command = $this->getArgument(0);
97
98                 switch ($command) {
99                         case 'add':
100                                 return $this->addContact();
101                         case 'remove':
102                                 return $this->removeContact();
103                         case 'search':
104                                 return $this->searchContact();
105                         case 'terminate':
106                                 return $this->terminateContact();
107                         default:
108                                 throw new \Asika\SimpleConsole\CommandArgsException('Wrong command.');
109                 }
110         }
111
112         /**
113          * Retrieves the user from a nick supplied as an argument or from a prompt
114          *
115          * @param int $arg_index Index of the nick argument in the arguments list
116          *
117          * @return array|boolean User record with uid field, or false if user is not found
118          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
119          */
120         private function getUserByNick($arg_index)
121         {
122                 $nick = $this->getArgument($arg_index);
123
124                 if (empty($nick)) {
125                         $this->out('Enter user nickname: ');
126                         $nick = CliPrompt::prompt();
127                         if (empty($nick)) {
128                                 throw new RuntimeException('A user nickname must be specified.');
129                         }
130                 }
131
132                 $user = UserModel::getByNickname($nick, ['uid', 'nickname']);
133                 if (empty($user)) {
134                         throw new RuntimeException('User not found');
135                 }
136
137                 return $user;
138         }
139
140         /**
141          * Adds a contact to a user from a URL
142          *
143          * @return bool True, if the command was successful
144          */
145         private function addContact()
146         {
147                 $user = $this->getUserByNick(1);
148
149                 $url = $this->getArgument(2);
150                 if (empty($url)) {
151                         $this->out('Enter contact URL: ');
152                         $url = CliPrompt::prompt();
153                         if (empty($url)) {
154                                 throw new RuntimeException('A contact URL must be specified.');
155                         }
156                 }
157
158                 $url = Probe::cleanURI($url);
159
160                 $contact = ContactModel::getByURL($url, null, [], $user['uid']);
161                 if (!empty($contact)) {
162                         throw new RuntimeException('Contact already exists');
163                 }
164
165                 $network = $this->getArgument(3);
166                 if ($network === null) {
167                         $this->out('Enter network, or leave blank: ');
168                         $network = CliPrompt::prompt();
169                 }
170
171                 $result = ContactModel::createFromProbeForUser($user['uid'], $url, $network);
172
173                 if ($result['success']) {
174                         $this->out('User ' . $user['nickname'] . ' now connected to ' . $url . ', contact ID ' . $result['cid']);
175                 } else {
176                         throw new RuntimeException($result['message']);
177                 }
178         }
179
180         /**
181          * Sends an unfriend message.
182          *
183          * @return bool True, if the command was successful
184          * @throws \Exception
185          */
186         private function terminateContact(): bool
187         {
188                 $cid = $this->getArgument(1);
189                 if (empty($cid)) {
190                         $this->out('Enter contact ID: ');
191                         $cid = CliPrompt::prompt();
192                         if (empty($cid)) {
193                                 throw new RuntimeException('A contact ID must be specified.');
194                         }
195                 }
196
197                 $contact = ContactModel::getById($cid);
198                 if (empty($contact)) {
199                         throw new RuntimeException('Contact not found');
200                 }
201
202                 if (empty($contact['uid'])) {
203                         throw new RuntimeException('Contact must be user-specific (uid != 0)');
204                 }
205
206                 try {
207                         ContactModel::unfollow($contact);
208
209                         $this->out('Contact was successfully unfollowed');
210
211                         return true;
212                 } catch (\Exception $e) {
213                         DI::logger()->error($e->getMessage(), ['contact' => $contact]);
214                         throw new RuntimeException('Unable to unfollow this contact, please check the log');
215                 }
216         }
217
218         /**
219          * Marks a contact for removal
220          */
221         private function removeContact()
222         {
223                 $cid = $this->getArgument(1);
224                 if (empty($cid)) {
225                         $this->out('Enter contact ID: ');
226                         $cid = CliPrompt::prompt();
227                         if (empty($cid)) {
228                                 throw new RuntimeException('A contact ID must be specified.');
229                         }
230                 }
231
232                 ContactModel::remove($cid);
233         }
234
235         /**
236          * Returns a contact based on search parameter
237          *
238          * @return bool True, if the command was successful
239          */
240         private function searchContact()
241         {
242                 $fields = [
243                         'id',
244                         'uid',
245                         'network',
246                         'name',
247                         'nick',
248                         'url',
249                         'addr',
250                         'created',
251                         'updated',
252                         'blocked',
253                         'deleted',
254                 ];
255
256                 $subCmd = $this->getArgument(1);
257
258                 $table = new Console_Table();
259                 $table->setHeaders(['ID', 'UID', 'Network', 'Name', 'Nick', 'URL', 'E-Mail', 'Created', 'Updated', 'Blocked', 'Deleted']);
260
261                 $addRow = function ($row) use (&$table) {
262                         $table->addRow([
263                                 $row['id'],
264                                 $row['uid'],
265                                 $row['network'],
266                                 $row['name'],
267                                 $row['nick'],
268                                 $row['url'],
269                                 $row['addr'],
270                                 Temporal::getRelativeDate($row['created']),
271                                 Temporal::getRelativeDate($row['updated']),
272                                 $row['blocked'],
273                                 $row['deleted'],
274                         ]);
275                 };
276                 switch ($subCmd) {
277                         case 'id':
278                                 $cid     = $this->getArgument(2);
279                                 $contact = ContactModel::getById($cid, $fields);
280                                 if (!empty($contact)) {
281                                         $addRow($contact);
282                                 }
283                                 break;
284                         case 'url':
285                                 $user    = $this->getUserByNick(2);
286                                 $url     = $this->getArgument(3);
287                                 $contact = ContactModel::getByURLForUser($url, $user['uid'], false, $fields);
288                                 if (!empty($contact)) {
289                                         $addRow($contact);
290                                 }
291                                 break;
292                         default:
293                                 $this->out($this->getHelp());
294                                 return false;
295                 }
296
297                 $this->out($table->getTable());
298
299                 return true;
300         }
301 }