1
0
Fork 0

Merge pull request #10969 from MrPetovan/task/remove-private-contacts

Move individual contact modules to their own class
This commit is contained in:
Philipp 2021-11-22 06:54:46 +01:00 committed by GitHub
commit 2e05dac7da
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 1532 additions and 991 deletions

View file

@ -1,6 +1,6 @@
-- ------------------------------------------
-- Friendica 2021.12-dev (Siberian Iris)
-- DB_UPDATE_VERSION 1443
-- DB_UPDATE_VERSION 1444
-- ------------------------------------------
@ -1511,6 +1511,7 @@ CREATE TABLE IF NOT EXISTS `user-contact` (
`blocked` boolean COMMENT 'Contact is completely blocked for this user',
`ignored` boolean COMMENT 'Posts from this contact are ignored',
`collapsed` boolean COMMENT 'Posts from this contact are collapsed',
`hidden` boolean COMMENT 'This contact is hidden from the others',
`pending` boolean COMMENT '',
`rel` tinyint unsigned COMMENT 'The kind of the relation between the user and the contact',
`info` mediumtext COMMENT '',

View file

@ -14,6 +14,7 @@ Fields
| blocked | Contact is completely blocked for this user | boolean | YES | | NULL | |
| ignored | Posts from this contact are ignored | 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 | |
| rel | The kind of the relation between the user and the contact | tinyint unsigned | YES | | NULL | |
| info | | mediumtext | YES | | NULL | |

View file

@ -33,7 +33,7 @@ function repair_ostatus_content(App $a) {
// NOTREACHED
}
$o = "<h2>" . DI::l10n()->t("Resubscribing to OStatus contacts") . "</h2>";
$o = '<h2>' . DI::l10n()->t('Resubscribing to OStatus contacts') . '</h2>';
$uid = local_user();
@ -43,20 +43,20 @@ function repair_ostatus_content(App $a) {
$total = DBA::count('contact', $condition);
if (!$total) {
return ($o . DI::l10n()->t("Error"));
return ($o . DI::l10n()->t('Error'));
}
$contact = Contact::selectToArray(['url'], $condition, ['order' => ['url'], 'limit' => [$counter++, 1]]);
if (!DBA::isResult($contact)) {
$o .= DI::l10n()->t("Done");
$o .= DI::l10n()->t('Done');
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 . '">';

View file

@ -23,22 +23,25 @@
use Friendica\App;
use Friendica\Core\System;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Model\Post;
use Friendica\Module\Contact;
use Friendica\Model\Contact;
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($_GET['item'])) {
$item = Post::selectFirst(['parent'], ['id' => $_GET['item']]);
$parentid = $item['parent'] ?? 0;
} else {
$parentid = 0;
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'])) {
$item = Post::selectFirst(['parent'], ['id' => $_GET['item']]);
}
$text = Contact::getPostsFromId($contact['id'], true, true, $item['parent'] ?? 0);
}
$text = Contact::getConversationsHMTL($a, DI::args()->getArgv()[1], true, $parentid);
} else {
$text = '';
}
System::htmlUpdateExit($text);
System::htmlUpdateExit($text ?? '');
}

View 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;
}
}

View file

@ -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);
}
}

View 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
);
}
}

View 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);
}
}
}

View file

@ -21,7 +21,9 @@
namespace Friendica\Core;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Model\User;
use Friendica\Network\HTTPException;
use Friendica\Protocol\Activity;
use Friendica\Protocol\ActivityPub;
@ -208,6 +210,59 @@ class Protocol
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
*

View file

@ -2492,7 +2492,7 @@ class Contact
$contact_id = $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
self::updateAvatar($contact_id, $ret['photo']);
@ -2508,61 +2508,11 @@ class Contact
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;
}
/**
* 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
*
@ -2699,7 +2649,7 @@ class Contact
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) &&
in_array($user['page-flags'], [User::PAGE_FLAGS_NORMAL])) {

View file

@ -95,16 +95,17 @@ class User
$update_fields = self::preparedFields($fields);
if (!empty($update_fields)) {
$contacts = DBA::select('contact', ['uri-id', 'uid'], $condition);
while ($row = DBA::fetch($contacts)) {
if (empty($row['uri-id']) || empty($contact['uid'])) {
while ($contact = DBA::fetch($contacts)) {
if (empty($contact['uri-id']) || empty($contact['uid'])) {
continue;
}
$ret = DBA::update('user-contact', $update_fields, ['uri-id' => $row['uri-id'], 'uid' => $row['uid']]);
Logger::info('Updated user contact', ['uid' => $row['uid'], 'uri-id' => $row['uri-id'], 'ret' => $ret]);
$ret = DBA::update('user-contact', $update_fields, ['uri-id' => $contact['uri-id'], 'uid' => $contact['uid']]);
Logger::info('Updated user contact', ['uid' => $contact['uid'], 'uri-id' => $contact['uri-id'], 'ret' => $ret]);
}
DBA::close($contacts);
}
DBA::commit();
}

View file

@ -481,13 +481,12 @@ class User
/**
* Returns the default group for a given user and network
*
* @param int $uid User id
* @param string $network network name
* @param int $uid User id
*
* @return int group id
* @throws Exception
*/
public static function getDefaultGroup($uid, $network = '')
public static function getDefaultGroup($uid)
{
$user = DBA::selectFirst('user', ['def_gid'], ['uid' => $uid]);
if (DBA::isResult($user)) {

View file

@ -40,8 +40,14 @@ class Follow extends BaseApi
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());
}
}

View file

@ -25,9 +25,7 @@ use Friendica\BaseModule;
use Friendica\Content\ContactSelector;
use Friendica\Content\Nav;
use Friendica\Content\Pager;
use Friendica\Content\Text\BBCode;
use Friendica\Content\Widget;
use Friendica\Core\Hook;
use Friendica\Core\Protocol;
use Friendica\Core\Renderer;
use Friendica\Core\Theme;
@ -37,10 +35,7 @@ use Friendica\DI;
use Friendica\Model;
use Friendica\Model\User;
use Friendica\Module\Security\Login;
use Friendica\Network\HTTPException\BadRequestException;
use Friendica\Network\HTTPException\NotFoundException;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Strings;
/**
* Manages and show Contacts and their content
@ -105,55 +100,7 @@ class Contact extends BaseModule
// @TODO: Replace with parameter from router
if (DI::args()->getArgv()[1] === 'batch') {
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 */
@ -164,7 +111,7 @@ class Contact extends BaseModule
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @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]);
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.
*
@ -232,8 +163,6 @@ class Contact extends BaseModule
return Login::form($_SERVER['REQUEST_URI']);
}
$a = DI::app();
$search = trim($_GET['search'] ?? '');
$nets = trim($_GET['nets'] ?? '');
$rel = trim($_GET['rel'] ?? '');
@ -249,71 +178,19 @@ class Contact extends BaseModule
$page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.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 = '';
}
$vcard_widget = '';
$findpeople_widget = Widget::findPeople();
if (isset($_GET['add'])) {
$follow_widget = Widget::follow($_GET['add']);
} else {
$vcard_widget = '';
$findpeople_widget = Widget::findPeople();
if (isset($_GET['add'])) {
$follow_widget = Widget::follow($_GET['add']);
} else {
$follow_widget = Widget::follow();
}
$account_widget = Widget::accounttypes($_SERVER['REQUEST_URI'], $accounttype);
$networks_widget = Widget::networks($_SERVER['REQUEST_URI'], $nets);
$rel_widget = Widget::contactRels($_SERVER['REQUEST_URI'], $rel);
$groups_widget = Widget::groups($_SERVER['REQUEST_URI'], $group);
$follow_widget = Widget::follow();
}
$account_widget = Widget::accounttypes($_SERVER['REQUEST_URI'], $accounttype);
$networks_widget = Widget::networks($_SERVER['REQUEST_URI'], $nets);
$rel_widget = Widget::contactRels($_SERVER['REQUEST_URI'], $rel);
$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;
$tpl = Renderer::getMarkupTemplate('contacts-head.tpl');
@ -324,274 +201,8 @@ class Contact extends BaseModule
$o = '';
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();
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()];
// @TODO: Replace with parameter from router
@ -875,66 +486,6 @@ class Contact extends BaseModule
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
*
@ -1013,79 +564,4 @@ class Contact extends BaseModule
'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;
}
}

View 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;
}
}

View 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;
}
}

View 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);
}
}

View file

@ -55,7 +55,7 @@
use Friendica\Database\DBA;
if (!defined('DB_UPDATE_VERSION')) {
define('DB_UPDATE_VERSION', 1443);
define('DB_UPDATE_VERSION', 1444);
}
return [
@ -1530,6 +1530,7 @@ return [
"blocked" => ["type" => "boolean", "comment" => "Contact is completely blocked for this user"],
"ignored" => ["type" => "boolean", "comment" => "Posts from this contact are ignored"],
"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" => ""],
"rel" => ["type" => "tinyint unsigned", "comment" => "The kind of the relation between the user and the contact"],
"info" => ["type" => "mediumtext", "comment" => ""],

View file

@ -329,19 +329,16 @@ return [
'/contact' => [
'[/]' => [Module\Contact::class, [R::GET]],
'/{id:\d+}[/]' => [Module\Contact::class, [R::GET, R::POST]],
'/{id:\d+}/archive' => [Module\Contact::class, [R::GET]],
'/{id:\d+}[/]' => [Module\Contact\Profile::class, [R::GET, R::POST]],
'/{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+}/block' => [Module\Contact::class, [R::GET]],
'/{id:\d+}/conversations' => [Module\Contact::class, [R::GET]],
'/{id:\d+}/conversations' => [Module\Contact\Conversations::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+}/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+}/update' => [Module\Contact::class, [R::GET]],
'/{id:\d+}/updateprofile' => [Module\Contact::class, [R::GET]],
'/archived' => [Module\Contact::class, [R::GET]],
'/batch' => [Module\Contact::class, [R::GET, R::POST]],
'/pending' => [Module\Contact::class, [R::GET]],

View file

@ -1000,14 +1000,6 @@ function update_1434()
return Update::SUCCESS;
}
function update_1435()
{
$contacts = DBA::select('contact', [], ["`uid` != ?", 0]);
while ($contact = DBA::fetch($contacts)) {
Contact\User::insertForContactArray($contact);
}
}
function update_1438()
{
DBA::update('photo', ['photo-type' => Photo::USER_AVATAR], ['profile' => true]);
@ -1061,3 +1053,20 @@ function update_1442()
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;
}

View file

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 2021.12-dev\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-11-21 17:12+0000\n"
"POT-Creation-Date: 2021-11-21 19:02-0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -18,21 +18,21 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
#: include/api.php:416 src/Module/BaseApi.php:257
#: include/api.php:415 src/Module/BaseApi.php:257
#, php-format
msgid "Daily posting limit of %d post reached. The post was rejected."
msgid_plural "Daily posting limit of %d posts reached. The post was rejected."
msgstr[0] ""
msgstr[1] ""
#: include/api.php:430 src/Module/BaseApi.php:273
#: include/api.php:429 src/Module/BaseApi.php:273
#, php-format
msgid "Weekly posting limit of %d post reached. The post was rejected."
msgid_plural "Weekly posting limit of %d posts reached. The post was rejected."
msgstr[0] ""
msgstr[1] ""
#: include/api.php:444 src/Module/BaseApi.php:289
#: include/api.php:443 src/Module/BaseApi.php:289
#, php-format
msgid "Monthly posting limit of %d post reached. The post was rejected."
msgstr ""
@ -103,7 +103,7 @@ msgstr ""
msgid "list"
msgstr ""
#: mod/cal.php:265 src/Console/User.php:182 src/Model/User.php:660
#: mod/cal.php:265 src/Console/User.php:182 src/Model/User.php:659
#: src/Module/Admin/Users/Active.php:73 src/Module/Admin/Users/Blocked.php:74
#: src/Module/Admin/Users/Index.php:80 src/Module/Admin/Users/Pending.php:71
#: src/Module/Api/Twitter/ContactEndpoint.php:72
@ -148,11 +148,10 @@ msgstr ""
#: mod/wallmessage.php:109 src/Module/Attach.php:55 src/Module/BaseApi.php:59
#: src/Module/BaseApi.php:68 src/Module/BaseApi.php:77
#: src/Module/BaseApi.php:86 src/Module/BaseNotifications.php:94
#: src/Module/Contact.php:328 src/Module/Contact/Advanced.php:60
#: src/Module/Delegation.php:118 src/Module/FollowConfirm.php:17
#: src/Module/FriendSuggest.php:56 src/Module/Group.php:44
#: src/Module/Group.php:89 src/Module/Invite.php:41 src/Module/Invite.php:130
#: src/Module/Notifications/Notification.php:48
#: src/Module/Contact/Advanced.php:60 src/Module/Delegation.php:118
#: src/Module/FollowConfirm.php:17 src/Module/FriendSuggest.php:56
#: src/Module/Group.php:44 src/Module/Group.php:89 src/Module/Invite.php:41
#: src/Module/Invite.php:130 src/Module/Notifications/Notification.php:48
#: src/Module/Notifications/Notification.php:79
#: src/Module/Profile/Common.php:56 src/Module/Profile/Contacts.php:56
#: src/Module/Profile/Schedule.php:39 src/Module/Profile/Schedule.php:56
@ -406,7 +405,7 @@ msgstr ""
#: mod/events.php:508 src/Content/Widget/VCard.php:98 src/Model/Event.php:80
#: src/Model/Event.php:107 src/Model/Event.php:466 src/Model/Event.php:915
#: src/Model/Profile.php:368 src/Module/Contact.php:565
#: src/Model/Profile.php:368 src/Module/Contact/Profile.php:375
#: src/Module/Directory.php:147 src/Module/Notifications/Introductions.php:181
#: src/Module/Profile/Profile.php:194
msgid "Location:"
@ -423,8 +422,8 @@ msgstr ""
#: mod/events.php:519 mod/message.php:201 mod/message.php:357
#: mod/photos.php:927 mod/photos.php:1031 mod/photos.php:1301
#: mod/photos.php:1342 mod/photos.php:1398 mod/photos.php:1472
#: src/Module/Admin/Item/Source.php:65 src/Module/Contact.php:523
#: src/Module/Contact/Advanced.php:147 src/Module/Contact/Poke.php:158
#: src/Module/Admin/Item/Source.php:65 src/Module/Contact/Advanced.php:147
#: src/Module/Contact/Poke.php:158 src/Module/Contact/Profile.php:333
#: src/Module/Debug/ActivityPubConversion.php:141
#: src/Module/Debug/Babel.php:313 src/Module/Debug/Localtime.php:64
#: src/Module/Debug/Probe.php:54 src/Module/Debug/WebFinger.php:51
@ -442,7 +441,7 @@ msgstr ""
msgid "Basic"
msgstr ""
#: mod/events.php:521 src/Module/Admin/Site.php:506 src/Module/Contact.php:863
#: mod/events.php:521 src/Module/Admin/Site.php:506 src/Module/Contact.php:474
#: src/Module/Profile/Profile.php:249
msgid "Advanced"
msgstr ""
@ -500,13 +499,14 @@ msgid "Your Identity Address:"
msgstr ""
#: mod/follow.php:141 mod/unfollow.php:100
#: src/Module/Admin/Blocklist/Contact.php:116 src/Module/Contact.php:561
#: src/Module/Admin/Blocklist/Contact.php:116
#: src/Module/Contact/Profile.php:371
#: src/Module/Notifications/Introductions.php:123
#: src/Module/Notifications/Introductions.php:192
msgid "Profile URL"
msgstr ""
#: mod/follow.php:142 src/Module/Contact.php:573
#: mod/follow.php:142 src/Module/Contact/Profile.php:383
#: src/Module/Notifications/Introductions.php:185
#: src/Module/Profile/Profile.php:207
msgid "Tags:"
@ -522,7 +522,7 @@ msgid "Add a personal note:"
msgstr ""
#: mod/follow.php:163 mod/unfollow.php:109 src/Module/BaseProfile.php:59
#: src/Module/Contact.php:833
#: src/Module/Contact.php:444
msgid "Status Messages and Posts"
msgstr ""
@ -1085,7 +1085,7 @@ msgid "Rotate CCW (left)"
msgstr ""
#: mod/photos.php:1339 mod/photos.php:1395 mod/photos.php:1469
#: src/Module/Contact.php:993 src/Module/Item/Compose.php:148
#: src/Module/Contact.php:544 src/Module/Item/Compose.php:148
#: src/Object/Post.php:960
msgid "This is you"
msgstr ""
@ -1148,8 +1148,14 @@ msgstr ""
#: mod/redir.php:55 mod/redir.php:129 src/Module/Contact/Advanced.php:70
#: src/Module/Contact/Advanced.php:119 src/Module/Contact/Contacts.php:36
#: src/Module/Contact/Media.php:43 src/Module/FriendSuggest.php:71
#: src/Module/FriendSuggest.php:109 src/Module/Group.php:104
#: src/Module/Contact/Conversations.php:80
#: src/Module/Contact/Conversations.php:85
#: src/Module/Contact/Conversations.php:90 src/Module/Contact/Media.php:43
#: src/Module/Contact/Posts.php:74 src/Module/Contact/Posts.php:79
#: src/Module/Contact/Posts.php:84 src/Module/Contact/Profile.php:147
#: src/Module/Contact/Profile.php:152 src/Module/Contact/Profile.php:157
#: src/Module/FriendSuggest.php:71 src/Module/FriendSuggest.php:109
#: src/Module/Group.php:104
msgid "Contact not found."
msgstr ""
@ -2164,16 +2170,16 @@ msgid "All contacts"
msgstr ""
#: src/BaseModule.php:210 src/Content/Widget.php:231 src/Core/ACL.php:193
#: src/Module/Contact.php:756 src/Module/PermissionTooltip.php:79
#: src/Module/Contact.php:367 src/Module/PermissionTooltip.php:79
#: src/Module/PermissionTooltip.php:101
msgid "Followers"
msgstr ""
#: src/BaseModule.php:215 src/Content/Widget.php:232 src/Module/Contact.php:757
#: src/BaseModule.php:215 src/Content/Widget.php:232 src/Module/Contact.php:368
msgid "Following"
msgstr ""
#: src/BaseModule.php:220 src/Content/Widget.php:233 src/Module/Contact.php:758
#: src/BaseModule.php:220 src/Content/Widget.php:233 src/Module/Contact.php:369
msgid "Mutual friends"
msgstr ""
@ -2766,13 +2772,13 @@ msgstr ""
#: src/Content/Item.php:449 src/Module/Admin/Blocklist/Contact.php:100
#: src/Module/Admin/Users/Active.php:140 src/Module/Admin/Users/Index.php:154
#: src/Module/Contact.php:544 src/Module/Contact.php:787
#: src/Module/Contact.php:1064
#: src/Module/Contact.php:398 src/Module/Contact/Profile.php:354
#: src/Module/Contact/Profile.php:455
msgid "Block"
msgstr ""
#: src/Content/Item.php:450 src/Module/Contact.php:545
#: src/Module/Contact.php:788 src/Module/Contact.php:1072
#: src/Content/Item.php:450 src/Module/Contact.php:399
#: src/Module/Contact/Profile.php:355 src/Module/Contact/Profile.php:463
#: src/Module/Notifications/Introductions.php:128
#: src/Module/Notifications/Introductions.php:200
#: src/Module/Notifications/Notification.php:61
@ -2821,7 +2827,7 @@ msgid "Sign in"
msgstr ""
#: src/Content/Nav.php:190 src/Module/BaseProfile.php:56
#: src/Module/Contact.php:576 src/Module/Contact.php:822
#: src/Module/Contact.php:433 src/Module/Contact/Profile.php:386
#: src/Module/Settings/TwoFactor/Index.php:112 view/theme/frio/theme.php:225
msgid "Status"
msgstr ""
@ -2832,8 +2838,8 @@ msgid "Your posts and conversations"
msgstr ""
#: src/Content/Nav.php:191 src/Module/BaseProfile.php:48
#: src/Module/BaseSettings.php:57 src/Module/Contact.php:578
#: src/Module/Contact.php:846 src/Module/Profile/Profile.php:241
#: src/Module/BaseSettings.php:57 src/Module/Contact.php:457
#: src/Module/Contact/Profile.php:388 src/Module/Profile/Profile.php:241
#: src/Module/Welcome.php:57 view/theme/frio/theme.php:226
msgid "Profile"
msgstr ""
@ -2847,7 +2853,7 @@ msgid "Your photos"
msgstr ""
#: src/Content/Nav.php:193 src/Module/BaseProfile.php:72
#: src/Module/BaseProfile.php:75 src/Module/Contact.php:838
#: src/Module/BaseProfile.php:75 src/Module/Contact.php:449
#: view/theme/frio/theme.php:228
msgid "Media"
msgstr ""
@ -2921,8 +2927,8 @@ msgstr ""
#: src/Content/Nav.php:235 src/Content/Nav.php:294
#: src/Content/Text/HTML.php:892 src/Module/BaseProfile.php:125
#: src/Module/BaseProfile.php:128 src/Module/Contact.php:759
#: src/Module/Contact.php:853 view/theme/frio/theme.php:236
#: src/Module/BaseProfile.php:128 src/Module/Contact.php:370
#: src/Module/Contact.php:464 view/theme/frio/theme.php:236
msgid "Contacts"
msgstr ""
@ -3152,7 +3158,7 @@ msgstr ""
msgid "Examples: Robert Morgenstein, Fishing"
msgstr ""
#: src/Content/Widget.php:78 src/Module/Contact.php:780
#: src/Content/Widget.php:78 src/Module/Contact.php:391
#: src/Module/Directory.php:96 view/theme/vier/theme.php:174
msgid "Find"
msgstr ""
@ -3179,7 +3185,7 @@ msgid "Local Directory"
msgstr ""
#: src/Content/Widget.php:207 src/Model/Group.php:493
#: src/Module/Contact.php:743 src/Module/Welcome.php:76
#: src/Module/Contact.php:354 src/Module/Welcome.php:76
msgid "Groups"
msgstr ""
@ -3191,7 +3197,7 @@ msgstr ""
msgid "Relationships"
msgstr ""
#: src/Content/Widget.php:240 src/Module/Contact.php:695
#: src/Content/Widget.php:240 src/Module/Contact.php:306
#: src/Module/Group.php:291
msgid "All Contacts"
msgstr ""
@ -3290,12 +3296,12 @@ msgid "More Trending Tags"
msgstr ""
#: src/Content/Widget/VCard.php:96 src/Model/Profile.php:373
#: src/Module/Contact.php:567 src/Module/Profile/Profile.php:176
#: src/Module/Contact/Profile.php:377 src/Module/Profile/Profile.php:176
msgid "XMPP:"
msgstr ""
#: src/Content/Widget/VCard.php:97 src/Model/Profile.php:374
#: src/Module/Contact.php:569 src/Module/Profile/Profile.php:180
#: src/Module/Contact/Profile.php:379 src/Module/Profile/Profile.php:180
msgid "Matrix:"
msgstr ""
@ -4300,7 +4306,7 @@ msgstr ""
msgid "Homepage:"
msgstr ""
#: src/Model/Profile.php:372 src/Module/Contact.php:571
#: src/Model/Profile.php:372 src/Module/Contact/Profile.php:381
#: src/Module/Notifications/Introductions.php:183
msgid "About:"
msgstr ""
@ -4426,142 +4432,142 @@ msgstr ""
msgid "Contact information and Social Networks"
msgstr ""
#: src/Model/User.php:208 src/Model/User.php:1030
#: src/Model/User.php:208 src/Model/User.php:1029
msgid "SERIOUS ERROR: Generation of security keys failed."
msgstr ""
#: src/Model/User.php:569 src/Model/User.php:602
#: src/Model/User.php:568 src/Model/User.php:601
msgid "Login failed"
msgstr ""
#: src/Model/User.php:634
#: src/Model/User.php:633
msgid "Not enough information to authenticate"
msgstr ""
#: src/Model/User.php:729
#: src/Model/User.php:728
msgid "Password can't be empty"
msgstr ""
#: src/Model/User.php:748
#: src/Model/User.php:747
msgid "Empty passwords are not allowed."
msgstr ""
#: src/Model/User.php:752
#: src/Model/User.php:751
msgid ""
"The new password has been exposed in a public data dump, please choose "
"another."
msgstr ""
#: src/Model/User.php:758
#: src/Model/User.php:757
msgid ""
"The password can't contain accentuated letters, white spaces or colons (:)"
msgstr ""
#: src/Model/User.php:910
#: src/Model/User.php:909
msgid "Passwords do not match. Password unchanged."
msgstr ""
#: src/Model/User.php:917
#: src/Model/User.php:916
msgid "An invitation is required."
msgstr ""
#: src/Model/User.php:921
#: src/Model/User.php:920
msgid "Invitation could not be verified."
msgstr ""
#: src/Model/User.php:929
#: src/Model/User.php:928
msgid "Invalid OpenID url"
msgstr ""
#: src/Model/User.php:942 src/Security/Authentication.php:235
#: src/Model/User.php:941 src/Security/Authentication.php:235
msgid ""
"We encountered a problem while logging in with the OpenID you provided. "
"Please check the correct spelling of the ID."
msgstr ""
#: src/Model/User.php:942 src/Security/Authentication.php:235
#: src/Model/User.php:941 src/Security/Authentication.php:235
msgid "The error message was:"
msgstr ""
#: src/Model/User.php:948
#: src/Model/User.php:947
msgid "Please enter the required information."
msgstr ""
#: src/Model/User.php:962
#: src/Model/User.php:961
#, php-format
msgid ""
"system.username_min_length (%s) and system.username_max_length (%s) are "
"excluding each other, swapping values."
msgstr ""
#: src/Model/User.php:969
#: src/Model/User.php:968
#, php-format
msgid "Username should be at least %s character."
msgid_plural "Username should be at least %s characters."
msgstr[0] ""
msgstr[1] ""
#: src/Model/User.php:973
#: src/Model/User.php:972
#, php-format
msgid "Username should be at most %s character."
msgid_plural "Username should be at most %s characters."
msgstr[0] ""
msgstr[1] ""
#: src/Model/User.php:981
#: src/Model/User.php:980
msgid "That doesn't appear to be your full (First Last) name."
msgstr ""
#: src/Model/User.php:986
#: src/Model/User.php:985
msgid "Your email domain is not among those allowed on this site."
msgstr ""
#: src/Model/User.php:990
#: src/Model/User.php:989
msgid "Not a valid email address."
msgstr ""
#: src/Model/User.php:993
#: src/Model/User.php:992
msgid "The nickname was blocked from registration by the nodes admin."
msgstr ""
#: src/Model/User.php:997 src/Model/User.php:1005
#: src/Model/User.php:996 src/Model/User.php:1004
msgid "Cannot use that email."
msgstr ""
#: src/Model/User.php:1012
#: src/Model/User.php:1011
msgid "Your nickname can only contain a-z, 0-9 and _."
msgstr ""
#: src/Model/User.php:1020 src/Model/User.php:1077
#: src/Model/User.php:1019 src/Model/User.php:1076
msgid "Nickname is already registered. Please choose another."
msgstr ""
#: src/Model/User.php:1064 src/Model/User.php:1068
#: src/Model/User.php:1063 src/Model/User.php:1067
msgid "An error occurred during registration. Please try again."
msgstr ""
#: src/Model/User.php:1091
#: src/Model/User.php:1090
msgid "An error occurred creating your default profile. Please try again."
msgstr ""
#: src/Model/User.php:1098
#: src/Model/User.php:1097
msgid "An error occurred creating your self contact. Please try again."
msgstr ""
#: src/Model/User.php:1103
#: src/Model/User.php:1102
msgid "Friends"
msgstr ""
#: src/Model/User.php:1107
#: src/Model/User.php:1106
msgid ""
"An error occurred creating your default contact group. Please try again."
msgstr ""
#: src/Model/User.php:1145
#: src/Model/User.php:1144
msgid "Profile Photos"
msgstr ""
#: src/Model/User.php:1339
#: src/Model/User.php:1338
#, php-format
msgid ""
"\n"
@ -4569,7 +4575,7 @@ msgid ""
"\t\t\tthe administrator of %2$s has set up an account for you."
msgstr ""
#: src/Model/User.php:1342
#: src/Model/User.php:1341
#, php-format
msgid ""
"\n"
@ -4606,12 +4612,12 @@ msgid ""
"\t\tThank you and welcome to %4$s."
msgstr ""
#: src/Model/User.php:1375 src/Model/User.php:1482
#: src/Model/User.php:1374 src/Model/User.php:1481
#, php-format
msgid "Registration details for %s"
msgstr ""
#: src/Model/User.php:1395
#: src/Model/User.php:1394
#, php-format
msgid ""
"\n"
@ -4627,12 +4633,12 @@ msgid ""
"\t\t"
msgstr ""
#: src/Model/User.php:1414
#: src/Model/User.php:1413
#, php-format
msgid "Registration at %s"
msgstr ""
#: src/Model/User.php:1438
#: src/Model/User.php:1437
#, php-format
msgid ""
"\n"
@ -4641,7 +4647,7 @@ msgid ""
"\t\t\t"
msgstr ""
#: src/Model/User.php:1446
#: src/Model/User.php:1445
#, php-format
msgid ""
"\n"
@ -4773,8 +4779,8 @@ msgstr ""
msgid "List of active accounts"
msgstr ""
#: src/Module/Admin/BaseUsers.php:66 src/Module/Contact.php:703
#: src/Module/Contact.php:763
#: src/Module/Admin/BaseUsers.php:66 src/Module/Contact.php:314
#: src/Module/Contact.php:374
msgid "Pending"
msgstr ""
@ -4782,8 +4788,8 @@ msgstr ""
msgid "List of pending registrations"
msgstr ""
#: src/Module/Admin/BaseUsers.php:74 src/Module/Contact.php:711
#: src/Module/Contact.php:764
#: src/Module/Admin/BaseUsers.php:74 src/Module/Contact.php:322
#: src/Module/Contact.php:375
msgid "Blocked"
msgstr ""
@ -4844,8 +4850,8 @@ msgstr ""
#: src/Module/Admin/Blocklist/Contact.php:101
#: src/Module/Admin/Users/Blocked.php:142 src/Module/Admin/Users/Index.php:156
#: src/Module/Contact.php:544 src/Module/Contact.php:787
#: src/Module/Contact.php:1064
#: src/Module/Contact.php:398 src/Module/Contact/Profile.php:354
#: src/Module/Contact/Profile.php:455
msgid "Unblock"
msgstr ""
@ -6266,7 +6272,7 @@ msgid ""
"received."
msgstr ""
#: src/Module/Admin/Site.php:610 src/Module/Contact.php:473
#: src/Module/Admin/Site.php:610 src/Module/Contact/Profile.php:279
#: src/Module/Settings/TwoFactor/Index.php:118
msgid "Disabled"
msgstr ""
@ -6843,8 +6849,7 @@ msgstr ""
msgid "Posts from %s can't be unshared"
msgstr ""
#: src/Module/Api/Twitter/ContactEndpoint.php:64 src/Module/Contact.php:343
#: src/Module/Contact.php:358
#: src/Module/Api/Twitter/ContactEndpoint.php:64
msgid "Contact not found"
msgstr ""
@ -6951,7 +6956,7 @@ msgstr ""
msgid "Too Many Requests"
msgstr ""
#: src/Module/BaseProfile.php:51 src/Module/Contact.php:849
#: src/Module/BaseProfile.php:51 src/Module/Contact.php:460
msgid "Profile Details"
msgstr ""
@ -7018,357 +7023,119 @@ msgstr ""
msgid "The post was created"
msgstr ""
#: src/Module/Contact.php:93
#: src/Module/Contact.php:88
#, php-format
msgid "%d contact edited."
msgid_plural "%d contacts edited."
msgstr[0] ""
msgstr[1] ""
#: src/Module/Contact.php:118
msgid "Could not access contact record."
msgstr ""
#: src/Module/Contact.php:154
msgid "Failed to update contact record."
msgstr ""
#: src/Module/Contact.php:375
msgid "You can't block yourself"
msgstr ""
#: src/Module/Contact.php:381
msgid "Contact has been blocked"
msgstr ""
#: src/Module/Contact.php:381
msgid "Contact has been unblocked"
msgstr ""
#: src/Module/Contact.php:389
msgid "You can't ignore yourself"
msgstr ""
#: src/Module/Contact.php:395
msgid "Contact has been ignored"
msgstr ""
#: src/Module/Contact.php:395
msgid "Contact has been unignored"
msgstr ""
#: src/Module/Contact.php:415
#, php-format
msgid "You are mutual friends with %s"
msgstr ""
#: src/Module/Contact.php:419
#, php-format
msgid "You are sharing with %s"
msgstr ""
#: src/Module/Contact.php:423
#, php-format
msgid "%s is sharing with you"
msgstr ""
#: src/Module/Contact.php:447
msgid "Private communications are not available for this contact."
msgstr ""
#: src/Module/Contact.php:449
msgid "Never"
msgstr ""
#: src/Module/Contact.php:452
msgid "(Update was not successful)"
msgstr ""
#: src/Module/Contact.php:452
msgid "(Update was successful)"
msgstr ""
#: src/Module/Contact.php:454 src/Module/Contact.php:1035
msgid "Suggest friends"
msgstr ""
#: src/Module/Contact.php:458
#, php-format
msgid "Network type: %s"
msgstr ""
#: src/Module/Contact.php:463
msgid "Communications lost with this contact!"
msgstr ""
#: src/Module/Contact.php:469
msgid "Fetch further information for feeds"
msgstr ""
#: src/Module/Contact.php:471
msgid ""
"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."
msgstr ""
#: src/Module/Contact.php:474
msgid "Fetch information"
msgstr ""
#: src/Module/Contact.php:475
msgid "Fetch keywords"
msgstr ""
#: src/Module/Contact.php:476
msgid "Fetch information and keywords"
msgstr ""
#: src/Module/Contact.php:488 src/Module/Contact.php:492
#: src/Module/Contact.php:495 src/Module/Contact.php:499
msgid "No mirroring"
msgstr ""
#: src/Module/Contact.php:489
msgid "Mirror as forwarded posting"
msgstr ""
#: src/Module/Contact.php:490 src/Module/Contact.php:496
#: src/Module/Contact.php:500
msgid "Mirror as my own posting"
msgstr ""
#: src/Module/Contact.php:493 src/Module/Contact.php:497
msgid "Native reshare"
msgstr ""
#: src/Module/Contact.php:512
msgid "Contact Information / Notes"
msgstr ""
#: src/Module/Contact.php:513
msgid "Contact Settings"
msgstr ""
#: src/Module/Contact.php:521
msgid "Contact"
msgstr ""
#: src/Module/Contact.php:525
msgid "Their personal note"
msgstr ""
#: src/Module/Contact.php:527
msgid "Edit contact notes"
msgstr ""
#: src/Module/Contact.php:530 src/Module/Contact.php:1001
#, php-format
msgid "Visit %s's profile [%s]"
msgstr ""
#: src/Module/Contact.php:531
msgid "Block/Unblock contact"
msgstr ""
#: src/Module/Contact.php:532
msgid "Ignore contact"
msgstr ""
#: src/Module/Contact.php:533
msgid "View conversations"
msgstr ""
#: src/Module/Contact.php:538
msgid "Last update:"
msgstr ""
#: src/Module/Contact.php:540
msgid "Update public posts"
msgstr ""
#: src/Module/Contact.php:542 src/Module/Contact.php:1045
msgid "Update now"
msgstr ""
#: src/Module/Contact.php:545 src/Module/Contact.php:788
#: src/Module/Contact.php:1072
msgid "Unignore"
msgstr ""
#: src/Module/Contact.php:549
msgid "Currently blocked"
msgstr ""
#: src/Module/Contact.php:550
msgid "Currently ignored"
msgstr ""
#: src/Module/Contact.php:551
msgid "Currently archived"
msgstr ""
#: src/Module/Contact.php:552
msgid "Awaiting connection acknowledge"
msgstr ""
#: src/Module/Contact.php:553 src/Module/Notifications/Introductions.php:186
msgid "Hide this contact from others"
msgstr ""
#: src/Module/Contact.php:553
msgid ""
"Replies/likes to your public posts <strong>may</strong> still be visible"
msgstr ""
#: src/Module/Contact.php:554
msgid "Notification for new posts"
msgstr ""
#: src/Module/Contact.php:554
msgid "Send a notification of every new post of this contact"
msgstr ""
#: src/Module/Contact.php:556
msgid "Keyword Deny List"
msgstr ""
#: src/Module/Contact.php:556
msgid ""
"Comma separated list of keywords that should not be converted to hashtags, "
"when \"Fetch information and keywords\" is selected"
msgstr ""
#: src/Module/Contact.php:574 src/Module/Settings/TwoFactor/Index.php:132
msgid "Actions"
msgstr ""
#: src/Module/Contact.php:581
msgid "Mirror postings from this contact"
msgstr ""
#: src/Module/Contact.php:583
msgid ""
"Mark this contact as remote_self, this will cause friendica to repost new "
"entries from this contact."
msgstr ""
#: src/Module/Contact.php:698
#: src/Module/Contact.php:309
msgid "Show all contacts"
msgstr ""
#: src/Module/Contact.php:706
#: src/Module/Contact.php:317
msgid "Only show pending contacts"
msgstr ""
#: src/Module/Contact.php:714
#: src/Module/Contact.php:325
msgid "Only show blocked contacts"
msgstr ""
#: src/Module/Contact.php:719 src/Module/Contact.php:766
#: src/Module/Contact.php:330 src/Module/Contact.php:377
#: src/Object/Post.php:309
msgid "Ignored"
msgstr ""
#: src/Module/Contact.php:722
#: src/Module/Contact.php:333
msgid "Only show ignored contacts"
msgstr ""
#: src/Module/Contact.php:727 src/Module/Contact.php:767
#: src/Module/Contact.php:338 src/Module/Contact.php:378
msgid "Archived"
msgstr ""
#: src/Module/Contact.php:730
#: src/Module/Contact.php:341
msgid "Only show archived contacts"
msgstr ""
#: src/Module/Contact.php:735 src/Module/Contact.php:765
#: src/Module/Contact.php:346 src/Module/Contact.php:376
msgid "Hidden"
msgstr ""
#: src/Module/Contact.php:738
#: src/Module/Contact.php:349
msgid "Only show hidden contacts"
msgstr ""
#: src/Module/Contact.php:746
#: src/Module/Contact.php:357
msgid "Organize your contact groups"
msgstr ""
#: src/Module/Contact.php:778
#: src/Module/Contact.php:389
msgid "Search your contacts"
msgstr ""
#: src/Module/Contact.php:779 src/Module/Search/Index.php:191
#: src/Module/Contact.php:390 src/Module/Search/Index.php:191
#, php-format
msgid "Results for: %s"
msgstr ""
#: src/Module/Contact.php:786
#: src/Module/Contact.php:397
msgid "Update"
msgstr ""
#: src/Module/Contact.php:790
#: src/Module/Contact.php:399 src/Module/Contact/Profile.php:355
#: src/Module/Contact/Profile.php:463
msgid "Unignore"
msgstr ""
#: src/Module/Contact.php:401
msgid "Batch Actions"
msgstr ""
#: src/Module/Contact.php:825
#: src/Module/Contact.php:436
msgid "Conversations started by this contact"
msgstr ""
#: src/Module/Contact.php:830
#: src/Module/Contact.php:441
msgid "Posts and Comments"
msgstr ""
#: src/Module/Contact.php:841
#: src/Module/Contact.php:452
msgid "Posts containing media objects"
msgstr ""
#: src/Module/Contact.php:856
#: src/Module/Contact.php:467
msgid "View all known contacts"
msgstr ""
#: src/Module/Contact.php:866
#: src/Module/Contact.php:477
msgid "Advanced Contact Settings"
msgstr ""
#: src/Module/Contact.php:960
#: src/Module/Contact.php:511
msgid "Mutual Friendship"
msgstr ""
#: src/Module/Contact.php:964
#: src/Module/Contact.php:515
msgid "is a fan of yours"
msgstr ""
#: src/Module/Contact.php:968
#: src/Module/Contact.php:519
msgid "you are a fan of"
msgstr ""
#: src/Module/Contact.php:986
#: src/Module/Contact.php:537
msgid "Pending outgoing contact request"
msgstr ""
#: src/Module/Contact.php:988
#: src/Module/Contact.php:539
msgid "Pending incoming contact request"
msgstr ""
#: src/Module/Contact.php:1055
msgid "Refetch contact data"
msgstr ""
#: src/Module/Contact.php:1066
msgid "Toggle Blocked status"
msgstr ""
#: src/Module/Contact.php:1074
msgid "Toggle Ignored status"
msgstr ""
#: src/Module/Contact.php:1081 src/Module/Contact/Revoke.php:111
msgid "Revoke Follow"
msgstr ""
#: src/Module/Contact.php:1083
msgid "Revoke the follow from this contact"
#: src/Module/Contact.php:552 src/Module/Contact/Profile.php:340
#, php-format
msgid "Visit %s's profile [%s]"
msgstr ""
#: src/Module/Contact/Advanced.php:109
@ -7510,6 +7277,234 @@ msgstr ""
msgid "Make this post private"
msgstr ""
#: src/Module/Contact/Profile.php:133
msgid "Failed to update contact record."
msgstr ""
#: src/Module/Contact/Profile.php:183
msgid "Contact has been unblocked"
msgstr ""
#: src/Module/Contact/Profile.php:187
msgid "Contact has been blocked"
msgstr ""
#: src/Module/Contact/Profile.php:199
msgid "Contact has been unignored"
msgstr ""
#: src/Module/Contact/Profile.php:203
msgid "Contact has been ignored"
msgstr ""
#: src/Module/Contact/Profile.php:235
#, php-format
msgid "You are mutual friends with %s"
msgstr ""
#: src/Module/Contact/Profile.php:236
#, php-format
msgid "You are sharing with %s"
msgstr ""
#: src/Module/Contact/Profile.php:237
#, php-format
msgid "%s is sharing with you"
msgstr ""
#: src/Module/Contact/Profile.php:253
msgid "Private communications are not available for this contact."
msgstr ""
#: src/Module/Contact/Profile.php:255
msgid "Never"
msgstr ""
#: src/Module/Contact/Profile.php:258
msgid "(Update was not successful)"
msgstr ""
#: src/Module/Contact/Profile.php:258
msgid "(Update was successful)"
msgstr ""
#: src/Module/Contact/Profile.php:260 src/Module/Contact/Profile.php:426
msgid "Suggest friends"
msgstr ""
#: src/Module/Contact/Profile.php:264
#, php-format
msgid "Network type: %s"
msgstr ""
#: src/Module/Contact/Profile.php:269
msgid "Communications lost with this contact!"
msgstr ""
#: src/Module/Contact/Profile.php:275
msgid "Fetch further information for feeds"
msgstr ""
#: src/Module/Contact/Profile.php:277
msgid ""
"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."
msgstr ""
#: src/Module/Contact/Profile.php:280
msgid "Fetch information"
msgstr ""
#: src/Module/Contact/Profile.php:281
msgid "Fetch keywords"
msgstr ""
#: src/Module/Contact/Profile.php:282
msgid "Fetch information and keywords"
msgstr ""
#: src/Module/Contact/Profile.php:292 src/Module/Contact/Profile.php:298
#: src/Module/Contact/Profile.php:303 src/Module/Contact/Profile.php:309
msgid "No mirroring"
msgstr ""
#: src/Module/Contact/Profile.php:293
msgid "Mirror as forwarded posting"
msgstr ""
#: src/Module/Contact/Profile.php:294 src/Module/Contact/Profile.php:304
#: src/Module/Contact/Profile.php:310
msgid "Mirror as my own posting"
msgstr ""
#: src/Module/Contact/Profile.php:299 src/Module/Contact/Profile.php:305
msgid "Native reshare"
msgstr ""
#: src/Module/Contact/Profile.php:322
msgid "Contact Information / Notes"
msgstr ""
#: src/Module/Contact/Profile.php:323
msgid "Contact Settings"
msgstr ""
#: src/Module/Contact/Profile.php:331
msgid "Contact"
msgstr ""
#: src/Module/Contact/Profile.php:335
msgid "Their personal note"
msgstr ""
#: src/Module/Contact/Profile.php:337
msgid "Edit contact notes"
msgstr ""
#: src/Module/Contact/Profile.php:341
msgid "Block/Unblock contact"
msgstr ""
#: src/Module/Contact/Profile.php:342
msgid "Ignore contact"
msgstr ""
#: src/Module/Contact/Profile.php:343
msgid "View conversations"
msgstr ""
#: src/Module/Contact/Profile.php:348
msgid "Last update:"
msgstr ""
#: src/Module/Contact/Profile.php:350
msgid "Update public posts"
msgstr ""
#: src/Module/Contact/Profile.php:352 src/Module/Contact/Profile.php:436
msgid "Update now"
msgstr ""
#: src/Module/Contact/Profile.php:359
msgid "Currently blocked"
msgstr ""
#: src/Module/Contact/Profile.php:360
msgid "Currently ignored"
msgstr ""
#: src/Module/Contact/Profile.php:361
msgid "Currently archived"
msgstr ""
#: src/Module/Contact/Profile.php:362
msgid "Awaiting connection acknowledge"
msgstr ""
#: src/Module/Contact/Profile.php:363
#: src/Module/Notifications/Introductions.php:186
msgid "Hide this contact from others"
msgstr ""
#: src/Module/Contact/Profile.php:363
msgid ""
"Replies/likes to your public posts <strong>may</strong> still be visible"
msgstr ""
#: src/Module/Contact/Profile.php:364
msgid "Notification for new posts"
msgstr ""
#: src/Module/Contact/Profile.php:364
msgid "Send a notification of every new post of this contact"
msgstr ""
#: src/Module/Contact/Profile.php:366
msgid "Keyword Deny List"
msgstr ""
#: src/Module/Contact/Profile.php:366
msgid ""
"Comma separated list of keywords that should not be converted to hashtags, "
"when \"Fetch information and keywords\" is selected"
msgstr ""
#: src/Module/Contact/Profile.php:384
#: src/Module/Settings/TwoFactor/Index.php:132
msgid "Actions"
msgstr ""
#: src/Module/Contact/Profile.php:392
msgid "Mirror postings from this contact"
msgstr ""
#: src/Module/Contact/Profile.php:394
msgid ""
"Mark this contact as remote_self, this will cause friendica to repost new "
"entries from this contact."
msgstr ""
#: src/Module/Contact/Profile.php:446
msgid "Refetch contact data"
msgstr ""
#: src/Module/Contact/Profile.php:457
msgid "Toggle Blocked status"
msgstr ""
#: src/Module/Contact/Profile.php:465
msgid "Toggle Ignored status"
msgstr ""
#: src/Module/Contact/Profile.php:472 src/Module/Contact/Revoke.php:111
msgid "Revoke Follow"
msgstr ""
#: src/Module/Contact/Profile.php:474
msgid "Revoke the follow from this contact"
msgstr ""
#: src/Module/Contact/Revoke.php:63
msgid "Unknown contact."
msgstr ""

View file

@ -174,7 +174,7 @@
{{* 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 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>&nbsp;{{$item.menu}}</button>

View file

@ -326,7 +326,7 @@ as the value of $top_child_total (this is done at the end of this file)
{{/if}}
{{* 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 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>&nbsp;{{$item.menu}}</button>