3 * @copyright Copyright (C) 2010-2022, 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;
27 use Friendica\Model\Contact as ContactModel;
28 use Friendica\Model\User as UserModel;
29 use Friendica\Network\Probe;
30 use Friendica\Util\Temporal;
32 use Seld\CliPrompt\CliPrompt;
35 * tool to manage contacts of users of the current node
37 class Contact extends \Asika\SimpleConsole\Console
39 protected $helpOptions = ['h', 'help', '?'];
50 protected function getHelp()
53 console contact - Modify contact settings per console commands.
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]
62 Modify contact settings per console commands.
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
72 public function __construct(App\Mode $appMode, array $argv = null)
74 parent::__construct($argv);
76 $this->appMode = $appMode;
79 protected function doExecute()
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));
87 if (count($this->args) == 0) {
88 $this->out($this->getHelp());
92 if ($this->appMode->isInstall()) {
93 throw new RuntimeException('Database isn\'t ready or populated yet');
96 $command = $this->getArgument(0);
100 return $this->addContact();
102 return $this->removeContact();
104 return $this->searchContact();
106 return $this->terminateContact();
108 throw new \Asika\SimpleConsole\CommandArgsException('Wrong command.');
113 * Retrieves the user from a nick supplied as an argument or from a prompt
115 * @param int $arg_index Index of the nick argument in the arguments list
117 * @return array|boolean User record with uid field, or false if user is not found
118 * @throws \Friendica\Network\HTTPException\InternalServerErrorException
120 private function getUserByNick($arg_index)
122 $nick = $this->getArgument($arg_index);
125 $this->out('Enter user nickname: ');
126 $nick = CliPrompt::prompt();
128 throw new RuntimeException('A user nickname must be specified.');
132 $user = UserModel::getByNickname($nick, ['uid', 'nickname']);
134 throw new RuntimeException('User not found');
141 * Adds a contact to a user from a URL
143 * @return bool True, if the command was successful
145 private function addContact()
147 $user = $this->getUserByNick(1);
149 $url = $this->getArgument(2);
151 $this->out('Enter contact URL: ');
152 $url = CliPrompt::prompt();
154 throw new RuntimeException('A contact URL must be specified.');
158 $url = Probe::cleanURI($url);
160 $contact = ContactModel::getByURLForUser($url, $user['uid']);
161 if (!empty($contact)) {
162 throw new RuntimeException('Contact already exists');
165 $network = $this->getArgument(3);
166 if ($network === null) {
167 $this->out('Enter network, or leave blank: ');
168 $network = CliPrompt::prompt();
171 $result = ContactModel::createFromProbeForUser($user['uid'], $url, $network);
173 if ($result['success']) {
174 $this->out('User ' . $user['nickname'] . ' now connected to ' . $url . ', contact ID ' . $result['cid']);
176 throw new RuntimeException($result['message']);
181 * Sends an unfriend message.
183 * @return bool True, if the command was successful
186 private function terminateContact(): bool
188 $cid = $this->getArgument(1);
190 $this->out('Enter contact ID: ');
191 $cid = CliPrompt::prompt();
193 throw new RuntimeException('A contact ID must be specified.');
197 $contact = ContactModel::getById($cid);
198 if (empty($contact)) {
199 throw new RuntimeException('Contact not found');
202 $user = UserModel::getById($contact['uid']);
205 $result = ContactModel::terminateFriendship($user, $contact);
206 if ($result === false) {
207 throw new RuntimeException('Unable to unfollow this contact, please retry in a few minutes or check the logs.');
210 $this->out('Contact was successfully unfollowed');
213 } catch (\Exception $e) {
214 DI::logger()->error($e->getMessage(), ['owner' => $user, 'contact' => $contact]);
215 throw new RuntimeException('Unable to unfollow this contact, please check the log');
220 * Marks a contact for removal
222 private function removeContact()
224 $cid = $this->getArgument(1);
226 $this->out('Enter contact ID: ');
227 $cid = CliPrompt::prompt();
229 throw new RuntimeException('A contact ID must be specified.');
233 ContactModel::remove($cid);
237 * Returns a contact based on search parameter
239 * @return bool True, if the command was successful
241 private function searchContact()
257 $subCmd = $this->getArgument(1);
259 $table = new Console_Table();
260 $table->setHeaders(['ID', 'UID', 'Network', 'Name', 'Nick', 'URL', 'E-Mail', 'Created', 'Updated', 'Blocked', 'Deleted']);
262 $addRow = function ($row) use (&$table) {
271 Temporal::getRelativeDate($row['created']),
272 Temporal::getRelativeDate($row['updated']),
279 $cid = $this->getArgument(2);
280 $contact = ContactModel::getById($cid, $fields);
281 if (!empty($contact)) {
286 $user = $this->getUserByNick(2);
287 $url = $this->getArgument(3);
288 $contact = ContactModel::getByURLForUser($url, $user['uid'], false, $fields);
289 if (!empty($contact)) {
294 $this->out($this->getHelp());
298 $this->out($table->getTable());