Merge remote-tracking branch 'upstream/develop' into api-status
This commit is contained in:
commit
214a0524dd
35 changed files with 1809 additions and 1235 deletions
|
@ -1511,6 +1511,7 @@ CREATE TABLE IF NOT EXISTS `user-contact` (
|
||||||
`blocked` boolean COMMENT 'Contact is completely blocked for this user',
|
`blocked` boolean COMMENT 'Contact is completely blocked for this user',
|
||||||
`ignored` boolean COMMENT 'Posts from this contact are ignored',
|
`ignored` boolean COMMENT 'Posts from this contact are ignored',
|
||||||
`collapsed` boolean COMMENT 'Posts from this contact are collapsed',
|
`collapsed` boolean COMMENT 'Posts from this contact are collapsed',
|
||||||
|
`hidden` boolean COMMENT 'This contact is hidden from the others',
|
||||||
`pending` boolean COMMENT '',
|
`pending` boolean COMMENT '',
|
||||||
`rel` tinyint unsigned COMMENT 'The kind of the relation between the user and the contact',
|
`rel` tinyint unsigned COMMENT 'The kind of the relation between the user and the contact',
|
||||||
`info` mediumtext COMMENT '',
|
`info` mediumtext COMMENT '',
|
||||||
|
|
|
@ -171,7 +171,9 @@ Example: Friendica Support
|
||||||
<a name="clients"></a>
|
<a name="clients"></a>
|
||||||
### What friendica clients can I use?
|
### What friendica clients can I use?
|
||||||
|
|
||||||
Friendica supports [Mastodon API](help/API-Mastodon) and [Twitter API | gnusocial](help/api). This means you can use some of the Mastodon and Twitter clients for Friendica. The available features are client specific and may differ.
|
Friendica supports [Mastodon API](help/API-Mastodon) and [Twitter API | gnusocial](help/api).
|
||||||
|
This means you can use some of the Mastodon and Twitter clients for Friendica.
|
||||||
|
The available features are client specific and may differ.
|
||||||
|
|
||||||
#### Android
|
#### Android
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ Fields
|
||||||
| blocked | Contact is completely blocked for this user | boolean | YES | | NULL | |
|
| blocked | Contact is completely blocked for this user | boolean | YES | | NULL | |
|
||||||
| ignored | Posts from this contact are ignored | boolean | YES | | NULL | |
|
| ignored | Posts from this contact are ignored | boolean | YES | | NULL | |
|
||||||
| collapsed | Posts from this contact are collapsed | boolean | YES | | NULL | |
|
| collapsed | Posts from this contact are collapsed | boolean | YES | | NULL | |
|
||||||
|
| hidden | This contact is hidden from the others | boolean | YES | | NULL | |
|
||||||
| pending | | boolean | YES | | NULL | |
|
| pending | | boolean | YES | | NULL | |
|
||||||
| rel | The kind of the relation between the user and the contact | tinyint unsigned | YES | | NULL | |
|
| rel | The kind of the relation between the user and the contact | tinyint unsigned | YES | | NULL | |
|
||||||
| info | | mediumtext | YES | | NULL | |
|
| info | | mediumtext | YES | | NULL | |
|
||||||
|
|
|
@ -180,7 +180,9 @@ Beispiel: Friendica Support
|
||||||
<a name="clients">
|
<a name="clients">
|
||||||
### Gibt es Clients für Friendica?
|
### Gibt es Clients für Friendica?
|
||||||
|
|
||||||
Friendica unterstützt [Mastodon API](help/API-Mastodon) und [Twitter API | gnusocial](help/api). Das bedeutet, du kannst einge der Mastodon und Twitter Clients für Friendica verwenden. Die verfügbaren Features sind Abhängig vom Client, so dass diese teils unterschiedlich sein können.
|
Friendica unterstützt [Mastodon API](help/API-Mastodon) und [Twitter API | gnusocial](help/api).
|
||||||
|
Das bedeutet, du kannst einge der Mastodon und Twitter Clients für Friendica verwenden.
|
||||||
|
Die verfügbaren Features sind Abhängig vom Client, so dass diese teils unterschiedlich sein können.
|
||||||
|
|
||||||
#### Android
|
#### Android
|
||||||
|
|
||||||
|
|
|
@ -264,15 +264,14 @@ function api_account_verify_credentials($type)
|
||||||
|
|
||||||
// - Adding last status
|
// - Adding last status
|
||||||
if (!$skip_status) {
|
if (!$skip_status) {
|
||||||
$item = api_get_last_status($user_info['pid'], $user_info['uid']);
|
$item = api_get_last_status($user_info['pid'], 0);
|
||||||
if (!empty($item)) {
|
if (!empty($item)) {
|
||||||
$user_info['status'] = api_format_item($item, $type);
|
$user_info['status'] = api_format_item($item, $type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// "uid" and "self" are only needed for some internal stuff, so remove it from here
|
// "uid" is only needed for some internal stuff, so remove it from here
|
||||||
unset($user_info['uid']);
|
unset($user_info['uid']);
|
||||||
unset($user_info['self']);
|
|
||||||
|
|
||||||
return DI::apiResponse()->formatData("user", $type, ['user' => $user_info]);
|
return DI::apiResponse()->formatData("user", $type, ['user' => $user_info]);
|
||||||
}
|
}
|
||||||
|
@ -697,14 +696,13 @@ function api_users_show($type)
|
||||||
|
|
||||||
$user_info = DI::twitterUser()->createFromUserId($uid)->toArray();
|
$user_info = DI::twitterUser()->createFromUserId($uid)->toArray();
|
||||||
|
|
||||||
$item = api_get_last_status($user_info['pid'], $user_info['uid']);
|
$item = api_get_last_status($user_info['pid'], 0);
|
||||||
if (!empty($item)) {
|
if (!empty($item)) {
|
||||||
$user_info['status'] = api_format_item($item, $type);
|
$user_info['status'] = api_format_item($item, $type);
|
||||||
}
|
}
|
||||||
|
|
||||||
// "uid" and "self" are only needed for some internal stuff, so remove it from here
|
// "uid" is only needed for some internal stuff, so remove it from here
|
||||||
unset($user_info['uid']);
|
unset($user_info['uid']);
|
||||||
unset($user_info['self']);
|
|
||||||
|
|
||||||
return DI::apiResponse()->formatData('user', $type, ['user' => $user_info]);
|
return DI::apiResponse()->formatData('user', $type, ['user' => $user_info]);
|
||||||
}
|
}
|
||||||
|
@ -1670,19 +1668,13 @@ function api_format_messages($item, $recipient, $sender)
|
||||||
'friendica_parent_uri' => $item['parent-uri'] ?? '',
|
'friendica_parent_uri' => $item['parent-uri'] ?? '',
|
||||||
];
|
];
|
||||||
|
|
||||||
// "uid" and "self" are only needed for some internal stuff, so remove it from here
|
// "uid" is only needed for some internal stuff, so remove it from here
|
||||||
if (isset($ret['sender']['uid'])) {
|
if (isset($ret['sender']['uid'])) {
|
||||||
unset($ret['sender']['uid']);
|
unset($ret['sender']['uid']);
|
||||||
}
|
}
|
||||||
if (isset($ret['sender']['self'])) {
|
|
||||||
unset($ret['sender']['self']);
|
|
||||||
}
|
|
||||||
if (isset($ret['recipient']['uid'])) {
|
if (isset($ret['recipient']['uid'])) {
|
||||||
unset($ret['recipient']['uid']);
|
unset($ret['recipient']['uid']);
|
||||||
}
|
}
|
||||||
if (isset($ret['recipient']['self'])) {
|
|
||||||
unset($ret['recipient']['self']);
|
|
||||||
}
|
|
||||||
|
|
||||||
//don't send title to regular StatusNET requests to avoid confusing these apps
|
//don't send title to regular StatusNET requests to avoid confusing these apps
|
||||||
if (!empty($_GET['getText'])) {
|
if (!empty($_GET['getText'])) {
|
||||||
|
@ -2268,9 +2260,8 @@ function api_format_item($item, $type = "json")
|
||||||
$status['quoted_status'] = $quoted_status;
|
$status['quoted_status'] = $quoted_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
// "uid" and "self" are only needed for some internal stuff, so remove it from here
|
// "uid" is only needed for some internal stuff, so remove it from here
|
||||||
unset($status["user"]['uid']);
|
unset($status["user"]['uid']);
|
||||||
unset($status["user"]['self']);
|
|
||||||
|
|
||||||
if ($item["coord"] != "") {
|
if ($item["coord"] != "") {
|
||||||
$coords = explode(' ', $item["coord"]);
|
$coords = explode(' ', $item["coord"]);
|
||||||
|
@ -2494,9 +2485,8 @@ function api_statuses_f($qtype)
|
||||||
$ret = [];
|
$ret = [];
|
||||||
foreach ($r as $cid) {
|
foreach ($r as $cid) {
|
||||||
$user = DI::twitterUser()->createFromContactId($cid['id'], $uid)->toArray();
|
$user = DI::twitterUser()->createFromContactId($cid['id'], $uid)->toArray();
|
||||||
// "uid" and "self" are only needed for some internal stuff, so remove it from here
|
// "uid" is only needed for some internal stuff, so remove it from here
|
||||||
unset($user['uid']);
|
unset($user['uid']);
|
||||||
unset($user['self']);
|
|
||||||
|
|
||||||
if ($user) {
|
if ($user) {
|
||||||
$ret[] = $user;
|
$ret[] = $user;
|
||||||
|
@ -2794,9 +2784,8 @@ function api_friendships_destroy($type)
|
||||||
throw new HTTPException\InternalServerErrorException('Unable to unfollow this contact, please contact your administrator');
|
throw new HTTPException\InternalServerErrorException('Unable to unfollow this contact, please contact your administrator');
|
||||||
}
|
}
|
||||||
|
|
||||||
// "uid" and "self" are only needed for some internal stuff, so remove it from here
|
// "uid" is only needed for some internal stuff, so remove it from here
|
||||||
unset($contact['uid']);
|
unset($contact['uid']);
|
||||||
unset($contact['self']);
|
|
||||||
|
|
||||||
// Set screen_name since Twidere requests it
|
// Set screen_name since Twidere requests it
|
||||||
$contact['screen_name'] = $contact['nick'];
|
$contact['screen_name'] = $contact['nick'];
|
||||||
|
|
|
@ -33,7 +33,7 @@ function repair_ostatus_content(App $a) {
|
||||||
// NOTREACHED
|
// NOTREACHED
|
||||||
}
|
}
|
||||||
|
|
||||||
$o = "<h2>" . DI::l10n()->t("Resubscribing to OStatus contacts") . "</h2>";
|
$o = '<h2>' . DI::l10n()->t('Resubscribing to OStatus contacts') . '</h2>';
|
||||||
|
|
||||||
$uid = local_user();
|
$uid = local_user();
|
||||||
|
|
||||||
|
@ -43,20 +43,20 @@ function repair_ostatus_content(App $a) {
|
||||||
$total = DBA::count('contact', $condition);
|
$total = DBA::count('contact', $condition);
|
||||||
|
|
||||||
if (!$total) {
|
if (!$total) {
|
||||||
return ($o . DI::l10n()->t("Error"));
|
return ($o . DI::l10n()->t('Error'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$contact = Contact::selectToArray(['url'], $condition, ['order' => ['url'], 'limit' => [$counter++, 1]]);
|
$contact = Contact::selectToArray(['url'], $condition, ['order' => ['url'], 'limit' => [$counter++, 1]]);
|
||||||
if (!DBA::isResult($contact)) {
|
if (!DBA::isResult($contact)) {
|
||||||
$o .= DI::l10n()->t("Done");
|
$o .= DI::l10n()->t('Done');
|
||||||
return $o;
|
return $o;
|
||||||
}
|
}
|
||||||
|
|
||||||
$o .= "<p>" . $counter . "/" . $total . ": " . $contact[0]["url"] . "</p>";
|
$o .= '<p>' . $counter . '/' . $total . ': ' . $contact[0]['url'] . '</p>';
|
||||||
|
|
||||||
$o .= "<p>" . DI::l10n()->t("Keep this window open until done.") . "</p>";
|
$o .= '<p>' . DI::l10n()->t('Keep this window open until done.') . '</p>';
|
||||||
|
|
||||||
Contact::createFromProbeForUser($a->getLoggedInUserId(), $contact[0]["url"]);
|
Contact::createFromProbeForUser($a->getLoggedInUserId(), $contact[0]['url']);
|
||||||
|
|
||||||
DI::page()['htmlhead'] = '<meta http-equiv="refresh" content="1; URL=' . DI::baseUrl() . '/repair_ostatus?counter=' . $counter . '">';
|
DI::page()['htmlhead'] = '<meta http-equiv="refresh" content="1; URL=' . DI::baseUrl() . '/repair_ostatus?counter=' . $counter . '">';
|
||||||
|
|
||||||
|
|
|
@ -23,22 +23,25 @@
|
||||||
|
|
||||||
use Friendica\App;
|
use Friendica\App;
|
||||||
use Friendica\Core\System;
|
use Friendica\Core\System;
|
||||||
|
use Friendica\Database\DBA;
|
||||||
use Friendica\DI;
|
use Friendica\DI;
|
||||||
use Friendica\Model\Post;
|
use Friendica\Model\Post;
|
||||||
use Friendica\Module\Contact;
|
use Friendica\Model\Contact;
|
||||||
|
|
||||||
function update_contact_content(App $a)
|
function update_contact_content(App $a)
|
||||||
{
|
{
|
||||||
if (!empty(DI::args()->getArgv()[1]) && (!empty($_GET['force']) || !DI::pConfig()->get(local_user(), 'system', 'no_auto_update'))) {
|
if (!empty(DI::args()->get(1)) && (!empty($_GET['force']) || !DI::pConfig()->get(local_user(), 'system', 'no_auto_update'))) {
|
||||||
|
$contact = Contact::getById(DI::args()->get(1), ['id', 'deleted']);
|
||||||
|
if (DBA::isResult($contact) && empty($contact['deleted'])) {
|
||||||
|
DI::page()['aside'] = '';
|
||||||
|
|
||||||
if (!empty($_GET['item'])) {
|
if (!empty($_GET['item'])) {
|
||||||
$item = Post::selectFirst(['parent'], ['id' => $_GET['item']]);
|
$item = Post::selectFirst(['parent'], ['id' => $_GET['item']]);
|
||||||
$parentid = $item['parent'] ?? 0;
|
|
||||||
} else {
|
|
||||||
$parentid = 0;
|
|
||||||
}
|
}
|
||||||
$text = Contact::getConversationsHMTL($a, DI::args()->getArgv()[1], true, $parentid);
|
|
||||||
} else {
|
$text = Contact::getPostsFromId($contact['id'], true, true, $item['parent'] ?? 0);
|
||||||
$text = '';
|
|
||||||
}
|
}
|
||||||
System::htmlUpdateExit($text);
|
}
|
||||||
|
|
||||||
|
System::htmlUpdateExit($text ?? '');
|
||||||
}
|
}
|
||||||
|
|
128
src/Contact/LocalRelationship/Entity/LocalRelationship.php
Normal file
128
src/Contact/LocalRelationship/Entity/LocalRelationship.php
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
<?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\Contact\LocalRelationship\Entity;
|
||||||
|
|
||||||
|
use Friendica\Core\Protocol;
|
||||||
|
use Friendica\Model\Contact;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property-read int $userId
|
||||||
|
* @property-read int $contactId
|
||||||
|
* @property-read int $uriId
|
||||||
|
* @property-read bool $blocked
|
||||||
|
* @property-read bool $ignored
|
||||||
|
* @property-read bool $collapsed
|
||||||
|
* @property-read bool $hidden
|
||||||
|
* @property-read bool $pending
|
||||||
|
* @property-read int $rel
|
||||||
|
* @property-read string $info
|
||||||
|
* @property-read bool $notifyNewPosts
|
||||||
|
* @property-read bool $isRemoteSelf
|
||||||
|
* @property-read int $fetchFurtherInformation
|
||||||
|
* @property-read string $ffiKeywordDenylist
|
||||||
|
* @property-read bool $subhub
|
||||||
|
* @property-read string $hubVerify
|
||||||
|
* @property-read string $protocol
|
||||||
|
* @property-read int $rating
|
||||||
|
* @property-read int $priority
|
||||||
|
*/
|
||||||
|
class LocalRelationship extends \Friendica\BaseEntity
|
||||||
|
{
|
||||||
|
/** @var int */
|
||||||
|
protected $userId;
|
||||||
|
/** @var int */
|
||||||
|
protected $contactId;
|
||||||
|
/** @var bool */
|
||||||
|
protected $blocked;
|
||||||
|
/** @var bool */
|
||||||
|
protected $ignored;
|
||||||
|
/** @var bool */
|
||||||
|
protected $collapsed;
|
||||||
|
/** @var bool */
|
||||||
|
protected $hidden;
|
||||||
|
/** @var bool */
|
||||||
|
protected $pending;
|
||||||
|
/** @var int */
|
||||||
|
protected $rel;
|
||||||
|
/** @var string */
|
||||||
|
protected $info;
|
||||||
|
/** @var bool */
|
||||||
|
protected $notifyNewPosts;
|
||||||
|
/** @var bool */
|
||||||
|
protected $isRemoteSelf;
|
||||||
|
/** @var int */
|
||||||
|
protected $fetchFurtherInformation;
|
||||||
|
/** @var string */
|
||||||
|
protected $ffiKeywordDenylist;
|
||||||
|
/** @var bool */
|
||||||
|
protected $subhub;
|
||||||
|
/** @var string */
|
||||||
|
protected $hubVerify;
|
||||||
|
/** @var string */
|
||||||
|
protected $protocol;
|
||||||
|
/** @var int */
|
||||||
|
protected $rating;
|
||||||
|
/** @var int */
|
||||||
|
protected $priority;
|
||||||
|
|
||||||
|
public function __construct(int $userId, int $contactId, bool $blocked = false, bool $ignored = false, bool $collapsed = false, bool $hidden = false, bool $pending = false, int $rel = Contact::NOTHING, string $info = '', bool $notifyNewPosts = false, bool $isRemoteSelf = false, int $fetchFurtherInformation = 0, string $ffiKeywordDenylist = '', bool $subhub = false, string $hubVerify = '', string $protocol = Protocol::PHANTOM, ?int $rating = null, ?int $priority = null)
|
||||||
|
{
|
||||||
|
$this->userId = $userId;
|
||||||
|
$this->contactId = $contactId;
|
||||||
|
$this->blocked = $blocked;
|
||||||
|
$this->ignored = $ignored;
|
||||||
|
$this->collapsed = $collapsed;
|
||||||
|
$this->hidden = $hidden;
|
||||||
|
$this->pending = $pending;
|
||||||
|
$this->rel = $rel;
|
||||||
|
$this->info = $info;
|
||||||
|
$this->notifyNewPosts = $notifyNewPosts;
|
||||||
|
$this->isRemoteSelf = $isRemoteSelf;
|
||||||
|
$this->fetchFurtherInformation = $fetchFurtherInformation;
|
||||||
|
$this->ffiKeywordDenylist = $ffiKeywordDenylist;
|
||||||
|
$this->subhub = $subhub;
|
||||||
|
$this->hubVerify = $hubVerify;
|
||||||
|
$this->protocol = $protocol;
|
||||||
|
$this->rating = $rating;
|
||||||
|
$this->priority = $priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addFollow()
|
||||||
|
{
|
||||||
|
$this->rel = in_array($this->rel, [Contact::FOLLOWER, Contact::FRIEND]) ? Contact::FRIEND : Contact::SHARING;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeFollow()
|
||||||
|
{
|
||||||
|
$this->rel = in_array($this->rel, [Contact::FOLLOWER, Contact::FRIEND]) ? Contact::FOLLOWER : Contact::NOTHING;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addFollower()
|
||||||
|
{
|
||||||
|
$this->rel = in_array($this->rel, [Contact::SHARING, Contact::FRIEND]) ? Contact::FRIEND : Contact::FOLLOWER;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeFollower()
|
||||||
|
{
|
||||||
|
$this->rel = in_array($this->rel, [Contact::SHARING, Contact::FRIEND]) ? Contact::SHARING : Contact::NOTHING;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Friendica\Contact\LocalRelationship\Exception;
|
||||||
|
|
||||||
|
class LocalRelationshipPersistenceException extends \RuntimeException
|
||||||
|
{
|
||||||
|
public function __construct($message = '', \Throwable $previous = null)
|
||||||
|
{
|
||||||
|
parent::__construct($message, 500, $previous);
|
||||||
|
}
|
||||||
|
}
|
58
src/Contact/LocalRelationship/Factory/LocalRelationship.php
Normal file
58
src/Contact/LocalRelationship/Factory/LocalRelationship.php
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
<?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\Contact\LocalRelationship\Factory;
|
||||||
|
|
||||||
|
use Friendica\BaseFactory;
|
||||||
|
use Friendica\Capabilities\ICanCreateFromTableRow;
|
||||||
|
use Friendica\Contact\LocalRelationship\Entity;
|
||||||
|
use Friendica\Core\Protocol;
|
||||||
|
use Friendica\Model\Contact;
|
||||||
|
|
||||||
|
class LocalRelationship extends BaseFactory implements ICanCreateFromTableRow
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function createFromTableRow(array $row): Entity\LocalRelationship
|
||||||
|
{
|
||||||
|
return new Entity\LocalRelationship(
|
||||||
|
$row['uid'],
|
||||||
|
$row['cid'],
|
||||||
|
$row['blocked'] ?? false,
|
||||||
|
$row['ignored'] ?? false,
|
||||||
|
$row['collapsed'] ?? false,
|
||||||
|
$row['hidden'] ?? false,
|
||||||
|
$row['pending'] ?? false,
|
||||||
|
$row['rel'] ?? Contact::NOTHING,
|
||||||
|
$row['info'] ?? '',
|
||||||
|
$row['notify_new_posts'] ?? false,
|
||||||
|
$row['remote_self'] ?? false,
|
||||||
|
$row['fetch_further_information'] ?? 0,
|
||||||
|
$row['ffi_keyword_denylist'] ?? '',
|
||||||
|
$row['subhub'] ?? false,
|
||||||
|
$row['hub-verify'] ?? '',
|
||||||
|
$row['protocol'] ?? Protocol::PHANTOM,
|
||||||
|
$row['rating'] ?? null,
|
||||||
|
$row['priority'] ?? null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
133
src/Contact/LocalRelationship/Repository/LocalRelationship.php
Normal file
133
src/Contact/LocalRelationship/Repository/LocalRelationship.php
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
<?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\Contact\LocalRelationship\Repository;
|
||||||
|
|
||||||
|
use Friendica\Contact\LocalRelationship\Entity;
|
||||||
|
use Friendica\Contact\LocalRelationship\Exception;
|
||||||
|
use Friendica\Contact\LocalRelationship\Factory;
|
||||||
|
use Friendica\Database\Database;
|
||||||
|
use Friendica\Network\HTTPException;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
|
class LocalRelationship extends \Friendica\BaseRepository
|
||||||
|
{
|
||||||
|
protected static $table_name = 'user-contact';
|
||||||
|
|
||||||
|
/** @var Factory\LocalRelationship */
|
||||||
|
protected $factory;
|
||||||
|
|
||||||
|
public function __construct(Database $database, LoggerInterface $logger, Factory\LocalRelationship $factory)
|
||||||
|
{
|
||||||
|
parent::__construct($database, $logger, $factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $uid
|
||||||
|
* @param int $cid
|
||||||
|
* @return Entity\LocalRelationship
|
||||||
|
* @throws HTTPException\NotFoundException
|
||||||
|
*/
|
||||||
|
public function selectForUserContact(int $uid, int $cid): Entity\LocalRelationship
|
||||||
|
{
|
||||||
|
return $this->_selectOne(['uid' => $uid, 'cid' => $cid]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the existing local relationship between a user and a public contact or a default
|
||||||
|
* relationship if it doesn't.
|
||||||
|
*
|
||||||
|
* @param int $uid
|
||||||
|
* @param int $cid
|
||||||
|
* @return Entity\LocalRelationship
|
||||||
|
* @throws HTTPException\NotFoundException
|
||||||
|
*/
|
||||||
|
public function getForUserContact(int $uid, int $cid): Entity\LocalRelationship
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return $this->selectForUserContact($uid, $cid);
|
||||||
|
} catch (HTTPException\NotFoundException $e) {
|
||||||
|
return $this->factory->createFromTableRow(['uid' => $uid, 'cid' => $cid]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $uid
|
||||||
|
* @param int $cid
|
||||||
|
* @return bool
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function existsForUserContact(int $uid, int $cid): bool
|
||||||
|
{
|
||||||
|
return $this->exists(['uid' => $uid, 'cid' => $cid]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a given local relationship into a DB compatible row array
|
||||||
|
*
|
||||||
|
* @param Entity\LocalRelationship $localRelationship
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function convertToTableRow(Entity\LocalRelationship $localRelationship): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'uid' => $localRelationship->userId,
|
||||||
|
'cid' => $localRelationship->contactId,
|
||||||
|
'uri-id' => $localRelationship->uriId,
|
||||||
|
'blocked' => $localRelationship->blocked,
|
||||||
|
'ignored' => $localRelationship->ignored,
|
||||||
|
'collapsed' => $localRelationship->collapsed,
|
||||||
|
'pending' => $localRelationship->pending,
|
||||||
|
'rel' => $localRelationship->rel,
|
||||||
|
'info' => $localRelationship->info,
|
||||||
|
'notify_new_posts' => $localRelationship->notifyNewPosts,
|
||||||
|
'remote_self' => $localRelationship->isRemoteSelf,
|
||||||
|
'fetch_further_information' => $localRelationship->fetchFurtherInformation,
|
||||||
|
'ffi_keyword_denylist' => $localRelationship->ffiKeywordDenylist,
|
||||||
|
'subhub' => $localRelationship->subhub,
|
||||||
|
'hub-verify' => $localRelationship->hubVerify,
|
||||||
|
'protocol' => $localRelationship->protocol,
|
||||||
|
'rating' => $localRelationship->rating,
|
||||||
|
'priority' => $localRelationship->priority,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Entity\LocalRelationship $localRelationship
|
||||||
|
*
|
||||||
|
* @return Entity\LocalRelationship
|
||||||
|
*
|
||||||
|
* @throws Exception\LocalRelationshipPersistenceException In case the underlying storage cannot save the LocalRelationship
|
||||||
|
*/
|
||||||
|
public function save(Entity\LocalRelationship $localRelationship): Entity\LocalRelationship
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$fields = $this->convertToTableRow($localRelationship);
|
||||||
|
|
||||||
|
$this->db->insert(self::$table_name, $fields, Database::INSERT_UPDATE);
|
||||||
|
|
||||||
|
return $localRelationship;
|
||||||
|
} catch (\Exception $exception) {
|
||||||
|
throw new Exception\LocalRelationshipPersistenceException(sprintf('Cannot insert/update the local relationship %d for user %d', $localRelationship->contactId, $localRelationship->userId), $exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,7 +21,9 @@
|
||||||
|
|
||||||
namespace Friendica\Core;
|
namespace Friendica\Core;
|
||||||
|
|
||||||
|
use Friendica\Database\DBA;
|
||||||
use Friendica\DI;
|
use Friendica\DI;
|
||||||
|
use Friendica\Model\User;
|
||||||
use Friendica\Network\HTTPException;
|
use Friendica\Network\HTTPException;
|
||||||
use Friendica\Protocol\Activity;
|
use Friendica\Protocol\Activity;
|
||||||
use Friendica\Protocol\ActivityPub;
|
use Friendica\Protocol\ActivityPub;
|
||||||
|
@ -208,6 +210,59 @@ class Protocol
|
||||||
return $display_name . ' (' . self::getAddrFromProfileUrl($profile_url) . ')';
|
return $display_name . ' (' . self::getAddrFromProfileUrl($profile_url) . ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a follow message to a remote server.
|
||||||
|
*
|
||||||
|
* @param int $uid User Id
|
||||||
|
* @param array $contact Contact being followed
|
||||||
|
* @param ?string $protocol Expected protocol
|
||||||
|
* @return bool Only returns false in the unlikely case an ActivityPub contact ID doesn't exist (???)
|
||||||
|
* @throws HTTPException\InternalServerErrorException
|
||||||
|
* @throws \ImagickException
|
||||||
|
*/
|
||||||
|
public static function follow(int $uid, array $contact, ?string $protocol = null): bool
|
||||||
|
{
|
||||||
|
$owner = User::getOwnerDataById($uid);
|
||||||
|
if (!DBA::isResult($owner)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$protocol = $protocol ?? $contact['protocol'];
|
||||||
|
|
||||||
|
if (in_array($protocol, [Protocol::OSTATUS, Protocol::DFRN])) {
|
||||||
|
// create a follow slap
|
||||||
|
$item = [
|
||||||
|
'verb' => Activity::FOLLOW,
|
||||||
|
'gravity' => GRAVITY_ACTIVITY,
|
||||||
|
'follow' => $contact['url'],
|
||||||
|
'body' => '',
|
||||||
|
'title' => '',
|
||||||
|
'guid' => '',
|
||||||
|
'uri-id' => 0,
|
||||||
|
];
|
||||||
|
|
||||||
|
$slap = OStatus::salmon($item, $owner);
|
||||||
|
|
||||||
|
if (!empty($contact['notify'])) {
|
||||||
|
Salmon::slapper($owner, $contact['notify'], $slap);
|
||||||
|
}
|
||||||
|
} elseif ($protocol == Protocol::DIASPORA) {
|
||||||
|
$contact = Diaspora::sendShare($owner, $contact);
|
||||||
|
Logger::notice('share returns: ' . $contact);
|
||||||
|
} elseif ($protocol == Protocol::ACTIVITYPUB) {
|
||||||
|
$activity_id = ActivityPub\Transmitter::activityIDFromContact($contact['id']);
|
||||||
|
if (empty($activity_id)) {
|
||||||
|
// This really should never happen
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$success = ActivityPub\Transmitter::sendActivity('Follow', $contact['url'], $owner['uid'], $activity_id);
|
||||||
|
Logger::notice('Follow returns: ' . $success);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends an unfriend message. Does not remove the contact
|
* Sends an unfriend message. Does not remove the contact
|
||||||
*
|
*
|
||||||
|
|
|
@ -2492,7 +2492,7 @@ class Contact
|
||||||
$contact_id = $contact['id'];
|
$contact_id = $contact['id'];
|
||||||
$result['cid'] = $contact_id;
|
$result['cid'] = $contact_id;
|
||||||
|
|
||||||
Group::addMember(User::getDefaultGroup($uid, $contact["network"]), $contact_id);
|
Group::addMember(User::getDefaultGroup($uid), $contact_id);
|
||||||
|
|
||||||
// Update the avatar
|
// Update the avatar
|
||||||
self::updateAvatar($contact_id, $ret['photo']);
|
self::updateAvatar($contact_id, $ret['photo']);
|
||||||
|
@ -2508,61 +2508,11 @@ class Contact
|
||||||
Worker::add(PRIORITY_HIGH, 'UpdateContact', $contact_id);
|
Worker::add(PRIORITY_HIGH, 'UpdateContact', $contact_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
$owner = User::getOwnerDataById($uid);
|
$result['success'] = Protocol::follow($uid, $contact, $protocol);
|
||||||
|
|
||||||
if (DBA::isResult($owner)) {
|
|
||||||
if (in_array($protocol, [Protocol::OSTATUS, Protocol::DFRN])) {
|
|
||||||
// create a follow slap
|
|
||||||
$item = [];
|
|
||||||
$item['verb'] = Activity::FOLLOW;
|
|
||||||
$item['gravity'] = GRAVITY_ACTIVITY;
|
|
||||||
$item['follow'] = $contact["url"];
|
|
||||||
$item['body'] = '';
|
|
||||||
$item['title'] = '';
|
|
||||||
$item['guid'] = '';
|
|
||||||
$item['uri-id'] = 0;
|
|
||||||
|
|
||||||
$slap = OStatus::salmon($item, $owner);
|
|
||||||
|
|
||||||
if (!empty($contact['notify'])) {
|
|
||||||
Salmon::slapper($owner, $contact['notify'], $slap);
|
|
||||||
}
|
|
||||||
} elseif ($protocol == Protocol::DIASPORA) {
|
|
||||||
$ret = Diaspora::sendShare($owner, $contact);
|
|
||||||
Logger::notice('share returns: ' . $ret);
|
|
||||||
} elseif ($protocol == Protocol::ACTIVITYPUB) {
|
|
||||||
$activity_id = ActivityPub\Transmitter::activityIDFromContact($contact_id);
|
|
||||||
if (empty($activity_id)) {
|
|
||||||
// This really should never happen
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$ret = ActivityPub\Transmitter::sendActivity('Follow', $contact['url'], $uid, $activity_id);
|
|
||||||
Logger::notice('Follow returns: ' . $ret);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$result['success'] = true;
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Follow a contact
|
|
||||||
*
|
|
||||||
* @param int $cid Public contact id
|
|
||||||
* @param int $uid User ID
|
|
||||||
*
|
|
||||||
* @return bool "true" if following had been successful
|
|
||||||
*/
|
|
||||||
public static function follow(int $cid, int $uid)
|
|
||||||
{
|
|
||||||
$contact = self::getById($cid, ['url']);
|
|
||||||
|
|
||||||
$result = self::createFromProbeForUser($uid, $contact['url']);
|
|
||||||
|
|
||||||
return $result['cid'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unfollow a contact
|
* Unfollow a contact
|
||||||
*
|
*
|
||||||
|
@ -2699,7 +2649,7 @@ class Contact
|
||||||
DI::intro()->save($intro);
|
DI::intro()->save($intro);
|
||||||
}
|
}
|
||||||
|
|
||||||
Group::addMember(User::getDefaultGroup($importer['uid'], $contact_record["network"]), $contact_record['id']);
|
Group::addMember(User::getDefaultGroup($importer['uid']), $contact_record['id']);
|
||||||
|
|
||||||
if (($user['notify-flags'] & Notification\Type::INTRO) &&
|
if (($user['notify-flags'] & Notification\Type::INTRO) &&
|
||||||
in_array($user['page-flags'], [User::PAGE_FLAGS_NORMAL])) {
|
in_array($user['page-flags'], [User::PAGE_FLAGS_NORMAL])) {
|
||||||
|
|
|
@ -95,16 +95,17 @@ class User
|
||||||
$update_fields = self::preparedFields($fields);
|
$update_fields = self::preparedFields($fields);
|
||||||
if (!empty($update_fields)) {
|
if (!empty($update_fields)) {
|
||||||
$contacts = DBA::select('contact', ['uri-id', 'uid'], $condition);
|
$contacts = DBA::select('contact', ['uri-id', 'uid'], $condition);
|
||||||
while ($row = DBA::fetch($contacts)) {
|
while ($contact = DBA::fetch($contacts)) {
|
||||||
if (empty($row['uri-id']) || empty($contact['uid'])) {
|
if (empty($contact['uri-id']) || empty($contact['uid'])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$ret = DBA::update('user-contact', $update_fields, ['uri-id' => $row['uri-id'], 'uid' => $row['uid']]);
|
$ret = DBA::update('user-contact', $update_fields, ['uri-id' => $contact['uri-id'], 'uid' => $contact['uid']]);
|
||||||
Logger::info('Updated user contact', ['uid' => $row['uid'], 'uri-id' => $row['uri-id'], 'ret' => $ret]);
|
Logger::info('Updated user contact', ['uid' => $contact['uid'], 'uri-id' => $contact['uri-id'], 'ret' => $ret]);
|
||||||
}
|
}
|
||||||
|
|
||||||
DBA::close($contacts);
|
DBA::close($contacts);
|
||||||
}
|
}
|
||||||
|
|
||||||
DBA::commit();
|
DBA::commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -482,12 +482,11 @@ class User
|
||||||
* Returns the default group for a given user and network
|
* Returns the default group for a given user and network
|
||||||
*
|
*
|
||||||
* @param int $uid User id
|
* @param int $uid User id
|
||||||
* @param string $network network name
|
|
||||||
*
|
*
|
||||||
* @return int group id
|
* @return int group id
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public static function getDefaultGroup($uid, $network = '')
|
public static function getDefaultGroup($uid)
|
||||||
{
|
{
|
||||||
$user = DBA::selectFirst('user', ['def_gid'], ['uid' => $uid]);
|
$user = DBA::selectFirst('user', ['def_gid'], ['uid' => $uid]);
|
||||||
if (DBA::isResult($user)) {
|
if (DBA::isResult($user)) {
|
||||||
|
|
|
@ -40,8 +40,14 @@ class Follow extends BaseApi
|
||||||
DI::mstdnError()->UnprocessableEntity();
|
DI::mstdnError()->UnprocessableEntity();
|
||||||
}
|
}
|
||||||
|
|
||||||
$cid = Contact::follow($this->parameters['id'], $uid);
|
$contact = Contact::getById($this->parameters['id'], ['url']);
|
||||||
|
|
||||||
System::jsonExit(DI::mstdnRelationship()->createFromContactId($cid, $uid)->toArray());
|
$result = Contact::createFromProbeForUser($uid, $contact['url']);
|
||||||
|
|
||||||
|
if (!$result['success']) {
|
||||||
|
DI::mstdnError()->UnprocessableEntity($result['message']);
|
||||||
|
}
|
||||||
|
|
||||||
|
System::jsonExit(DI::mstdnRelationship()->createFromContactId($result['cid'], $uid)->toArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,8 @@ abstract class ContactEndpoint extends BaseApi
|
||||||
/**
|
/**
|
||||||
* This methods expands the contact ids into full user objects in an existing result set.
|
* This methods expands the contact ids into full user objects in an existing result set.
|
||||||
*
|
*
|
||||||
* @param mixed $rel A relationship constant or a list of them
|
* @param array $ids List of contact ids
|
||||||
|
* @param int $total_count Total list of contacts
|
||||||
* @param int $uid The local user id we query the contacts from
|
* @param int $uid The local user id we query the contacts from
|
||||||
* @param int $cursor
|
* @param int $cursor
|
||||||
* @param int $count
|
* @param int $count
|
||||||
|
@ -92,9 +93,9 @@ abstract class ContactEndpoint extends BaseApi
|
||||||
* @throws HTTPException\NotFoundException
|
* @throws HTTPException\NotFoundException
|
||||||
* @throws \ImagickException
|
* @throws \ImagickException
|
||||||
*/
|
*/
|
||||||
protected static function list($rel, int $uid, int $cursor = -1, int $count = self::DEFAULT_COUNT, bool $skip_status = false, bool $include_user_entities = true)
|
protected static function list(array $ids, int $total_count, int $uid, int $cursor = -1, int $count = self::DEFAULT_COUNT, bool $skip_status = false, bool $include_user_entities = true)
|
||||||
{
|
{
|
||||||
$return = self::ids($rel, $uid, $cursor, $count);
|
$return = self::ids($ids, $total_count, $cursor, $count, false);
|
||||||
|
|
||||||
$users = [];
|
$users = [];
|
||||||
foreach ($return['ids'] as $contactId) {
|
foreach ($return['ids'] as $contactId) {
|
||||||
|
@ -110,71 +111,25 @@ abstract class ContactEndpoint extends BaseApi
|
||||||
'next_cursor_str' => $return['next_cursor_str'],
|
'next_cursor_str' => $return['next_cursor_str'],
|
||||||
'previous_cursor' => $return['previous_cursor'],
|
'previous_cursor' => $return['previous_cursor'],
|
||||||
'previous_cursor_str' => $return['previous_cursor_str'],
|
'previous_cursor_str' => $return['previous_cursor_str'],
|
||||||
'total_count' => (int)$return['total_count'],
|
'total_count' => $return['total_count'],
|
||||||
];
|
];
|
||||||
|
|
||||||
return $return;
|
return $return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param mixed $rel A relationship constant or a list of them
|
* @param array $ids List of contact ids
|
||||||
* @param int $uid The local user id we query the contacts from
|
* @param int $total_count Total list of contacts
|
||||||
* @param int $cursor
|
* @param int $cursor
|
||||||
* @param int $count
|
* @param int $count Number of elements to return
|
||||||
* @param bool $stringify_ids
|
* @param bool $stringify_ids if "true" then the id is converted to a string
|
||||||
* @return array
|
* @return array
|
||||||
* @throws HTTPException\NotFoundException
|
* @throws HTTPException\NotFoundException
|
||||||
*/
|
*/
|
||||||
protected static function ids($rel, int $uid, int $cursor = -1, int $count = self::DEFAULT_COUNT, bool $stringify_ids = false)
|
protected static function ids(array $ids, int $total_count, int $cursor = -1, int $count = self::DEFAULT_COUNT, bool $stringify_ids = false)
|
||||||
{
|
{
|
||||||
$hide_friends = false;
|
|
||||||
if ($uid != self::getCurrentUserID()) {
|
|
||||||
$profile = Profile::getByUID($uid);
|
|
||||||
if (empty($profile)) {
|
|
||||||
throw new HTTPException\NotFoundException(DI::l10n()->t('Profile not found'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$hide_friends = (bool)$profile['hide-friends'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$ids = [];
|
|
||||||
$next_cursor = 0;
|
$next_cursor = 0;
|
||||||
$previous_cursor = 0;
|
$previous_cursor = 0;
|
||||||
$total_count = 0;
|
|
||||||
if (!$hide_friends) {
|
|
||||||
$condition = [
|
|
||||||
'rel' => $rel,
|
|
||||||
'uid' => $uid,
|
|
||||||
'self' => false,
|
|
||||||
'deleted' => false,
|
|
||||||
'hidden' => false,
|
|
||||||
'archive' => false,
|
|
||||||
'pending' => false
|
|
||||||
];
|
|
||||||
|
|
||||||
$total_count = (int)DBA::count('contact', $condition);
|
|
||||||
|
|
||||||
$params = ['limit' => $count, 'order' => ['id' => 'ASC']];
|
|
||||||
|
|
||||||
if ($cursor !== -1) {
|
|
||||||
if ($cursor > 0) {
|
|
||||||
$condition = DBA::mergeConditions($condition, ['`id` > ?', $cursor]);
|
|
||||||
} else {
|
|
||||||
$condition = DBA::mergeConditions($condition, ['`id` < ?', -$cursor]);
|
|
||||||
// Previous page case: we want the items closest to cursor but for that we need to reverse the query order
|
|
||||||
$params['order']['id'] = 'DESC';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$contacts = Contact::selectToArray(['id'], $condition, $params);
|
|
||||||
|
|
||||||
// Previous page case: once we get the relevant items closest to cursor, we need to restore the expected display order
|
|
||||||
if ($cursor !== -1 && $cursor <= 0) {
|
|
||||||
$contacts = array_reverse($contacts);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Contains user-specific contact ids
|
|
||||||
$ids = array_column($contacts, 'id');
|
|
||||||
|
|
||||||
// Cursor is on the user-specific contact id since it's the sort field
|
// Cursor is on the user-specific contact id since it's the sort field
|
||||||
if (count($ids)) {
|
if (count($ids)) {
|
||||||
|
@ -183,11 +138,11 @@ abstract class ContactEndpoint extends BaseApi
|
||||||
}
|
}
|
||||||
|
|
||||||
// No next page
|
// No next page
|
||||||
if ($total_count <= count($contacts) || count($contacts) < $count) {
|
if ($total_count <= count($ids) || count($ids) < $count) {
|
||||||
$next_cursor = 0;
|
$next_cursor = 0;
|
||||||
}
|
}
|
||||||
// End of results
|
// End of results
|
||||||
if ($cursor < 0 && count($contacts) === 0) {
|
if ($cursor < 0 && count($ids) === 0) {
|
||||||
$next_cursor = -1;
|
$next_cursor = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,22 +151,17 @@ abstract class ContactEndpoint extends BaseApi
|
||||||
$previous_cursor = 0;
|
$previous_cursor = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($cursor > 0 && count($contacts) === 0) {
|
if ($cursor > 0 && count($ids) === 0) {
|
||||||
$previous_cursor = -$cursor;
|
$previous_cursor = -$cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($cursor < 0 && count($contacts) === 0) {
|
if ($cursor < 0 && count($ids) === 0) {
|
||||||
$next_cursor = -1;
|
$next_cursor = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Conversion to public contact ids
|
|
||||||
array_walk($ids, function (&$contactId) use ($uid, $stringify_ids) {
|
|
||||||
$cdata = Contact::getPublicAndUserContactID($contactId, $uid);
|
|
||||||
if ($stringify_ids) {
|
if ($stringify_ids) {
|
||||||
$contactId = (string)$cdata['public'];
|
array_walk($ids, function (&$contactId) {
|
||||||
} else {
|
$contactId = (string)$contactId;
|
||||||
$contactId = (int)$cdata['public'];
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,21 +22,25 @@
|
||||||
namespace Friendica\Module\Api\Twitter\Followers;
|
namespace Friendica\Module\Api\Twitter\Followers;
|
||||||
|
|
||||||
use Friendica\Core\System;
|
use Friendica\Core\System;
|
||||||
use Friendica\Model\Contact;
|
use Friendica\Database\DBA;
|
||||||
use Friendica\Module\Api\Twitter\ContactEndpoint;
|
use Friendica\Module\Api\Twitter\ContactEndpoint;
|
||||||
|
use Friendica\Module\BaseApi;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-followers-ids
|
* @see https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-followers-ids
|
||||||
*/
|
*/
|
||||||
class FollowersIds extends ContactEndpoint
|
class Ids extends ContactEndpoint
|
||||||
{
|
{
|
||||||
public function rawContent()
|
public function rawContent()
|
||||||
{
|
{
|
||||||
|
self::checkAllowedScope(self::SCOPE_READ);
|
||||||
|
$uid = BaseApi::getCurrentUserID();
|
||||||
|
|
||||||
// Expected value for user_id parameter: public/user contact id
|
// Expected value for user_id parameter: public/user contact id
|
||||||
$contact_id = filter_input(INPUT_GET, 'user_id' , FILTER_VALIDATE_INT);
|
$contact_id = filter_input(INPUT_GET, 'user_id' , FILTER_VALIDATE_INT);
|
||||||
$screen_name = filter_input(INPUT_GET, 'screen_name');
|
$screen_name = filter_input(INPUT_GET, 'screen_name');
|
||||||
$cursor = filter_input(INPUT_GET, 'cursor' , FILTER_VALIDATE_INT);
|
$cursor = filter_input(INPUT_GET, 'cursor' , FILTER_VALIDATE_INT, ['options' => ['default' => -1]]);
|
||||||
$stringify_ids = filter_input(INPUT_GET, 'stringify_ids', FILTER_VALIDATE_BOOLEAN);
|
$stringify_ids = filter_input(INPUT_GET, 'stringify_ids', FILTER_VALIDATE_BOOLEAN, ['options' => ['default' => false]]);
|
||||||
$count = filter_input(INPUT_GET, 'count' , FILTER_VALIDATE_INT, ['options' => [
|
$count = filter_input(INPUT_GET, 'count' , FILTER_VALIDATE_INT, ['options' => [
|
||||||
'default' => self::DEFAULT_COUNT,
|
'default' => self::DEFAULT_COUNT,
|
||||||
'min_range' => 1,
|
'min_range' => 1,
|
||||||
|
@ -44,18 +48,48 @@ class FollowersIds extends ContactEndpoint
|
||||||
]]);
|
]]);
|
||||||
// Friendica-specific
|
// Friendica-specific
|
||||||
$since_id = filter_input(INPUT_GET, 'since_id' , FILTER_VALIDATE_INT);
|
$since_id = filter_input(INPUT_GET, 'since_id' , FILTER_VALIDATE_INT);
|
||||||
$max_id = filter_input(INPUT_GET, 'max_id' , FILTER_VALIDATE_INT, ['options' => [
|
$max_id = filter_input(INPUT_GET, 'max_id' , FILTER_VALIDATE_INT);
|
||||||
'default' => 1,
|
$min_id = filter_input(INPUT_GET, 'min_id' , FILTER_VALIDATE_INT);
|
||||||
]]);
|
|
||||||
|
|
||||||
// @todo Use Model\Contact\Relation::listFollowers($cid, $condition, $count);
|
$cid = BaseApi::getContactIDForSearchterm($screen_name, $contact_id, $uid);
|
||||||
|
|
||||||
System::jsonExit(self::ids(
|
$params = ['order' => ['relation-cid' => true], 'limit' => $count];
|
||||||
[Contact::FOLLOWER, Contact::FRIEND],
|
|
||||||
self::getUid($contact_id, $screen_name),
|
$condition = ['cid' => $cid, 'follows' => true];
|
||||||
$cursor ?? $since_id ?? - $max_id,
|
|
||||||
$count,
|
$total_count = (int)DBA::count('contact-relation', $condition);
|
||||||
$stringify_ids
|
|
||||||
));
|
if (!empty($max_id)) {
|
||||||
|
$condition = DBA::mergeConditions($condition, ["`relation-cid` < ?", $max_id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($since_id)) {
|
||||||
|
$condition = DBA::mergeConditions($condition, ["`relation-cid` > ?", $since_id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($min_id)) {
|
||||||
|
$condition = DBA::mergeConditions($condition, ["`relation-cid` > ?", $min_id]);
|
||||||
|
|
||||||
|
$params['order'] = ['relation-cid'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$ids = [];
|
||||||
|
|
||||||
|
$followers = DBA::select('contact-relation', ['relation-cid'], $condition, $params);
|
||||||
|
while ($follower = DBA::fetch($followers)) {
|
||||||
|
self::setBoundaries($follower['relation-cid']);
|
||||||
|
$ids[] = $follower['relation-cid'];
|
||||||
|
}
|
||||||
|
DBA::close($followers);
|
||||||
|
|
||||||
|
if (!empty($min_id)) {
|
||||||
|
array_reverse($ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
$return = self::ids($ids, $total_count, $cursor, $count, $stringify_ids);
|
||||||
|
|
||||||
|
self::setLinkHeader();
|
||||||
|
|
||||||
|
System::jsonExit($return);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,43 +22,75 @@
|
||||||
namespace Friendica\Module\Api\Twitter\Followers;
|
namespace Friendica\Module\Api\Twitter\Followers;
|
||||||
|
|
||||||
use Friendica\Core\System;
|
use Friendica\Core\System;
|
||||||
use Friendica\Model\Contact;
|
use Friendica\Database\DBA;
|
||||||
use Friendica\Module\Api\Twitter\ContactEndpoint;
|
use Friendica\Module\Api\Twitter\ContactEndpoint;
|
||||||
|
use Friendica\Module\BaseApi;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-followers-list
|
* @see https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-followers-list
|
||||||
*/
|
*/
|
||||||
class FollowersList extends ContactEndpoint
|
class Lists extends ContactEndpoint
|
||||||
{
|
{
|
||||||
public function rawContent()
|
public function rawContent()
|
||||||
{
|
{
|
||||||
|
self::checkAllowedScope(self::SCOPE_READ);
|
||||||
|
$uid = BaseApi::getCurrentUserID();
|
||||||
|
|
||||||
// Expected value for user_id parameter: public/user contact id
|
// Expected value for user_id parameter: public/user contact id
|
||||||
$contact_id = filter_input(INPUT_GET, 'user_id' , FILTER_VALIDATE_INT);
|
$contact_id = filter_input(INPUT_GET, 'user_id' , FILTER_VALIDATE_INT);
|
||||||
$screen_name = filter_input(INPUT_GET, 'screen_name');
|
$screen_name = filter_input(INPUT_GET, 'screen_name');
|
||||||
$cursor = filter_input(INPUT_GET, 'cursor' , FILTER_VALIDATE_INT);
|
$cursor = filter_input(INPUT_GET, 'cursor' , FILTER_VALIDATE_INT, ['options' => ['default' => -1]]);
|
||||||
|
$skip_status = filter_input(INPUT_GET, 'skip_status' , FILTER_VALIDATE_BOOLEAN, ['options' => ['default' => false]]);
|
||||||
|
$include_user_entities = filter_input(INPUT_GET, 'include_user_entities', FILTER_VALIDATE_BOOLEAN, ['options' => ['default' => false]]);
|
||||||
$count = filter_input(INPUT_GET, 'count' , FILTER_VALIDATE_INT, ['options' => [
|
$count = filter_input(INPUT_GET, 'count' , FILTER_VALIDATE_INT, ['options' => [
|
||||||
'default' => self::DEFAULT_COUNT,
|
'default' => self::DEFAULT_COUNT,
|
||||||
'min_range' => 1,
|
'min_range' => 1,
|
||||||
'max_range' => self::MAX_COUNT,
|
'max_range' => self::MAX_COUNT,
|
||||||
]]);
|
]]);
|
||||||
$skip_status = filter_input(INPUT_GET, 'skip_status' , FILTER_VALIDATE_BOOLEAN);
|
|
||||||
$include_user_entities = filter_input(INPUT_GET, 'include_user_entities', FILTER_VALIDATE_BOOLEAN);
|
|
||||||
|
|
||||||
// Friendica-specific
|
// Friendica-specific
|
||||||
$since_id = filter_input(INPUT_GET, 'since_id', FILTER_VALIDATE_INT);
|
$since_id = filter_input(INPUT_GET, 'since_id', FILTER_VALIDATE_INT);
|
||||||
$max_id = filter_input(INPUT_GET, 'max_id' , FILTER_VALIDATE_INT, ['options' => [
|
$max_id = filter_input(INPUT_GET, 'max_id' , FILTER_VALIDATE_INT);
|
||||||
'default' => 1,
|
$min_id = filter_input(INPUT_GET, 'min_id' , FILTER_VALIDATE_INT);
|
||||||
]]);
|
|
||||||
|
|
||||||
// @todo Use Model\Contact\Relation::listFollowers($cid, $condition, $count);
|
$cid = BaseApi::getContactIDForSearchterm($screen_name, $contact_id, $uid);
|
||||||
|
|
||||||
System::jsonExit(self::list(
|
$params = ['order' => ['relation-cid' => true], 'limit' => $count];
|
||||||
[Contact::FOLLOWER, Contact::FRIEND],
|
|
||||||
self::getUid($contact_id, $screen_name),
|
$condition = ['cid' => $cid, 'follows' => true];
|
||||||
$cursor ?? $since_id ?? - $max_id,
|
|
||||||
$count,
|
$total_count = (int)DBA::count('contact-relation', $condition);
|
||||||
$skip_status,
|
|
||||||
$include_user_entities
|
if (!empty($max_id)) {
|
||||||
));
|
$condition = DBA::mergeConditions($condition, ["`relation-cid` < ?", $max_id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($since_id)) {
|
||||||
|
$condition = DBA::mergeConditions($condition, ["`relation-cid` > ?", $since_id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($min_id)) {
|
||||||
|
$condition = DBA::mergeConditions($condition, ["`relation-cid` > ?", $min_id]);
|
||||||
|
|
||||||
|
$params['order'] = ['relation-cid'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$ids = [];
|
||||||
|
|
||||||
|
$followers = DBA::select('contact-relation', ['relation-cid'], $condition, $params);
|
||||||
|
while ($follower = DBA::fetch($followers)) {
|
||||||
|
self::setBoundaries($follower['relation-cid']);
|
||||||
|
$ids[] = $follower['relation-cid'];
|
||||||
|
}
|
||||||
|
DBA::close($followers);
|
||||||
|
|
||||||
|
if (!empty($min_id)) {
|
||||||
|
array_reverse($ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
$return = self::list($ids, $total_count, $uid, $cursor, $count, $skip_status, $include_user_entities);
|
||||||
|
|
||||||
|
self::setLinkHeader();
|
||||||
|
|
||||||
|
System::jsonExit($return);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,9 @@
|
||||||
namespace Friendica\Module\Api\Twitter\Friends;
|
namespace Friendica\Module\Api\Twitter\Friends;
|
||||||
|
|
||||||
use Friendica\Core\System;
|
use Friendica\Core\System;
|
||||||
use Friendica\Model\Contact;
|
use Friendica\Database\DBA;
|
||||||
use Friendica\Module\Api\Twitter\ContactEndpoint;
|
use Friendica\Module\Api\Twitter\ContactEndpoint;
|
||||||
|
use Friendica\Module\BaseApi;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friends-ids
|
* @see https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friends-ids
|
||||||
|
@ -32,11 +33,14 @@ class Ids extends ContactEndpoint
|
||||||
{
|
{
|
||||||
public function rawContent()
|
public function rawContent()
|
||||||
{
|
{
|
||||||
|
self::checkAllowedScope(self::SCOPE_READ);
|
||||||
|
$uid = BaseApi::getCurrentUserID();
|
||||||
|
|
||||||
// Expected value for user_id parameter: public/user contact id
|
// Expected value for user_id parameter: public/user contact id
|
||||||
$contact_id = filter_input(INPUT_GET, 'user_id' , FILTER_VALIDATE_INT);
|
$contact_id = filter_input(INPUT_GET, 'user_id' , FILTER_VALIDATE_INT);
|
||||||
$screen_name = filter_input(INPUT_GET, 'screen_name');
|
$screen_name = filter_input(INPUT_GET, 'screen_name');
|
||||||
$cursor = filter_input(INPUT_GET, 'cursor' , FILTER_VALIDATE_INT);
|
$cursor = filter_input(INPUT_GET, 'cursor' , FILTER_VALIDATE_INT, ['options' => ['default' => -1]]);
|
||||||
$stringify_ids = filter_input(INPUT_GET, 'stringify_ids', FILTER_VALIDATE_BOOLEAN);
|
$stringify_ids = filter_input(INPUT_GET, 'stringify_ids', FILTER_VALIDATE_BOOLEAN, ['options' => ['default' => false]]);
|
||||||
$count = filter_input(INPUT_GET, 'count' , FILTER_VALIDATE_INT, ['options' => [
|
$count = filter_input(INPUT_GET, 'count' , FILTER_VALIDATE_INT, ['options' => [
|
||||||
'default' => self::DEFAULT_COUNT,
|
'default' => self::DEFAULT_COUNT,
|
||||||
'min_range' => 1,
|
'min_range' => 1,
|
||||||
|
@ -44,18 +48,48 @@ class Ids extends ContactEndpoint
|
||||||
]]);
|
]]);
|
||||||
// Friendica-specific
|
// Friendica-specific
|
||||||
$since_id = filter_input(INPUT_GET, 'since_id' , FILTER_VALIDATE_INT);
|
$since_id = filter_input(INPUT_GET, 'since_id' , FILTER_VALIDATE_INT);
|
||||||
$max_id = filter_input(INPUT_GET, 'max_id' , FILTER_VALIDATE_INT, ['options' => [
|
$max_id = filter_input(INPUT_GET, 'max_id' , FILTER_VALIDATE_INT);
|
||||||
'default' => 1,
|
$min_id = filter_input(INPUT_GET, 'min_id' , FILTER_VALIDATE_INT);
|
||||||
]]);
|
|
||||||
|
|
||||||
// @todo Use Model\Contact\Relation::listFollows($cid, $condition, $count);
|
$cid = BaseApi::getContactIDForSearchterm($screen_name, $contact_id, $uid);
|
||||||
|
|
||||||
System::jsonExit(self::ids(
|
$params = ['order' => ['cid' => true], 'limit' => $count];
|
||||||
[Contact::SHARING, Contact::FRIEND],
|
|
||||||
self::getUid($contact_id, $screen_name),
|
$condition = ['relation-cid' => $cid, 'follows' => true];
|
||||||
$cursor ?? $since_id ?? - $max_id,
|
|
||||||
$count,
|
$total_count = (int)DBA::count('contact-relation', $condition);
|
||||||
$stringify_ids
|
|
||||||
));
|
if (!empty($max_id)) {
|
||||||
|
$condition = DBA::mergeConditions($condition, ["`cid` < ?", $max_id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($since_id)) {
|
||||||
|
$condition = DBA::mergeConditions($condition, ["`cid` > ?", $since_id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($min_id)) {
|
||||||
|
$condition = DBA::mergeConditions($condition, ["`cid` > ?", $min_id]);
|
||||||
|
|
||||||
|
$params['order'] = ['cid'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$ids = [];
|
||||||
|
|
||||||
|
$followers = DBA::select('contact-relation', ['cid'], $condition, $params);
|
||||||
|
while ($follower = DBA::fetch($followers)) {
|
||||||
|
self::setBoundaries($follower['cid']);
|
||||||
|
$ids[] = $follower['cid'];
|
||||||
|
}
|
||||||
|
DBA::close($followers);
|
||||||
|
|
||||||
|
if (!empty($min_id)) {
|
||||||
|
array_reverse($ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
$return = self::ids($ids, $total_count, $cursor, $count, $stringify_ids);
|
||||||
|
|
||||||
|
self::setLinkHeader();
|
||||||
|
|
||||||
|
System::jsonExit($return);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,9 @@
|
||||||
namespace Friendica\Module\Api\Twitter\Friends;
|
namespace Friendica\Module\Api\Twitter\Friends;
|
||||||
|
|
||||||
use Friendica\Core\System;
|
use Friendica\Core\System;
|
||||||
use Friendica\Model\Contact;
|
use Friendica\Database\DBA;
|
||||||
use Friendica\Module\Api\Twitter\ContactEndpoint;
|
use Friendica\Module\Api\Twitter\ContactEndpoint;
|
||||||
|
use Friendica\Module\BaseApi;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friends-list
|
* @see https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friends-list
|
||||||
|
@ -32,33 +33,64 @@ class Lists extends ContactEndpoint
|
||||||
{
|
{
|
||||||
public function rawContent()
|
public function rawContent()
|
||||||
{
|
{
|
||||||
|
self::checkAllowedScope(self::SCOPE_READ);
|
||||||
|
$uid = BaseApi::getCurrentUserID();
|
||||||
|
|
||||||
// Expected value for user_id parameter: public/user contact id
|
// Expected value for user_id parameter: public/user contact id
|
||||||
$contact_id = filter_input(INPUT_GET, 'user_id' , FILTER_VALIDATE_INT);
|
$contact_id = filter_input(INPUT_GET, 'user_id' , FILTER_VALIDATE_INT);
|
||||||
$screen_name = filter_input(INPUT_GET, 'screen_name');
|
$screen_name = filter_input(INPUT_GET, 'screen_name');
|
||||||
$cursor = filter_input(INPUT_GET, 'cursor' , FILTER_VALIDATE_INT);
|
$cursor = filter_input(INPUT_GET, 'cursor' , FILTER_VALIDATE_INT, ['options' => ['default' => -1]]);
|
||||||
|
$skip_status = filter_input(INPUT_GET, 'skip_status' , FILTER_VALIDATE_BOOLEAN, ['options' => ['default' => false]]);
|
||||||
|
$include_user_entities = filter_input(INPUT_GET, 'include_user_entities', FILTER_VALIDATE_BOOLEAN, ['options' => ['default' => false]]);
|
||||||
$count = filter_input(INPUT_GET, 'count' , FILTER_VALIDATE_INT, ['options' => [
|
$count = filter_input(INPUT_GET, 'count' , FILTER_VALIDATE_INT, ['options' => [
|
||||||
'default' => self::DEFAULT_COUNT,
|
'default' => self::DEFAULT_COUNT,
|
||||||
'min_range' => 1,
|
'min_range' => 1,
|
||||||
'max_range' => self::MAX_COUNT,
|
'max_range' => self::MAX_COUNT,
|
||||||
]]);
|
]]);
|
||||||
$skip_status = filter_input(INPUT_GET, 'skip_status' , FILTER_VALIDATE_BOOLEAN);
|
|
||||||
$include_user_entities = filter_input(INPUT_GET, 'include_user_entities', FILTER_VALIDATE_BOOLEAN);
|
|
||||||
|
|
||||||
// Friendica-specific
|
// Friendica-specific
|
||||||
$since_id = filter_input(INPUT_GET, 'since_id', FILTER_VALIDATE_INT);
|
$since_id = filter_input(INPUT_GET, 'since_id', FILTER_VALIDATE_INT);
|
||||||
$max_id = filter_input(INPUT_GET, 'max_id' , FILTER_VALIDATE_INT, ['options' => [
|
$max_id = filter_input(INPUT_GET, 'max_id' , FILTER_VALIDATE_INT);
|
||||||
'default' => 1,
|
$min_id = filter_input(INPUT_GET, 'min_id' , FILTER_VALIDATE_INT);
|
||||||
]]);
|
|
||||||
|
|
||||||
// @todo Use Model\Contact\Relation::listFollows($cid, $condition, $count);
|
$cid = BaseApi::getContactIDForSearchterm($screen_name, $contact_id, $uid);
|
||||||
|
|
||||||
System::jsonExit(self::list(
|
$params = ['order' => ['cid' => true], 'limit' => $count];
|
||||||
[Contact::SHARING, Contact::FRIEND],
|
|
||||||
self::getUid($contact_id, $screen_name),
|
$condition = ['relation-cid' => $cid, 'follows' => true];
|
||||||
$cursor ?? $since_id ?? - $max_id,
|
|
||||||
$count,
|
$total_count = (int)DBA::count('contact-relation', $condition);
|
||||||
$skip_status,
|
|
||||||
$include_user_entities
|
if (!empty($max_id)) {
|
||||||
));
|
$condition = DBA::mergeConditions($condition, ["`cid` < ?", $max_id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($since_id)) {
|
||||||
|
$condition = DBA::mergeConditions($condition, ["`cid` > ?", $since_id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($min_id)) {
|
||||||
|
$condition = DBA::mergeConditions($condition, ["`cid` > ?", $min_id]);
|
||||||
|
|
||||||
|
$params['order'] = ['cid'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$ids = [];
|
||||||
|
|
||||||
|
$followers = DBA::select('contact-relation', ['cid'], $condition, $params);
|
||||||
|
while ($follower = DBA::fetch($followers)) {
|
||||||
|
self::setBoundaries($follower['cid']);
|
||||||
|
$ids[] = $follower['cid'];
|
||||||
|
}
|
||||||
|
DBA::close($followers);
|
||||||
|
|
||||||
|
if (!empty($min_id)) {
|
||||||
|
array_reverse($ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
$return = self::list($ids, $total_count, $uid, $cursor, $count, $skip_status, $include_user_entities);
|
||||||
|
|
||||||
|
self::setLinkHeader();
|
||||||
|
|
||||||
|
System::jsonExit($return);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -293,7 +293,7 @@ class BaseApi extends BaseModule
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getContactIDForSearchterm(string $screen_name, int $cid, int $uid)
|
public static function getContactIDForSearchterm(string $screen_name = null, int $cid = null, int $uid)
|
||||||
{
|
{
|
||||||
if (!empty($cid)) {
|
if (!empty($cid)) {
|
||||||
return $cid;
|
return $cid;
|
||||||
|
|
|
@ -25,9 +25,7 @@ use Friendica\BaseModule;
|
||||||
use Friendica\Content\ContactSelector;
|
use Friendica\Content\ContactSelector;
|
||||||
use Friendica\Content\Nav;
|
use Friendica\Content\Nav;
|
||||||
use Friendica\Content\Pager;
|
use Friendica\Content\Pager;
|
||||||
use Friendica\Content\Text\BBCode;
|
|
||||||
use Friendica\Content\Widget;
|
use Friendica\Content\Widget;
|
||||||
use Friendica\Core\Hook;
|
|
||||||
use Friendica\Core\Protocol;
|
use Friendica\Core\Protocol;
|
||||||
use Friendica\Core\Renderer;
|
use Friendica\Core\Renderer;
|
||||||
use Friendica\Core\Theme;
|
use Friendica\Core\Theme;
|
||||||
|
@ -37,10 +35,7 @@ use Friendica\DI;
|
||||||
use Friendica\Model;
|
use Friendica\Model;
|
||||||
use Friendica\Model\User;
|
use Friendica\Model\User;
|
||||||
use Friendica\Module\Security\Login;
|
use Friendica\Module\Security\Login;
|
||||||
use Friendica\Network\HTTPException\BadRequestException;
|
|
||||||
use Friendica\Network\HTTPException\NotFoundException;
|
use Friendica\Network\HTTPException\NotFoundException;
|
||||||
use Friendica\Util\DateTimeFormat;
|
|
||||||
use Friendica\Util\Strings;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages and show Contacts and their content
|
* Manages and show Contacts and their content
|
||||||
|
@ -105,55 +100,7 @@ class Contact extends BaseModule
|
||||||
// @TODO: Replace with parameter from router
|
// @TODO: Replace with parameter from router
|
||||||
if (DI::args()->getArgv()[1] === 'batch') {
|
if (DI::args()->getArgv()[1] === 'batch') {
|
||||||
self::batchActions();
|
self::batchActions();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @TODO: Replace with parameter from router
|
|
||||||
$contact_id = intval(DI::args()->getArgv()[1]);
|
|
||||||
if (!$contact_id) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!DBA::exists('contact', ['id' => $contact_id, 'uid' => local_user(), 'deleted' => false])) {
|
|
||||||
notice(DI::l10n()->t('Could not access contact record.'));
|
|
||||||
DI::baseUrl()->redirect('contact');
|
|
||||||
return; // NOTREACHED
|
|
||||||
}
|
|
||||||
|
|
||||||
Hook::callAll('contact_edit_post', $_POST);
|
|
||||||
|
|
||||||
$hidden = !empty($_POST['hidden']);
|
|
||||||
|
|
||||||
$notify = !empty($_POST['notify']);
|
|
||||||
|
|
||||||
$fetch_further_information = intval($_POST['fetch_further_information'] ?? 0);
|
|
||||||
|
|
||||||
$remote_self = $_POST['remote_self'] ?? false;
|
|
||||||
|
|
||||||
$ffi_keyword_denylist = Strings::escapeHtml(trim($_POST['ffi_keyword_denylist'] ?? ''));
|
|
||||||
|
|
||||||
$priority = intval($_POST['poll'] ?? 0);
|
|
||||||
if ($priority > 5 || $priority < 0) {
|
|
||||||
$priority = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
$info = Strings::escapeHtml(trim($_POST['info'] ?? ''));
|
|
||||||
|
|
||||||
$r = Model\Contact::update([
|
|
||||||
'priority' => $priority,
|
|
||||||
'info' => $info,
|
|
||||||
'hidden' => $hidden,
|
|
||||||
'notify_new_posts' => $notify,
|
|
||||||
'fetch_further_information' => $fetch_further_information,
|
|
||||||
'remote_self' => $remote_self,
|
|
||||||
'ffi_keyword_denylist' => $ffi_keyword_denylist],
|
|
||||||
['id' => $contact_id, 'uid' => local_user()]
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!DBA::isResult($r)) {
|
|
||||||
notice(DI::l10n()->t('Failed to update contact record.'));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* contact actions */
|
/* contact actions */
|
||||||
|
@ -164,7 +111,7 @@ class Contact extends BaseModule
|
||||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||||
* @throws \ImagickException
|
* @throws \ImagickException
|
||||||
*/
|
*/
|
||||||
private static function updateContactFromPoll(int $contact_id)
|
public static function updateContactFromPoll(int $contact_id)
|
||||||
{
|
{
|
||||||
$contact = DBA::selectFirst('contact', ['uid', 'url', 'network'], ['id' => $contact_id, 'uid' => local_user(), 'deleted' => false]);
|
$contact = DBA::selectFirst('contact', ['uid', 'url', 'network'], ['id' => $contact_id, 'uid' => local_user(), 'deleted' => false]);
|
||||||
if (!DBA::isResult($contact)) {
|
if (!DBA::isResult($contact)) {
|
||||||
|
@ -185,22 +132,6 @@ class Contact extends BaseModule
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int $contact_id Id of the contact with uid != 0
|
|
||||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
|
||||||
* @throws \ImagickException
|
|
||||||
*/
|
|
||||||
private static function updateContactFromProbe(int $contact_id)
|
|
||||||
{
|
|
||||||
$contact = DBA::selectFirst('contact', ['url'], ['id' => $contact_id, 'uid' => local_user(), 'deleted' => false]);
|
|
||||||
if (!DBA::isResult($contact)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the entry in the contact table
|
|
||||||
Model\Contact::updateFromProbe($contact_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggles the blocked status of a contact identified by id.
|
* Toggles the blocked status of a contact identified by id.
|
||||||
*
|
*
|
||||||
|
@ -232,8 +163,6 @@ class Contact extends BaseModule
|
||||||
return Login::form($_SERVER['REQUEST_URI']);
|
return Login::form($_SERVER['REQUEST_URI']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$a = DI::app();
|
|
||||||
|
|
||||||
$search = trim($_GET['search'] ?? '');
|
$search = trim($_GET['search'] ?? '');
|
||||||
$nets = trim($_GET['nets'] ?? '');
|
$nets = trim($_GET['nets'] ?? '');
|
||||||
$rel = trim($_GET['rel'] ?? '');
|
$rel = trim($_GET['rel'] ?? '');
|
||||||
|
@ -249,57 +178,6 @@ class Contact extends BaseModule
|
||||||
$page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.css'));
|
$page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.css'));
|
||||||
$page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput-typeahead.css'));
|
$page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput-typeahead.css'));
|
||||||
|
|
||||||
$contact = null;
|
|
||||||
// @TODO: Replace with parameter from router
|
|
||||||
if (DI::args()->getArgc() == 2 && intval(DI::args()->getArgv()[1])
|
|
||||||
|| DI::args()->getArgc() == 3 && intval(DI::args()->getArgv()[1]) && in_array(DI::args()->getArgv()[2], ['posts', 'conversations'])
|
|
||||||
) {
|
|
||||||
$contact_id = intval(DI::args()->getArgv()[1]);
|
|
||||||
|
|
||||||
// Ensure to use the user contact when the public contact was provided
|
|
||||||
$data = Model\Contact::getPublicAndUserContactID($contact_id, local_user());
|
|
||||||
if (!empty($data['user']) && ($contact_id == $data['public'])) {
|
|
||||||
$contact_id = $data['user'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($data)) {
|
|
||||||
$contact = DBA::selectFirst('contact', [], [
|
|
||||||
'id' => $contact_id,
|
|
||||||
'uid' => [0, local_user()],
|
|
||||||
'deleted' => false
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Don't display contacts that are about to be deleted
|
|
||||||
if (DBA::isResult($contact) && !empty($contact['network']) && $contact['network'] == Protocol::PHANTOM) {
|
|
||||||
$contact = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DBA::isResult($contact)) {
|
|
||||||
if ($contact['self']) {
|
|
||||||
// @TODO: Replace with parameter from router
|
|
||||||
if ((DI::args()->getArgc() == 3) && intval(DI::args()->getArgv()[1]) && in_array(DI::args()->getArgv()[2], ['posts', 'conversations'])) {
|
|
||||||
DI::baseUrl()->redirect('profile/' . $contact['nick']);
|
|
||||||
} else {
|
|
||||||
DI::baseUrl()->redirect('profile/' . $contact['nick'] . '/profile');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$vcard_widget = Widget\VCard::getHTML($contact);
|
|
||||||
|
|
||||||
$findpeople_widget = '';
|
|
||||||
$follow_widget = '';
|
|
||||||
$account_widget = '';
|
|
||||||
$networks_widget = '';
|
|
||||||
$rel_widget = '';
|
|
||||||
|
|
||||||
if ($contact['uid'] != 0) {
|
|
||||||
$groups_widget = Model\Group::sidebarWidget('contact', 'group', 'full', 'everyone', $contact_id);
|
|
||||||
} else {
|
|
||||||
$groups_widget = '';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$vcard_widget = '';
|
$vcard_widget = '';
|
||||||
$findpeople_widget = Widget::findPeople();
|
$findpeople_widget = Widget::findPeople();
|
||||||
if (isset($_GET['add'])) {
|
if (isset($_GET['add'])) {
|
||||||
|
@ -312,7 +190,6 @@ class Contact extends BaseModule
|
||||||
$networks_widget = Widget::networks($_SERVER['REQUEST_URI'], $nets);
|
$networks_widget = Widget::networks($_SERVER['REQUEST_URI'], $nets);
|
||||||
$rel_widget = Widget::contactRels($_SERVER['REQUEST_URI'], $rel);
|
$rel_widget = Widget::contactRels($_SERVER['REQUEST_URI'], $rel);
|
||||||
$groups_widget = Widget::groups($_SERVER['REQUEST_URI'], $group);
|
$groups_widget = Widget::groups($_SERVER['REQUEST_URI'], $group);
|
||||||
}
|
|
||||||
|
|
||||||
DI::page()['aside'] .= $vcard_widget . $findpeople_widget . $follow_widget . $account_widget . $groups_widget . $networks_widget . $rel_widget;
|
DI::page()['aside'] .= $vcard_widget . $findpeople_widget . $follow_widget . $account_widget . $groups_widget . $networks_widget . $rel_widget;
|
||||||
|
|
||||||
|
@ -324,274 +201,8 @@ class Contact extends BaseModule
|
||||||
$o = '';
|
$o = '';
|
||||||
Nav::setSelected('contact');
|
Nav::setSelected('contact');
|
||||||
|
|
||||||
if (!local_user()) {
|
|
||||||
notice(DI::l10n()->t('Permission denied.'));
|
|
||||||
return Login::form();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DI::args()->getArgc() == 3) {
|
|
||||||
$contact_id = intval(DI::args()->getArgv()[1]);
|
|
||||||
if (!$contact_id) {
|
|
||||||
throw new BadRequestException();
|
|
||||||
}
|
|
||||||
|
|
||||||
// @TODO: Replace with parameter from router
|
|
||||||
$cmd = DI::args()->getArgv()[2];
|
|
||||||
|
|
||||||
$orig_record = DBA::selectFirst('contact', [], ['id' => $contact_id, 'uid' => [0, local_user()], 'self' => false, 'deleted' => false]);
|
|
||||||
if (!DBA::isResult($orig_record)) {
|
|
||||||
throw new NotFoundException(DI::l10n()->t('Contact not found'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($cmd === 'posts') {
|
|
||||||
return self::getPostsHTML($contact_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($cmd === 'conversations') {
|
|
||||||
return self::getConversationsHMTL($a, $contact_id, $update);
|
|
||||||
}
|
|
||||||
|
|
||||||
self::checkFormSecurityTokenRedirectOnError('contact/' . $contact_id, 'contact_action', 't');
|
|
||||||
|
|
||||||
$cdata = Model\Contact::getPublicAndUserContactID($orig_record['id'], local_user());
|
|
||||||
if (empty($cdata)) {
|
|
||||||
throw new NotFoundException(DI::l10n()->t('Contact not found'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($cmd === 'update' && $cdata['user']) {
|
|
||||||
self::updateContactFromPoll($cdata['user']);
|
|
||||||
DI::baseUrl()->redirect('contact/' . $contact_id);
|
|
||||||
// NOTREACHED
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($cmd === 'updateprofile' && $cdata['user']) {
|
|
||||||
self::updateContactFromProbe($cdata['user']);
|
|
||||||
DI::baseUrl()->redirect('contact/' . $contact_id);
|
|
||||||
// NOTREACHED
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($cmd === 'block') {
|
|
||||||
if (public_contact() === $cdata['public']) {
|
|
||||||
throw new BadRequestException(DI::l10n()->t('You can\'t block yourself'));
|
|
||||||
}
|
|
||||||
|
|
||||||
self::toggleBlockContact($cdata['public'], local_user());
|
|
||||||
|
|
||||||
$blocked = Model\Contact\User::isBlocked($contact_id, local_user());
|
|
||||||
info(($blocked ? DI::l10n()->t('Contact has been blocked') : DI::l10n()->t('Contact has been unblocked')));
|
|
||||||
|
|
||||||
DI::baseUrl()->redirect('contact/' . $contact_id);
|
|
||||||
// NOTREACHED
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($cmd === 'ignore') {
|
|
||||||
if (public_contact() === $cdata['public']) {
|
|
||||||
throw new BadRequestException(DI::l10n()->t('You can\'t ignore yourself'));
|
|
||||||
}
|
|
||||||
|
|
||||||
self::toggleIgnoreContact($cdata['public']);
|
|
||||||
|
|
||||||
$ignored = Model\Contact\User::isIgnored($cdata['public'], local_user());
|
|
||||||
info(($ignored ? DI::l10n()->t('Contact has been ignored') : DI::l10n()->t('Contact has been unignored')));
|
|
||||||
|
|
||||||
DI::baseUrl()->redirect('contact/' . $contact_id);
|
|
||||||
// NOTREACHED
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$_SESSION['return_path'] = DI::args()->getQueryString();
|
$_SESSION['return_path'] = DI::args()->getQueryString();
|
||||||
|
|
||||||
if (!empty($contact)) {
|
|
||||||
DI::page()['htmlhead'] .= Renderer::replaceMacros(Renderer::getMarkupTemplate('contact_head.tpl'), [
|
|
||||||
'$baseurl' => DI::baseUrl()->get(true),
|
|
||||||
]);
|
|
||||||
|
|
||||||
$contact['blocked'] = Model\Contact\User::isBlocked($contact['id'], local_user());
|
|
||||||
$contact['readonly'] = Model\Contact\User::isIgnored($contact['id'], local_user());
|
|
||||||
|
|
||||||
$relation_text = '';
|
|
||||||
switch ($contact['rel']) {
|
|
||||||
case Model\Contact::FRIEND:
|
|
||||||
$relation_text = DI::l10n()->t('You are mutual friends with %s');
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Model\Contact::FOLLOWER;
|
|
||||||
$relation_text = DI::l10n()->t('You are sharing with %s');
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Model\Contact::SHARING;
|
|
||||||
$relation_text = DI::l10n()->t('%s is sharing with you');
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($contact['uid'] == 0) {
|
|
||||||
$relation_text = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!in_array($contact['network'], array_merge(Protocol::FEDERATED, [Protocol::TWITTER]))) {
|
|
||||||
$relation_text = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$relation_text = sprintf($relation_text, $contact['name']);
|
|
||||||
|
|
||||||
$url = Model\Contact::magicLinkByContact($contact);
|
|
||||||
if (strpos($url, 'redir/') === 0) {
|
|
||||||
$sparkle = ' class="sparkle" ';
|
|
||||||
} else {
|
|
||||||
$sparkle = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$insecure = DI::l10n()->t('Private communications are not available for this contact.');
|
|
||||||
|
|
||||||
$last_update = (($contact['last-update'] <= DBA::NULL_DATETIME) ? DI::l10n()->t('Never') : DateTimeFormat::local($contact['last-update'], 'D, j M Y, g:i A'));
|
|
||||||
|
|
||||||
if ($contact['last-update'] > DBA::NULL_DATETIME) {
|
|
||||||
$last_update .= ' ' . ($contact['failed'] ? DI::l10n()->t('(Update was not successful)') : DI::l10n()->t('(Update was successful)'));
|
|
||||||
}
|
|
||||||
$lblsuggest = (($contact['network'] === Protocol::DFRN) ? DI::l10n()->t('Suggest friends') : '');
|
|
||||||
|
|
||||||
$poll_enabled = in_array($contact['network'], [Protocol::DFRN, Protocol::OSTATUS, Protocol::FEED, Protocol::MAIL]);
|
|
||||||
|
|
||||||
$nettype = DI::l10n()->t('Network type: %s', ContactSelector::networkToName($contact['network'], $contact['url'], $contact['protocol'], $contact['gsid']));
|
|
||||||
|
|
||||||
// tabs
|
|
||||||
$tab_str = self::getTabsHTML($contact, self::TAB_PROFILE);
|
|
||||||
|
|
||||||
$lost_contact = (($contact['archive'] && $contact['term-date'] > DBA::NULL_DATETIME && $contact['term-date'] < DateTimeFormat::utcNow()) ? DI::l10n()->t('Communications lost with this contact!') : '');
|
|
||||||
|
|
||||||
$fetch_further_information = null;
|
|
||||||
if ($contact['network'] == Protocol::FEED) {
|
|
||||||
$fetch_further_information = [
|
|
||||||
'fetch_further_information',
|
|
||||||
DI::l10n()->t('Fetch further information for feeds'),
|
|
||||||
$contact['fetch_further_information'],
|
|
||||||
DI::l10n()->t('Fetch information like preview pictures, title and teaser from the feed item. You can activate this if the feed doesn\'t contain much text. Keywords are taken from the meta header in the feed item and are posted as hash tags.'),
|
|
||||||
[
|
|
||||||
'0' => DI::l10n()->t('Disabled'),
|
|
||||||
'1' => DI::l10n()->t('Fetch information'),
|
|
||||||
'3' => DI::l10n()->t('Fetch keywords'),
|
|
||||||
'2' => DI::l10n()->t('Fetch information and keywords')
|
|
||||||
]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable remote self for everything except feeds.
|
|
||||||
// There is an issue when you repeat an item from maybe twitter and you got comments from friendica and twitter
|
|
||||||
// Problem is, you couldn't reply to both networks.
|
|
||||||
$allow_remote_self = in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::FEED, Protocol::DFRN, Protocol::DIASPORA, Protocol::TWITTER])
|
|
||||||
&& DI::config()->get('system', 'allow_users_remote_self');
|
|
||||||
|
|
||||||
if ($contact['network'] == Protocol::FEED) {
|
|
||||||
$remote_self_options = [Model\Contact::MIRROR_DEACTIVATED => DI::l10n()->t('No mirroring'),
|
|
||||||
Model\Contact::MIRROR_FORWARDED => DI::l10n()->t('Mirror as forwarded posting'),
|
|
||||||
Model\Contact::MIRROR_OWN_POST => DI::l10n()->t('Mirror as my own posting')];
|
|
||||||
} elseif (in_array($contact['network'], [Protocol::ACTIVITYPUB])) {
|
|
||||||
$remote_self_options = [Model\Contact::MIRROR_DEACTIVATED => DI::l10n()->t('No mirroring'),
|
|
||||||
Model\Contact::MIRROR_NATIVE_RESHARE => DI::l10n()->t('Native reshare')];
|
|
||||||
} elseif (in_array($contact['network'], [Protocol::DFRN])) {
|
|
||||||
$remote_self_options = [Model\Contact::MIRROR_DEACTIVATED => DI::l10n()->t('No mirroring'),
|
|
||||||
Model\Contact::MIRROR_OWN_POST => DI::l10n()->t('Mirror as my own posting'),
|
|
||||||
Model\Contact::MIRROR_NATIVE_RESHARE => DI::l10n()->t('Native reshare')];
|
|
||||||
} else {
|
|
||||||
$remote_self_options = [Model\Contact::MIRROR_DEACTIVATED => DI::l10n()->t('No mirroring'),
|
|
||||||
Model\Contact::MIRROR_OWN_POST => DI::l10n()->t('Mirror as my own posting')];
|
|
||||||
}
|
|
||||||
|
|
||||||
$poll_interval = null;
|
|
||||||
if ((($contact['network'] == Protocol::FEED) && !DI::config()->get('system', 'adjust_poll_frequency')) || ($contact['network'] == Protocol::MAIL)) {
|
|
||||||
$poll_interval = ContactSelector::pollInterval($contact['priority'], !$poll_enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load contactact related actions like hide, suggest, delete and others
|
|
||||||
$contact_actions = self::getContactActions($contact);
|
|
||||||
|
|
||||||
if ($contact['uid'] != 0) {
|
|
||||||
$lbl_info1 = DI::l10n()->t('Contact Information / Notes');
|
|
||||||
$contact_settings_label = DI::l10n()->t('Contact Settings');
|
|
||||||
} else {
|
|
||||||
$lbl_info1 = null;
|
|
||||||
$contact_settings_label = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$tpl = Renderer::getMarkupTemplate('contact_edit.tpl');
|
|
||||||
$o .= Renderer::replaceMacros($tpl, [
|
|
||||||
'$header' => DI::l10n()->t('Contact'),
|
|
||||||
'$tab_str' => $tab_str,
|
|
||||||
'$submit' => DI::l10n()->t('Submit'),
|
|
||||||
'$lbl_info1' => $lbl_info1,
|
|
||||||
'$lbl_info2' => DI::l10n()->t('Their personal note'),
|
|
||||||
'$reason' => trim($contact['reason']),
|
|
||||||
'$infedit' => DI::l10n()->t('Edit contact notes'),
|
|
||||||
'$common_link' => 'contact/' . $contact['id'] . '/contacts/common',
|
|
||||||
'$relation_text' => $relation_text,
|
|
||||||
'$visit' => DI::l10n()->t('Visit %s\'s profile [%s]', $contact['name'], $contact['url']),
|
|
||||||
'$blockunblock' => DI::l10n()->t('Block/Unblock contact'),
|
|
||||||
'$ignorecont' => DI::l10n()->t('Ignore contact'),
|
|
||||||
'$lblrecent' => DI::l10n()->t('View conversations'),
|
|
||||||
'$lblsuggest' => $lblsuggest,
|
|
||||||
'$nettype' => $nettype,
|
|
||||||
'$poll_interval' => $poll_interval,
|
|
||||||
'$poll_enabled' => $poll_enabled,
|
|
||||||
'$lastupdtext' => DI::l10n()->t('Last update:'),
|
|
||||||
'$lost_contact' => $lost_contact,
|
|
||||||
'$updpub' => DI::l10n()->t('Update public posts'),
|
|
||||||
'$last_update' => $last_update,
|
|
||||||
'$udnow' => DI::l10n()->t('Update now'),
|
|
||||||
'$contact_id' => $contact['id'],
|
|
||||||
'$block_text' => ($contact['blocked'] ? DI::l10n()->t('Unblock') : DI::l10n()->t('Block')),
|
|
||||||
'$ignore_text' => ($contact['readonly'] ? DI::l10n()->t('Unignore') : DI::l10n()->t('Ignore')),
|
|
||||||
'$insecure' => (in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::MAIL, Protocol::DIASPORA]) ? '' : $insecure),
|
|
||||||
'$info' => $contact['info'],
|
|
||||||
'$cinfo' => ['info', '', $contact['info'], ''],
|
|
||||||
'$blocked' => ($contact['blocked'] ? DI::l10n()->t('Currently blocked') : ''),
|
|
||||||
'$ignored' => ($contact['readonly'] ? DI::l10n()->t('Currently ignored') : ''),
|
|
||||||
'$archived' => ($contact['archive'] ? DI::l10n()->t('Currently archived') : ''),
|
|
||||||
'$pending' => ($contact['pending'] ? DI::l10n()->t('Awaiting connection acknowledge') : ''),
|
|
||||||
'$hidden' => ['hidden', DI::l10n()->t('Hide this contact from others'), ($contact['hidden'] == 1), DI::l10n()->t('Replies/likes to your public posts <strong>may</strong> still be visible')],
|
|
||||||
'$notify' => ['notify', DI::l10n()->t('Notification for new posts'), ($contact['notify_new_posts'] == 1), DI::l10n()->t('Send a notification of every new post of this contact')],
|
|
||||||
'$fetch_further_information' => $fetch_further_information,
|
|
||||||
'$ffi_keyword_denylist' => ['ffi_keyword_denylist', DI::l10n()->t('Keyword Deny List'), $contact['ffi_keyword_denylist'], DI::l10n()->t('Comma separated list of keywords that should not be converted to hashtags, when "Fetch information and keywords" is selected')],
|
|
||||||
'$photo' => Model\Contact::getPhoto($contact),
|
|
||||||
'$name' => $contact['name'],
|
|
||||||
'$sparkle' => $sparkle,
|
|
||||||
'$url' => $url,
|
|
||||||
'$profileurllabel'=> DI::l10n()->t('Profile URL'),
|
|
||||||
'$profileurl' => $contact['url'],
|
|
||||||
'$account_type' => Model\Contact::getAccountType($contact),
|
|
||||||
'$location' => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['location']),
|
|
||||||
'$location_label' => DI::l10n()->t('Location:'),
|
|
||||||
'$xmpp' => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['xmpp']),
|
|
||||||
'$xmpp_label' => DI::l10n()->t('XMPP:'),
|
|
||||||
'$matrix' => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['matrix']),
|
|
||||||
'$matrix_label' => DI::l10n()->t('Matrix:'),
|
|
||||||
'$about' => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['about'], BBCode::EXTERNAL),
|
|
||||||
'$about_label' => DI::l10n()->t('About:'),
|
|
||||||
'$keywords' => $contact['keywords'],
|
|
||||||
'$keywords_label' => DI::l10n()->t('Tags:'),
|
|
||||||
'$contact_action_button' => DI::l10n()->t('Actions'),
|
|
||||||
'$contact_actions'=> $contact_actions,
|
|
||||||
'$contact_status' => DI::l10n()->t('Status'),
|
|
||||||
'$contact_settings_label' => $contact_settings_label,
|
|
||||||
'$contact_profile_label' => DI::l10n()->t('Profile'),
|
|
||||||
'$allow_remote_self' => $allow_remote_self,
|
|
||||||
'$remote_self' => ['remote_self',
|
|
||||||
DI::l10n()->t('Mirror postings from this contact'),
|
|
||||||
$contact['remote_self'],
|
|
||||||
DI::l10n()->t('Mark this contact as remote_self, this will cause friendica to repost new entries from this contact.'),
|
|
||||||
$remote_self_options
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
|
|
||||||
$arr = ['contact' => $contact, 'output' => $o];
|
|
||||||
|
|
||||||
Hook::callAll('contact_edit', $arr);
|
|
||||||
|
|
||||||
return $arr['output'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$sql_values = [local_user()];
|
$sql_values = [local_user()];
|
||||||
|
|
||||||
// @TODO: Replace with parameter from router
|
// @TODO: Replace with parameter from router
|
||||||
|
@ -875,66 +486,6 @@ class Contact extends BaseModule
|
||||||
return $tab_str;
|
return $tab_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getConversationsHMTL($a, $contact_id, $update, $parent = 0)
|
|
||||||
{
|
|
||||||
$o = '';
|
|
||||||
|
|
||||||
if (!$update) {
|
|
||||||
// We need the editor here to be able to reshare an item.
|
|
||||||
if (local_user()) {
|
|
||||||
$o = DI::conversation()->statusEditor([], 0, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$contact = DBA::selectFirst('contact', ['uid', 'url', 'id'], ['id' => $contact_id, 'deleted' => false]);
|
|
||||||
|
|
||||||
if (!$update) {
|
|
||||||
$o .= self::getTabsHTML($contact, self::TAB_CONVERSATIONS);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DBA::isResult($contact)) {
|
|
||||||
if (!$update) {
|
|
||||||
$profiledata = Model\Contact::getByURLForUser($contact['url'], local_user());
|
|
||||||
DI::page()['aside'] = Widget\VCard::getHTML($profiledata);
|
|
||||||
} else {
|
|
||||||
DI::page()['aside'] = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($contact['uid'] == 0) {
|
|
||||||
$o .= Model\Contact::getPostsFromId($contact['id'], true, $update, $parent);
|
|
||||||
} else {
|
|
||||||
$o .= Model\Contact::getPostsFromUrl($contact['url'], true, $update, $parent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $o;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function getPostsHTML(int $contact_id)
|
|
||||||
{
|
|
||||||
$contact = DBA::selectFirst('contact', ['uid', 'url', 'id'], ['id' => $contact_id, 'deleted' => false]);
|
|
||||||
|
|
||||||
$o = self::getTabsHTML($contact, self::TAB_POSTS);
|
|
||||||
|
|
||||||
if (DBA::isResult($contact)) {
|
|
||||||
$profiledata = Model\Contact::getByURLForUser($contact['url'], local_user());
|
|
||||||
|
|
||||||
if (local_user() && in_array($profiledata['network'], Protocol::FEDERATED)) {
|
|
||||||
$profiledata['remoteconnect'] = DI::baseUrl() . '/follow?url=' . urlencode($profiledata['url']);
|
|
||||||
}
|
|
||||||
|
|
||||||
DI::page()['aside'] = Widget\VCard::getHTML($profiledata);
|
|
||||||
|
|
||||||
if ($contact['uid'] == 0) {
|
|
||||||
$o .= Model\Contact::getPostsFromId($contact['id']);
|
|
||||||
} else {
|
|
||||||
$o .= Model\Contact::getPostsFromUrl($contact['url']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $o;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the fields for the contact template
|
* Return the fields for the contact template
|
||||||
*
|
*
|
||||||
|
@ -1013,79 +564,4 @@ class Contact extends BaseModule
|
||||||
'network' => ContactSelector::networkToName($contact['network'], $contact['url'], $contact['protocol'], $contact['gsid']),
|
'network' => ContactSelector::networkToName($contact['network'], $contact['url'], $contact['protocol'], $contact['gsid']),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gives a array with actions which can performed to a given contact
|
|
||||||
*
|
|
||||||
* This includes actions like e.g. 'block', 'hide', 'delete' and others
|
|
||||||
*
|
|
||||||
* @param array $contact Data about the Contact
|
|
||||||
* @return array with contact related actions
|
|
||||||
*/
|
|
||||||
private static function getContactActions($contact)
|
|
||||||
{
|
|
||||||
$poll_enabled = in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::OSTATUS, Protocol::FEED, Protocol::MAIL]);
|
|
||||||
$contact_actions = [];
|
|
||||||
|
|
||||||
$formSecurityToken = self::getFormSecurityToken('contact_action');
|
|
||||||
|
|
||||||
// Provide friend suggestion only for Friendica contacts
|
|
||||||
if ($contact['network'] === Protocol::DFRN) {
|
|
||||||
$contact_actions['suggest'] = [
|
|
||||||
'label' => DI::l10n()->t('Suggest friends'),
|
|
||||||
'url' => 'fsuggest/' . $contact['id'],
|
|
||||||
'title' => '',
|
|
||||||
'sel' => '',
|
|
||||||
'id' => 'suggest',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($poll_enabled) {
|
|
||||||
$contact_actions['update'] = [
|
|
||||||
'label' => DI::l10n()->t('Update now'),
|
|
||||||
'url' => 'contact/' . $contact['id'] . '/update?t=' . $formSecurityToken,
|
|
||||||
'title' => '',
|
|
||||||
'sel' => '',
|
|
||||||
'id' => 'update',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (in_array($contact['network'], Protocol::NATIVE_SUPPORT)) {
|
|
||||||
$contact_actions['updateprofile'] = [
|
|
||||||
'label' => DI::l10n()->t('Refetch contact data'),
|
|
||||||
'url' => 'contact/' . $contact['id'] . '/updateprofile?t=' . $formSecurityToken,
|
|
||||||
'title' => '',
|
|
||||||
'sel' => '',
|
|
||||||
'id' => 'updateprofile',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
$contact_actions['block'] = [
|
|
||||||
'label' => (intval($contact['blocked']) ? DI::l10n()->t('Unblock') : DI::l10n()->t('Block')),
|
|
||||||
'url' => 'contact/' . $contact['id'] . '/block?t=' . $formSecurityToken,
|
|
||||||
'title' => DI::l10n()->t('Toggle Blocked status'),
|
|
||||||
'sel' => (intval($contact['blocked']) ? 'active' : ''),
|
|
||||||
'id' => 'toggle-block',
|
|
||||||
];
|
|
||||||
|
|
||||||
$contact_actions['ignore'] = [
|
|
||||||
'label' => (intval($contact['readonly']) ? DI::l10n()->t('Unignore') : DI::l10n()->t('Ignore')),
|
|
||||||
'url' => 'contact/' . $contact['id'] . '/ignore?t=' . $formSecurityToken,
|
|
||||||
'title' => DI::l10n()->t('Toggle Ignored status'),
|
|
||||||
'sel' => (intval($contact['readonly']) ? 'active' : ''),
|
|
||||||
'id' => 'toggle-ignore',
|
|
||||||
];
|
|
||||||
|
|
||||||
if ($contact['uid'] != 0 && Protocol::supportsRevokeFollow($contact['network']) && in_array($contact['rel'], [Model\Contact::FOLLOWER, Model\Contact::FRIEND])) {
|
|
||||||
$contact_actions['revoke_follow'] = [
|
|
||||||
'label' => DI::l10n()->t('Revoke Follow'),
|
|
||||||
'url' => 'contact/' . $contact['id'] . '/revoke',
|
|
||||||
'title' => DI::l10n()->t('Revoke the follow from this contact'),
|
|
||||||
'sel' => '',
|
|
||||||
'id' => 'revoke_follow',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $contact_actions;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
116
src/Module/Contact/Conversations.php
Normal file
116
src/Module/Contact/Conversations.php
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
<?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\Module\Contact;
|
||||||
|
|
||||||
|
use Friendica\App;
|
||||||
|
use Friendica\BaseModule;
|
||||||
|
use Friendica\Contact\LocalRelationship\Repository\LocalRelationship;
|
||||||
|
use Friendica\Content\Conversation;
|
||||||
|
use Friendica\Content\Nav;
|
||||||
|
use Friendica\Content\Widget;
|
||||||
|
use Friendica\Core\L10n;
|
||||||
|
use Friendica\Core\Protocol;
|
||||||
|
use Friendica\Core\Theme;
|
||||||
|
use Friendica\Model;
|
||||||
|
use Friendica\Module\Contact;
|
||||||
|
use Friendica\Module\Security\Login;
|
||||||
|
use Friendica\Network\HTTPException\NotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages and show Contacts and their content
|
||||||
|
*/
|
||||||
|
class Conversations extends BaseModule
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var App\Page
|
||||||
|
*/
|
||||||
|
private $page;
|
||||||
|
/**
|
||||||
|
* @var Conversation
|
||||||
|
*/
|
||||||
|
private $conversation;
|
||||||
|
/**
|
||||||
|
* @var App\BaseURL
|
||||||
|
*/
|
||||||
|
private $baseUrl;
|
||||||
|
/**
|
||||||
|
* @var LocalRelationship
|
||||||
|
*/
|
||||||
|
private $localRelationship;
|
||||||
|
|
||||||
|
public function __construct(L10n $l10n, LocalRelationship $localRelationship, App\BaseURL $baseUrl, App\Page $page, Conversation $conversation, array $parameters = [])
|
||||||
|
{
|
||||||
|
parent::__construct($l10n, $parameters);
|
||||||
|
|
||||||
|
$this->page = $page;
|
||||||
|
$this->conversation = $conversation;
|
||||||
|
$this->baseUrl = $baseUrl;
|
||||||
|
$this->localRelationship = $localRelationship;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function content(): string
|
||||||
|
{
|
||||||
|
if (!local_user()) {
|
||||||
|
return Login::form($_SERVER['REQUEST_URI']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backward compatibility: Ensure to use the public contact when the user contact is provided
|
||||||
|
// Remove by version 2022.03
|
||||||
|
$data = Model\Contact::getPublicAndUserContactID(intval($this->parameters['id']), local_user());
|
||||||
|
if (empty($data)) {
|
||||||
|
throw new NotFoundException($this->t('Contact not found.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$contact = Model\Contact::getById($data['public']);
|
||||||
|
if (empty($contact)) {
|
||||||
|
throw new NotFoundException($this->t('Contact not found.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't display contacts that are about to be deleted
|
||||||
|
if (!empty($contact['deleted']) || !empty($contact['network']) && $contact['network'] == Protocol::PHANTOM) {
|
||||||
|
throw new NotFoundException($this->t('Contact not found.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$localRelationship = $this->localRelationship->getForUserContact(local_user(), $contact['id']);
|
||||||
|
if ($localRelationship->rel === Model\Contact::SELF) {
|
||||||
|
$this->baseUrl->redirect('profile/' . $contact['nick']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load necessary libraries for the status editor
|
||||||
|
$this->page->registerFooterScript(Theme::getPathForFile('asset/typeahead.js/dist/typeahead.bundle.js'));
|
||||||
|
$this->page->registerFooterScript(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.js'));
|
||||||
|
$this->page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.css'));
|
||||||
|
$this->page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput-typeahead.css'));
|
||||||
|
|
||||||
|
$this->page['aside'] .= Widget\VCard::getHTML($contact);
|
||||||
|
|
||||||
|
Nav::setSelected('contact');
|
||||||
|
|
||||||
|
// We need the editor here to be able to reshare an item.
|
||||||
|
$o = $this->conversation->statusEditor([], 0, true);
|
||||||
|
|
||||||
|
$o .= Contact::getTabsHTML($contact, Contact::TAB_CONVERSATIONS);
|
||||||
|
$o .= Model\Contact::getPostsFromId($contact['id'], true);
|
||||||
|
|
||||||
|
return $o;
|
||||||
|
}
|
||||||
|
}
|
102
src/Module/Contact/Posts.php
Normal file
102
src/Module/Contact/Posts.php
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
<?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\Module\Contact;
|
||||||
|
|
||||||
|
use Friendica\App;
|
||||||
|
use Friendica\BaseModule;
|
||||||
|
use Friendica\Contact\LocalRelationship\Repository\LocalRelationship;
|
||||||
|
use Friendica\Content\Nav;
|
||||||
|
use Friendica\Content\Widget;
|
||||||
|
use Friendica\Core\L10n;
|
||||||
|
use Friendica\Core\Protocol;
|
||||||
|
use Friendica\Database\DBA;
|
||||||
|
use Friendica\Model;
|
||||||
|
use Friendica\Module\Contact;
|
||||||
|
use Friendica\Module\Security\Login;
|
||||||
|
use Friendica\Network\HTTPException\NotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show a contact posts and comments
|
||||||
|
*/
|
||||||
|
class Posts extends BaseModule
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var LocalRelationship
|
||||||
|
*/
|
||||||
|
private $localRelationship;
|
||||||
|
/**
|
||||||
|
* @var App\BaseURL
|
||||||
|
*/
|
||||||
|
private $baseUrl;
|
||||||
|
/**
|
||||||
|
* @var App\Page
|
||||||
|
*/
|
||||||
|
private $page;
|
||||||
|
|
||||||
|
public function __construct(L10n $l10n, LocalRelationship $localRelationship, App\BaseURL $baseUrl, App\Page $page, array $parameters = [])
|
||||||
|
{
|
||||||
|
parent::__construct($l10n, $parameters);
|
||||||
|
|
||||||
|
$this->localRelationship = $localRelationship;
|
||||||
|
$this->baseUrl = $baseUrl;
|
||||||
|
$this->page = $page;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function content(): string
|
||||||
|
{
|
||||||
|
if (!local_user()) {
|
||||||
|
return Login::form($_SERVER['REQUEST_URI']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backward compatibility: Ensure to use the public contact when the user contact is provided
|
||||||
|
// Remove by version 2022.03
|
||||||
|
$data = Model\Contact::getPublicAndUserContactID(intval($this->parameters['id']), local_user());
|
||||||
|
if (empty($data)) {
|
||||||
|
throw new NotFoundException($this->t('Contact not found.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$contact = Model\Contact::getById($data['public']);
|
||||||
|
if (!DBA::isResult($contact)) {
|
||||||
|
throw new NotFoundException($this->t('Contact not found.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't display contacts that are about to be deleted
|
||||||
|
if (DBA::isResult($contact) && (!empty($contact['deleted']) || !empty($contact['network']) && $contact['network'] == Protocol::PHANTOM)) {
|
||||||
|
throw new NotFoundException($this->t('Contact not found.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$localRelationship = $this->localRelationship->getForUserContact(local_user(), $contact['id']);
|
||||||
|
if ($localRelationship->rel === Model\Contact::SELF) {
|
||||||
|
$this->baseUrl->redirect('profile/' . $contact['nick']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->page['aside'] .= Widget\VCard::getHTML($contact);
|
||||||
|
|
||||||
|
Nav::setSelected('contact');
|
||||||
|
|
||||||
|
$o = Contact::getTabsHTML($contact, Contact::TAB_POSTS);
|
||||||
|
|
||||||
|
$o .= Model\Contact::getPostsFromId($contact['id']);
|
||||||
|
|
||||||
|
return $o;
|
||||||
|
}
|
||||||
|
}
|
499
src/Module/Contact/Profile.php
Normal file
499
src/Module/Contact/Profile.php
Normal file
|
@ -0,0 +1,499 @@
|
||||||
|
<?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\Module\Contact;
|
||||||
|
|
||||||
|
use Friendica\App;
|
||||||
|
use Friendica\BaseModule;
|
||||||
|
use Friendica\Contact\LocalRelationship\Entity;
|
||||||
|
use Friendica\Contact\LocalRelationship\Repository;
|
||||||
|
use Friendica\Content\ContactSelector;
|
||||||
|
use Friendica\Content\Nav;
|
||||||
|
use Friendica\Content\Text\BBCode;
|
||||||
|
use Friendica\Content\Widget;
|
||||||
|
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||||
|
use Friendica\Core\Hook;
|
||||||
|
use Friendica\Core\L10n;
|
||||||
|
use Friendica\Core\Protocol;
|
||||||
|
use Friendica\Core\Renderer;
|
||||||
|
use Friendica\Database\DBA;
|
||||||
|
use Friendica\Model\Contact;
|
||||||
|
use Friendica\Model\Group;
|
||||||
|
use Friendica\Module;
|
||||||
|
use Friendica\Network\HTTPException;
|
||||||
|
use Friendica\Util\DateTimeFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show a contact profile
|
||||||
|
*/
|
||||||
|
class Profile extends BaseModule
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Repository\LocalRelationship
|
||||||
|
*/
|
||||||
|
private $localRelationship;
|
||||||
|
/**
|
||||||
|
* @var App\BaseURL
|
||||||
|
*/
|
||||||
|
private $baseUrl;
|
||||||
|
/**
|
||||||
|
* @var App\Page
|
||||||
|
*/
|
||||||
|
private $page;
|
||||||
|
/**
|
||||||
|
* @var App\Arguments
|
||||||
|
*/
|
||||||
|
private $args;
|
||||||
|
/**
|
||||||
|
* @var IManageConfigValues
|
||||||
|
*/
|
||||||
|
private $config;
|
||||||
|
|
||||||
|
public function __construct(L10n $l10n, Repository\LocalRelationship $localRelationship, App\BaseURL $baseUrl, App\Page $page, App\Arguments $args, IManageConfigValues $config, array $parameters = [])
|
||||||
|
{
|
||||||
|
parent::__construct($l10n, $parameters);
|
||||||
|
|
||||||
|
$this->localRelationship = $localRelationship;
|
||||||
|
$this->baseUrl = $baseUrl;
|
||||||
|
$this->page = $page;
|
||||||
|
$this->args = $args;
|
||||||
|
$this->config = $config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function post()
|
||||||
|
{
|
||||||
|
if (!local_user()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$contact_id = $this->parameters['id'];
|
||||||
|
|
||||||
|
// Backward compatibility: The update still needs a user-specific contact ID
|
||||||
|
// Change to user-contact table check by version 2022.03
|
||||||
|
$cdata = Contact::getPublicAndUserContactID($contact_id, local_user());
|
||||||
|
if (empty($cdata['user']) || !DBA::exists('contact', ['id' => $cdata['user'], 'deleted' => false])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Hook::callAll('contact_edit_post', $_POST);
|
||||||
|
|
||||||
|
$fields = [];
|
||||||
|
|
||||||
|
if (isset($_POST['hidden'])) {
|
||||||
|
$fields['hidden'] = !empty($_POST['hidden']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_POST['notify'])) {
|
||||||
|
$fields['notify'] = !empty($_POST['notify']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_POST['fetch_further_information'])) {
|
||||||
|
$fields['fetch_further_information'] = intval($_POST['fetch_further_information']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_POST['remote_self'])) {
|
||||||
|
$fields['remote_self'] = intval($_POST['remote_self']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_POST['ffi_keyword_denylist'])) {
|
||||||
|
$fields['ffi_keyword_denylist'] = $_POST['ffi_keyword_denylist'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_POST['poll'])) {
|
||||||
|
$priority = intval($_POST['poll']);
|
||||||
|
if ($priority > 5 || $priority < 0) {
|
||||||
|
$priority = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fields['priority'] = $priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_POST['info'])) {
|
||||||
|
$fields['info'] = $_POST['info'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Contact::update($fields, ['id' => $cdata['user'], 'uid' => local_user()])) {
|
||||||
|
notice($this->t('Failed to update contact record.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function content(): string
|
||||||
|
{
|
||||||
|
if (!local_user()) {
|
||||||
|
return Module\Security\Login::form($_SERVER['REQUEST_URI']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backward compatibility: Ensure to use the public contact when the user contact is provided
|
||||||
|
// Remove by version 2022.03
|
||||||
|
$data = Contact::getPublicAndUserContactID(intval($this->parameters['id']), local_user());
|
||||||
|
if (empty($data)) {
|
||||||
|
throw new HTTPException\NotFoundException($this->t('Contact not found.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$contact = Contact::getById($data['public']);
|
||||||
|
if (!DBA::isResult($contact)) {
|
||||||
|
throw new HTTPException\NotFoundException($this->t('Contact not found.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't display contacts that are about to be deleted
|
||||||
|
if (DBA::isResult($contact) && (!empty($contact['deleted']) || !empty($contact['network']) && $contact['network'] == Protocol::PHANTOM)) {
|
||||||
|
throw new HTTPException\NotFoundException($this->t('Contact not found.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$localRelationship = $this->localRelationship->getForUserContact(local_user(), $contact['id']);
|
||||||
|
|
||||||
|
if ($localRelationship->rel === Contact::SELF) {
|
||||||
|
$this->baseUrl->redirect('profile/' . $contact['nick'] . '/profile');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($parameters['action'])) {
|
||||||
|
self::checkFormSecurityTokenRedirectOnError('contact/' . $contact['id'], 'contact_action', 't');
|
||||||
|
|
||||||
|
$cmd = $parameters['action'];
|
||||||
|
if ($cmd === 'update' && $localRelationship->rel !== Contact::NOTHING) {
|
||||||
|
Module\Contact::updateContactFromPoll($contact['id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($cmd === 'updateprofile' && $localRelationship->rel !== Contact::NOTHING) {
|
||||||
|
self::updateContactFromProbe($contact['id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($cmd === 'block') {
|
||||||
|
if ($localRelationship->blocked) {
|
||||||
|
// @TODO Backward compatibility, replace with $localRelationship->unblock()
|
||||||
|
Contact\User::setBlocked($contact['id'], local_user(), false);
|
||||||
|
|
||||||
|
$message = $this->t('Contact has been unblocked');
|
||||||
|
} else {
|
||||||
|
// @TODO Backward compatibility, replace with $localRelationship->block()
|
||||||
|
Contact\User::setBlocked($contact['id'], local_user(), true);
|
||||||
|
$message = $this->t('Contact has been blocked');
|
||||||
|
}
|
||||||
|
|
||||||
|
// @TODO: add $this->localRelationship->save($localRelationship);
|
||||||
|
info($message);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($cmd === 'ignore') {
|
||||||
|
if ($localRelationship->ignored) {
|
||||||
|
// @TODO Backward compatibility, replace with $localRelationship->unblock()
|
||||||
|
Contact\User::setIgnored($contact['id'], local_user(), false);
|
||||||
|
|
||||||
|
$message = $this->t('Contact has been unignored');
|
||||||
|
} else {
|
||||||
|
// @TODO Backward compatibility, replace with $localRelationship->block()
|
||||||
|
Contact\User::setIgnored($contact['id'], local_user(), true);
|
||||||
|
$message = $this->t('Contact has been ignored');
|
||||||
|
}
|
||||||
|
|
||||||
|
// @TODO: add $this->localRelationship->save($localRelationship);
|
||||||
|
info($message);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->baseUrl->redirect('contact/' . $contact['id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$vcard_widget = Widget\VCard::getHTML($contact);
|
||||||
|
$groups_widget = '';
|
||||||
|
|
||||||
|
if (!in_array($localRelationship->rel, [Contact::NOTHING, Contact::SELF])) {
|
||||||
|
$groups_widget = Group::sidebarWidget('contact', 'group', 'full', 'everyone', $contact['id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->page['aside'] .= $vcard_widget . $groups_widget;
|
||||||
|
|
||||||
|
$o = '';
|
||||||
|
Nav::setSelected('contact');
|
||||||
|
|
||||||
|
$_SESSION['return_path'] = $this->args->getQueryString();
|
||||||
|
|
||||||
|
$this->page['htmlhead'] .= Renderer::replaceMacros(Renderer::getMarkupTemplate('contact_head.tpl'), [
|
||||||
|
'$baseurl' => $this->baseUrl->get(true),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$contact['blocked'] = Contact\User::isBlocked($contact['id'], local_user());
|
||||||
|
$contact['readonly'] = Contact\User::isIgnored($contact['id'], local_user());
|
||||||
|
|
||||||
|
switch ($localRelationship->rel) {
|
||||||
|
case Contact::FRIEND: $relation_text = $this->t('You are mutual friends with %s', $contact['name']); break;
|
||||||
|
case Contact::FOLLOWER: $relation_text = $this->t('You are sharing with %s', $contact['name']); break;
|
||||||
|
case Contact::SHARING: $relation_text = $this->t('%s is sharing with you', $contact['name']); break;
|
||||||
|
default:
|
||||||
|
$relation_text = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!in_array($contact['network'], array_merge(Protocol::FEDERATED, [Protocol::TWITTER]))) {
|
||||||
|
$relation_text = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$url = Contact::magicLinkByContact($contact);
|
||||||
|
if (strpos($url, 'redir/') === 0) {
|
||||||
|
$sparkle = ' class="sparkle" ';
|
||||||
|
} else {
|
||||||
|
$sparkle = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$insecure = $this->t('Private communications are not available for this contact.');
|
||||||
|
|
||||||
|
$last_update = (($contact['last-update'] <= DBA::NULL_DATETIME) ? $this->t('Never') : DateTimeFormat::local($contact['last-update'], 'D, j M Y, g:i A'));
|
||||||
|
|
||||||
|
if ($contact['last-update'] > DBA::NULL_DATETIME) {
|
||||||
|
$last_update .= ' ' . ($contact['failed'] ? $this->t('(Update was not successful)') : $this->t('(Update was successful)'));
|
||||||
|
}
|
||||||
|
$lblsuggest = (($contact['network'] === Protocol::DFRN) ? $this->t('Suggest friends') : '');
|
||||||
|
|
||||||
|
$poll_enabled = in_array($contact['network'], [Protocol::DFRN, Protocol::OSTATUS, Protocol::FEED, Protocol::MAIL]);
|
||||||
|
|
||||||
|
$nettype = $this->t('Network type: %s', ContactSelector::networkToName($contact['network'], $contact['url'], $contact['protocol'], $contact['gsid']));
|
||||||
|
|
||||||
|
// tabs
|
||||||
|
$tab_str = Module\Contact::getTabsHTML($contact, Module\Contact::TAB_PROFILE);
|
||||||
|
|
||||||
|
$lost_contact = (($contact['archive'] && $contact['term-date'] > DBA::NULL_DATETIME && $contact['term-date'] < DateTimeFormat::utcNow()) ? $this->t('Communications lost with this contact!') : '');
|
||||||
|
|
||||||
|
$fetch_further_information = null;
|
||||||
|
if ($contact['network'] == Protocol::FEED) {
|
||||||
|
$fetch_further_information = [
|
||||||
|
'fetch_further_information',
|
||||||
|
$this->t('Fetch further information for feeds'),
|
||||||
|
$localRelationship->fetchFurtherInformation,
|
||||||
|
$this->t('Fetch information like preview pictures, title and teaser from the feed item. You can activate this if the feed doesn\'t contain much text. Keywords are taken from the meta header in the feed item and are posted as hash tags.'),
|
||||||
|
[
|
||||||
|
'0' => $this->t('Disabled'),
|
||||||
|
'1' => $this->t('Fetch information'),
|
||||||
|
'3' => $this->t('Fetch keywords'),
|
||||||
|
'2' => $this->t('Fetch information and keywords')
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$allow_remote_self = in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::FEED, Protocol::DFRN, Protocol::DIASPORA, Protocol::TWITTER])
|
||||||
|
&& $this->config->get('system', 'allow_users_remote_self');
|
||||||
|
|
||||||
|
if ($contact['network'] == Protocol::FEED) {
|
||||||
|
$remote_self_options = [
|
||||||
|
Contact::MIRROR_DEACTIVATED => $this->t('No mirroring'),
|
||||||
|
Contact::MIRROR_FORWARDED => $this->t('Mirror as forwarded posting'),
|
||||||
|
Contact::MIRROR_OWN_POST => $this->t('Mirror as my own posting')
|
||||||
|
];
|
||||||
|
} elseif ($contact['network'] == Protocol::ACTIVITYPUB) {
|
||||||
|
$remote_self_options = [
|
||||||
|
Contact::MIRROR_DEACTIVATED => $this->t('No mirroring'),
|
||||||
|
Contact::MIRROR_NATIVE_RESHARE => $this->t('Native reshare')
|
||||||
|
];
|
||||||
|
} elseif ($contact['network'] == Protocol::DFRN) {
|
||||||
|
$remote_self_options = [
|
||||||
|
Contact::MIRROR_DEACTIVATED => $this->t('No mirroring'),
|
||||||
|
Contact::MIRROR_OWN_POST => $this->t('Mirror as my own posting'),
|
||||||
|
Contact::MIRROR_NATIVE_RESHARE => $this->t('Native reshare')
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$remote_self_options = [
|
||||||
|
Contact::MIRROR_DEACTIVATED => $this->t('No mirroring'),
|
||||||
|
Contact::MIRROR_OWN_POST => $this->t('Mirror as my own posting')
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$poll_interval = null;
|
||||||
|
if ((($contact['network'] == Protocol::FEED) && !$this->config->get('system', 'adjust_poll_frequency')) || ($contact['network'] == Protocol::MAIL)) {
|
||||||
|
$poll_interval = ContactSelector::pollInterval($localRelationship->priority, !$poll_enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
$contact_actions = $this->getContactActions($contact, $localRelationship);
|
||||||
|
|
||||||
|
if ($localRelationship->rel !== Contact::NOTHING) {
|
||||||
|
$lbl_info1 = $this->t('Contact Information / Notes');
|
||||||
|
$contact_settings_label = $this->t('Contact Settings');
|
||||||
|
} else {
|
||||||
|
$lbl_info1 = null;
|
||||||
|
$contact_settings_label = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$tpl = Renderer::getMarkupTemplate('contact_edit.tpl');
|
||||||
|
$o .= Renderer::replaceMacros($tpl, [
|
||||||
|
'$header' => $this->t('Contact'),
|
||||||
|
'$tab_str' => $tab_str,
|
||||||
|
'$submit' => $this->t('Submit'),
|
||||||
|
'$lbl_info1' => $lbl_info1,
|
||||||
|
'$lbl_info2' => $this->t('Their personal note'),
|
||||||
|
'$reason' => trim($contact['reason']),
|
||||||
|
'$infedit' => $this->t('Edit contact notes'),
|
||||||
|
'$common_link' => 'contact/' . $contact['id'] . '/contacts/common',
|
||||||
|
'$relation_text' => $relation_text,
|
||||||
|
'$visit' => $this->t('Visit %s\'s profile [%s]', $contact['name'], $contact['url']),
|
||||||
|
'$blockunblock' => $this->t('Block/Unblock contact'),
|
||||||
|
'$ignorecont' => $this->t('Ignore contact'),
|
||||||
|
'$lblrecent' => $this->t('View conversations'),
|
||||||
|
'$lblsuggest' => $lblsuggest,
|
||||||
|
'$nettype' => $nettype,
|
||||||
|
'$poll_interval' => $poll_interval,
|
||||||
|
'$poll_enabled' => $poll_enabled,
|
||||||
|
'$lastupdtext' => $this->t('Last update:'),
|
||||||
|
'$lost_contact' => $lost_contact,
|
||||||
|
'$updpub' => $this->t('Update public posts'),
|
||||||
|
'$last_update' => $last_update,
|
||||||
|
'$udnow' => $this->t('Update now'),
|
||||||
|
'$contact_id' => $contact['id'],
|
||||||
|
'$block_text' => ($contact['blocked'] ? $this->t('Unblock') : $this->t('Block')),
|
||||||
|
'$ignore_text' => ($contact['readonly'] ? $this->t('Unignore') : $this->t('Ignore')),
|
||||||
|
'$insecure' => (in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::MAIL, Protocol::DIASPORA]) ? '' : $insecure),
|
||||||
|
'$info' => $localRelationship->info,
|
||||||
|
'$cinfo' => ['info', '', $localRelationship->info, ''],
|
||||||
|
'$blocked' => ($contact['blocked'] ? $this->t('Currently blocked') : ''),
|
||||||
|
'$ignored' => ($contact['readonly'] ? $this->t('Currently ignored') : ''),
|
||||||
|
'$archived' => ($contact['archive'] ? $this->t('Currently archived') : ''),
|
||||||
|
'$pending' => ($contact['pending'] ? $this->t('Awaiting connection acknowledge') : ''),
|
||||||
|
'$hidden' => ['hidden', $this->t('Hide this contact from others'), $localRelationship->hidden, $this->t('Replies/likes to your public posts <strong>may</strong> still be visible')],
|
||||||
|
'$notify' => ['notify', $this->t('Notification for new posts'), ($contact['notify_new_posts'] == 1), $this->t('Send a notification of every new post of this contact')],
|
||||||
|
'$fetch_further_information' => $fetch_further_information,
|
||||||
|
'$ffi_keyword_denylist' => ['ffi_keyword_denylist', $this->t('Keyword Deny List'), $localRelationship->ffiKeywordDenylist, $this->t('Comma separated list of keywords that should not be converted to hashtags, when "Fetch information and keywords" is selected')],
|
||||||
|
'$photo' => Contact::getPhoto($contact),
|
||||||
|
'$name' => $contact['name'],
|
||||||
|
'$sparkle' => $sparkle,
|
||||||
|
'$url' => $url,
|
||||||
|
'$profileurllabel' => $this->t('Profile URL'),
|
||||||
|
'$profileurl' => $contact['url'],
|
||||||
|
'$account_type' => Contact::getAccountType($contact),
|
||||||
|
'$location' => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['location']),
|
||||||
|
'$location_label' => $this->t('Location:'),
|
||||||
|
'$xmpp' => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['xmpp']),
|
||||||
|
'$xmpp_label' => $this->t('XMPP:'),
|
||||||
|
'$matrix' => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['matrix']),
|
||||||
|
'$matrix_label' => $this->t('Matrix:'),
|
||||||
|
'$about' => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['about'], BBCode::EXTERNAL),
|
||||||
|
'$about_label' => $this->t('About:'),
|
||||||
|
'$keywords' => $contact['keywords'],
|
||||||
|
'$keywords_label' => $this->t('Tags:'),
|
||||||
|
'$contact_action_button' => $this->t('Actions'),
|
||||||
|
'$contact_actions' => $contact_actions,
|
||||||
|
'$contact_status' => $this->t('Status'),
|
||||||
|
'$contact_settings_label' => $contact_settings_label,
|
||||||
|
'$contact_profile_label' => $this->t('Profile'),
|
||||||
|
'$allow_remote_self' => $allow_remote_self,
|
||||||
|
'$remote_self' => [
|
||||||
|
'remote_self',
|
||||||
|
$this->t('Mirror postings from this contact'),
|
||||||
|
$localRelationship->isRemoteSelf,
|
||||||
|
$this->t('Mark this contact as remote_self, this will cause friendica to repost new entries from this contact.'),
|
||||||
|
$remote_self_options
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$arr = ['contact' => $contact, 'output' => $o];
|
||||||
|
|
||||||
|
Hook::callAll('contact_edit', $arr);
|
||||||
|
|
||||||
|
return $arr['output'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of available actions that can performed on the provided contact
|
||||||
|
*
|
||||||
|
* This includes actions like e.g. 'block', 'hide', 'delete' and others
|
||||||
|
*
|
||||||
|
* @param array $contact Public contact row
|
||||||
|
* @param Entity\LocalRelationship $localRelationship
|
||||||
|
* @return array with contact related actions
|
||||||
|
* @throws HTTPException\InternalServerErrorException
|
||||||
|
*/
|
||||||
|
private function getContactActions(array $contact, Entity\LocalRelationship $localRelationship): array
|
||||||
|
{
|
||||||
|
$poll_enabled = in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::OSTATUS, Protocol::FEED, Protocol::MAIL]);
|
||||||
|
$contact_actions = [];
|
||||||
|
|
||||||
|
$formSecurityToken = self::getFormSecurityToken('contact_action');
|
||||||
|
|
||||||
|
// Provide friend suggestion only for Friendica contacts
|
||||||
|
if ($contact['network'] === Protocol::DFRN) {
|
||||||
|
$contact_actions['suggest'] = [
|
||||||
|
'label' => $this->t('Suggest friends'),
|
||||||
|
'url' => 'fsuggest/' . $contact['id'],
|
||||||
|
'title' => '',
|
||||||
|
'sel' => '',
|
||||||
|
'id' => 'suggest',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($poll_enabled) {
|
||||||
|
$contact_actions['update'] = [
|
||||||
|
'label' => $this->t('Update now'),
|
||||||
|
'url' => 'contact/' . $contact['id'] . '/update?t=' . $formSecurityToken,
|
||||||
|
'title' => '',
|
||||||
|
'sel' => '',
|
||||||
|
'id' => 'update',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array($contact['network'], Protocol::NATIVE_SUPPORT)) {
|
||||||
|
$contact_actions['updateprofile'] = [
|
||||||
|
'label' => $this->t('Refetch contact data'),
|
||||||
|
'url' => 'contact/' . $contact['id'] . '/updateprofile?t=' . $formSecurityToken,
|
||||||
|
'title' => '',
|
||||||
|
'sel' => '',
|
||||||
|
'id' => 'updateprofile',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$contact_actions['block'] = [
|
||||||
|
'label' => $localRelationship->blocked ? $this->t('Unblock') : $this->t('Block'),
|
||||||
|
'url' => 'contact/' . $contact['id'] . '/block?t=' . $formSecurityToken,
|
||||||
|
'title' => $this->t('Toggle Blocked status'),
|
||||||
|
'sel' => $localRelationship->blocked ? 'active' : '',
|
||||||
|
'id' => 'toggle-block',
|
||||||
|
];
|
||||||
|
|
||||||
|
$contact_actions['ignore'] = [
|
||||||
|
'label' => $localRelationship->ignored ? $this->t('Unignore') : $this->t('Ignore'),
|
||||||
|
'url' => 'contact/' . $contact['id'] . '/ignore?t=' . $formSecurityToken,
|
||||||
|
'title' => $this->t('Toggle Ignored status'),
|
||||||
|
'sel' => $localRelationship->ignored ? 'active' : '',
|
||||||
|
'id' => 'toggle-ignore',
|
||||||
|
];
|
||||||
|
|
||||||
|
if (Protocol::supportsRevokeFollow($contact['network']) && in_array($localRelationship->rel, [Contact::FOLLOWER, Contact::FRIEND])) {
|
||||||
|
$contact_actions['revoke_follow'] = [
|
||||||
|
'label' => $this->t('Revoke Follow'),
|
||||||
|
'url' => 'contact/' . $contact['id'] . '/revoke',
|
||||||
|
'title' => $this->t('Revoke the follow from this contact'),
|
||||||
|
'sel' => '',
|
||||||
|
'id' => 'revoke_follow',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $contact_actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $contact_id Id of the contact with uid != 0
|
||||||
|
* @throws HTTPException\InternalServerErrorException
|
||||||
|
* @throws \ImagickException
|
||||||
|
*/
|
||||||
|
private static function updateContactFromProbe(int $contact_id)
|
||||||
|
{
|
||||||
|
$contact = DBA::selectFirst('contact', ['url'], ['id' => $contact_id, 'uid' => local_user(), 'deleted' => false]);
|
||||||
|
if (!DBA::isResult($contact)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the entry in the contact table
|
||||||
|
Contact::updateFromProbe($contact_id);
|
||||||
|
}
|
||||||
|
}
|
|
@ -160,8 +160,6 @@ class User extends BaseDataTransferObject
|
||||||
$this->uid = (int)$uid;
|
$this->uid = (int)$uid;
|
||||||
$this->cid = (int)($userContact['id'] ?? 0);
|
$this->cid = (int)($userContact['id'] ?? 0);
|
||||||
$this->pid = (int)$publicContact['id'];
|
$this->pid = (int)$publicContact['id'];
|
||||||
$this->self = (boolean)($userContact['self'] ?? false);
|
|
||||||
$this->network = $publicContact['network'] ?: Protocol::DFRN;
|
|
||||||
$this->statusnet_profile_url = $publicContact['url'];
|
$this->statusnet_profile_url = $publicContact['url'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1530,6 +1530,7 @@ return [
|
||||||
"blocked" => ["type" => "boolean", "comment" => "Contact is completely blocked for this user"],
|
"blocked" => ["type" => "boolean", "comment" => "Contact is completely blocked for this user"],
|
||||||
"ignored" => ["type" => "boolean", "comment" => "Posts from this contact are ignored"],
|
"ignored" => ["type" => "boolean", "comment" => "Posts from this contact are ignored"],
|
||||||
"collapsed" => ["type" => "boolean", "comment" => "Posts from this contact are collapsed"],
|
"collapsed" => ["type" => "boolean", "comment" => "Posts from this contact are collapsed"],
|
||||||
|
"hidden" => ["type" => "boolean", "comment" => "This contact is hidden from the others"],
|
||||||
"pending" => ["type" => "boolean", "comment" => ""],
|
"pending" => ["type" => "boolean", "comment" => ""],
|
||||||
"rel" => ["type" => "tinyint unsigned", "comment" => "The kind of the relation between the user and the contact"],
|
"rel" => ["type" => "tinyint unsigned", "comment" => "The kind of the relation between the user and the contact"],
|
||||||
"info" => ["type" => "mediumtext", "comment" => ""],
|
"info" => ["type" => "mediumtext", "comment" => ""],
|
||||||
|
|
|
@ -329,19 +329,16 @@ return [
|
||||||
|
|
||||||
'/contact' => [
|
'/contact' => [
|
||||||
'[/]' => [Module\Contact::class, [R::GET]],
|
'[/]' => [Module\Contact::class, [R::GET]],
|
||||||
'/{id:\d+}[/]' => [Module\Contact::class, [R::GET, R::POST]],
|
'/{id:\d+}[/]' => [Module\Contact\Profile::class, [R::GET, R::POST]],
|
||||||
'/{id:\d+}/archive' => [Module\Contact::class, [R::GET]],
|
'/{id:\d+}/{action:block|ignore|update|updateprofile}'
|
||||||
|
=> [Module\Contact\Profile::class, [R::GET]],
|
||||||
'/{id:\d+}/advanced' => [Module\Contact\Advanced::class, [R::GET, R::POST]],
|
'/{id:\d+}/advanced' => [Module\Contact\Advanced::class, [R::GET, R::POST]],
|
||||||
'/{id:\d+}/block' => [Module\Contact::class, [R::GET]],
|
'/{id:\d+}/conversations' => [Module\Contact\Conversations::class, [R::GET]],
|
||||||
'/{id:\d+}/conversations' => [Module\Contact::class, [R::GET]],
|
|
||||||
'/{id:\d+}/contacts[/{type}]' => [Module\Contact\Contacts::class, [R::GET]],
|
'/{id:\d+}/contacts[/{type}]' => [Module\Contact\Contacts::class, [R::GET]],
|
||||||
'/{id:\d+}/ignore' => [Module\Contact::class, [R::GET]],
|
|
||||||
'/{id:\d+}/media' => [Module\Contact\Media::class, [R::GET]],
|
'/{id:\d+}/media' => [Module\Contact\Media::class, [R::GET]],
|
||||||
'/{id:\d+}/poke' => [Module\Contact\Poke::class, [R::GET, R::POST]],
|
'/{id:\d+}/poke' => [Module\Contact\Poke::class, [R::GET, R::POST]],
|
||||||
'/{id:\d+}/posts' => [Module\Contact::class, [R::GET]],
|
'/{id:\d+}/posts' => [Module\Contact\Posts::class, [R::GET]],
|
||||||
'/{id:\d+}/revoke' => [Module\Contact\Revoke::class, [R::GET, R::POST]],
|
'/{id:\d+}/revoke' => [Module\Contact\Revoke::class, [R::GET, R::POST]],
|
||||||
'/{id:\d+}/update' => [Module\Contact::class, [R::GET]],
|
|
||||||
'/{id:\d+}/updateprofile' => [Module\Contact::class, [R::GET]],
|
|
||||||
'/archived' => [Module\Contact::class, [R::GET]],
|
'/archived' => [Module\Contact::class, [R::GET]],
|
||||||
'/batch' => [Module\Contact::class, [R::GET, R::POST]],
|
'/batch' => [Module\Contact::class, [R::GET, R::POST]],
|
||||||
'/pending' => [Module\Contact::class, [R::GET]],
|
'/pending' => [Module\Contact::class, [R::GET]],
|
||||||
|
|
|
@ -147,7 +147,6 @@ class ApiTest extends FixtureTest
|
||||||
{
|
{
|
||||||
self::assertEquals($this->otherUser['id'], $user['id']);
|
self::assertEquals($this->otherUser['id'], $user['id']);
|
||||||
self::assertEquals($this->otherUser['id'], $user['id_str']);
|
self::assertEquals($this->otherUser['id'], $user['id_str']);
|
||||||
self::assertEquals(0, $user['self']);
|
|
||||||
self::assertEquals($this->otherUser['name'], $user['name']);
|
self::assertEquals($this->otherUser['name'], $user['name']);
|
||||||
self::assertEquals($this->otherUser['nick'], $user['screen_name']);
|
self::assertEquals($this->otherUser['nick'], $user['screen_name']);
|
||||||
self::assertFalse($user['verified']);
|
self::assertFalse($user['verified']);
|
||||||
|
@ -738,16 +737,6 @@ class ApiTest extends FixtureTest
|
||||||
// self::assertSelfUser(api_get_user());
|
// self::assertSelfUser(api_get_user());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test the api_get_user() function with a 0 user ID.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function testApiGetUserWithZeroUser()
|
|
||||||
{
|
|
||||||
self::assertSelfUser(DI::twitterUser()->createFromUserId(BaseApi::getCurrentUserID())->toArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test the Arrays::walkRecursive() function.
|
* Test the Arrays::walkRecursive() function.
|
||||||
*
|
*
|
||||||
|
@ -1177,7 +1166,6 @@ class ApiTest extends FixtureTest
|
||||||
self::assertEquals('DFRN', $result['user']['location']);
|
self::assertEquals('DFRN', $result['user']['location']);
|
||||||
self::assertEquals($this->selfUser['name'], $result['user']['name']);
|
self::assertEquals($this->selfUser['name'], $result['user']['name']);
|
||||||
self::assertEquals($this->selfUser['nick'], $result['user']['screen_name']);
|
self::assertEquals($this->selfUser['nick'], $result['user']['screen_name']);
|
||||||
self::assertEquals('dfrn', $result['user']['network']);
|
|
||||||
self::assertTrue($result['user']['verified']);
|
self::assertTrue($result['user']['verified']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3000,7 +2988,6 @@ class ApiTest extends FixtureTest
|
||||||
self::assertEquals($this->selfUser['id'], $result['user']['cid']);
|
self::assertEquals($this->selfUser['id'], $result['user']['cid']);
|
||||||
self::assertEquals('DFRN', $result['user']['location']);
|
self::assertEquals('DFRN', $result['user']['location']);
|
||||||
self::assertEquals($this->selfUser['nick'], $result['user']['screen_name']);
|
self::assertEquals($this->selfUser['nick'], $result['user']['screen_name']);
|
||||||
self::assertEquals('dfrn', $result['user']['network']);
|
|
||||||
self::assertEquals('new_name', $result['user']['name']);
|
self::assertEquals('new_name', $result['user']['name']);
|
||||||
self::assertEquals('new_description', $result['user']['description']);
|
self::assertEquals('new_description', $result['user']['description']);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,39 +30,9 @@ use Friendica\Test\FixtureTest;
|
||||||
|
|
||||||
class ContactEndpointTest extends FixtureTest
|
class ContactEndpointTest extends FixtureTest
|
||||||
{
|
{
|
||||||
public function testGetUid()
|
|
||||||
{
|
|
||||||
self::assertSame(42, ContactEndpointMock::getUid(42));
|
|
||||||
self::assertSame(42, ContactEndpointMock::getUid(null, 'selfcontact'));
|
|
||||||
self::assertSame(42, ContactEndpointMock::getUid(84, 'selfcontact'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetUidContactIdNotFound()
|
|
||||||
{
|
|
||||||
$this->expectException(NotFoundException::class);
|
|
||||||
$this->expectExceptionMessage('Contact not found');
|
|
||||||
|
|
||||||
ContactEndpointMock::getUid(84);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetUidScreenNameNotFound()
|
|
||||||
{
|
|
||||||
$this->expectException(NotFoundException::class);
|
|
||||||
$this->expectExceptionMessage('User not found');
|
|
||||||
|
|
||||||
ContactEndpointMock::getUid(null, 'othercontact');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetUidContactIdScreenNameNotFound()
|
|
||||||
{
|
|
||||||
$this->expectException(NotFoundException::class);
|
|
||||||
$this->expectExceptionMessage('User not found');
|
|
||||||
|
|
||||||
ContactEndpointMock::getUid(42, 'othercontact');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testIds()
|
public function testIds()
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
$expectedEmpty = [
|
$expectedEmpty = [
|
||||||
'ids' => [],
|
'ids' => [],
|
||||||
'next_cursor' => -1,
|
'next_cursor' => -1,
|
||||||
|
@ -97,6 +67,7 @@ class ContactEndpointTest extends FixtureTest
|
||||||
self::assertArrayHasKey('ids', $result);
|
self::assertArrayHasKey('ids', $result);
|
||||||
self::assertContainsOnly('int', $result['ids']);
|
self::assertContainsOnly('int', $result['ids']);
|
||||||
self::assertSame(45, $result['ids'][0]);
|
self::assertSame(45, $result['ids'][0]);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -106,15 +77,18 @@ class ContactEndpointTest extends FixtureTest
|
||||||
*/
|
*/
|
||||||
public function testIdsStringify()
|
public function testIdsStringify()
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
$result = ContactEndpointMock::ids(Contact::SHARING, 42, -1, ContactEndpoint::DEFAULT_COUNT, true);
|
$result = ContactEndpointMock::ids(Contact::SHARING, 42, -1, ContactEndpoint::DEFAULT_COUNT, true);
|
||||||
|
|
||||||
self::assertArrayHasKey('ids', $result);
|
self::assertArrayHasKey('ids', $result);
|
||||||
self::assertContainsOnly('string', $result['ids']);
|
self::assertContainsOnly('string', $result['ids']);
|
||||||
self::assertSame('45', $result['ids'][0]);
|
self::assertSame('45', $result['ids'][0]);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testIdsPagination()
|
public function testIdsPagination()
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
$expectedDefaultPageResult = [
|
$expectedDefaultPageResult = [
|
||||||
'ids' => [45],
|
'ids' => [45],
|
||||||
'next_cursor' => 44,
|
'next_cursor' => 44,
|
||||||
|
@ -186,6 +160,7 @@ class ContactEndpointTest extends FixtureTest
|
||||||
$result = ContactEndpointMock::ids([Contact::SHARING, Contact::FRIEND], 42, $emptyNextPageCursor, 1);
|
$result = ContactEndpointMock::ids([Contact::SHARING, Contact::FRIEND], 42, $emptyNextPageCursor, 1);
|
||||||
|
|
||||||
self::assertSame($expectedEmptyNextPageResult, $result);
|
self::assertSame($expectedEmptyNextPageResult, $result);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -197,6 +172,7 @@ class ContactEndpointTest extends FixtureTest
|
||||||
*/
|
*/
|
||||||
public function testList()
|
public function testList()
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
$expectedEmpty = [
|
$expectedEmpty = [
|
||||||
'users' => [],
|
'users' => [],
|
||||||
'next_cursor' => -1,
|
'next_cursor' => -1,
|
||||||
|
@ -270,5 +246,6 @@ class ContactEndpointTest extends FixtureTest
|
||||||
self::assertArrayHasKey('users', $result);
|
self::assertArrayHasKey('users', $result);
|
||||||
self::assertContainsOnlyInstancesOf(User::class, $result['users']);
|
self::assertContainsOnlyInstancesOf(User::class, $result['users']);
|
||||||
self::assertSame($expectedFriendContactUser, $result['users'][0]->toArray());
|
self::assertSame($expectedFriendContactUser, $result['users'][0]->toArray());
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
25
update.php
25
update.php
|
@ -1000,14 +1000,6 @@ function update_1434()
|
||||||
return Update::SUCCESS;
|
return Update::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
function update_1435()
|
|
||||||
{
|
|
||||||
$contacts = DBA::select('contact', [], ["`uid` != ?", 0]);
|
|
||||||
while ($contact = DBA::fetch($contacts)) {
|
|
||||||
Contact\User::insertForContactArray($contact);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function update_1438()
|
function update_1438()
|
||||||
{
|
{
|
||||||
DBA::update('photo', ['photo-type' => Photo::USER_AVATAR], ['profile' => true]);
|
DBA::update('photo', ['photo-type' => Photo::USER_AVATAR], ['profile' => true]);
|
||||||
|
@ -1061,3 +1053,20 @@ function update_1442()
|
||||||
|
|
||||||
return Update::SUCCESS;
|
return Update::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A bug in Contact\User::updateByContactUpdate prevented any update to the user-contact table since the rows have been
|
||||||
|
* created in version 1435. This version fixes this bug but the user-contact rows are outdated, we need to regenerate
|
||||||
|
* them.
|
||||||
|
*/
|
||||||
|
function update_1444()
|
||||||
|
{
|
||||||
|
DBA::e('TRUNCATE TABLE `user-contact`');
|
||||||
|
|
||||||
|
$contacts = DBA::select('contact', [], ["`uid` != ?", 0]);
|
||||||
|
while ($contact = DBA::fetch($contacts)) {
|
||||||
|
Contact\User::insertForContactArray($contact);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Update::SUCCESS;
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -174,7 +174,7 @@
|
||||||
|
|
||||||
|
|
||||||
{{* Put additional actions in a dropdown menu *}}
|
{{* Put additional actions in a dropdown menu *}}
|
||||||
{{if $item.edpost || $item.tagger || $item.filer || $item.pin || $item.star || $item.follow_thread || $item.ignore || $item.drop.dropping}}
|
{{if $item.menu && ($item.edpost || $item.tagger || $item.filer || $item.pin || $item.star || $item.follow_thread || $item.ignore || $item.drop.dropping)}}
|
||||||
<span role="presentation" class="separator"></span>
|
<span role="presentation" class="separator"></span>
|
||||||
<span class="more-links btn-group{{if $item.thread_level> 1}} dropup{{/if}}">
|
<span class="more-links btn-group{{if $item.thread_level> 1}} dropup{{/if}}">
|
||||||
<button type="button" class="btn-link dropdown-toggle" data-toggle="dropdown" id="dropdownMenuOptions-{{$item.id}}" aria-haspopup="true" aria-expanded="false" title="{{$item.menu}}"><i class="fa fa-ellipsis-h" aria-hidden="true"></i> {{$item.menu}}</button>
|
<button type="button" class="btn-link dropdown-toggle" data-toggle="dropdown" id="dropdownMenuOptions-{{$item.id}}" aria-haspopup="true" aria-expanded="false" title="{{$item.menu}}"><i class="fa fa-ellipsis-h" aria-hidden="true"></i> {{$item.menu}}</button>
|
||||||
|
|
|
@ -326,7 +326,7 @@ as the value of $top_child_total (this is done at the end of this file)
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{* Put additional actions in a dropdown menu *}}
|
{{* Put additional actions in a dropdown menu *}}
|
||||||
{{if $item.edpost || $item.tagger || $item.filer || $item.pin || $item.star || $item.follow_thread || $item.ignore || $item.drop.dropping}}
|
{{if $item.menu && ($item.edpost || $item.tagger || $item.filer || $item.pin || $item.star || $item.follow_thread || $item.ignore || $item.drop.dropping)}}
|
||||||
<span role="presentation" class="separator"></span>
|
<span role="presentation" class="separator"></span>
|
||||||
<span class="more-links btn-group{{if $item.thread_level > 1}} dropup{{/if}}">
|
<span class="more-links btn-group{{if $item.thread_level > 1}} dropup{{/if}}">
|
||||||
<button type="button" class="btn-link dropdown-toggle" data-toggle="dropdown" id="dropdownMenuOptions-{{$item.id}}" aria-haspopup="true" aria-expanded="false" title="{{$item.menu}}"><i class="fa fa-ellipsis-h" aria-hidden="true"></i> {{$item.menu}}</button>
|
<button type="button" class="btn-link dropdown-toggle" data-toggle="dropdown" id="dropdownMenuOptions-{{$item.id}}" aria-haspopup="true" aria-expanded="false" title="{{$item.menu}}"><i class="fa fa-ellipsis-h" aria-hidden="true"></i> {{$item.menu}}</button>
|
||||||
|
|
Loading…
Reference in a new issue