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\Model\Contact as ContactModel;
27 use Friendica\Model\User as UserModel;
28 use Friendica\Util\Temporal;
30 use Seld\CliPrompt\CliPrompt;
33 * tool to manage contacts of users of the current node
35 class Contact extends \Asika\SimpleConsole\Console
37 protected $helpOptions = ['h', 'help', '?'];
48 protected function getHelp()
51 console contact - Modify contact settings per console commands.
53 bin/console contact add <user nick> <URL> [<network>] [-h|--help|-?] [-v]
54 bin/console contact remove <CID> [-h|--help|-?] [-v]
55 bin/console contact search id <CID> [-h|--help|-?] [-v]
56 bin/console contact search url <user nick> <URL> [-h|--help|-?] [-v]
57 bin/console contact terminate <CID> [-h|--help|-?] [-v]
60 Modify contact settings per console commands.
63 -h|--help|-? Show help information
64 -v Show more debug information
65 -y Non-interactive mode, assume "yes" as answer to the user deletion prompt
70 public function __construct(App\Mode $appMode, array $argv = null)
72 parent::__construct($argv);
74 $this->appMode = $appMode;
77 protected function doExecute()
79 if ($this->getOption('v')) {
80 $this->out('Class: ' . __CLASS__);
81 $this->out('Arguments: ' . var_export($this->args, true));
82 $this->out('Options: ' . var_export($this->options, true));
85 if (count($this->args) == 0) {
86 $this->out($this->getHelp());
90 if ($this->appMode->isInstall()) {
91 throw new RuntimeException('Database isn\'t ready or populated yet');
94 $command = $this->getArgument(0);
98 return $this->addContact();
100 return $this->removeContact();
102 return $this->searchContact();
104 return $this->terminateContact();
106 throw new \Asika\SimpleConsole\CommandArgsException('Wrong command.');
111 * Retrieves the user from a nick supplied as an argument or from a prompt
113 * @param int $arg_index Index of the nick argument in the arguments list
115 * @return array|boolean User record with uid field, or false if user is not found
116 * @throws \Friendica\Network\HTTPException\InternalServerErrorException
118 private function getUserByNick($arg_index)
120 $nick = $this->getArgument($arg_index);
123 $this->out('Enter user nickname: ');
124 $nick = CliPrompt::prompt();
126 throw new RuntimeException('A user nickname must be specified.');
130 $user = UserModel::getByNickname($nick, ['uid', 'nickname']);
132 throw new RuntimeException('User not found');
139 * Adds a contact to a user from a URL
141 * @return bool True, if the command was successful
143 private function addContact()
145 $user = $this->getUserByNick(1);
147 $url = $this->getArgument(2);
149 $this->out('Enter contact URL: ');
150 $url = CliPrompt::prompt();
152 throw new RuntimeException('A contact URL must be specified.');
156 $contact = ContactModel::getByURLForUser($url, $user['uid']);
157 if (!empty($contact)) {
158 throw new RuntimeException('Contact already exists');
161 $network = $this->getArgument(3);
162 if (empty($network) && $network !== '') {
163 $this->out('Enter network, or leave blank: ');
164 $network = CliPrompt::prompt();
167 $result = ContactModel::createFromProbe($user, $url, false, $network);
169 if ($result['success']) {
170 $this->out('User ' . $user['nickname'] . ' now connected to ' . $url . ', contact ID ' . $result['cid']);
172 throw new RuntimeException($result['message']);
177 * Sends an unfriend message. Does not remove the contact
179 * @return bool True, if the command was successful
181 private function terminateContact()
183 $cid = $this->getArgument(1);
185 $this->out('Enter contact ID: ');
186 $cid = CliPrompt::prompt();
188 throw new RuntimeException('A contact ID must be specified.');
192 $contact = ContactModel::getById($cid);
193 if (empty($contact)) {
194 throw new RuntimeException('Contact not found');
197 $user = UserModel::getById($contact['uid']);
199 $result = ContactModel::terminateFriendship($user, $contact);
203 * Marks a contact for removal
205 * @return bool True, if the command was successful
207 private function removeContact()
209 $cid = $this->getArgument(1);
211 $this->out('Enter contact ID: ');
212 $cid = CliPrompt::prompt();
214 throw new RuntimeException('A contact ID must be specified.');
218 $result = ContactModel::remove($cid);
222 * Returns a contact based on search parameter
224 * @return bool True, if the command was successful
226 private function searchContact()
242 $subCmd = $this->getArgument(1);
244 $table = new Console_Table();
245 $table->setHeaders(['ID', 'UID', 'Network', 'Name', 'Nick', 'URL', 'E-Mail', 'Created', 'Updated', 'Blocked', 'Deleted']);
247 $addRow = function ($row) use (&$table) {
256 Temporal::getRelativeDate($row['created']),
257 Temporal::getRelativeDate($row['updated']),
264 $cid = $this->getArgument(2);
265 $contact = ContactModel::getById($cid, $fields);
266 if (!empty($contact)) {
271 $user = $this->getUserByNick(2);
272 $url = $this->getArgument(3);
273 $contact = ContactModel::getByURLForUser($url, $user['uid'], false, $fields);
274 if (!empty($contact)) {
279 $this->out($this->getHelp());
283 $this->out($table->getTable());