--- /dev/null
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Console;
+
+use Console_Table;
+use Friendica\App;
+use Friendica\Content\Pager;
+use Friendica\Model\Contact as ContactModel;
+use Friendica\Model\User as UserModel;
+use Friendica\Util\Temporal;
+use RuntimeException;
+use Seld\CliPrompt\CliPrompt;
+
+/**
+ * tool to manage contacts of users of the current node
+ */
+class Contact extends \Asika\SimpleConsole\Console
+{
+ protected $helpOptions = ['h', 'help', '?'];
+
+ /**
+ * @var App\Mode
+ */
+ private $appMode;
+ /**
+ * @var IPConfig
+ */
+ private $pConfig;
+
+ protected function getHelp()
+ {
+ $help = <<<HELP
+console contact - Modify contact settings per console commands.
+Usage
+ bin/console contact add <user nick> <URL> [<network>] [-h|--help|-?] [-v]
+ bin/console contact remove <CID> [-h|--help|-?] [-v]
+ bin/console contact search id <CID> [-h|--help|-?] [-v]
+ bin/console contact search url <user nick> <URL> [-h|--help|-?] [-v]
+ bin/console contact terminate <CID> [-h|--help|-?] [-v]
+
+Description
+ Modify contact settings per console commands.
+
+Options
+ -h|--help|-? Show help information
+ -v Show more debug information
+ -y Non-interactive mode, assume "yes" as answer to the user deletion prompt
+HELP;
+ return $help;
+ }
+
+ public function __construct(App\Mode $appMode, array $argv = null)
+ {
+ parent::__construct($argv);
+
+ $this->appMode = $appMode;
+ }
+
+ protected function doExecute()
+ {
+ if ($this->getOption('v')) {
+ $this->out('Class: ' . __CLASS__);
+ $this->out('Arguments: ' . var_export($this->args, true));
+ $this->out('Options: ' . var_export($this->options, true));
+ }
+
+ if (count($this->args) == 0) {
+ $this->out($this->getHelp());
+ return 0;
+ }
+
+ if ($this->appMode->isInstall()) {
+ throw new RuntimeException('Database isn\'t ready or populated yet');
+ }
+
+ $command = $this->getArgument(0);
+
+ switch ($command) {
+ case 'add':
+ return $this->addContact();
+ case 'remove':
+ return $this->removeContact();
+ case 'search':
+ return $this->searchContact();
+ case 'terminate':
+ return $this->terminateContact();
+ default:
+ throw new \Asika\SimpleConsole\CommandArgsException('Wrong command.');
+ }
+ }
+
+ /**
+ * Retrieves the user from a nick supplied as an argument or from a prompt
+ *
+ * @param int $arg_index Index of the nick argument in the arguments list
+ *
+ * @return array|boolean User record with uid field, or false if user is not found
+ * @throws \Friendica\Network\HTTPException\InternalServerErrorException
+ */
+ private function getUserByNick($arg_index)
+ {
+ $nick = $this->getArgument($arg_index);
+
+ if (empty($nick)) {
+ $this->out('Enter user nickname: ');
+ $nick = CliPrompt::prompt();
+ if (empty($nick)) {
+ throw new RuntimeException('A user nickname must be specified.');
+ }
+ }
+
+ $user = UserModel::getByNickname($nick, ['uid', 'nickname']);
+ if (empty($user)) {
+ throw new RuntimeException('User not found');
+ }
+
+ return $user;
+ }
+
+ /**
+ * Adds a contact to a user from a URL
+ *
+ * @return bool True, if the command was successful
+ */
+ private function addContact()
+ {
+ $user = $this->getUserByNick(1);
+
+ $url = $this->getArgument(2);
+ if (empty($url)) {
+ $this->out('Enter contact URL: ');
+ $url = CliPrompt::prompt();
+ if (empty($url)) {
+ throw new RuntimeException('A contact URL must be specified.');
+ }
+ }
+
+ $contact = ContactModel::getByURLForUser($url, $user['uid']);
+ if (!empty($contact)) {
+ throw new RuntimeException('Contact already exists');
+ }
+
+ $network = $this->getArgument(3);
+ if (empty($network) && $network !== '') {
+ $this->out('Enter network, or leave blank: ');
+ $network = CliPrompt::prompt();
+ }
+
+ $result = ContactModel::createFromProbe($user, $url, false, $network);
+
+ if ($result['success']) {
+ $this->out('User ' . $user['nickname'] . ' now connected to ' . $url . ', contact ID ' . $result['cid']);
+ }
+ else {
+ throw new RuntimeException($result['message']);
+ }
+ }
+
+ /**
+ * Sends an unfriend message. Does not remove the contact
+ *
+ * @return bool True, if the command was successful
+ */
+ private function terminateContact()
+ {
+ $cid = $this->getArgument(1);
+ if (empty($cid)) {
+ $this->out('Enter contact ID: ');
+ $cid = CliPrompt::prompt();
+ if (empty($cid)) {
+ throw new RuntimeException('A contact ID must be specified.');
+ }
+ }
+
+ $contact = ContactModel::getById($cid);
+ if (empty($contact)) {
+ throw new RuntimeException('Contact not found');
+ }
+
+ $user = UserModel::getById($contact['uid']);
+
+ $result = ContactModel::terminateFriendship($user, $contact);
+ }
+
+ /**
+ * Marks a contact for removal
+ *
+ * @return bool True, if the command was successful
+ */
+ private function removeContact()
+ {
+ $cid = $this->getArgument(1);
+ if (empty($cid)) {
+ $this->out('Enter contact ID: ');
+ $cid = CliPrompt::prompt();
+ if (empty($cid)) {
+ throw new RuntimeException('A contact ID must be specified.');
+ }
+ }
+
+ $result = ContactModel::remove($cid);
+ }
+
+ /**
+ * Returns a contact based on search parameter
+ *
+ * @return bool True, if the command was successful
+ */
+ private function searchContact()
+ {
+ $fields = [
+ 'id',
+ 'uid',
+ 'network',
+ 'name',
+ 'nick',
+ 'url',
+ 'addr',
+ 'created',
+ 'updated',
+ 'blocked',
+ 'deleted',
+ ];
+
+ $subCmd = $this->getArgument(1);
+
+ $table = new Console_Table();
+ $table->setHeaders(['ID', 'UID', 'Network', 'Name', 'Nick', 'URL', 'E-Mail', 'Created', 'Updated', 'Blocked', 'Deleted']);
+
+ $addRow = function($row) use (&$table) {
+ $table->addRow([
+ $row['id'],
+ $row['uid'],
+ $row['network'],
+ $row['name'],
+ $row['nick'],
+ $row['url'],
+ $row['addr'],
+ Temporal::getRelativeDate($row['created']),
+ Temporal::getRelativeDate($row['updated']),
+ $row['blocked'],
+ $row['deleted'],
+ ]);
+ };
+ switch ($subCmd) {
+ case 'id':
+ $cid = $this->getArgument(2);
+ $contact = ContactModel::getById($cid, $fields);
+ if (!empty($contact)) {
+ $addRow($contact);
+ }
+ break;
+ case 'url':
+ $user = $this->getUserByNick(2);
+ $url = $this->getArgument(3);
+ $contact = ContactModel::getByURLForUser($url, $user['uid'], false, $fields);
+ if (!empty($contact)) {
+ $addRow($contact);
+ }
+ break;
+ default:
+ $this->out($this->getHelp());
+ return false;
+ }
+
+ $this->out($table->getTable());
+
+ return true;
+ }
+}