3 * @copyright Copyright (C) 2010-2021, the Friendica project
5 * @license GNU AGPL version 3 or any later version
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.
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.
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/>.
22 namespace Friendica\Console;
26 use Friendica\Content\Pager;
27 use Friendica\Model\Contact as ContactModel;
28 use Friendica\Model\User as UserModel;
29 use Friendica\Util\Temporal;
31 use Seld\CliPrompt\CliPrompt;
34 * tool to manage contacts of users of the current node
36 class Contact extends \Asika\SimpleConsole\Console
38 protected $helpOptions = ['h', 'help', '?'];
49 protected function getHelp()
52 console contact - Modify contact settings per console commands.
54 bin/console contact add <user nick> <URL> [<network>] [-h|--help|-?] [-v]
55 bin/console contact remove <CID> [-h|--help|-?] [-v]
56 bin/console contact search id <CID> [-h|--help|-?] [-v]
57 bin/console contact search url <user nick> <URL> [-h|--help|-?] [-v]
58 bin/console contact terminate <CID> [-h|--help|-?] [-v]
61 Modify contact settings per console commands.
64 -h|--help|-? Show help information
65 -v Show more debug information
66 -y Non-interactive mode, assume "yes" as answer to the user deletion prompt
71 public function __construct(App\Mode $appMode, array $argv = null)
73 parent::__construct($argv);
75 $this->appMode = $appMode;
78 protected function doExecute()
80 if ($this->getOption('v')) {
81 $this->out('Class: ' . __CLASS__);
82 $this->out('Arguments: ' . var_export($this->args, true));
83 $this->out('Options: ' . var_export($this->options, true));
86 if (count($this->args) == 0) {
87 $this->out($this->getHelp());
91 if ($this->appMode->isInstall()) {
92 throw new RuntimeException('Database isn\'t ready or populated yet');
95 $command = $this->getArgument(0);
99 return $this->addContact();
101 return $this->removeContact();
103 return $this->searchContact();
105 return $this->terminateContact();
107 throw new \Asika\SimpleConsole\CommandArgsException('Wrong command.');
112 * Retrieves the user from a nick supplied as an argument or from a prompt
114 * @param int $arg_index Index of the nick argument in the arguments list
116 * @return array|boolean User record with uid field, or false if user is not found
117 * @throws \Friendica\Network\HTTPException\InternalServerErrorException
119 private function getUserByNick($arg_index)
121 $nick = $this->getArgument($arg_index);
124 $this->out('Enter user nickname: ');
125 $nick = CliPrompt::prompt();
127 throw new RuntimeException('A user nickname must be specified.');
131 $user = UserModel::getByNickname($nick, ['uid', 'nickname']);
133 throw new RuntimeException('User not found');
140 * Adds a contact to a user from a URL
142 * @return bool True, if the command was successful
144 private function addContact()
146 $user = $this->getUserByNick(1);
148 $url = $this->getArgument(2);
150 $this->out('Enter contact URL: ');
151 $url = CliPrompt::prompt();
153 throw new RuntimeException('A contact URL must be specified.');
157 $contact = ContactModel::getByURLForUser($url, $user['uid']);
158 if (!empty($contact)) {
159 throw new RuntimeException('Contact already exists');
162 $network = $this->getArgument(3);
163 if (empty($network) && $network !== '') {
164 $this->out('Enter network, or leave blank: ');
165 $network = CliPrompt::prompt();
168 $result = ContactModel::createFromProbe($user, $url, false, $network);
170 if ($result['success']) {
171 $this->out('User ' . $user['nickname'] . ' now connected to ' . $url . ', contact ID ' . $result['cid']);
174 throw new RuntimeException($result['message']);
179 * Sends an unfriend message. Does not remove the contact
181 * @return bool True, if the command was successful
183 private function terminateContact()
185 $cid = $this->getArgument(1);
187 $this->out('Enter contact ID: ');
188 $cid = CliPrompt::prompt();
190 throw new RuntimeException('A contact ID must be specified.');
194 $contact = ContactModel::getById($cid);
195 if (empty($contact)) {
196 throw new RuntimeException('Contact not found');
199 $user = UserModel::getById($contact['uid']);
201 $result = ContactModel::terminateFriendship($user, $contact);
205 * Marks a contact for removal
207 * @return bool True, if the command was successful
209 private function removeContact()
211 $cid = $this->getArgument(1);
213 $this->out('Enter contact ID: ');
214 $cid = CliPrompt::prompt();
216 throw new RuntimeException('A contact ID must be specified.');
220 $result = ContactModel::remove($cid);
224 * Returns a contact based on search parameter
226 * @return bool True, if the command was successful
228 private function searchContact()
244 $subCmd = $this->getArgument(1);
246 $table = new Console_Table();
247 $table->setHeaders(['ID', 'UID', 'Network', 'Name', 'Nick', 'URL', 'E-Mail', 'Created', 'Updated', 'Blocked', 'Deleted']);
249 $addRow = function($row) use (&$table) {
258 Temporal::getRelativeDate($row['created']),
259 Temporal::getRelativeDate($row['updated']),
266 $cid = $this->getArgument(2);
267 $contact = ContactModel::getById($cid, $fields);
268 if (!empty($contact)) {
273 $user = $this->getUserByNick(2);
274 $url = $this->getArgument(3);
275 $contact = ContactModel::getByURLForUser($url, $user['uid'], false, $fields);
276 if (!empty($contact)) {
281 $this->out($this->getHelp());
285 $this->out($table->getTable());