friendica/src/Console/Contact.php

302 lines
7.4 KiB
PHP

<?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\DI;
use Friendica\Model\Contact as ContactModel;
use Friendica\Model\User as UserModel;
use Friendica\Network\Probe;
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.');
}
}
$url = Probe::cleanURI($url);
$contact = ContactModel::getByURLForUser($url, $user['uid']);
if (!empty($contact)) {
throw new RuntimeException('Contact already exists');
}
$network = $this->getArgument(3);
if ($network === null) {
$this->out('Enter network, or leave blank: ');
$network = CliPrompt::prompt();
}
$result = ContactModel::createFromProbeForUser($user['uid'], $url, $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.
*
* @return bool True, if the command was successful
* @throws \Exception
*/
private function terminateContact(): bool
{
$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']);
try {
$result = ContactModel::terminateFriendship($user, $contact);
if ($result === false) {
throw new RuntimeException('Unable to unfollow this contact, please retry in a few minutes or check the logs.');
}
$this->out('Contact was successfully unfollowed');
return true;
} catch (\Exception $e) {
DI::logger()->error($e->getMessage(), ['owner' => $user, 'contact' => $contact]);
throw new RuntimeException('Unable to unfollow this contact, please check the log');
}
}
/**
* Marks a contact for removal
*/
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.');
}
}
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;
}
}