]> git.mxchange.org Git - friendica.git/blob - src/Console/User.php
More list sub commands
[friendica.git] / src / Console / User.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2020, Friendica
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\Content\Pager;
27 use Friendica\Core\L10n;
28 use Friendica\Database\Database;
29 use Friendica\Model\Register;
30 use Friendica\Model\User as UserModel;
31 use Friendica\Util\Temporal;
32 use RuntimeException;
33 use Seld\CliPrompt\CliPrompt;
34
35 /**
36  * tool to manage users of the current node
37  */
38 class User extends \Asika\SimpleConsole\Console
39 {
40         protected $helpOptions = ['h', 'help', '?'];
41
42         /**
43          * @var App\Mode
44          */
45         private $appMode;
46         /**
47          * @var L10n
48          */
49         private $l10n;
50         /**
51          * @var Database
52          */
53         private $dba;
54
55         protected function getHelp()
56         {
57                 $help = <<<HELP
58 console user - Modify user settings per console commands.
59 Usage
60         bin/console user password <nickname> [<password>] [-h|--help|-?] [-v]
61         bin/console user add [<name> [<nickname> [<email> [<language>]]]] [-h|--help|-?] [-v]
62         bin/console user delete [<nickname>] [-q] [-h|--help|-?] [-v]
63         bin/console user allow [<nickname>] [-h|--help|-?] [-v]
64         bin/console user deny [<nickname>] [-h|--help|-?] [-v]
65         bin/console user block [<nickname>] [-h|--help|-?] [-v]
66         bin/console user unblock [<nickname>] [-h|--help|-?] [-v]
67         bin/console user list pending [start=0 [count=50]] [-h|--help|-?] [-v]
68         bin/console user list removed [start=0 [count=50]] [-h|--help|-?] [-v]
69         bin/console user list all [start=0 [count=50]] [-h|--help|-?] [-v]
70
71 Description
72         Modify user settings per console commands.
73
74 Options
75     -h|--help|-? Show help information
76     -v           Show more debug information.
77     -q           Quiet mode (don't ask for a command).
78 HELP;
79                 return $help;
80         }
81
82         public function __construct(App\Mode $appMode, L10n $l10n, Database $dba, array $argv = null)
83         {
84                 parent::__construct($argv);
85
86                 $this->appMode     = $appMode;
87                 $this->l10n        = $l10n;
88                 $this->dba         = $dba;
89         }
90
91         protected function doExecute()
92         {
93                 if ($this->getOption('v')) {
94                         $this->out('Class: ' . __CLASS__);
95                         $this->out('Arguments: ' . var_export($this->args, true));
96                         $this->out('Options: ' . var_export($this->options, true));
97                 }
98
99                 if (count($this->args) == 0) {
100                         $this->out($this->getHelp());
101                         return 0;
102                 }
103
104                 if ($this->appMode->isInstall()) {
105                         throw new RuntimeException('Database isn\'t ready or populated yet');
106                 }
107
108                 $command = $this->getArgument(0);
109
110                 switch ($command) {
111                         case 'password':
112                                 return $this->password();
113                         case 'add':
114                                 return $this->addUser();
115                         case 'allow':
116                                 return $this->pendingUser(true);
117                         case 'deny':
118                                 return $this->pendingUser(false);
119                         case 'block':
120                                 return $this->blockUser(true);
121                         case 'unblock':
122                                 return $this->blockUser(false);
123                         case 'delete':
124                                 return $this->deleteUser();
125                         case 'list':
126                                 return $this->listUser();
127                         default:
128                                 throw new \Asika\SimpleConsole\CommandArgsException('Wrong command.');
129                 }
130         }
131
132         /**
133          * Sets a new password
134          *
135          * @return int Return code of this command
136          *
137          * @throws \Exception
138          */
139         private function password()
140         {
141                 $nick = $this->getArgument(1);
142
143                 $user = $this->dba->selectFirst('user', ['uid'], ['nickname' => $nick]);
144                 if (!$this->dba->isResult($user)) {
145                         throw new RuntimeException($this->l10n->t('User not found'));
146                 }
147
148                 $password = $this->getArgument(2);
149
150                 if (is_null($password)) {
151                         $this->out($this->l10n->t('Enter new password: '), false);
152                         $password = CliPrompt::hiddenPrompt(true);
153                 }
154
155                 try {
156                         $result = UserModel::updatePassword($user['uid'], $password);
157
158                         if (!$this->dba->isResult($result)) {
159                                 throw new \Exception($this->l10n->t('Password update failed. Please try again.'));
160                         }
161
162                         $this->out($this->l10n->t('Password changed.'));
163                 } catch (\Exception $e) {
164                         throw new RuntimeException($e->getMessage(), $e->getCode(), $e);
165                 }
166
167                 return 0;
168         }
169
170         /**
171          * Adds a new user based on given console arguments
172          *
173          * @return bool True, if the command was successful
174          * @throws \ErrorException
175          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
176          * @throws \ImagickException
177          */
178         private function addUser()
179         {
180                 $name  = $this->getArgument(1);
181                 $nick  = $this->getArgument(2);
182                 $email = $this->getArgument(3);
183                 $lang  = $this->getArgument(4);
184
185                 if (empty($name)) {
186                         $this->out($this->l10n->t('Enter user name: '));
187                         $name = CliPrompt::prompt();
188                         if (empty($name)) {
189                                 throw new RuntimeException('A name must be set.');
190                         }
191                 }
192
193                 if (empty($nick)) {
194                         $this->out($this->l10n->t('Enter user nickname: '));
195                         $nick = CliPrompt::prompt();
196                         if (empty($nick)) {
197                                 throw new RuntimeException('A nick name must be set.');
198                         }
199                 }
200
201                 if (empty($email)) {
202                         $this->out($this->l10n->t('Enter user email address: '));
203                         $email = CliPrompt::prompt();
204                         if (empty($email)) {
205                                 throw new RuntimeException('A email address must be set.');
206                         }
207                 }
208
209                 if (empty($lang)) {
210                         $this->out($this->l10n->t('Enter a language (optional): '));
211                         $lang = CliPrompt::prompt();
212                 }
213
214                 if (empty($lang)) {
215                         return UserModel::createMinimal($name, $email, $nick);
216                 } else {
217                         return UserModel::createMinimal($name, $email, $nick, $lang);
218                 }
219         }
220
221         /**
222          * Allows or denys a user based on it's nickname
223          *
224          * @param bool $allow True, if the pending user is allowed, false if denies
225          *
226          * @return bool True, if allow was successful
227          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
228          */
229         private function pendingUser(bool $allow = true)
230         {
231                 $nick = $this->getArgument(1);
232
233                 if (!$nick) {
234                         $this->out($this->l10n->t('Enter user nickname: '));
235                         $nick = CliPrompt::prompt();
236                         if (empty($nick)) {
237                                 throw new RuntimeException('A nick name must be set.');
238                         }
239                 }
240
241                 $user = $this->dba->selectFirst('user', ['uid'], ['nickname' => $nick]);
242                 if (empty($user)) {
243                         throw new RuntimeException($this->l10n->t('User not found'));
244                 }
245
246                 $pending = Register::getPendingForUser($user['uid'] ?? 0);
247                 if (empty($pending)) {
248                         throw new RuntimeException($this->l10n->t('User is not pending.'));
249                 }
250
251                 return ($allow) ? UserModel::allow($pending['hash']) : UserModel::deny($pending['hash']);
252         }
253
254         /**
255          * Blocks/unblocks a user
256          *
257          * @param bool $block True, if the given user should get blocked
258          *
259          * @return bool True, if the command was successful
260          * @throws \Exception
261          */
262         private function blockUser(bool $block = true)
263         {
264                 $nick = $this->getArgument(1);
265
266                 if (!$nick) {
267                         $this->out($this->l10n->t('Enter user nickname: '));
268                         $nick = CliPrompt::prompt();
269                         if (empty($nick)) {
270                                 throw new RuntimeException('A nick name must be set.');
271                         }
272                 }
273
274                 $user = $this->dba->selectFirst('user', ['uid'], ['nickname' => $nick]);
275                 if (empty($user)) {
276                         throw new RuntimeException($this->l10n->t('User not found'));
277                 }
278
279                 return $block ? UserModel::block($user['uid'] ?? 0) : UserModel::block($user['uid'] ?? 0, false);
280         }
281
282         /**
283          * Deletes a user
284          *
285          * @return bool True, if the delete was successful
286          * @throws \Exception
287          */
288         private function deleteUser()
289         {
290                 $nick = $this->getArgument(1);
291
292                 if (!$nick) {
293                         $this->out($this->l10n->t('Enter user nickname: '));
294                         $nick = CliPrompt::prompt();
295                         if (empty($nick)) {
296                                 throw new RuntimeException('A nick name must be set.');
297                         }
298                 }
299
300                 $user = $this->dba->selectFirst('user', ['uid'], ['nickname' => $nick]);
301                 if (empty($user)) {
302                         throw new RuntimeException($this->l10n->t('User not found'));
303                 }
304
305                 if (!$this->getOption('q')) {
306                         $this->out($this->l10n->t('Type "yes" to delete %s', $nick));
307                         if (CliPrompt::prompt() !== 'yes') {
308                                 throw new RuntimeException('Delete abort.');
309                         }
310                 }
311
312                 return UserModel::remove($user['uid'] ?? -1);
313         }
314
315         /**
316          * List user of the current node
317          *
318          * @return bool True, if the command was successful
319          */
320         private function listUser()
321         {
322                 $subCmd = $this->getArgument(1);
323                 $start = $this->getArgument(2, 0);
324                 $count = $this->getArgument(3, Pager::ITEMS_PER_PAGE);
325
326                 $table = new Console_Table();
327
328                 switch ($subCmd) {
329                         case 'pending':
330                                 $table->setHeaders(['Nick', 'Name', 'URL', 'E-Mail', 'Register Date', 'Comment']);
331                                 $pending = Register::getPending($start, $count);
332                                 foreach ($pending as $contact) {
333                                         $table->addRow([
334                                                 $contact['nick'],
335                                                 $contact['name'],
336                                                 $contact['url'],
337                                                 $contact['email'],
338                                                 Temporal::getRelativeDate($contact['created']),
339                                                 $contact['note'],
340                                         ]);
341                                 }
342                                 $this->out($table->getTable());
343                                 return true;
344                         case 'all':
345                         case 'removed':
346                         default:
347                                 $table->setHeaders(['Nick', 'Name', 'URL', 'E-Mail', 'Register', 'Login', 'Last Item']);
348                                 $contacts = UserModel::getUsers($start, $count);
349                                 foreach ($contacts as $contact) {
350                                         if (($subCmd != 'removed') && !empty($contact['account_removed']) ||
351                                             ($subCmd == 'removed') && empty($contact['account_removed'])) {
352                                                 continue;
353                                         }
354
355                                         $table->addRow([
356                                                 $contact['nick'],
357                                                 $contact['name'],
358                                                 $contact['url'],
359                                                 $contact['email'],
360                                                 Temporal::getRelativeDate($contact['created']),
361                                                 Temporal::getRelativeDate($contact['login_date']),
362                                                 Temporal::getRelativeDate($contact['lastitem_date']),
363                                         ]);
364                                 }
365                                 $this->out($table->getTable());
366                                 return true;
367                 }
368         }
369 }