diff --git a/database.sql b/database.sql index 74b7552c30..11fbd514e7 100644 --- a/database.sql +++ b/database.sql @@ -1,6 +1,6 @@ -- ------------------------------------------ -- Friendica 2023.09-dev (Giant Rhubarb) --- DB_UPDATE_VERSION 1524 +-- DB_UPDATE_VERSION 1529 -- ------------------------------------------ @@ -101,6 +101,19 @@ CREATE TABLE IF NOT EXISTS `user` ( FOREIGN KEY (`parent-uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='The local users'; +-- +-- TABLE user-gserver +-- +CREATE TABLE IF NOT EXISTS `user-gserver` ( + `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'Owner User id', + `gsid` int unsigned NOT NULL DEFAULT 0 COMMENT 'Gserver id', + `ignored` boolean NOT NULL DEFAULT '0' COMMENT 'server accounts are ignored for the user', + PRIMARY KEY(`uid`,`gsid`), + INDEX `gsid` (`gsid`), + FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE, + FOREIGN KEY (`gsid`) REFERENCES `gserver` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='User settings about remote servers'; + -- -- TABLE item-uri -- @@ -160,8 +173,8 @@ CREATE TABLE IF NOT EXISTS `contact` ( `archive` boolean NOT NULL DEFAULT '0' COMMENT '', `unsearchable` boolean NOT NULL DEFAULT '0' COMMENT 'Contact prefers to not be searchable', `sensitive` boolean NOT NULL DEFAULT '0' COMMENT 'Contact posts sensitive content', - `baseurl` varbinary(383) DEFAULT '' COMMENT 'baseurl of the contact', - `gsid` int unsigned COMMENT 'Global Server ID', + `baseurl` varbinary(383) DEFAULT '' COMMENT 'baseurl of the contact from the gserver record, can be missing', + `gsid` int unsigned COMMENT 'Global Server ID, can be missing', `bd` date NOT NULL DEFAULT '0001-01-01' COMMENT '', `reason` text COMMENT '', `self` boolean NOT NULL DEFAULT '0' COMMENT '1 if the contact is the user him/her self', @@ -1586,7 +1599,7 @@ CREATE TABLE IF NOT EXISTS `profile` ( `profile-name` varchar(255) COMMENT 'Deprecated', `is-default` boolean COMMENT 'Deprecated', `hide-friends` boolean NOT NULL DEFAULT '0' COMMENT 'Hide friend list from viewers of this profile', - `name` varchar(255) NOT NULL DEFAULT '' COMMENT '', + `name` varchar(255) NOT NULL DEFAULT '' COMMENT 'Unused in favor of user.username', `pdesc` varchar(255) COMMENT 'Deprecated', `dob` varchar(32) NOT NULL DEFAULT '0000-00-00' COMMENT 'Day of birth', `address` varchar(255) NOT NULL DEFAULT '' COMMENT '', @@ -2032,6 +2045,7 @@ CREATE VIEW `post-user-view` AS SELECT `author`.`hidden` AS `author-hidden`, `author`.`updated` AS `author-updated`, `author`.`gsid` AS `author-gsid`, + `author`.`baseurl` AS `author-baseurl`, `post-user`.`owner-id` AS `owner-id`, `owner`.`uri-id` AS `owner-uri-id`, `owner`.`url` AS `owner-link`, @@ -2044,6 +2058,7 @@ CREATE VIEW `post-user-view` AS SELECT `owner`.`blocked` AS `owner-blocked`, `owner`.`hidden` AS `owner-hidden`, `owner`.`updated` AS `owner-updated`, + `owner`.`gsid` AS `owner-gsid`, `owner`.`contact-type` AS `owner-contact-type`, `post-user`.`causer-id` AS `causer-id`, `causer`.`uri-id` AS `causer-uri-id`, @@ -2056,6 +2071,7 @@ CREATE VIEW `post-user-view` AS SELECT `causer`.`network` AS `causer-network`, `causer`.`blocked` AS `causer-blocked`, `causer`.`hidden` AS `causer-hidden`, + `causer`.`gsid` AS `causer-gsid`, `causer`.`contact-type` AS `causer-contact-type`, `post-delivery-data`.`postopts` AS `postopts`, `post-delivery-data`.`inform` AS `inform`, @@ -2189,6 +2205,7 @@ CREATE VIEW `post-thread-user-view` AS SELECT `contact`.`pending` AS `contact-pending`, `contact`.`rel` AS `contact-rel`, `contact`.`uid` AS `contact-uid`, + `contact`.`gsid` AS `contact-gsid`, `contact`.`contact-type` AS `contact-contact-type`, IF (`post-user`.`network` IN ('apub', 'dfrn', 'dspr', 'stat'), true, `contact`.`writable`) AS `writable`, `contact`.`self` AS `self`, @@ -2224,6 +2241,7 @@ CREATE VIEW `post-thread-user-view` AS SELECT `owner`.`blocked` AS `owner-blocked`, `owner`.`hidden` AS `owner-hidden`, `owner`.`updated` AS `owner-updated`, + `owner`.`gsid` AS `owner-gsid`, `owner`.`contact-type` AS `owner-contact-type`, `post-thread-user`.`causer-id` AS `causer-id`, `causer`.`uri-id` AS `causer-uri-id`, @@ -2236,6 +2254,7 @@ CREATE VIEW `post-thread-user-view` AS SELECT `causer`.`network` AS `causer-network`, `causer`.`blocked` AS `causer-blocked`, `causer`.`hidden` AS `causer-hidden`, + `causer`.`gsid` AS `causer-gsid`, `causer`.`contact-type` AS `causer-contact-type`, `post-delivery-data`.`postopts` AS `postopts`, `post-delivery-data`.`inform` AS `inform`, @@ -2391,6 +2410,7 @@ CREATE VIEW `post-view` AS SELECT `owner`.`hidden` AS `owner-hidden`, `owner`.`updated` AS `owner-updated`, `owner`.`contact-type` AS `owner-contact-type`, + `owner`.`gsid` AS `owner-gsid`, `post`.`causer-id` AS `causer-id`, `causer`.`uri-id` AS `causer-uri-id`, `causer`.`url` AS `causer-link`, @@ -2403,6 +2423,7 @@ CREATE VIEW `post-view` AS SELECT `causer`.`blocked` AS `causer-blocked`, `causer`.`hidden` AS `causer-hidden`, `causer`.`contact-type` AS `causer-contact-type`, + `causer`.`gsid` AS `causer-gsid`, `post-question`.`id` AS `question-id`, `post-question`.`multiple` AS `question-multiple`, `post-question`.`voters` AS `question-voters`, @@ -2533,6 +2554,7 @@ CREATE VIEW `post-thread-view` AS SELECT `owner`.`blocked` AS `owner-blocked`, `owner`.`hidden` AS `owner-hidden`, `owner`.`updated` AS `owner-updated`, + `owner`.`gsid` AS `owner-gsid`, `owner`.`contact-type` AS `owner-contact-type`, `post-thread`.`causer-id` AS `causer-id`, `causer`.`uri-id` AS `causer-uri-id`, @@ -2545,6 +2567,7 @@ CREATE VIEW `post-thread-view` AS SELECT `causer`.`network` AS `causer-network`, `causer`.`blocked` AS `causer-blocked`, `causer`.`hidden` AS `causer-hidden`, + `causer`.`gsid` AS `causer-gsid`, `causer`.`contact-type` AS `causer-contact-type`, `post-question`.`id` AS `question-id`, `post-question`.`multiple` AS `question-multiple`, @@ -2666,18 +2689,16 @@ CREATE VIEW `network-item-view` AS SELECT `post-user`.`contact-id` AS `contact-id`, `ownercontact`.`contact-type` AS `contact-type` FROM `post-user` - INNER JOIN `post-thread-user` ON `post-thread-user`.`uri-id` = `post-user`.`parent-uri-id` AND `post-thread-user`.`uid` = `post-user`.`uid` + INNER JOIN `post-thread-user` ON `post-thread-user`.`uri-id` = `post-user`.`parent-uri-id` AND `post-thread-user`.`uid` = `post-user`.`uid` STRAIGHT_JOIN `contact` ON `contact`.`id` = `post-thread-user`.`contact-id` STRAIGHT_JOIN `contact` AS `authorcontact` ON `authorcontact`.`id` = `post-thread-user`.`author-id` STRAIGHT_JOIN `contact` AS `ownercontact` ON `ownercontact`.`id` = `post-thread-user`.`owner-id` - LEFT JOIN `user-contact` AS `author` ON `author`.`uid` = `post-thread-user`.`uid` AND `author`.`cid` = `post-thread-user`.`author-id` - LEFT JOIN `user-contact` AS `owner` ON `owner`.`uid` = `post-thread-user`.`uid` AND `owner`.`cid` = `post-thread-user`.`owner-id` WHERE `post-user`.`visible` AND NOT `post-user`.`deleted` AND (NOT `contact`.`readonly` AND NOT `contact`.`blocked` AND NOT `contact`.`pending`) AND (`post-user`.`hidden` IS NULL OR NOT `post-user`.`hidden`) AND NOT `authorcontact`.`blocked` AND NOT `ownercontact`.`blocked` - AND (`author`.`blocked` IS NULL OR NOT `author`.`blocked`) - AND (`owner`.`blocked` IS NULL OR NOT `owner`.`blocked`); + AND NOT EXISTS(SELECT `cid` FROM `user-contact` WHERE `uid` = `post-thread-user`.`uid` AND `cid` IN (`authorcontact`.`id`, `ownercontact`.`id`) AND (`blocked` OR `ignored`)) + AND NOT EXISTS(SELECT `gsid` FROM `user-gserver` WHERE `uid` = `post-thread-user`.`uid` AND `gsid` IN (`authorcontact`.`gsid`, `ownercontact`.`gsid`) AND `ignored`); -- -- VIEW network-thread-view @@ -2700,14 +2721,12 @@ CREATE VIEW `network-thread-view` AS SELECT STRAIGHT_JOIN `contact` ON `contact`.`id` = `post-thread-user`.`contact-id` STRAIGHT_JOIN `contact` AS `authorcontact` ON `authorcontact`.`id` = `post-thread-user`.`author-id` STRAIGHT_JOIN `contact` AS `ownercontact` ON `ownercontact`.`id` = `post-thread-user`.`owner-id` - LEFT JOIN `user-contact` AS `author` ON `author`.`uid` = `post-thread-user`.`uid` AND `author`.`cid` = `post-thread-user`.`author-id` - LEFT JOIN `user-contact` AS `owner` ON `owner`.`uid` = `post-thread-user`.`uid` AND `owner`.`cid` = `post-thread-user`.`owner-id` WHERE `post-user`.`visible` AND NOT `post-user`.`deleted` AND (NOT `contact`.`readonly` AND NOT `contact`.`blocked` AND NOT `contact`.`pending`) AND (`post-thread-user`.`hidden` IS NULL OR NOT `post-thread-user`.`hidden`) AND NOT `authorcontact`.`blocked` AND NOT `ownercontact`.`blocked` - AND (`author`.`blocked` IS NULL OR NOT `author`.`blocked`) - AND (`owner`.`blocked` IS NULL OR NOT `owner`.`blocked`); + AND NOT EXISTS(SELECT `cid` FROM `user-contact` WHERE `uid` = `post-thread-user`.`uid` AND `cid` IN (`authorcontact`.`id`, `ownercontact`.`id`) AND (`blocked` OR `ignored`)) + AND NOT EXISTS(SELECT `gsid` FROM `user-gserver` WHERE `uid` = `post-thread-user`.`uid` AND `gsid` IN (`authorcontact`.`gsid`, `ownercontact`.`gsid`) AND `ignored`); -- -- VIEW owner-view diff --git a/doc/Update.md b/doc/Update.md index d019d03b03..40de14082c 100644 --- a/doc/Update.md +++ b/doc/Update.md @@ -10,8 +10,10 @@ If you installed Friendica in the ``path/to/friendica`` folder: 1. Unpack the new Friendica archive in ``path/to/friendica_new``. 2. Copy the following items from ``path/to/friendica`` to ``path/to/friendica_new``: * ``config/local.config.php`` - * ``proxy/`` -The following items only need to be copied if they are located inside your friendica path: + * ``proxy/`` + * ``.htaccess`` if using Apache web server + + The following items only need to be copied if they are located inside your friendica path: * your storage folder as set in **Admin -> Site -> File Upload -> Storage base path** * your item cache as set in **Admin -> Site -> Performance -> Path to item cache** * your temp folder as set in **Admin -> Site -> Advanced -> Temp path** diff --git a/doc/database.md b/doc/database.md index b928591574..2848706570 100644 --- a/doc/database.md +++ b/doc/database.md @@ -86,6 +86,7 @@ Database Tables | [tag](help/database/db_tag) | tags and mentions | | [user](help/database/db_user) | The local users | | [user-contact](help/database/db_user-contact) | User specific public contact data | +| [user-gserver](help/database/db_user-gserver) | User settings about remote servers | | [userd](help/database/db_userd) | Deleted usernames | | [verb](help/database/db_verb) | Activity Verbs | | [worker-ipc](help/database/db_worker-ipc) | Inter process communication between the frontend and the worker | diff --git a/doc/database/db_contact.md b/doc/database/db_contact.md index 496210067a..8221f279e2 100644 --- a/doc/database/db_contact.md +++ b/doc/database/db_contact.md @@ -51,8 +51,8 @@ Fields | archive | | boolean | NO | | 0 | | | unsearchable | Contact prefers to not be searchable | boolean | NO | | 0 | | | sensitive | Contact posts sensitive content | boolean | NO | | 0 | | -| baseurl | baseurl of the contact | varbinary(383) | YES | | | | -| gsid | Global Server ID | int unsigned | YES | | NULL | | +| baseurl | baseurl of the contact from the gserver record, can be missing | varbinary(383) | YES | | | | +| gsid | Global Server ID, can be missing | int unsigned | YES | | NULL | | | bd | | date | NO | | 0001-01-01 | | | reason | | text | YES | | NULL | | | self | 1 if the contact is the user him/her self | boolean | NO | | 0 | | diff --git a/doc/database/db_profile.md b/doc/database/db_profile.md index ec47b94ec6..c4a8b01709 100644 --- a/doc/database/db_profile.md +++ b/doc/database/db_profile.md @@ -13,7 +13,7 @@ Fields | profile-name | Deprecated | varchar(255) | YES | | NULL | | | is-default | Deprecated | boolean | YES | | NULL | | | hide-friends | Hide friend list from viewers of this profile | boolean | NO | | 0 | | -| name | | varchar(255) | NO | | | | +| name | Unused in favor of user.username | varchar(255) | NO | | | | | pdesc | Deprecated | varchar(255) | YES | | NULL | | | dob | Day of birth | varchar(32) | NO | | 0000-00-00 | | | address | | varchar(255) | NO | | | | diff --git a/doc/database/db_user-gserver.md b/doc/database/db_user-gserver.md new file mode 100644 index 0000000000..6cfbe34eb1 --- /dev/null +++ b/doc/database/db_user-gserver.md @@ -0,0 +1,31 @@ +Table user-gserver +=========== + +User settings about remote servers + +Fields +------ + +| Field | Description | Type | Null | Key | Default | Extra | +| ------- | ---------------------------------------- | ------------------ | ---- | --- | ------- | ----- | +| uid | Owner User id | mediumint unsigned | NO | | 0 | | +| gsid | Gserver id | int unsigned | NO | | 0 | | +| ignored | server accounts are ignored for the user | boolean | NO | | 0 | | + +Indexes +------------ + +| Name | Fields | +| ------- | --------- | +| PRIMARY | uid, gsid | +| gsid | gsid | + +Foreign Keys +------------ + +| Field | Target Table | Target Field | +|-------|--------------|--------------| +| uid | [user](help/database/db_user) | uid | +| gsid | [gserver](help/database/db_gserver) | id | + +Return to [database documentation](help/database) diff --git a/src/App/Page.php b/src/App/Page.php index 96bb59425e..e369d482e8 100644 --- a/src/App/Page.php +++ b/src/App/Page.php @@ -245,10 +245,12 @@ class Page implements ArrayAccess */ $this->page['htmlhead'] = Renderer::replaceMacros($tpl, [ '$l10n' => [ - 'delitem' => $l10n->t('Delete this item?'), - 'blockAuthor' => $l10n->t('Block this author? They won\'t be able to follow you nor see your public posts, and you won\'t be able to see their posts and their notifications.'), - 'ignoreAuthor' => $l10n->t('Ignore this author? You won\'t be able to see their posts and their notifications.'), - 'collapseAuthor' => $l10n->t('Collapse this author\'s posts?'), + 'delitem' => $l10n->t('Delete this item?'), + 'blockAuthor' => $l10n->t("Block this author? They won't be able to follow you nor see your public posts, and you won't be able to see their posts and their notifications."), + 'ignoreAuthor' => $l10n->t("Ignore this author? You won't be able to see their posts and their notifications."), + 'collapseAuthor' => $l10n->t("Collapse this author's posts?"), + 'ignoreServer' => $l10n->t("Ignore this author's server?"), + 'ignoreServerDesc' => $l10n->t("You won't see any content from this server including reshares in your Network page, the community pages and individual conversations."), 'likeError' => $l10n->t('Like not successful'), 'dislikeError' => $l10n->t('Dislike not successful'), diff --git a/src/Content/Conversation.php b/src/Content/Conversation.php index 710422ee76..7edd4415db 100644 --- a/src/Content/Conversation.php +++ b/src/Content/Conversation.php @@ -38,6 +38,7 @@ use Friendica\Database\DBA; use Friendica\Model\Contact; use Friendica\Model\Item as ItemModel; use Friendica\Model\Post; +use Friendica\Model\Post\Category; use Friendica\Model\Tag; use Friendica\Model\User; use Friendica\Model\Verb; @@ -45,6 +46,8 @@ use Friendica\Network\HTTPException\InternalServerErrorException; use Friendica\Object\Post as PostObject; use Friendica\Object\Thread; use Friendica\Protocol\Activity; +use Friendica\User\Settings\Entity\UserGServer; +use Friendica\User\Settings\Repository; use Friendica\Util\Crypto; use Friendica\Util\DateTimeFormat; use Friendica\Util\Profiler; @@ -90,22 +93,25 @@ class Conversation private $mode; /** @var IHandleUserSessions */ private $session; + /** @var Repository\UserGServer */ + private $userGServer; - public function __construct(LoggerInterface $logger, Profiler $profiler, Activity $activity, L10n $l10n, Item $item, Arguments $args, BaseURL $baseURL, IManageConfigValues $config, IManagePersonalConfigValues $pConfig, App\Page $page, App\Mode $mode, App $app, IHandleUserSessions $session) + public function __construct(Repository\UserGServer $userGServer, LoggerInterface $logger, Profiler $profiler, Activity $activity, L10n $l10n, Item $item, Arguments $args, BaseURL $baseURL, IManageConfigValues $config, IManagePersonalConfigValues $pConfig, App\Page $page, App\Mode $mode, App $app, IHandleUserSessions $session) { - $this->activity = $activity; - $this->item = $item; - $this->config = $config; - $this->mode = $mode; - $this->baseURL = $baseURL; - $this->profiler = $profiler; - $this->logger = $logger; - $this->l10n = $l10n; - $this->args = $args; - $this->pConfig = $pConfig; - $this->page = $page; - $this->app = $app; - $this->session = $session; + $this->activity = $activity; + $this->item = $item; + $this->config = $config; + $this->mode = $mode; + $this->baseURL = $baseURL; + $this->profiler = $profiler; + $this->logger = $logger; + $this->l10n = $l10n; + $this->args = $args; + $this->pConfig = $pConfig; + $this->page = $page; + $this->app = $app; + $this->session = $session; + $this->userGServer = $userGServer; } /** @@ -459,8 +465,14 @@ class Conversation $live_update_div = ''; + $userGservers = $this->userGServer->listIgnoredByUser($this->session->getLocalUserId()); + + $ignoredGsids = array_map(function (UserGServer $userGServer) { + return $userGServer->gsid; + }, $userGservers->getArrayCopy()); + if ($mode === self::MODE_NETWORK) { - $items = $this->addChildren($items, false, $order, $uid, $mode); + $items = $this->addChildren($items, false, $order, $uid, $mode, $ignoredGsids); if (!$update) { /* * The special div is needed for liveUpdate to kick in for this page. @@ -486,7 +498,7 @@ class Conversation . "'; \r\n"; } } elseif ($mode === self::MODE_PROFILE) { - $items = $this->addChildren($items, false, $order, $uid, $mode); + $items = $this->addChildren($items, false, $order, $uid, $mode, $ignoredGsids); if (!$update) { $tab = !empty($_GET['tab']) ? trim($_GET['tab']) : 'posts'; @@ -511,7 +523,7 @@ class Conversation . "; var netargs = '?f='; \r\n"; } } elseif ($mode === self::MODE_DISPLAY) { - $items = $this->addChildren($items, false, $order, $uid, $mode); + $items = $this->addChildren($items, false, $order, $uid, $mode, $ignoredGsids); if (!$update) { $live_update_div = '
' . "\r\n" @@ -519,7 +531,7 @@ class Conversation . ""; } } elseif ($mode === self::MODE_COMMUNITY) { - $items = $this->addChildren($items, true, $order, $uid, $mode); + $items = $this->addChildren($items, true, $order, $uid, $mode, $ignoredGsids); if (!$update) { $live_update_div = '
' . "\r\n" @@ -530,7 +542,7 @@ class Conversation . "'; \r\n"; } } elseif ($mode === self::MODE_CONTACTS) { - $items = $this->addChildren($items, false, $order, $uid, $mode); + $items = $this->addChildren($items, false, $order, $uid, $mode, $ignoredGsids); if (!$update) { $live_update_div = '
' . "\r\n" @@ -743,7 +755,12 @@ class Conversation $row['direction'] = ['direction' => 6, 'title' => $this->l10n->t('You are following %s.', $row['causer-name'] ?: $row['author-name'])]; break; case ItemModel::PR_TAG: - $row['direction'] = ['direction' => 4, 'title' => $this->l10n->t('You subscribed to one or more tags in this post.')]; + $tags = Category::getArrayByURIId($row['uri-id'], $row['uid'], Category::SUBCRIPTION); + if (!empty($tags)) { + $row['direction'] = ['direction' => 4, 'title' => $this->l10n->t('You subscribed to %s.', implode(', ', $tags))]; + } else { + $row['direction'] = ['direction' => 4, 'title' => $this->l10n->t('You subscribed to one or more tags in this post.')]; + } break; case ItemModel::PR_ANNOUNCEMENT: if (!empty($row['causer-id']) && $this->pConfig->get($this->session->getLocalUserId(), 'system', 'display_resharer')) { @@ -812,13 +829,14 @@ class Conversation * * @param array $parents Parent items * @param bool $block_authors - * @param bool $order + * @param string $order Either "received" or "commented" * @param int $uid - * @param string $mode + * @param string $mode One of self::MODE_* + * @param array $ignoredGsids List of ids of servers ignored by the user * @return array items with parents and comments - * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws InternalServerErrorException */ - private function addChildren(array $parents, bool $block_authors, string $order, int $uid, string $mode): array + private function addChildren(array $parents, bool $block_authors, string $order, int $uid, string $mode, array $ignoredGsids = []): array { $this->profiler->startRecording('rendering'); if (count($parents) > 1) { @@ -900,6 +918,13 @@ class Conversation continue; } + if (in_array($row['author-gsid'], $ignoredGsids) + || in_array($row['owner-gsid'], $ignoredGsids) + || in_array($row['causer-gsid'], $ignoredGsids) + ) { + continue; + } + if (($mode != self::MODE_CONTACTS) && !$row['origin']) { $row['featured'] = false; } @@ -1462,6 +1487,7 @@ class Conversation 'received' => $item['received'], 'created_date' => $item['created'], 'uriid' => $item['uri-id'], + 'author_gsid' => $item['author-gsid'], 'network' => $item['network'], 'network_name' => ContactSelector::networkToName($item['author-network'], $item['author-link'], $item['network'], $item['author-gsid']), 'network_icon' => ContactSelector::networkToIcon($item['network'], $item['author-link'], $item['author-gsid']), diff --git a/src/Content/Item.php b/src/Content/Item.php index c25e5296f0..163db89aa4 100644 --- a/src/Content/Item.php +++ b/src/Content/Item.php @@ -34,15 +34,16 @@ use Friendica\Core\Protocol; use Friendica\Core\Session\Capability\IHandleUserSessions; use Friendica\Core\System; use Friendica\Database\DBA; +use Friendica\DI; use Friendica\Model\Attach; +use Friendica\Model\Circle; use Friendica\Model\Contact; use Friendica\Model\Conversation; use Friendica\Model\FileTag; -use Friendica\Model\Circle; use Friendica\Model\Item as ItemModel; use Friendica\Model\Photo; -use Friendica\Model\Tag; use Friendica\Model\Post; +use Friendica\Model\Tag; use Friendica\Model\User; use Friendica\Network\HTTPException; use Friendica\Object\EMail\ItemCCEMail; @@ -54,6 +55,7 @@ use Friendica\Util\ParseUrl; use Friendica\Util\Profiler; use Friendica\Util\Proxy; use Friendica\Util\XML; +use GuzzleHttp\Psr7\Uri; /** * A content helper class for displaying items @@ -367,7 +369,7 @@ class Item { $this->profiler->startRecording('rendering'); $sub_link = $contact_url = $pm_url = $status_link = ''; - $photos_link = $posts_link = $block_link = $ignore_link = ''; + $photos_link = $posts_link = $block_link = $ignore_link = $collapse_link = $ignoreserver_link = ''; if ($this->userSession->getLocalUserId() && $this->userSession->getLocalUserId() == $item['uid'] && $item['gravity'] == ItemModel::GRAVITY_PARENT && !$item['self'] && !$item['mention']) { $sub_link = 'javascript:doFollowThread(' . $item['id'] . '); return false;'; @@ -407,6 +409,11 @@ class Item $collapse_link = $item['self'] ? '' : $contact_url . '/collapse?t=' . $formSecurityToken; } + $authorBaseUri = new Uri($item['author-baseurl'] ?? ''); + if (!empty($item['author-gsid']) && $authorBaseUri->getHost() && !DI::baseUrl()->isLocalUrl($authorBaseUri)) { + $ignoreserver_link = 'settings/server/' . $item['author-gsid'] . '/ignore'; + } + if ($cid && !$item['self']) { $contact_url = 'contact/' . $cid; $posts_link = $contact_url . '/posts'; @@ -427,7 +434,8 @@ class Item $this->l10n->t('Send PM') => $pm_url, $this->l10n->t('Block') => $block_link, $this->l10n->t('Ignore') => $ignore_link, - $this->l10n->t('Collapse') => $collapse_link + $this->l10n->t('Collapse') => $collapse_link, + $this->l10n->t("Ignore %s server", $authorBaseUri->getHost()) => $ignoreserver_link, ]; if (!empty($item['language'])) { diff --git a/src/DI.php b/src/DI.php index 34cf1c68d5..2d6eb6ede4 100644 --- a/src/DI.php +++ b/src/DI.php @@ -671,6 +671,15 @@ abstract class DI return self::$dice->create(Security\Authentication::class); } + // + // "User" namespace instances + // + + public static function userGServer(): User\Settings\Repository\UserGServer + { + return self::$dice->create(User\Settings\Repository\UserGServer::class); + } + // // "Util" namespace instances // diff --git a/src/Federation/Entity/GServer.php b/src/Federation/Entity/GServer.php new file mode 100644 index 0000000000..0e331f4803 --- /dev/null +++ b/src/Federation/Entity/GServer.php @@ -0,0 +1,151 @@ +. + * + */ + +namespace Friendica\Federation\Entity; + +use DateTimeImmutable; +use Psr\Http\Message\UriInterface; + +/** + * @property-read int $id + * @property-read string $url + * @property-read string $nurl + * @property-read string $version + * @property-read string $siteName + * @property-read string $info + * @property-read int $registerPolicy + * @property-read int $registeredUsers + * @property-read string $poco + * @property-read string $noscrape + * @property-read string $network + * @property-read string $platform + * @property-read int $relaySubscribe + * @property-read string $relayScope + * @property-read DateTimeImmutable $created + * @property-read ?DateTimeImmutable $lastPocoQuery + * @property-read ?DateTimeImmutable $lastContact + * @property-read ?DateTimeImmutable $lastFailure + * @property-read int $directoryType + * @property-read int $detectionMethod + * @property-read bool $failed + * @property-read DateTimeImmutable $nextContact + * @property-read int $protocol + * @property-read int $activeWeekUsers + * @property-read int $activeMonthUsers + * @property-read int $activeHalfyearUsers + * @property-read int $localPosts + * @property-read int $localComments + * @property-read bool $blocked + */ +class GServer extends \Friendica\BaseEntity +{ + /** @var ?int */ + protected $id; + /** @var UriInterface */ + protected $url; + /** @var UriInterface */ + protected $nurl; + /** @var string */ + protected $version; + /** @var string */ + protected $siteName; + /** @var string */ + protected $info; + /** @var int One of Module\Register::* constant values */ + protected $registerPolicy; + /** @var int */ + protected $registeredUsers; + /** @var ?UriInterface */ + protected $poco; + /** @var ?UriInterface */ + protected $noscrape; + /** @var string One of the Protocol::* constant values */ + protected $network; + /** @var string */ + protected $platform; + /** @var bool */ + protected $relaySubscribe; + /** @var string */ + protected $relayScope; + /** @var DateTimeImmutable */ + protected $created; + /** @var DateTimeImmutable */ + protected $lastPocoQuery; + /** @var DateTimeImmutable */ + protected $lastContact; + /** @var DateTimeImmutable */ + protected $lastFailure; + /** @var int One of Model\Gserver::DT_* constant values */ + protected $directoryType; + /** @var ?int One of Model\Gserver::DETECT_* constant values */ + protected $detectionMethod; + /** @var bool */ + protected $failed; + /** @var DateTimeImmutable */ + protected $nextContact; + /** @var ?int One of Model\Post\DeliveryData::* constant values */ + protected $protocol; + /** @var ?int */ + protected $activeWeekUsers; + /** @var ?int */ + protected $activeMonthUsers; + /** @var ?int */ + protected $activeHalfyearUsers; + /** @var ?int */ + protected $localPosts; + /** @var ?int */ + protected $localComments; + /** @var bool */ + protected $blocked; + + public function __construct(UriInterface $url, UriInterface $nurl, string $version, string $siteName, string $info, int $registerPolicy, int $registeredUsers, ?UriInterface $poco, ?UriInterface $noscrape, string $network, string $platform, bool $relaySubscribe, string $relayScope, DateTimeImmutable $created, ?DateTimeImmutable $lastPocoQuery, ?DateTimeImmutable $lastContact, ?DateTimeImmutable $lastFailure, int $directoryType, ?int $detectionMethod, bool $failed, ?DateTimeImmutable $nextContact, ?int $protocol, ?int $activeWeekUsers, ?int $activeMonthUsers, ?int $activeHalfyearUsers, ?int $localPosts, ?int $localComments, bool $blocked, ?int $id = null) + { + $this->url = $url; + $this->nurl = $nurl; + $this->version = $version; + $this->siteName = $siteName; + $this->info = $info; + $this->registerPolicy = $registerPolicy; + $this->registeredUsers = $registeredUsers; + $this->poco = $poco; + $this->noscrape = $noscrape; + $this->network = $network; + $this->platform = $platform; + $this->relaySubscribe = $relaySubscribe; + $this->relayScope = $relayScope; + $this->created = $created; + $this->lastPocoQuery = $lastPocoQuery; + $this->lastContact = $lastContact; + $this->lastFailure = $lastFailure; + $this->directoryType = $directoryType; + $this->detectionMethod = $detectionMethod; + $this->failed = $failed; + $this->nextContact = $nextContact; + $this->protocol = $protocol; + $this->activeWeekUsers = $activeWeekUsers; + $this->activeMonthUsers = $activeMonthUsers; + $this->activeHalfyearUsers = $activeHalfyearUsers; + $this->localPosts = $localPosts; + $this->localComments = $localComments; + $this->blocked = $blocked; + $this->id = $id; + } +} diff --git a/src/Federation/Factory/GServer.php b/src/Federation/Factory/GServer.php new file mode 100644 index 0000000000..681cad7af4 --- /dev/null +++ b/src/Federation/Factory/GServer.php @@ -0,0 +1,68 @@ +. + * + */ + +namespace Friendica\Federation\Factory; + +use Friendica\Capabilities\ICanCreateFromTableRow; +use Friendica\Database\DBA; +use Friendica\Federation\Entity; +use GuzzleHttp\Psr7\Uri; + +class GServer extends \Friendica\BaseFactory implements ICanCreateFromTableRow +{ + /** + * @inheritDoc + */ + public function createFromTableRow(array $row): Entity\GServer + { + return new Entity\GServer( + new Uri($row['url']), + new Uri($row['nurl']), + $row['version'], + $row['site_name'], + $row['info'] ?? '', + $row['register_policy'], + $row['registered-users'], + $row['poco'] ? new Uri($row['poco']) : null, + $row['noscrape'] ? new Uri($row['noscrape']) : null, + $row['network'], + $row['platform'], + $row['relay-subscribe'], + $row['relay-scope'], + new \DateTimeImmutable($row['created']), + $row['last_poco_query'] !== DBA::NULL_DATETIME ? new \DateTimeImmutable($row['last_poco_query']) : null, + $row['last_contact'] !== DBA::NULL_DATETIME ? new \DateTimeImmutable($row['last_contact']) : null, + $row['last_failure'] !== DBA::NULL_DATETIME ? new \DateTimeImmutable($row['last_failure']) : null, + $row['directory-type'], + $row['detection-method'], + $row['failed'], + $row['next_contact'] !== DBA::NULL_DATETIME ? new \DateTimeImmutable($row['next_contact']) : null, + $row['protocol'], + $row['active-week-users'], + $row['active-month-users'], + $row['active-halfyear-users'], + $row['local-posts'], + $row['local-comments'], + $row['blocked'], + $row['id'], + ); + } +} diff --git a/src/Federation/Repository/GServer.php b/src/Federation/Repository/GServer.php new file mode 100644 index 0000000000..47a9244f6a --- /dev/null +++ b/src/Federation/Repository/GServer.php @@ -0,0 +1,47 @@ +. + * + */ + +namespace Friendica\Federation\Repository; + +use Friendica\Database\Database; +use Friendica\Federation\Factory; +use Friendica\Federation\Entity; +use Psr\Log\LoggerInterface; + +class GServer extends \Friendica\BaseRepository +{ + protected static $table_name = 'gserver'; + + public function __construct(Database $database, LoggerInterface $logger, Factory\GServer $factory) + { + parent::__construct($database, $logger, $factory); + } + + /** + * @param int $gsid + * @return Entity\GServer + * @throws \Friendica\Network\HTTPException\NotFoundException + */ + public function selectOneById(int $gsid): Entity\GServer + { + return $this->_selectOne(['id' => $gsid]); + } +} diff --git a/src/Model/Contact.php b/src/Model/Contact.php index a18d6b9d0f..dcb7ff99c4 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -793,10 +793,10 @@ class Contact /** * Updates the self-contact for the provided user id * - * @param int $uid - * @param bool $update_avatar Force the avatar update + * @param int $uid + * @param bool $update_avatar Force the avatar update * @return bool "true" if updated - * @throws HTTPException\InternalServerErrorException + * @throws \Exception */ public static function updateSelfFromUserID(int $uid, bool $update_avatar = false): bool { diff --git a/src/Model/Item.php b/src/Model/Item.php index a2304056d3..9eddf885ca 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -32,6 +32,7 @@ use Friendica\Core\System; use Friendica\Core\Worker; use Friendica\Database\DBA; use Friendica\DI; +use Friendica\Model\Post\Category; use Friendica\Network\HTTPException\InternalServerErrorException; use Friendica\Protocol\Activity; use Friendica\Protocol\ActivityPub; @@ -95,9 +96,9 @@ class Item 'wall', 'private', 'starred', 'origin', 'parent-origin', 'title', 'body', 'language', 'content-warning', 'location', 'coord', 'app', 'rendered-hash', 'rendered-html', 'object', 'quote-uri', 'quote-uri-id', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', 'mention', 'global', - 'author-id', 'author-link', 'author-alias', 'author-name', 'author-avatar', 'author-network', 'author-updated', 'author-gsid', 'author-addr', 'author-uri-id', - 'owner-id', 'owner-link', 'owner-alias', 'owner-name', 'owner-avatar', 'owner-network', 'owner-contact-type', 'owner-updated', - 'causer-id', 'causer-link', 'causer-alias', 'causer-name', 'causer-avatar', 'causer-contact-type', 'causer-network', + 'author-id', 'author-link', 'author-alias', 'author-name', 'author-avatar', 'author-network', 'author-updated', 'author-gsid', 'author-baseurl', 'author-addr', 'author-uri-id', + 'owner-id', 'owner-link', 'owner-alias', 'owner-name', 'owner-avatar', 'owner-network', 'owner-contact-type', 'owner-updated', 'owner-gsid', + 'causer-id', 'causer-link', 'causer-alias', 'causer-name', 'causer-avatar', 'causer-contact-type', 'causer-network', 'causer-gsid', 'contact-id', 'contact-uid', 'contact-link', 'contact-name', 'contact-avatar', 'writable', 'self', 'cid', 'alias', 'event-created', 'event-edited', 'event-start', 'event-finish', @@ -1509,10 +1510,13 @@ class Item return; } - $uids = Tag::getUIDListByURIId($item['uri-id']); - foreach ($uids as $uid) { + foreach (Tag::getUIDListByURIId($item['uri-id']) as $uid => $tags) { $stored = self::storeForUserByUriId($item['uri-id'], $uid, ['post-reason' => self::PR_TAG]); Logger::info('Stored item for users', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'stored' => $stored]); + foreach ($tags as $tag) { + $stored = Category::storeFileByURIId($item['uri-id'], $uid, Category::SUBCRIPTION, $tag); + Logger::debug('Stored tag subscription for user', ['uri-id' => $item['uri-id'], 'uid' => $uid, $tag, 'stored' => $stored]); + } } } diff --git a/src/Model/Post.php b/src/Model/Post.php index 770ab08317..6f855867f6 100644 --- a/src/Model/Post.php +++ b/src/Model/Post.php @@ -453,12 +453,10 @@ class Post AND (NOT `causer-blocked` OR `causer-id` = ? OR `causer-id` IS NULL) AND NOT `contact-blocked` AND ((NOT `contact-readonly` AND NOT `contact-pending` AND (`contact-rel` IN (?, ?))) OR `self` OR `contact-uid` = ?) - AND NOT `" . $view . "`.`uri-id` IN (SELECT `uri-id` FROM `post-user` WHERE `uid` = ? AND `hidden`) - AND NOT `author-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND `blocked` AND `cid` = `author-id`) - AND NOT `owner-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND `blocked` AND `cid` = `owner-id`) - AND NOT `author-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND `ignored` AND `cid` = `author-id`) - AND NOT `owner-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND `ignored` AND `cid` = `owner-id`)", - 0, Contact::SHARING, Contact::FRIEND, 0, $uid, $uid, $uid, $uid, $uid]); + AND NOT EXISTS(SELECT `uri-id` FROM `post-user` WHERE `uid` = ? AND `uri-id` = " . DBA::quoteIdentifier($view) . ".`uri-id` AND `hidden`) + AND NOT EXISTS(SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND `cid` IN (`author-id`, `owner-id`) AND (`blocked` OR `ignored`)) + AND NOT EXISTS(SELECT `gsid` FROM `user-gserver` WHERE `uid` = ? AND `gsid` IN (`author-gsid`, `owner-gsid`, `causer-gsid`) AND `ignored`)", + 0, Contact::SHARING, Contact::FRIEND, 0, $uid, $uid, $uid]); $select_string = implode(', ', array_map([DBA::class, 'quoteIdentifier'], $selected)); diff --git a/src/Model/Post/Category.php b/src/Model/Post/Category.php index 2c35a40ad4..c242e8ffd8 100644 --- a/src/Model/Post/Category.php +++ b/src/Model/Post/Category.php @@ -33,9 +33,10 @@ use Friendica\Model\Tag; */ class Category { - const UNKNOWN = 0; - const CATEGORY = 3; - const FILE = 5; + const UNKNOWN = 0; + const CATEGORY = 3; + const FILE = 5; + const SUBCRIPTION = 10; /** * Delete all categories and files from a given uri-id and user @@ -80,7 +81,7 @@ class Category { $file_text = ''; - $tags = DBA::selectToArray('category-view', ['type', 'name'], ['uri-id' => $uri_id, 'uid' => $uid]); + $tags = DBA::selectToArray('category-view', ['type', 'name'], ['uri-id' => $uri_id, 'uid' => $uid, 'type' => [Category::FILE, Category::CATEGORY]]); foreach ($tags as $tag) { if ($tag['type'] == self::CATEGORY) { $file_text .= '<' . $tag['name'] . '>'; @@ -177,12 +178,7 @@ class Category continue; } - DBA::replace('post-category', [ - 'uri-id' => $uri_id, - 'uid' => $uid, - 'type' => self::FILE, - 'tid' => $tagid - ]); + self::storeByURIId($uri_id, $uid, self::FILE, $tagid); } } @@ -193,13 +189,18 @@ class Category } } - public static function storeFileByURIId(int $uri_id, int $uid, int $type, string $file) + public static function storeFileByURIId(int $uri_id, int $uid, int $type, string $file, string $url = ''): bool { - $tagid = Tag::getID($file); + $tagid = Tag::getID($file, $url); if (empty($tagid)) { return false; } + return self::storeByURIId($uri_id, $uid, $type, $tagid); + } + + private static function storeByURIId(int $uri_id, int $uid, int $type, int $tagid): bool + { return DBA::replace('post-category', [ 'uri-id' => $uri_id, 'uid' => $uid, diff --git a/src/Model/Post/UserNotification.php b/src/Model/Post/UserNotification.php index 012a49dbf5..726e82d7e0 100644 --- a/src/Model/Post/UserNotification.php +++ b/src/Model/Post/UserNotification.php @@ -133,14 +133,14 @@ class UserNotification public static function setNotification(int $uri_id, int $uid) { $fields = ['id', 'uri-id', 'parent-uri-id', 'uid', 'body', 'parent', 'gravity', 'vid', 'gravity', - 'contact-id', 'author-id', 'owner-id', 'causer-id', + 'contact-id', 'author-id', 'author-gsid', 'owner-id', 'owner-gsid', 'causer-id', 'causer-gsid', 'private', 'thr-parent', 'thr-parent-id', 'parent-uri-id', 'parent-uri', 'verb']; $item = Post::selectFirst($fields, ['uri-id' => $uri_id, 'uid' => $uid, 'origin' => false]); if (!DBA::isResult($item)) { return; } - $parent = Post::selectFirstPost(['author-id', 'owner-id', 'causer-id'], ['uri-id' => $item['parent-uri-id']]); + $parent = Post::selectFirstPost(['author-id', 'author-gsid', 'owner-id', 'owner-gsid', 'causer-id', 'causer-gsid',], ['uri-id' => $item['parent-uri-id']]); if (!DBA::isResult($parent)) { return; } @@ -195,6 +195,13 @@ class UserNotification } } + foreach (array_unique([$parent['author-gsid'], $parent['owner-gsid'], $parent['causer-gsid'], $item['author-gsid'], $item['owner-gsid'], $item['causer-gsid']]) as $gsid) { + if ($gsid && DI::userGServer()->isIgnoredByUser($uid, $gsid)) { + Logger::debug('Server is ignored by user', ['uid' => $uid, 'gsid' => $gsid, 'uri-id' => $item['uri-id']]); + return; + } + } + $user = User::getById($uid, ['account-type', 'account_removed', 'account_expired']); if (in_array($user['account-type'], [User::ACCOUNT_TYPE_COMMUNITY, User::ACCOUNT_TYPE_RELAY])) { return; diff --git a/src/Model/Profile.php b/src/Model/Profile.php index 0602df10aa..c1a350673e 100644 --- a/src/Model/Profile.php +++ b/src/Model/Profile.php @@ -37,6 +37,7 @@ use Friendica\DI; use Friendica\Network\HTTPClient\Client\HttpClientAccept; use Friendica\Network\HTTPClient\Client\HttpClientOptions; use Friendica\Network\HTTPException; +use Friendica\Network\HTTPException\InternalServerErrorException; use Friendica\Protocol\Activity; use Friendica\Protocol\Diaspora; use Friendica\Security\PermissionSet\Entity\PermissionSet; @@ -93,10 +94,11 @@ class Profile /** * Update a profile entry and distribute the changes if needed * - * @param array $fields Profile fields to update - * @param integer $uid User id + * @param array $fields Profile fields to update + * @param integer $uid User id * * @return boolean Whether update was successful + * @throws \Exception */ public static function update(array $fields, int $uid): bool { @@ -116,10 +118,6 @@ class Profile return false; } - if ($old_owner['name'] != $owner['name']) { - User::update(['username' => $owner['name']], $uid); - } - $profile_fields = ['postal-code', 'dob', 'prv_keywords', 'homepage']; foreach ($profile_fields as $field) { if ($old_owner[$field] != $owner[$field]) { diff --git a/src/Model/Tag.php b/src/Model/Tag.php index 1645dc1255..04f3f1627e 100644 --- a/src/Model/Tag.php +++ b/src/Model/Tag.php @@ -828,12 +828,13 @@ class Tag public static function getUIDListByURIId(int $uriId): array { $uids = []; - $tags = self::getByURIId($uriId, [self::HASHTAG]); - foreach ($tags as $tag) { - $uids = array_merge($uids, self::getUIDListByTag(self::TAG_CHARACTER[self::HASHTAG] . $tag['name'])); + foreach (self::getByURIId($uriId, [self::HASHTAG]) as $tag) { + foreach (self::getUIDListByTag(self::TAG_CHARACTER[self::HASHTAG] . $tag['name']) as $uid) { + $uids[$uid][] = $tag['name']; + } } - return array_unique($uids); + return $uids; } } diff --git a/src/Model/User.php b/src/Model/User.php index 18da3e9560..af7a81a15d 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -37,6 +37,7 @@ use Friendica\Database\DBA; use Friendica\DI; use Friendica\Module; use Friendica\Network\HTTPClient\Client\HttpClientAccept; +use Friendica\Network\HTTPException\InternalServerErrorException; use Friendica\Security\TwoFactor\Model\AppSpecificPassword; use Friendica\Network\HTTPException; use Friendica\Object\Image; @@ -1328,33 +1329,18 @@ class User /** * Update a user entry and distribute the changes if needed * - * @param array $fields + * @param array $fields * @param integer $uid * @return boolean + * @throws Exception */ public static function update(array $fields, int $uid): bool { - $old_owner = self::getOwnerDataById($uid); - if (empty($old_owner)) { - return false; - } - if (!DBA::update('user', $fields, ['uid' => $uid])) { return false; } - $update = Contact::updateSelfFromUserID($uid); - - $owner = self::getOwnerDataById($uid); - if (empty($owner)) { - return false; - } - - if ($old_owner['name'] != $owner['name']) { - Profile::update(['name' => $owner['name']], $uid); - } - - if ($update) { + if (Contact::updateSelfFromUserID($uid)) { Profile::publishUpdate($uid); } diff --git a/src/Moderation/Repository/Report.php b/src/Moderation/Repository/Report.php index e405f78081..29f0343517 100644 --- a/src/Moderation/Repository/Report.php +++ b/src/Moderation/Repository/Report.php @@ -48,7 +48,7 @@ final class Report extends \Friendica\BaseRepository $this->factory = $factory; $this->postFactory = $postFactory; - $this->ruleFactory = $postFactory; + $this->ruleFactory = $ruleFactory; } public function selectOneById(int $lastInsertId): \Friendica\Moderation\Entity\Report diff --git a/src/Module/BaseSettings.php b/src/Module/BaseSettings.php index a1e88e9a10..4b26a0f262 100644 --- a/src/Module/BaseSettings.php +++ b/src/Module/BaseSettings.php @@ -151,6 +151,13 @@ class BaseSettings extends BaseModule 'accesskey' => 'b', ]; + $tabs[] = [ + 'label' => $this->t('Remote servers'), + 'url' => 'settings/server', + 'selected' => static::class == Settings\Server\Index::class ? 'active' : '', + 'accesskey' => 's', + ]; + $tabs[] = [ 'label' => $this->t('Export personal data'), 'url' => 'settings/userexport', diff --git a/src/Module/Contact/Profile.php b/src/Module/Contact/Profile.php index 090f7cd86a..d6f5a90ce8 100644 --- a/src/Module/Contact/Profile.php +++ b/src/Module/Contact/Profile.php @@ -23,8 +23,7 @@ namespace Friendica\Module\Contact; use Friendica\App; use Friendica\BaseModule; -use Friendica\Contact\LocalRelationship\Entity; -use Friendica\Contact\LocalRelationship\Repository; +use Friendica\Contact\LocalRelationship; use Friendica\Content\ContactSelector; use Friendica\Content\Nav; use Friendica\Content\Text\BBCode; @@ -34,13 +33,16 @@ use Friendica\Core\Hook; use Friendica\Core\L10n; use Friendica\Core\Protocol; use Friendica\Core\Renderer; +use Friendica\Core\Session\Capability\IHandleUserSessions; +use Friendica\Database\Database; use Friendica\Database\DBA; -use Friendica\DI; -use Friendica\Model\Contact; use Friendica\Model\Circle; +use Friendica\Model\Contact; use Friendica\Module; use Friendica\Module\Response; +use Friendica\Navigation\SystemMessages; use Friendica\Network\HTTPException; +use Friendica\User\Settings; use Friendica\Util\DateTimeFormat; use Friendica\Util\Profiler; use Psr\Log\LoggerInterface; @@ -50,31 +52,37 @@ use Psr\Log\LoggerInterface; */ class Profile extends BaseModule { - /** - * @var Repository\LocalRelationship - */ + /** @var LocalRelationship\Repository\LocalRelationship */ private $localRelationship; - /** - * @var App\Page - */ + /** @var App\Page */ private $page; - /** - * @var IManageConfigValues - */ + /** @var IManageConfigValues */ private $config; + /** @var IHandleUserSessions */ + private $session; + /** @var SystemMessages */ + private $systemMessages; + /** @var Database */ + private $db; + /** @var Settings\Repository\UserGServer */ + private $userGServer; - public function __construct(L10n $l10n, Repository\LocalRelationship $localRelationship, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, App\Page $page, IManageConfigValues $config, array $server, array $parameters = []) + public function __construct(Settings\Repository\UserGServer $userGServer, Database $db, SystemMessages $systemMessages, IHandleUserSessions $session, L10n $l10n, LocalRelationship\Repository\LocalRelationship $localRelationship, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, App\Page $page, IManageConfigValues $config, array $server, array $parameters = []) { parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); $this->localRelationship = $localRelationship; $this->page = $page; $this->config = $config; + $this->session = $session; + $this->systemMessages = $systemMessages; + $this->db = $db; + $this->userGServer = $userGServer; } protected function post(array $request = []) { - if (!DI::userSession()->getLocalUserId()) { + if (!$this->session->getLocalUserId()) { return; } @@ -82,8 +90,8 @@ class Profile extends BaseModule // 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, DI::userSession()->getLocalUserId()); - if (empty($cdata['user']) || !DBA::exists('contact', ['id' => $cdata['user'], 'deleted' => false])) { + $cdata = Contact::getPublicAndUserContactID($contact_id, $this->session->getLocalUserId()); + if (empty($cdata['user']) || !$this->db->exists('contact', ['id' => $cdata['user'], 'deleted' => false])) { return; } @@ -124,35 +132,35 @@ class Profile extends BaseModule $fields['info'] = $_POST['info']; } - if (!Contact::update($fields, ['id' => $cdata['user'], 'uid' => DI::userSession()->getLocalUserId()])) { - DI::sysmsg()->addNotice($this->t('Failed to update contact record.')); + if (!Contact::update($fields, ['id' => $cdata['user'], 'uid' => $this->session->getLocalUserId()])) { + $this->systemMessages->addNotice($this->t('Failed to update contact record.')); } } protected function content(array $request = []): string { - if (!DI::userSession()->getLocalUserId()) { + if (!$this->session->getLocalUserId()) { 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']), DI::userSession()->getLocalUserId()); + $data = Contact::getPublicAndUserContactID(intval($this->parameters['id']), $this->session->getLocalUserId()); if (empty($data)) { throw new HTTPException\NotFoundException($this->t('Contact not found.')); } $contact = Contact::getById($data['public']); - if (!DBA::isResult($contact)) { + if (!$this->db->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)) { + if ($this->db->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(DI::userSession()->getLocalUserId(), $contact['id']); + $localRelationship = $this->localRelationship->getForUserContact($this->session->getLocalUserId(), $contact['id']); if ($localRelationship->rel === Contact::SELF) { $this->baseUrl->redirect('profile/' . $contact['nick'] . '/profile'); @@ -167,55 +175,55 @@ class Profile extends BaseModule } if ($cmd === 'updateprofile') { - self::updateContactFromProbe($contact['id']); + $this->updateContactFromProbe($contact['id']); } if ($cmd === 'block') { if ($localRelationship->blocked) { // @TODO Backward compatibility, replace with $localRelationship->unblock() - Contact\User::setBlocked($contact['id'], DI::userSession()->getLocalUserId(), false); + Contact\User::setBlocked($contact['id'], $this->session->getLocalUserId(), false); $message = $this->t('Contact has been unblocked'); } else { // @TODO Backward compatibility, replace with $localRelationship->block() - Contact\User::setBlocked($contact['id'], DI::userSession()->getLocalUserId(), true); + Contact\User::setBlocked($contact['id'], $this->session->getLocalUserId(), true); $message = $this->t('Contact has been blocked'); } // @TODO: add $this->localRelationship->save($localRelationship); - DI::sysmsg()->addInfo($message); + $this->systemMessages->addInfo($message); } if ($cmd === 'ignore') { if ($localRelationship->ignored) { // @TODO Backward compatibility, replace with $localRelationship->unblock() - Contact\User::setIgnored($contact['id'], DI::userSession()->getLocalUserId(), false); + Contact\User::setIgnored($contact['id'], $this->session->getLocalUserId(), false); $message = $this->t('Contact has been unignored'); } else { // @TODO Backward compatibility, replace with $localRelationship->block() - Contact\User::setIgnored($contact['id'], DI::userSession()->getLocalUserId(), true); + Contact\User::setIgnored($contact['id'], $this->session->getLocalUserId(), true); $message = $this->t('Contact has been ignored'); } // @TODO: add $this->localRelationship->save($localRelationship); - DI::sysmsg()->addInfo($message); + $this->systemMessages->addInfo($message); } if ($cmd === 'collapse') { if ($localRelationship->collapsed) { // @TODO Backward compatibility, replace with $localRelationship->unblock() - Contact\User::setCollapsed($contact['id'], DI::userSession()->getLocalUserId(), false); + Contact\User::setCollapsed($contact['id'], $this->session->getLocalUserId(), false); $message = $this->t('Contact has been uncollapsed'); } else { // @TODO Backward compatibility, replace with $localRelationship->block() - Contact\User::setCollapsed($contact['id'], DI::userSession()->getLocalUserId(), true); + Contact\User::setCollapsed($contact['id'], $this->session->getLocalUserId(), true); $message = $this->t('Contact has been collapsed'); } // @TODO: add $this->localRelationship->save($localRelationship); - DI::sysmsg()->addInfo($message); + $this->systemMessages->addInfo($message); } $this->baseUrl->redirect('contact/' . $contact['id']); @@ -259,6 +267,17 @@ class Profile extends BaseModule $insecure = $this->t('Private communications are not available for this contact.'); + // @TODO: Figure out why gsid can be empty + if (empty($contact['gsid'])) { + $this->logger->notice('Empty gsid for contact', ['contact' => $contact]); + } + + $serverIgnored = + $contact['gsid'] && + $this->userGServer->isIgnoredByUser($this->session->getLocalUserId(), $contact['gsid']) ? + $this->t('This contact is on a server you ignored.') + : ''; + $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) { @@ -363,6 +382,8 @@ class Profile extends BaseModule '$collapsed' => $localRelationship->collapsed ? $this->t('Currently collapsed') : '', '$archived' => ($contact['archive'] ? $this->t('Currently archived') : ''), '$insecure' => (in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::MAIL, Protocol::DIASPORA]) ? '' : $insecure), + '$serverIgnored' => $serverIgnored, + '$manageServers' => $this->t('Manage remote servers'), '$cinfo' => ['info', '', $localRelationship->info, ''], '$hidden' => ['hidden', $this->t('Hide this contact from others'), $localRelationship->hidden, $this->t('Replies/likes to your public posts may still be visible')], '$notify_new_posts' => ['notify_new_posts', $this->t('Notification for new posts'), ($localRelationship->notifyNewPosts), $this->t('Send a notification of every new post of this contact')], @@ -413,11 +434,11 @@ class Profile extends BaseModule * This includes actions like e.g. 'block', 'hide', 'delete' and others * * @param array $contact Public contact row - * @param Entity\LocalRelationship $localRelationship + * @param LocalRelationship\Entity\LocalRelationship $localRelationship * @return array with contact related actions * @throws HTTPException\InternalServerErrorException */ - private function getContactActions(array $contact, Entity\LocalRelationship $localRelationship): array + private function getContactActions(array $contact, LocalRelationship\Entity\LocalRelationship $localRelationship): array { $poll_enabled = in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::OSTATUS, Protocol::FEED, Protocol::MAIL]); $contact_actions = []; @@ -518,10 +539,9 @@ class Profile extends BaseModule * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function updateContactFromProbe(int $contact_id) + private function updateContactFromProbe(int $contact_id) { - $contact = DBA::selectFirst('contact', ['url'], ['id' => $contact_id, 'uid' => [0, DI::userSession()->getLocalUserId()], 'deleted' => false]); - if (!DBA::isResult($contact)) { + if (!$this->db->exists('contact', ['id' => $contact_id, 'uid' => [0, $this->session->getLocalUserId()], 'deleted' => false])) { return; } diff --git a/src/Module/Conversation/Community.php b/src/Module/Conversation/Community.php index 7525ba1c16..3c3bbb8a83 100644 --- a/src/Module/Conversation/Community.php +++ b/src/Module/Conversation/Community.php @@ -356,7 +356,7 @@ class Community extends BaseModule } } - $r = Post::selectThreadForUser(0, ['uri-id', 'commented', 'author-link'], $condition, $params); + $r = Post::selectThreadForUser(DI::userSession()->getLocalUserId() ?: 0, ['uri-id', 'commented', 'author-link'], $condition, $params); $items = Post::toArray($r); if (empty($items)) { diff --git a/src/Module/Item/Display.php b/src/Module/Item/Display.php index 21046628fe..714598a8e6 100644 --- a/src/Module/Item/Display.php +++ b/src/Module/Item/Display.php @@ -133,7 +133,9 @@ class Display extends BaseModule } if (empty($item)) { - throw new HTTPException\NotFoundException($this->t('The requested item doesn\'t exist or has been deleted.')); + $this->page['aside'] = ''; + $displayNotFound = new DisplayNotFound($this->l10n, $this->baseUrl, $this->args, $this->logger, $this->profiler, $this->response, $this->server, $this->parameters); + return $displayNotFound->content(); } if ($item['gravity'] != Item::GRAVITY_PARENT) { diff --git a/src/Module/RobotsTxt.php b/src/Module/RobotsTxt.php index 415a8ab472..a084c1f4a6 100644 --- a/src/Module/RobotsTxt.php +++ b/src/Module/RobotsTxt.php @@ -38,6 +38,8 @@ class RobotsTxt extends BaseModule '/search', '/help', '/proxy', + '/photo', + '/avatar', ]; header('Content-Type: text/plain'); @@ -50,6 +52,10 @@ class RobotsTxt extends BaseModule echo 'User-agent: ChatGPT-User' . PHP_EOL; echo 'Disallow: /' . PHP_EOL; + echo PHP_EOL; + echo 'User-agent: GPTBot' . PHP_EOL; + echo 'Disallow: /' . PHP_EOL; + System::exit(); } } diff --git a/src/Module/Settings/Account.php b/src/Module/Settings/Account.php index 1039b92e2e..8ff00addb5 100644 --- a/src/Module/Settings/Account.php +++ b/src/Module/Settings/Account.php @@ -573,7 +573,7 @@ class Account extends BaseSettings '$delete_openid' => ['delete_openid', DI::l10n()->t('Delete OpenID URL'), false, ''], '$h_basic' => DI::l10n()->t('Basic Settings'), - '$username' => ['username', DI::l10n()->t('Full Name:'), $username, '', false, 'autocomplete="off"'], + '$username' => ['username', DI::l10n()->t('Display name:'), $username, '', false, 'autocomplete="off"'], '$email' => ['email', DI::l10n()->t('Email Address:'), $email, '', '', 'autocomplete="off"', 'email'], '$timezone' => ['timezone_select', DI::l10n()->t('Your Timezone:'), Temporal::getTimezoneSelect($timezone), ''], '$language' => ['language', DI::l10n()->t('Your Language:'), $language, DI::l10n()->t('Set the language we use to show you friendica interface and to send you emails'), $lang_choices], diff --git a/src/Module/Settings/Profile/Index.php b/src/Module/Settings/Profile/Index.php index c8b27e394a..38d816833f 100644 --- a/src/Module/Settings/Profile/Index.php +++ b/src/Module/Settings/Profile/Index.php @@ -21,43 +21,75 @@ namespace Friendica\Module\Settings\Profile; +use Friendica\App; use Friendica\Core\ACL; use Friendica\Core\Hook; +use Friendica\Core\L10n; use Friendica\Core\Protocol; use Friendica\Core\Renderer; +use Friendica\Core\Session\Capability\IHandleUserSessions; use Friendica\Core\Theme; use Friendica\Database\DBA; -use Friendica\DI; use Friendica\Model\Contact; use Friendica\Model\Profile; -use Friendica\Profile\ProfileField\Collection\ProfileFields; -use Friendica\Profile\ProfileField\Entity\ProfileField; +use Friendica\Module\Response; +use Friendica\Navigation\SystemMessages; +use Friendica\Profile\ProfileField; use Friendica\Model\User; use Friendica\Module\BaseSettings; use Friendica\Module\Security\Login; use Friendica\Network\HTTPException; +use Friendica\Security\PermissionSet; +use Friendica\Util\ACLFormatter; use Friendica\Util\DateTimeFormat; +use Friendica\Util\Profiler; use Friendica\Util\Temporal; use Friendica\Core\Worker; +use Psr\Log\LoggerInterface; class Index extends BaseSettings { + /** @var ProfileField\Repository\ProfileField */ + private $profileFieldRepo; + /** @var ProfileField\Factory\ProfileField */ + private $profileFieldFactory; + /** @var SystemMessages */ + private $systemMessages; + /** @var PermissionSet\Repository\PermissionSet */ + private $permissionSetRepo; + /** @var PermissionSet\Factory\PermissionSet */ + private $permissionSetFactory; + /** @var ACLFormatter */ + private $aclFormatter; + + public function __construct(ACLFormatter $aclFormatter, PermissionSet\Factory\PermissionSet $permissionSetFactory, PermissionSet\Repository\PermissionSet $permissionSetRepo, SystemMessages $systemMessages, ProfileField\Factory\ProfileField $profileFieldFactory, ProfileField\Repository\ProfileField $profileFieldRepo, IHandleUserSessions $session, App\Page $page, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) + { + parent::__construct($session, $page, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); + + $this->profileFieldRepo = $profileFieldRepo; + $this->profileFieldFactory = $profileFieldFactory; + $this->systemMessages = $systemMessages; + $this->permissionSetRepo = $permissionSetRepo; + $this->permissionSetFactory = $permissionSetFactory; + $this->aclFormatter = $aclFormatter; + } + protected function post(array $request = []) { - if (!DI::userSession()->getLocalUserId()) { + if (!$this->session->getLocalUserId()) { return; } - $profile = Profile::getByUID(DI::userSession()->getLocalUserId()); - if (!DBA::isResult($profile)) { + $profile = Profile::getByUID($this->session->getLocalUserId()); + if (!$profile) { return; } self::checkFormSecurityTokenRedirectOnError('/settings/profile', 'settings_profile'); - Hook::callAll('profile_post', $_POST); + Hook::callAll('profile_post', $request); - $dob = trim($_POST['dob'] ?? ''); + $dob = trim($request['dob'] ?? ''); if ($dob && !in_array($dob, ['0000-00-00', DBA::NULL_DATE])) { $y = substr($dob, 0, 4); @@ -79,39 +111,40 @@ class Index extends BaseSettings } } - $name = trim($_POST['name'] ?? ''); - if (!strlen($name)) { - DI::sysmsg()->addNotice(DI::l10n()->t('Profile Name is required.')); + $username = trim($request['username'] ?? ''); + if (!$username) { + $this->systemMessages->addNotice($this->t('Display Name is required.')); return; } - $about = trim($_POST['about']); - $address = trim($_POST['address']); - $locality = trim($_POST['locality']); - $region = trim($_POST['region']); - $postal_code = trim($_POST['postal_code']); - $country_name = trim($_POST['country_name']); - $pub_keywords = self::cleanKeywords(trim($_POST['pub_keywords'])); - $prv_keywords = self::cleanKeywords(trim($_POST['prv_keywords'])); - $xmpp = trim($_POST['xmpp']); - $matrix = trim($_POST['matrix']); - $homepage = trim($_POST['homepage']); + $about = trim($request['about']); + $address = trim($request['address']); + $locality = trim($request['locality']); + $region = trim($request['region']); + $postal_code = trim($request['postal_code']); + $country_name = trim($request['country_name']); + $pub_keywords = self::cleanKeywords(trim($request['pub_keywords'])); + $prv_keywords = self::cleanKeywords(trim($request['prv_keywords'])); + $xmpp = trim($request['xmpp']); + $matrix = trim($request['matrix']); + $homepage = trim($request['homepage']); if ((strpos($homepage, 'http') !== 0) && (strlen($homepage))) { // neither http nor https in URL, add them $homepage = 'http://' . $homepage; } - $profileFieldsNew = self::getProfileFieldsFromInput( - DI::userSession()->getLocalUserId(), - $_REQUEST['profile_field'], - $_REQUEST['profile_field_order'] + $profileFieldsNew = $this->getProfileFieldsFromInput( + $this->session->getLocalUserId(), + $request['profile_field'], + $request['profile_field_order'] ); - DI::profileField()->saveCollectionForUser(DI::userSession()->getLocalUserId(), $profileFieldsNew); + $this->profileFieldRepo->saveCollectionForUser($this->session->getLocalUserId(), $profileFieldsNew); + + User::update(['username' => $username], $this->session->getLocalUserId()); $result = Profile::update( [ - 'name' => $name, 'about' => $about, 'dob' => $dob, 'address' => $address, @@ -125,23 +158,23 @@ class Index extends BaseSettings 'pub_keywords' => $pub_keywords, 'prv_keywords' => $prv_keywords, ], - DI::userSession()->getLocalUserId() + $this->session->getLocalUserId() ); - Worker::add(Worker::PRIORITY_MEDIUM, 'CheckRelMeProfileLink', DI::userSession()->getLocalUserId()); + Worker::add(Worker::PRIORITY_MEDIUM, 'CheckRelMeProfileLink', $this->session->getLocalUserId()); if (!$result) { - DI::sysmsg()->addNotice(DI::l10n()->t('Profile couldn\'t be updated.')); + $this->systemMessages->addNotice($this->t("Profile couldn't be updated.")); return; } - DI::baseUrl()->redirect('settings/profile'); + $this->baseUrl->redirect('settings/profile'); } protected function content(array $request = []): string { - if (!DI::userSession()->getLocalUserId()) { - DI::sysmsg()->addNotice(DI::l10n()->t('You must be logged in to use this module')); + if (!$this->session->getLocalUserId()) { + $this->systemMessages->addNotice($this->t('You must be logged in to use this module')); return Login::form(); } @@ -149,147 +182,145 @@ class Index extends BaseSettings $o = ''; - $profile = User::getOwnerDataById(DI::userSession()->getLocalUserId()); - if (!DBA::isResult($profile)) { + $owner = User::getOwnerDataById($this->session->getLocalUserId()); + if (!$owner) { throw new HTTPException\NotFoundException(); } - $a = DI::app(); - - DI::page()->registerFooterScript('view/asset/es-jquery-sortable/source/js/jquery-sortable-min.js'); - DI::page()->registerFooterScript(Theme::getPathForFile('js/module/settings/profile/index.js')); + $this->page->registerFooterScript('view/asset/es-jquery-sortable/source/js/jquery-sortable-min.js'); + $this->page->registerFooterScript(Theme::getPathForFile('js/module/settings/profile/index.js')); $custom_fields = []; - $profileFields = DI::profileField()->selectByUserId(DI::userSession()->getLocalUserId()); + $profileFields = $this->profileFieldRepo->selectByUserId($this->session->getLocalUserId()); foreach ($profileFields as $profileField) { - /** @var ProfileField $profileField */ $defaultPermissions = $profileField->permissionSet->withAllowedContacts( Contact::pruneUnavailable($profileField->permissionSet->allow_cid) ); $custom_fields[] = [ - 'id' => $profileField->id, + 'id' => $profileField->id, 'legend' => $profileField->label, 'fields' => [ - 'label' => ['profile_field[' . $profileField->id . '][label]', DI::l10n()->t('Label:'), $profileField->label], - 'value' => ['profile_field[' . $profileField->id . '][value]', DI::l10n()->t('Value:'), $profileField->value], - 'acl' => ACL::getFullSelectorHTML( - DI::page(), - $a->getLoggedInUserId(), + 'label' => ['profile_field[' . $profileField->id . '][label]', $this->t('Label:'), $profileField->label], + 'value' => ['profile_field[' . $profileField->id . '][value]', $this->t('Value:'), $profileField->value], + 'acl' => ACL::getFullSelectorHTML( + $this->page, + $this->session->getLocalUserId(), false, $defaultPermissions->toArray(), ['network' => Protocol::DFRN], 'profile_field[' . $profileField->id . ']' ), ], - 'permissions' => DI::l10n()->t('Field Permissions'), - 'permdesc' => DI::l10n()->t("(click to open/close)"), + + 'permissions' => $this->t('Field Permissions'), + 'permdesc' => $this->t("(click to open/close)"), ]; - }; + } $custom_fields[] = [ - 'id' => 'new', - 'legend' => DI::l10n()->t('Add a new profile field'), + 'id' => 'new', + 'legend' => $this->t('Add a new profile field'), 'fields' => [ - 'label' => ['profile_field[new][label]', DI::l10n()->t('Label:')], - 'value' => ['profile_field[new][value]', DI::l10n()->t('Value:')], - 'acl' => ACL::getFullSelectorHTML( - DI::page(), - $a->getLoggedInUserId(), + 'label' => ['profile_field[new][label]', $this->t('Label:')], + 'value' => ['profile_field[new][value]', $this->t('Value:')], + 'acl' => ACL::getFullSelectorHTML( + $this->page, + $this->session->getLocalUserId(), false, ['allow_cid' => []], ['network' => Protocol::DFRN], 'profile_field[new]' ), ], - 'permissions' => DI::l10n()->t('Field Permissions'), - 'permdesc' => DI::l10n()->t("(click to open/close)"), + + 'permissions' => $this->t('Field Permissions'), + 'permdesc' => $this->t("(click to open/close)"), ]; - DI::page()['htmlhead'] .= Renderer::replaceMacros(Renderer::getMarkupTemplate('settings/profile/index_head.tpl'), [ - ]); + $this->page['htmlhead'] .= Renderer::replaceMacros(Renderer::getMarkupTemplate('settings/profile/index_head.tpl')); - $personal_account = ($profile['account-type'] != User::ACCOUNT_TYPE_COMMUNITY); + $personal_account = ($owner['account-type'] != User::ACCOUNT_TYPE_COMMUNITY); - if ($profile['homepage_verified']) { - $homepage_help_text = DI::l10n()->t('The homepage is verified. A rel="me" link back to your Friendica profile page was found on the homepage.'); + if ($owner['homepage_verified']) { + $homepage_help_text = $this->t('The homepage is verified. A rel="me" link back to your Friendica profile page was found on the homepage.'); } else { - $homepage_help_text = DI::l10n()->t('To verify your homepage, add a rel="me" link to it, pointing to your profile URL (%s).', $profile['url']); + $homepage_help_text = $this->t('To verify your homepage, add a rel="me" link to it, pointing to your profile URL (%s).', $owner['url']); } $tpl = Renderer::getMarkupTemplate('settings/profile/index.tpl'); $o .= Renderer::replaceMacros($tpl, [ - '$personal_account' => $personal_account, - - '$form_security_token' => self::getFormSecurityToken('settings_profile'), - '$form_security_token_photo' => self::getFormSecurityToken('settings_profile_photo'), - - '$profile_action' => DI::l10n()->t('Profile Actions'), - '$banner' => DI::l10n()->t('Edit Profile Details'), - '$submit' => DI::l10n()->t('Submit'), - '$profpic' => DI::l10n()->t('Change Profile Photo'), - '$profpiclink' => '/profile/' . $profile['nickname'] . '/photos', - '$viewprof' => DI::l10n()->t('View Profile'), - - '$lbl_personal_section' => DI::l10n()->t('Personal'), - '$lbl_picture_section' => DI::l10n()->t('Profile picture'), - '$lbl_location_section' => DI::l10n()->t('Location'), - '$lbl_miscellaneous_section' => DI::l10n()->t('Miscellaneous'), - '$lbl_custom_fields_section' => DI::l10n()->t('Custom Profile Fields'), - - '$lbl_profile_photo' => DI::l10n()->t('Upload Profile Photo'), - - '$baseurl' => DI::baseUrl(), - '$nickname' => $profile['nickname'], - '$name' => ['name', DI::l10n()->t('Display name:'), $profile['name']], - '$about' => ['about', DI::l10n()->t('Description:'), $profile['about']], - '$dob' => Temporal::getDateofBirthField($profile['dob'], $profile['timezone']), - '$address' => ['address', DI::l10n()->t('Street Address:'), $profile['address']], - '$locality' => ['locality', DI::l10n()->t('Locality/City:'), $profile['locality']], - '$region' => ['region', DI::l10n()->t('Region/State:'), $profile['region']], - '$postal_code' => ['postal_code', DI::l10n()->t('Postal/Zip Code:'), $profile['postal-code']], - '$country_name' => ['country_name', DI::l10n()->t('Country:'), $profile['country-name']], - '$age' => ((intval($profile['dob'])) ? '(' . DI::l10n()->t('Age: ') . DI::l10n()->tt('%d year old', '%d years old', Temporal::getAgeByTimezone($profile['dob'], $profile['timezone'])) . ')' : ''), - '$xmpp' => ['xmpp', DI::l10n()->t('XMPP (Jabber) address:'), $profile['xmpp'], DI::l10n()->t('The XMPP address will be published so that people can follow you there.')], - '$matrix' => ['matrix', DI::l10n()->t('Matrix (Element) address:'), $profile['matrix'], DI::l10n()->t('The Matrix address will be published so that people can follow you there.')], - '$homepage' => ['homepage', DI::l10n()->t('Homepage URL:'), $profile['homepage'], $homepage_help_text], - '$pub_keywords' => ['pub_keywords', DI::l10n()->t('Public Keywords:'), $profile['pub_keywords'], DI::l10n()->t('(Used for suggesting potential friends, can be seen by others)')], - '$prv_keywords' => ['prv_keywords', DI::l10n()->t('Private Keywords:'), $profile['prv_keywords'], DI::l10n()->t('(Used for searching profiles, never shown to others)')], - '$custom_fields_description' => DI::l10n()->t("

Custom fields appear on your profile page.

+ '$l10n' => [ + 'profile_action' => $this->t('Profile Actions'), + 'banner' => $this->t('Edit Profile Details'), + 'submit' => $this->t('Submit'), + 'profpic' => $this->t('Change Profile Photo'), + 'viewprof' => $this->t('View Profile'), + 'personal_section' => $this->t('Personal'), + 'picture_section' => $this->t('Profile picture'), + 'location_section' => $this->t('Location'), + 'miscellaneous_section' => $this->t('Miscellaneous'), + 'custom_fields_section' => $this->t('Custom Profile Fields'), + 'profile_photo' => $this->t('Upload Profile Photo'), + 'custom_fields_description' => $this->t('

Custom fields appear on your profile page.

You can use BBCodes in the field values.

Reorder by dragging the field title.

Empty the label field to remove a custom field.

-

Non-public fields can only be seen by the selected Friendica contacts or the Friendica contacts in the selected circles.

", - 'profile/' . $profile['nickname'] . '/profile' - ), +

Non-public fields can only be seen by the selected Friendica contacts or the Friendica contacts in the selected circles.

', + 'profile/' . $owner['nickname'] . '/profile' + ), + ], + + '$personal_account' => $personal_account, + + '$form_security_token' => self::getFormSecurityToken('settings_profile'), + '$form_security_token_photo' => self::getFormSecurityToken('settings_profile_photo'), + + '$profpiclink' => '/profile/' . $owner['nickname'] . '/photos', + + '$nickname' => $owner['nickname'], + '$username' => ['username', $this->t('Display name:'), $owner['name']], + '$about' => ['about', $this->t('Description:'), $owner['about']], + '$dob' => Temporal::getDateofBirthField($owner['dob'], $owner['timezone']), + '$address' => ['address', $this->t('Street Address:'), $owner['address']], + '$locality' => ['locality', $this->t('Locality/City:'), $owner['locality']], + '$region' => ['region', $this->t('Region/State:'), $owner['region']], + '$postal_code' => ['postal_code', $this->t('Postal/Zip Code:'), $owner['postal-code']], + '$country_name' => ['country_name', $this->t('Country:'), $owner['country-name']], + '$age' => ((intval($owner['dob'])) ? '(' . $this->t('Age: ') . $this->tt('%d year old', '%d years old', Temporal::getAgeByTimezone($owner['dob'], $owner['timezone'])) . ')' : ''), + '$xmpp' => ['xmpp', $this->t('XMPP (Jabber) address:'), $owner['xmpp'], $this->t('The XMPP address will be published so that people can follow you there.')], + '$matrix' => ['matrix', $this->t('Matrix (Element) address:'), $owner['matrix'], $this->t('The Matrix address will be published so that people can follow you there.')], + '$homepage' => ['homepage', $this->t('Homepage URL:'), $owner['homepage'], $homepage_help_text], + '$pub_keywords' => ['pub_keywords', $this->t('Public Keywords:'), $owner['pub_keywords'], $this->t('(Used for suggesting potential friends, can be seen by others)')], + '$prv_keywords' => ['prv_keywords', $this->t('Private Keywords:'), $owner['prv_keywords'], $this->t('(Used for searching profiles, never shown to others)')], '$custom_fields' => $custom_fields, ]); - $arr = ['profile' => $profile, 'entry' => $o]; + $arr = ['profile' => $owner, 'entry' => $o]; Hook::callAll('profile_edit', $arr); return $o; } - private static function getProfileFieldsFromInput(int $uid, array $profileFieldInputs, array $profileFieldOrder): ProfileFields + private function getProfileFieldsFromInput(int $uid, array $profileFieldInputs, array $profileFieldOrder): ProfileField\Collection\ProfileFields { - $profileFields = new ProfileFields(); + $profileFields = new ProfileField\Collection\ProfileFields(); // Returns an associative array of id => order values $profileFieldOrder = array_flip($profileFieldOrder); // Creation of the new field if (!empty($profileFieldInputs['new']['label'])) { - $permissionSet = DI::permissionSet()->selectOrCreate(DI::permissionSetFactory()->createFromString( + $permissionSet = $this->permissionSetRepo->selectOrCreate($this->permissionSetFactory->createFromString( $uid, - DI::aclFormatter()->toString($profileFieldInputs['new']['contact_allow'] ?? ''), - DI::aclFormatter()->toString($profileFieldInputs['new']['circle_allow'] ?? ''), - DI::aclFormatter()->toString($profileFieldInputs['new']['contact_deny'] ?? ''), - DI::aclFormatter()->toString($profileFieldInputs['new']['circle_deny'] ?? '') + $this->aclFormatter->toString($profileFieldInputs['new']['contact_allow'] ?? ''), + $this->aclFormatter->toString($profileFieldInputs['new']['circle_allow'] ?? ''), + $this->aclFormatter->toString($profileFieldInputs['new']['contact_deny'] ?? ''), + $this->aclFormatter->toString($profileFieldInputs['new']['circle_deny'] ?? '') )); - $profileFields->append(DI::profileFieldFactory()->createFromValues( + $profileFields->append($this->profileFieldFactory->createFromValues( $uid, $profileFieldOrder['new'], $profileFieldInputs['new']['label'], @@ -302,15 +333,15 @@ class Index extends BaseSettings unset($profileFieldOrder['new']); foreach ($profileFieldInputs as $id => $profileFieldInput) { - $permissionSet = DI::permissionSet()->selectOrCreate(DI::permissionSetFactory()->createFromString( + $permissionSet = $this->permissionSetRepo->selectOrCreate($this->permissionSetFactory->createFromString( $uid, - DI::aclFormatter()->toString($profileFieldInput['contact_allow'] ?? ''), - DI::aclFormatter()->toString($profileFieldInput['circle_allow'] ?? ''), - DI::aclFormatter()->toString($profileFieldInput['contact_deny'] ?? ''), - DI::aclFormatter()->toString($profileFieldInput['circle_deny'] ?? '') + $this->aclFormatter->toString($profileFieldInput['contact_allow'] ?? ''), + $this->aclFormatter->toString($profileFieldInput['circle_allow'] ?? ''), + $this->aclFormatter->toString($profileFieldInput['contact_deny'] ?? ''), + $this->aclFormatter->toString($profileFieldInput['circle_deny'] ?? '') )); - $profileFields->append(DI::profileFieldFactory()->createFromValues( + $profileFields->append($this->profileFieldFactory->createFromValues( $uid, $profileFieldOrder[$id], $profileFieldInput['label'], @@ -322,22 +353,20 @@ class Index extends BaseSettings return $profileFields; } - private static function cleanKeywords($keywords) + private static function cleanKeywords($keywords): string { $keywords = str_replace(',', ' ', $keywords); $keywords = explode(' ', $keywords); $cleaned = []; foreach ($keywords as $keyword) { - $keyword = trim(strtolower($keyword)); + $keyword = trim($keyword); $keyword = trim($keyword, '#'); if ($keyword != '') { $cleaned[] = $keyword; } } - $keywords = implode(', ', $cleaned); - - return $keywords; + return implode(', ', $cleaned); } } diff --git a/src/Module/Settings/Server/Action.php b/src/Module/Settings/Server/Action.php new file mode 100644 index 0000000000..e06cbf26be --- /dev/null +++ b/src/Module/Settings/Server/Action.php @@ -0,0 +1,117 @@ +. + * + */ + +namespace Friendica\Module\Settings\Server; + +use Friendica\App; +use Friendica\Core\L10n; +use Friendica\Core\Renderer; +use Friendica\Core\Session\Capability\IHandleUserSessions; +use Friendica\Core\System; +use Friendica\Federation\Repository\GServer; +use Friendica\Module\Response; +use Friendica\Network\HTTPException\BadRequestException; +use Friendica\User\Settings\Repository\UserGServer; +use Friendica\Util\Profiler; +use Psr\Log\LoggerInterface; + +class Action extends \Friendica\BaseModule +{ + /** @var IHandleUserSessions */ + private $session; + /** @var UserGServer */ + private $repository; + /** @var GServer */ + private $gserverRepo; + + public function __construct(GServer $gserverRepo, UserGServer $repository, IHandleUserSessions $session, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) + { + parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); + + $this->session = $session; + $this->repository = $repository; + $this->gserverRepo = $gserverRepo; + } + + public function content(array $request = []): string + { + $GServer = $this->gserverRepo->selectOneById($this->parameters['gsid']); + + switch ($this->parameters['action']) { + case 'ignore': + $action = $this->t('Do you want to ignore this server?'); + $desc = $this->t("You won't see any content from this server including reshares in your Network page, the community pages and individual conversations."); + break; + case 'unignore': + $action = $this->t('Do you want to unignore this server?'); + $desc = ''; + break; + default: + throw new BadRequestException('Unknown user server action ' . $this->parameters['action']); + } + + $tpl = Renderer::getMarkupTemplate('settings/server/action.tpl'); + return Renderer::replaceMacros($tpl, [ + '$l10n' => [ + 'title' => $this->t('Remote server settings'), + 'action' => $action, + 'siteName' => $this->t('Server Name'), + 'siteUrl' => $this->t('Server URL'), + 'desc' => $desc, + 'submit' => $this->t('Submit'), + ], + + '$action' => $this->args->getQueryString(), + + '$GServer' => $GServer, + + '$form_security_token' => self::getFormSecurityToken('settings-server'), + ]); + } + + public function post(array $request = []) + { + if (!empty($request['redirect_url'])) { + self::checkFormSecurityTokenRedirectOnError($this->args->getQueryString(), 'settings-server'); + } + + $userGServer = $this->repository->getOneByUserAndServer($this->session->getLocalUserId(), $this->parameters['gsid']); + + switch ($this->parameters['action']) { + case 'ignore': + $userGServer->ignore(); + break; + case 'unignore': + $userGServer->unignore(); + break; + default: + throw new BadRequestException('Unknown user server action ' . $this->parameters['action']); + } + + $this->repository->save($userGServer); + + if (!empty($request['redirect_url'])) { + $this->baseUrl->redirect($request['redirect_url']); + } + + System::exit(); + } +} diff --git a/src/Module/Settings/Server/Index.php b/src/Module/Settings/Server/Index.php new file mode 100644 index 0000000000..f59e23a87b --- /dev/null +++ b/src/Module/Settings/Server/Index.php @@ -0,0 +1,126 @@ +. + * + */ + +namespace Friendica\Module\Settings\Server; + +use Friendica\App; +use Friendica\Content\Pager; +use Friendica\Core\L10n; +use Friendica\Core\Renderer; +use Friendica\Core\Session\Capability\IHandleUserSessions; +use Friendica\Module\BaseSettings; +use Friendica\Module\Response; +use Friendica\Navigation\SystemMessages; +use Friendica\Network\HTTPException\NotFoundException; +use Friendica\User\Settings\Entity\UserGServer; +use Friendica\User\Settings\Repository; +use Friendica\Util\Profiler; +use Psr\Log\LoggerInterface; + +class Index extends BaseSettings +{ + /** @var Repository\UserGServer */ + private $repository; + /** @var SystemMessages */ + private $systemMessages; + + public function __construct(SystemMessages $systemMessages, Repository\UserGServer $repository, IHandleUserSessions $session, App\Page $page, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) + { + parent::__construct($session, $page, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); + + $this->repository = $repository; + $this->systemMessages = $systemMessages; + } + + protected function post(array $request = []) + { + self::checkFormSecurityTokenRedirectOnError($this->args->getQueryString(), 'settings-server'); + + foreach ($request['delete'] ?? [] as $gsid => $delete) { + if ($delete) { + unset($request['ignored'][$gsid]); + + try { + $userGServer = $this->repository->selectOneByUserAndServer($this->session->getLocalUserId(), $gsid, false); + $this->repository->delete($userGServer); + } catch (NotFoundException $e) { + // Nothing to delete + } + } + } + + foreach ($request['ignored'] ?? [] as $gsid => $ignored) { + $userGServer = $this->repository->getOneByUserAndServer($this->session->getLocalUserId(), $gsid, false); + if ($userGServer->ignored != $ignored) { + $userGServer->toggleIgnored(); + $this->repository->save($userGServer); + } + } + + $this->systemMessages->addInfo($this->t('Settings saved')); + + $this->baseUrl->redirect($this->args->getQueryString()); + } + + protected function content(array $request = []): string + { + parent::content(); + + $pager = new Pager($this->l10n, $this->args->getQueryString(), 30); + + $total = $this->repository->countByUser($this->session->getLocalUserId()); + + $servers = $this->repository->selectByUserWithPagination($this->session->getLocalUserId(), $pager); + + $ignoredCheckboxes = array_map(function (UserGServer $server) { + return ['ignored[' . $server->gsid . ']', '', $server->ignored]; + }, $servers->getArrayCopy()); + + $deleteCheckboxes = array_map(function (UserGServer $server) { + return ['delete[' . $server->gsid . ']']; + }, $servers->getArrayCopy()); + + $tpl = Renderer::getMarkupTemplate('settings/server/index.tpl'); + return Renderer::replaceMacros($tpl, [ + '$l10n' => [ + 'title' => $this->t('Remote server settings'), + 'desc' => $this->t('Here you can find all the remote servers you have taken individual moderation actions against. For a list of servers your node has blocked, please check out the Information page.'), + 'siteName' => $this->t('Server Name'), + 'ignored' => $this->t('Ignored'), + 'ignored_title' => $this->t("You won't see any content from this server including reshares in your Network page, the community pages and individual conversations."), + 'delete' => $this->t('Delete'), + 'delete_title' => $this->t('Delete all your settings for the remote server'), + 'submit' => $this->t('Save changes'), + ], + + '$count' => $total, + + '$servers' => $servers, + + '$form_security_token' => self::getFormSecurityToken('settings-server'), + + '$ignoredCheckboxes' => $ignoredCheckboxes, + '$deleteCheckboxes' => $deleteCheckboxes, + + '$paginate' => $pager->renderFull($total), + ]); + } +} diff --git a/src/Module/Special/DisplayNotFound.php b/src/Module/Special/DisplayNotFound.php index d66ececdd0..293f40aa06 100644 --- a/src/Module/Special/DisplayNotFound.php +++ b/src/Module/Special/DisplayNotFound.php @@ -31,18 +31,21 @@ class DisplayNotFound extends \Friendica\BaseModule { protected function content(array $request = []): string { + $reasons = [ + $this->t("The top-level post isn't visible."), + $this->t('The top-level post was deleted.'), + $this->t('This node has blocked the top-level author or the author of the shared post.'), + $this->t('You have ignored or blocked the top-level author or the author of the shared post.'), + $this->t("You have ignored the top-level author's server or the shared post author's server."), + ]; + $tpl = Renderer::getMarkupTemplate('special/displaynotfound.tpl'); return Renderer::replaceMacros($tpl, [ '$l10n' => [ - 'title' => $this->t('Not Found'), - 'message' => $this->t("

Unfortunately, the requested conversation isn't available to you.

-

Possible reasons include:

-"), + 'title' => $this->t('Conversation Not Found'), + 'desc1' => $this->t("Unfortunately, the requested conversation isn't available to you."), + 'desc2' => $this->t('Possible reasons include:'), + 'reasons' => $reasons, ] ]); } diff --git a/src/Object/Post.php b/src/Object/Post.php index e7a178ef12..dd3074cfa3 100644 --- a/src/Object/Post.php +++ b/src/Object/Post.php @@ -31,16 +31,15 @@ use Friendica\Core\Renderer; use Friendica\DI; use Friendica\Model\Contact; use Friendica\Model\Item; -use Friendica\Model\Photo; use Friendica\Model\Post as PostModel; use Friendica\Model\Tag; use Friendica\Model\User; use Friendica\Protocol\Activity; use Friendica\Util\Crypto; use Friendica\Util\DateTimeFormat; -use Friendica\Util\Proxy; use Friendica\Util\Strings; use Friendica\Util\Temporal; +use GuzzleHttp\Psr7\Uri; use InvalidArgumentException; /** @@ -248,11 +247,12 @@ class Post $pinned = DI::l10n()->t('Pinned item'); } - $drop = false; - $block = false; - $ignore = false; - $collapse = false; - $report = false; + $drop = false; + $block = false; + $ignore = false; + $collapse = false; + $report = false; + $ignoreServer = false; if (DI::userSession()->getLocalUserId()) { $drop = [ 'dropping' => $dropping, @@ -282,6 +282,12 @@ class Post 'label' => DI::l10n()->t('Report post'), 'href' => 'moderation/report/create?' . http_build_query(['cid' => $item['author-id'], 'uri-ids' => [$item['uri-id']]]), ]; + $authorBaseUri = new Uri($item['author-baseurl'] ?? ''); + if ($authorBaseUri->getHost() && !DI::baseUrl()->isLocalUrl($authorBaseUri)) { + $ignoreServer = [ + 'label' => DI::l10n()->t("Ignore %s server", $authorBaseUri->getHost()), + ]; + } } $filer = DI::userSession()->getLocalUserId() ? DI::l10n()->t('Save to folder') : false; @@ -557,6 +563,7 @@ class Post 'ignore_author' => $ignore, 'collapse' => $collapse, 'report' => $report, + 'ignore_server' => $ignoreServer, 'vote' => $buttons, 'like_html' => $responses['like']['output'], 'dislike_html' => $responses['dislike']['output'], @@ -571,6 +578,7 @@ class Post 'wait' => DI::l10n()->t('Please wait'), 'thread_level' => $thread_level, 'edited' => $edited, + 'author_gsid' => $item['author-gsid'], 'network' => $item['network'], 'network_name' => ContactSelector::networkToName($item['author-network'], $item['author-link'], $item['network'], $item['author-gsid']), 'network_icon' => ContactSelector::networkToIcon($item['network'], $item['author-link'], $item['author-gsid']), diff --git a/src/Security/PermissionSet/Repository/PermissionSet.php b/src/Security/PermissionSet/Repository/PermissionSet.php index 58cf6e42f5..5abfb9305d 100644 --- a/src/Security/PermissionSet/Repository/PermissionSet.php +++ b/src/Security/PermissionSet/Repository/PermissionSet.php @@ -211,7 +211,7 @@ class PermissionSet extends BaseRepository } /** - * Selects or creates a PermissionSet based on it's fields + * Selects or creates a PermissionSet based on its fields * * @param Entity\PermissionSet $permissionSet * diff --git a/src/User/Settings/Collection/UserGServers.php b/src/User/Settings/Collection/UserGServers.php new file mode 100644 index 0000000000..689b801cf9 --- /dev/null +++ b/src/User/Settings/Collection/UserGServers.php @@ -0,0 +1,30 @@ +. + * + */ + +namespace Friendica\User\Settings\Collection; + +class UserGServers extends \Friendica\BaseCollection +{ + public function current(): \Friendica\User\Settings\Entity\UserGServer + { + return parent::current(); + } +} diff --git a/src/User/Settings/Entity/UserGServer.php b/src/User/Settings/Entity/UserGServer.php new file mode 100644 index 0000000000..e5afdc51e7 --- /dev/null +++ b/src/User/Settings/Entity/UserGServer.php @@ -0,0 +1,92 @@ +. + * + */ + +namespace Friendica\User\Settings\Entity; + +use Friendica\Federation\Entity\GServer; + +/** + * @property-read int $uid + * @property-read int $gsid + * @property-read bool $ignored + * @property-read ?GServer $gserver + */ +class UserGServer extends \Friendica\BaseEntity +{ + /** @var int User id */ + protected $uid; + /** @var int GServer id */ + protected $gsid; + /** @var bool Whether the user ignored this server */ + protected $ignored; + /** @var ?GServer */ + protected $gserver; + + public function __construct(int $uid, int $gsid, bool $ignored = false, ?GServer $gserver = null) + { + $this->uid = $uid; + $this->gsid = $gsid; + $this->ignored = $ignored; + $this->gserver = $gserver; + } + + /** + * Toggle the ignored property. + * + * Chainable. + * + * @return $this + */ + public function toggleIgnored(): UserGServer + { + $this->ignored = !$this->ignored; + + return $this; + } + + /** + * Set the ignored property. + * + * Chainable. + * + * @return $this + */ + public function ignore(): UserGServer + { + $this->ignored = true; + + return $this; + } + + /** + * Unset the ignored property. + * + * Chainable. + * + * @return $this + */ + public function unignore(): UserGServer + { + $this->ignored = false; + + return $this; + } +} diff --git a/src/User/Settings/Factory/UserGServer.php b/src/User/Settings/Factory/UserGServer.php new file mode 100644 index 0000000000..61abe28ccc --- /dev/null +++ b/src/User/Settings/Factory/UserGServer.php @@ -0,0 +1,60 @@ +. + * + */ + +namespace Friendica\User\Settings\Factory; + +use Friendica\Capabilities\ICanCreateFromTableRow; +use Friendica\Federation\Entity\GServer; +use Friendica\User\Settings\Entity; + +class UserGServer extends \Friendica\BaseFactory implements ICanCreateFromTableRow +{ + /** + * @param array $row `user-gserver` table row + * @param GServer|null $server Corresponding GServer entity + * @return Entity\UserGServer + */ + public function createFromTableRow(array $row, GServer $server = null): Entity\UserGServer + { + return new Entity\UserGServer( + $row['uid'], + $row['gsid'], + $row['ignored'], + $server, + ); + } + + /** + * @param int $uid + * @param int $gsid + * @param GServer|null $gserver Corresponding GServer entity + * @return Entity\UserGServer + */ + public function createFromUserAndServer(int $uid, int $gsid, GServer $gserver = null): Entity\UserGServer + { + return new Entity\UserGServer( + $uid, + $gsid, + false, + $gserver, + ); + } +} diff --git a/src/User/Settings/Repository/UserGServer.php b/src/User/Settings/Repository/UserGServer.php new file mode 100644 index 0000000000..baf70095ce --- /dev/null +++ b/src/User/Settings/Repository/UserGServer.php @@ -0,0 +1,156 @@ +. + * + */ + +namespace Friendica\User\Settings\Repository; + +use Exception; +use Friendica\BaseCollection; +use Friendica\BaseEntity; +use Friendica\Content\Pager; +use Friendica\Database\Database; +use Friendica\Federation\Repository\GServer; +use Friendica\Network\HTTPException\InternalServerErrorException; +use Friendica\Network\HTTPException\NotFoundException; +use Friendica\User\Settings\Collection; +use Friendica\User\Settings\Entity; +use Friendica\User\Settings\Factory; +use Psr\Log\LoggerInterface; + +class UserGServer extends \Friendica\BaseRepository +{ + protected static $table_name = 'user-gserver'; + + /** @var Factory\UserGServer */ + protected $factory; + /** @var GServer */ + protected $gserverRepository; + + public function __construct(GServer $gserverRepository, Database $database, LoggerInterface $logger, Factory\UserGServer $factory) + { + parent::__construct($database, $logger, $factory); + + $this->gserverRepository = $gserverRepository; + } + + /** + * Returns an existing UserGServer entity or create one on the fly + * + * @param int $uid + * @param int $gsid + * @param bool $hydrate Populate the related GServer entity + * @return Entity\UserGServer + */ + public function getOneByUserAndServer(int $uid, int $gsid, bool $hydrate = true): Entity\UserGServer + { + try { + return $this->selectOneByUserAndServer($uid, $gsid, $hydrate); + } catch (NotFoundException $e) { + return $this->factory->createFromUserAndServer($uid, $gsid, $hydrate ? $this->gserverRepository->selectOneById($gsid) : null); + } + } + + /** + * @param int $uid + * @param int $gsid + * @param bool $hydrate Populate the related GServer entity + * @return Entity\UserGServer + * @throws NotFoundException + */ + public function selectOneByUserAndServer(int $uid, int $gsid, bool $hydrate = true): Entity\UserGServer + { + return $this->_selectOne(['uid' => $uid, 'gsid' => $gsid], [], $hydrate); + } + + public function save(Entity\UserGServer $userGServer): Entity\UserGServer + { + $fields = [ + 'uid' => $userGServer->uid, + 'gsid' => $userGServer->gsid, + 'ignored' => $userGServer->ignored, + ]; + + $this->db->insert(static::$table_name, $fields, Database::INSERT_UPDATE); + + return $userGServer; + } + + public function selectByUserWithPagination(int $uid, Pager $pager): Collection\UserGServers + { + return $this->_select(['uid' => $uid], ['limit' => [$pager->getStart(), $pager->getItemsPerPage()]]); + } + + public function countByUser(int $uid): int + { + return $this->count(['uid' => $uid]); + } + + public function isIgnoredByUser(int $uid, int $gsid): bool + { + return $this->exists(['uid' => $uid, 'gsid' => $gsid, 'ignored' => 1]); + } + + /** + * @param Entity\UserGServer $userGServer + * @return bool + * @throws InternalServerErrorException in case the underlying storage cannot delete the record + */ + public function delete(Entity\UserGServer $userGServer): bool + { + try { + return $this->db->delete(self::$table_name, ['uid' => $userGServer->uid, 'gsid' => $userGServer->gsid]); + } catch (\Exception $exception) { + throw new InternalServerErrorException('Cannot delete the UserGServer', $exception); + } + } + + protected function _selectOne(array $condition, array $params = [], bool $hydrate = true): BaseEntity + { + $fields = $this->db->selectFirst(static::$table_name, [], $condition, $params); + if (!$this->db->isResult($fields)) { + throw new NotFoundException(); + } + + return $this->factory->createFromTableRow($fields, $hydrate ? $this->gserverRepository->selectOneById($fields['gsid']) : null); + } + + /** + * @param array $condition + * @param array $params + * @return Collection\UserGServers + * @throws Exception + */ + protected function _select(array $condition, array $params = [], bool $hydrate = true): BaseCollection + { + $rows = $this->db->selectToArray(static::$table_name, [], $condition, $params); + + $Entities = new Collection\UserGServers(); + foreach ($rows as $fields) { + $Entities[] = $this->factory->createFromTableRow($fields, $hydrate ? $this->gserverRepository->selectOneById($fields['gsid']) : null); + } + + return $Entities; + } + + public function listIgnoredByUser(int $uid): Collection\UserGServers + { + return $this->_select(['uid' => $uid, 'ignored' => 1], [], false); + } +} diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index 970aeb9ccf..71c7d5cb1d 100644 --- a/static/dbstructure.config.php +++ b/static/dbstructure.config.php @@ -56,7 +56,7 @@ use Friendica\Database\DBA; // This file is required several times during the test in DbaDefinition which justifies this condition if (!defined('DB_UPDATE_VERSION')) { - define('DB_UPDATE_VERSION', 1524); + define('DB_UPDATE_VERSION', 1529); } return [ @@ -159,6 +159,18 @@ return [ "email" => ["email(64)"], ] ], + "user-gserver" => [ + "comment" => "User settings about remote servers", + "fields" => [ + "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "foreign" => ["user" => "uid"], "comment" => "Owner User id"], + "gsid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "foreign" => ["gserver" => "id"], "comment" => "Gserver id"], + "ignored" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "server accounts are ignored for the user"], + ], + "indexes" => [ + "PRIMARY" => ["uid", "gsid"], + "gsid" => ["gsid"] + ], + ], "item-uri" => [ "comment" => "URI and GUID for items", "fields" => [ @@ -218,8 +230,8 @@ return [ "archive" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], "unsearchable" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Contact prefers to not be searchable"], "sensitive" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Contact posts sensitive content"], - "baseurl" => ["type" => "varbinary(383)", "default" => "", "comment" => "baseurl of the contact"], - "gsid" => ["type" => "int unsigned", "foreign" => ["gserver" => "id", "on delete" => "restrict"], "comment" => "Global Server ID"], + "baseurl" => ["type" => "varbinary(383)", "default" => "", "comment" => "baseurl of the contact from the gserver record, can be missing"], + "gsid" => ["type" => "int unsigned", "foreign" => ["gserver" => "id", "on delete" => "restrict"], "comment" => "Global Server ID, can be missing"], "bd" => ["type" => "date", "not null" => "1", "default" => DBA::NULL_DATE, "comment" => ""], // User depending fields "reason" => ["type" => "text", "comment" => ""], @@ -1583,7 +1595,7 @@ return [ "profile-name" => ["type" => "varchar(255)", "comment" => "Deprecated"], "is-default" => ["type" => "boolean", "comment" => "Deprecated"], "hide-friends" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Hide friend list from viewers of this profile"], - "name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Unused in favor of user.username"], "pdesc" => ["type" => "varchar(255)", "comment" => "Deprecated"], "dob" => ["type" => "varchar(32)", "not null" => "1", "default" => "0000-00-00", "comment" => "Day of birth"], "address" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], diff --git a/static/dbview.config.php b/static/dbview.config.php index e8641240c2..d688cef3fa 100644 --- a/static/dbview.config.php +++ b/static/dbview.config.php @@ -185,6 +185,7 @@ "author-hidden" => ["author", "hidden"], "author-updated" => ["author", "updated"], "author-gsid" => ["author", "gsid"], + "author-baseurl" => ["author", "baseurl"], "owner-id" => ["post-user", "owner-id"], "owner-uri-id" => ["owner", "uri-id"], "owner-link" => ["owner", "url"], @@ -197,6 +198,7 @@ "owner-blocked" => ["owner", "blocked"], "owner-hidden" => ["owner", "hidden"], "owner-updated" => ["owner", "updated"], + "owner-gsid" => ["owner", "gsid"], "owner-contact-type" => ["owner", "contact-type"], "causer-id" => ["post-user", "causer-id"], "causer-uri-id" => ["causer", "uri-id"], @@ -209,6 +211,7 @@ "causer-network" => ["causer", "network"], "causer-blocked" => ["causer", "blocked"], "causer-hidden" => ["causer", "hidden"], + "causer-gsid" => ["causer", "gsid"], "causer-contact-type" => ["causer", "contact-type"], "postopts" => ["post-delivery-data", "postopts"], "inform" => ["post-delivery-data", "inform"], @@ -340,6 +343,7 @@ "contact-pending" => ["contact", "pending"], "contact-rel" => ["contact", "rel"], "contact-uid" => ["contact", "uid"], + "contact-gsid" => ["contact", "gsid"], "contact-contact-type" => ["contact", "contact-type"], "writable" => "IF (`post-user`.`network` IN ('apub', 'dfrn', 'dspr', 'stat'), true, `contact`.`writable`)", "self" => ["contact", "self"], @@ -375,6 +379,7 @@ "owner-blocked" => ["owner", "blocked"], "owner-hidden" => ["owner", "hidden"], "owner-updated" => ["owner", "updated"], + "owner-gsid" => ["owner", "gsid"], "owner-contact-type" => ["owner", "contact-type"], "causer-id" => ["post-thread-user", "causer-id"], "causer-uri-id" => ["causer", "uri-id"], @@ -387,6 +392,7 @@ "causer-network" => ["causer", "network"], "causer-blocked" => ["causer", "blocked"], "causer-hidden" => ["causer", "hidden"], + "causer-gsid" => ["causer", "gsid"], "causer-contact-type" => ["causer", "contact-type"], "postopts" => ["post-delivery-data", "postopts"], "inform" => ["post-delivery-data", "inform"], @@ -540,6 +546,7 @@ "owner-hidden" => ["owner", "hidden"], "owner-updated" => ["owner", "updated"], "owner-contact-type" => ["owner", "contact-type"], + "owner-gsid" => ["owner", "gsid"], "causer-id" => ["post", "causer-id"], "causer-uri-id" => ["causer", "uri-id"], "causer-link" => ["causer", "url"], @@ -552,6 +559,7 @@ "causer-blocked" => ["causer", "blocked"], "causer-hidden" => ["causer", "hidden"], "causer-contact-type" => ["causer", "contact-type"], + "causer-gsid" => ["causer", "gsid"], "question-id" => ["post-question", "id"], "question-multiple" => ["post-question", "multiple"], "question-voters" => ["post-question", "voters"], @@ -680,6 +688,7 @@ "owner-blocked" => ["owner", "blocked"], "owner-hidden" => ["owner", "hidden"], "owner-updated" => ["owner", "updated"], + "owner-gsid" => ["owner", "gsid"], "owner-contact-type" => ["owner", "contact-type"], "causer-id" => ["post-thread", "causer-id"], "causer-uri-id" => ["causer", "uri-id"], @@ -692,6 +701,7 @@ "causer-network" => ["causer", "network"], "causer-blocked" => ["causer", "blocked"], "causer-hidden" => ["causer", "hidden"], + "causer-gsid" => ["causer", "gsid"], "causer-contact-type" => ["causer", "contact-type"], "question-id" => ["post-question", "id"], "question-multiple" => ["post-question", "multiple"], @@ -804,18 +814,16 @@ "contact-type" => ["ownercontact", "contact-type"], ], "query" => "FROM `post-user` - INNER JOIN `post-thread-user` ON `post-thread-user`.`uri-id` = `post-user`.`parent-uri-id` AND `post-thread-user`.`uid` = `post-user`.`uid` + INNER JOIN `post-thread-user` ON `post-thread-user`.`uri-id` = `post-user`.`parent-uri-id` AND `post-thread-user`.`uid` = `post-user`.`uid` STRAIGHT_JOIN `contact` ON `contact`.`id` = `post-thread-user`.`contact-id` STRAIGHT_JOIN `contact` AS `authorcontact` ON `authorcontact`.`id` = `post-thread-user`.`author-id` STRAIGHT_JOIN `contact` AS `ownercontact` ON `ownercontact`.`id` = `post-thread-user`.`owner-id` - LEFT JOIN `user-contact` AS `author` ON `author`.`uid` = `post-thread-user`.`uid` AND `author`.`cid` = `post-thread-user`.`author-id` - LEFT JOIN `user-contact` AS `owner` ON `owner`.`uid` = `post-thread-user`.`uid` AND `owner`.`cid` = `post-thread-user`.`owner-id` WHERE `post-user`.`visible` AND NOT `post-user`.`deleted` AND (NOT `contact`.`readonly` AND NOT `contact`.`blocked` AND NOT `contact`.`pending`) AND (`post-user`.`hidden` IS NULL OR NOT `post-user`.`hidden`) AND NOT `authorcontact`.`blocked` AND NOT `ownercontact`.`blocked` - AND (`author`.`blocked` IS NULL OR NOT `author`.`blocked`) - AND (`owner`.`blocked` IS NULL OR NOT `owner`.`blocked`)" + AND NOT EXISTS(SELECT `cid` FROM `user-contact` WHERE `uid` = `post-thread-user`.`uid` AND `cid` IN (`authorcontact`.`id`, `ownercontact`.`id`) AND (`blocked` OR `ignored`)) + AND NOT EXISTS(SELECT `gsid` FROM `user-gserver` WHERE `uid` = `post-thread-user`.`uid` AND `gsid` IN (`authorcontact`.`gsid`, `ownercontact`.`gsid`) AND `ignored`)" ], "network-thread-view" => [ "fields" => [ @@ -836,14 +844,12 @@ STRAIGHT_JOIN `contact` ON `contact`.`id` = `post-thread-user`.`contact-id` STRAIGHT_JOIN `contact` AS `authorcontact` ON `authorcontact`.`id` = `post-thread-user`.`author-id` STRAIGHT_JOIN `contact` AS `ownercontact` ON `ownercontact`.`id` = `post-thread-user`.`owner-id` - LEFT JOIN `user-contact` AS `author` ON `author`.`uid` = `post-thread-user`.`uid` AND `author`.`cid` = `post-thread-user`.`author-id` - LEFT JOIN `user-contact` AS `owner` ON `owner`.`uid` = `post-thread-user`.`uid` AND `owner`.`cid` = `post-thread-user`.`owner-id` WHERE `post-user`.`visible` AND NOT `post-user`.`deleted` AND (NOT `contact`.`readonly` AND NOT `contact`.`blocked` AND NOT `contact`.`pending`) AND (`post-thread-user`.`hidden` IS NULL OR NOT `post-thread-user`.`hidden`) AND NOT `authorcontact`.`blocked` AND NOT `ownercontact`.`blocked` - AND (`author`.`blocked` IS NULL OR NOT `author`.`blocked`) - AND (`owner`.`blocked` IS NULL OR NOT `owner`.`blocked`)" + AND NOT EXISTS(SELECT `cid` FROM `user-contact` WHERE `uid` = `post-thread-user`.`uid` AND `cid` IN (`authorcontact`.`id`, `ownercontact`.`id`) AND (`blocked` OR `ignored`)) + AND NOT EXISTS(SELECT `gsid` FROM `user-gserver` WHERE `uid` = `post-thread-user`.`uid` AND `gsid` IN (`authorcontact`.`gsid`, `ownercontact`.`gsid`) AND `ignored`)" ], "owner-view" => [ "fields" => [ diff --git a/static/routes.config.php b/static/routes.config.php index 71595e5a82..36ba2f2493 100644 --- a/static/routes.config.php +++ b/static/routes.config.php @@ -639,6 +639,10 @@ return [ ], '/settings' => [ + '/server' => [ + '[/]' => [Module\Settings\Server\Index::class, [R::GET, R::POST]], + '/{gsid:\d+}/{action}' => [Module\Settings\Server\Action::class, [R::GET, R::POST]], + ], '[/]' => [Module\Settings\Account::class, [R::GET, R::POST]], '/account' => [ '[/]' => [Module\Settings\Account::class, [R::GET, R::POST]], diff --git a/update.php b/update.php index 980ec721ab..59340eed83 100644 --- a/update.php +++ b/update.php @@ -1349,3 +1349,31 @@ function update_1524(): int return Update::SUCCESS; } + +function update_1525(): int +{ + // Use expected value for user.username + if (!DBA::e('UPDATE `user` u + JOIN `profile` p + ON p.`uid` = u.`uid` + SET u.`username` = p.`name` + WHERE p.`name` != ""')) { + return Update::FAILED; + } + + // Blank out deprecated field profile.name to avoid future confusion + if (!DBA::e('UPDATE `profile` p + SET p.`name` = ""')) { + return Update::FAILED; + } + + // Update users' self-contact name if needed + if (!DBA::e('UPDATE `contact` c + JOIN `user` u + ON u.`uid` = c.`uid` AND c.`self` = 1 + SET c.`name` = u.`username`')) { + return Update::FAILED; + } + + return Update::SUCCESS; +} diff --git a/view/lang/C/messages.po b/view/lang/C/messages.po index 7a49e009de..b758e68c03 100644 --- a/view/lang/C/messages.po +++ b/view/lang/C/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 2023.09-dev\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-08-10 21:16+0000\n" +"POT-Creation-Date: 2023-08-28 04:37+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -38,13 +38,13 @@ msgstr "" msgid "Empty post discarded." msgstr "" -#: mod/item.php:427 src/Module/Admin/Themes/Details.php:39 +#: mod/item.php:428 src/Module/Admin/Themes/Details.php:39 #: src/Module/Admin/Themes/Index.php:59 src/Module/Debug/ItemBody.php:42 #: src/Module/Debug/ItemBody.php:57 src/Module/Item/Feed.php:80 msgid "Item not found." msgstr "" -#: mod/item.php:451 mod/message.php:67 mod/message.php:113 mod/notes.php:45 +#: mod/item.php:452 mod/message.php:67 mod/message.php:113 mod/notes.php:45 #: mod/photos.php:152 mod/photos.php:670 src/Model/Event.php:520 #: src/Module/Attach.php:55 src/Module/BaseApi.php:99 #: src/Module/BaseNotifications.php:98 src/Module/BaseSettings.php:52 @@ -281,7 +281,7 @@ msgstr "" msgid "Your message:" msgstr "" -#: mod/message.php:199 mod/message.php:354 src/Content/Conversation.php:361 +#: mod/message.php:199 mod/message.php:354 src/Content/Conversation.php:367 #: src/Module/Post/Edit.php:131 msgid "Upload photo" msgstr "" @@ -292,9 +292,9 @@ msgid "Insert web link" msgstr "" #: mod/message.php:201 mod/message.php:357 mod/photos.php:1301 -#: src/Content/Conversation.php:392 src/Content/Conversation.php:1508 +#: src/Content/Conversation.php:398 src/Content/Conversation.php:1534 #: src/Module/Item/Compose.php:206 src/Module/Post/Edit.php:145 -#: src/Module/Profile/UnkMail.php:154 src/Object/Post.php:571 +#: src/Module/Profile/UnkMail.php:154 src/Object/Post.php:578 msgid "Please wait" msgstr "" @@ -302,7 +302,7 @@ msgstr "" #: mod/photos.php:824 mod/photos.php:1101 mod/photos.php:1142 #: mod/photos.php:1198 mod/photos.php:1278 #: src/Module/Calendar/Event/Form.php:250 src/Module/Contact/Advanced.php:132 -#: src/Module/Contact/Profile.php:339 +#: src/Module/Contact/Profile.php:358 #: src/Module/Debug/ActivityPubConversion.php:140 #: src/Module/Debug/Babel.php:313 src/Module/Debug/Localtime.php:64 #: src/Module/Debug/Probe.php:54 src/Module/Debug/WebFinger.php:51 @@ -315,7 +315,8 @@ msgstr "" #: src/Module/Moderation/Report/Create.php:211 #: src/Module/Moderation/Report/Create.php:263 #: src/Module/Profile/Profile.php:274 src/Module/Profile/UnkMail.php:155 -#: src/Module/Settings/Profile/Index.php:230 src/Object/Post.php:1087 +#: src/Module/Settings/Profile/Index.php:257 +#: src/Module/Settings/Server/Action.php:79 src/Object/Post.php:1095 #: view/theme/duepuntozero/config.php:85 view/theme/frio/config.php:171 #: view/theme/quattro/config.php:87 view/theme/vier/config.php:135 msgid "Submit" @@ -388,7 +389,7 @@ msgid "Save" msgstr "" #: mod/photos.php:67 mod/photos.php:132 mod/photos.php:578 -#: src/Model/Event.php:512 src/Model/Profile.php:234 +#: src/Model/Event.php:512 src/Model/Profile.php:232 #: src/Module/Calendar/Export.php:74 src/Module/Calendar/Show.php:74 #: src/Module/DFRN/Poll.php:43 src/Module/Feed.php:65 src/Module/HCard.php:51 #: src/Module/Profile/Common.php:62 src/Module/Profile/Common.php:71 @@ -479,7 +480,7 @@ msgstr "" msgid "Do not show a status post for this upload" msgstr "" -#: mod/photos.php:736 mod/photos.php:1097 src/Content/Conversation.php:394 +#: mod/photos.php:736 mod/photos.php:1097 src/Content/Conversation.php:400 #: src/Module/Calendar/Event/Form.php:253 src/Module/Post/Edit.php:183 msgid "Permissions" msgstr "" @@ -492,7 +493,7 @@ msgstr "" msgid "Delete Album" msgstr "" -#: mod/photos.php:803 mod/photos.php:903 src/Content/Conversation.php:410 +#: mod/photos.php:803 mod/photos.php:903 src/Content/Conversation.php:416 #: src/Module/Contact/Follow.php:173 src/Module/Contact/Revoke.php:109 #: src/Module/Contact/Unfollow.php:126 #: src/Module/Media/Attachment/Browser.php:77 @@ -600,53 +601,54 @@ msgstr "" #: mod/photos.php:1139 mod/photos.php:1195 mod/photos.php:1275 #: src/Module/Contact.php:619 src/Module/Item/Compose.php:188 -#: src/Object/Post.php:1084 +#: src/Object/Post.php:1092 msgid "This is you" msgstr "" #: mod/photos.php:1141 mod/photos.php:1197 mod/photos.php:1277 -#: src/Object/Post.php:565 src/Object/Post.php:1086 +#: src/Object/Post.php:572 src/Object/Post.php:1094 msgid "Comment" msgstr "" #: mod/photos.php:1143 mod/photos.php:1199 mod/photos.php:1279 -#: src/Content/Conversation.php:407 src/Module/Calendar/Event/Form.php:248 +#: src/Content/Conversation.php:413 src/Module/Calendar/Event/Form.php:248 #: src/Module/Item/Compose.php:201 src/Module/Post/Edit.php:165 -#: src/Object/Post.php:1100 +#: src/Object/Post.php:1108 msgid "Preview" msgstr "" -#: mod/photos.php:1144 src/Content/Conversation.php:360 -#: src/Module/Post/Edit.php:130 src/Object/Post.php:1088 +#: mod/photos.php:1144 src/Content/Conversation.php:366 +#: src/Module/Post/Edit.php:130 src/Object/Post.php:1096 msgid "Loading..." msgstr "" -#: mod/photos.php:1236 src/Content/Conversation.php:1424 +#: mod/photos.php:1236 src/Content/Conversation.php:1449 #: src/Object/Post.php:260 msgid "Select" msgstr "" -#: mod/photos.php:1237 src/Content/Conversation.php:1425 +#: mod/photos.php:1237 src/Content/Conversation.php:1450 #: src/Module/Moderation/Users/Active.php:136 #: src/Module/Moderation/Users/Blocked.php:136 #: src/Module/Moderation/Users/Index.php:151 #: src/Module/Settings/Connectors.php:244 +#: src/Module/Settings/Server/Index.php:109 msgid "Delete" msgstr "" -#: mod/photos.php:1298 src/Object/Post.php:402 +#: mod/photos.php:1298 src/Object/Post.php:408 msgid "Like" msgstr "" -#: mod/photos.php:1299 src/Object/Post.php:402 +#: mod/photos.php:1299 src/Object/Post.php:408 msgid "I like this (toggle)" msgstr "" -#: mod/photos.php:1300 src/Object/Post.php:403 +#: mod/photos.php:1300 src/Object/Post.php:409 msgid "Dislike" msgstr "" -#: mod/photos.php:1302 src/Object/Post.php:403 +#: mod/photos.php:1302 src/Object/Post.php:409 msgid "I don't like this (toggle)" msgstr "" @@ -682,77 +684,88 @@ msgstr "" msgid "Collapse this author's posts?" msgstr "" -#: src/App/Page.php:253 -msgid "Like not successful" +#: src/App/Page.php:252 +msgid "Ignore this author's server?" msgstr "" -#: src/App/Page.php:254 -msgid "Dislike not successful" +#: src/App/Page.php:253 src/Module/Settings/Server/Action.php:61 +#: src/Module/Settings/Server/Index.php:108 +msgid "" +"You won't see any content from this server including reshares in your " +"Network page, the community pages and individual conversations." msgstr "" #: src/App/Page.php:255 -msgid "Sharing not successful" +msgid "Like not successful" msgstr "" #: src/App/Page.php:256 -msgid "Attendance unsuccessful" +msgid "Dislike not successful" msgstr "" #: src/App/Page.php:257 -msgid "Backend error" +msgid "Sharing not successful" msgstr "" #: src/App/Page.php:258 +msgid "Attendance unsuccessful" +msgstr "" + +#: src/App/Page.php:259 +msgid "Backend error" +msgstr "" + +#: src/App/Page.php:260 msgid "Network error" msgstr "" -#: src/App/Page.php:261 +#: src/App/Page.php:263 msgid "Drop files here to upload" msgstr "" -#: src/App/Page.php:262 +#: src/App/Page.php:264 msgid "Your browser does not support drag and drop file uploads." msgstr "" -#: src/App/Page.php:263 +#: src/App/Page.php:265 msgid "" "Please use the fallback form below to upload your files like in the olden " "days." msgstr "" -#: src/App/Page.php:264 +#: src/App/Page.php:266 msgid "File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB." msgstr "" -#: src/App/Page.php:265 +#: src/App/Page.php:267 msgid "You can't upload files of this type." msgstr "" -#: src/App/Page.php:266 +#: src/App/Page.php:268 msgid "Server responded with {{statusCode}} code." msgstr "" -#: src/App/Page.php:267 +#: src/App/Page.php:269 msgid "Cancel upload" msgstr "" -#: src/App/Page.php:268 +#: src/App/Page.php:270 msgid "Upload canceled." msgstr "" -#: src/App/Page.php:269 +#: src/App/Page.php:271 msgid "Are you sure you want to cancel this upload?" msgstr "" -#: src/App/Page.php:270 +#: src/App/Page.php:272 msgid "Remove file" msgstr "" -#: src/App/Page.php:271 +#: src/App/Page.php:273 msgid "You can't upload any more files." msgstr "" -#: src/App/Page.php:349 +#: src/App/Page.php:351 msgid "toggle mobile" msgstr "" @@ -779,17 +792,17 @@ msgstr "" msgid "All contacts" msgstr "" -#: src/BaseModule.php:433 src/Content/Widget.php:243 src/Core/ACL.php:195 +#: src/BaseModule.php:433 src/Content/Widget.php:239 src/Core/ACL.php:195 #: src/Module/Contact.php:415 src/Module/PermissionTooltip.php:127 #: src/Module/PermissionTooltip.php:149 msgid "Followers" msgstr "" -#: src/BaseModule.php:438 src/Content/Widget.php:244 src/Module/Contact.php:418 +#: src/BaseModule.php:438 src/Content/Widget.php:240 src/Module/Contact.php:418 msgid "Following" msgstr "" -#: src/BaseModule.php:443 src/Content/Widget.php:245 src/Module/Contact.php:421 +#: src/BaseModule.php:443 src/Content/Widget.php:241 src/Module/Contact.php:421 msgid "Mutual friends" msgstr "" @@ -943,7 +956,7 @@ msgstr "" msgid "Enter user nickname: " msgstr "" -#: src/Console/User.php:182 src/Model/User.php:692 +#: src/Console/User.php:182 src/Model/User.php:693 #: src/Module/Api/Twitter/ContactEndpoint.php:74 #: src/Module/Moderation/Users/Active.php:71 #: src/Module/Moderation/Users/Blocked.php:71 @@ -1127,65 +1140,65 @@ msgstr "" msgid "%s (via %s)" msgstr "" -#: src/Content/Conversation.php:219 +#: src/Content/Conversation.php:225 msgid "and" msgstr "" -#: src/Content/Conversation.php:222 +#: src/Content/Conversation.php:228 #, php-format msgid "and %d other people" msgstr "" -#: src/Content/Conversation.php:228 +#: src/Content/Conversation.php:234 #, php-format msgid "%2$s likes this." msgid_plural "%2$s like this." msgstr[0] "" msgstr[1] "" -#: src/Content/Conversation.php:230 +#: src/Content/Conversation.php:236 #, php-format msgid "%2$s doesn't like this." msgid_plural "%2$s don't like this." msgstr[0] "" msgstr[1] "" -#: src/Content/Conversation.php:232 +#: src/Content/Conversation.php:238 #, php-format msgid "%2$s attends." msgid_plural "%2$s attend." msgstr[0] "" msgstr[1] "" -#: src/Content/Conversation.php:234 +#: src/Content/Conversation.php:240 #, php-format msgid "%2$s doesn't attend." msgid_plural "%2$s don't attend." msgstr[0] "" msgstr[1] "" -#: src/Content/Conversation.php:236 +#: src/Content/Conversation.php:242 #, php-format msgid "%2$s attends maybe." msgid_plural "%2$s attend maybe." msgstr[0] "" msgstr[1] "" -#: src/Content/Conversation.php:238 +#: src/Content/Conversation.php:244 #, php-format msgid "%2$s reshared this." msgid_plural "%2$s reshared this." msgstr[0] "" msgstr[1] "" -#: src/Content/Conversation.php:267 +#: src/Content/Conversation.php:273 #, php-format msgid " likes this" msgid_plural " like this" msgstr[0] "" msgstr[1] "" -#: src/Content/Conversation.php:270 +#: src/Content/Conversation.php:276 #, php-format msgid " doesn't like this" msgid_plural "" @@ -1193,304 +1206,309 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" -#: src/Content/Conversation.php:273 +#: src/Content/Conversation.php:279 #, php-format msgid " attends" msgid_plural " attend" msgstr[0] "" msgstr[1] "" -#: src/Content/Conversation.php:276 +#: src/Content/Conversation.php:282 #, php-format msgid " doesn't attend" msgid_plural " don't attend" msgstr[0] "" msgstr[1] "" -#: src/Content/Conversation.php:279 +#: src/Content/Conversation.php:285 #, php-format msgid " attends maybe" msgid_plural " attend maybe" msgstr[0] "" msgstr[1] "" -#: src/Content/Conversation.php:282 +#: src/Content/Conversation.php:288 #, php-format msgid " reshared this" msgid_plural " reshared this" msgstr[0] "" msgstr[1] "" -#: src/Content/Conversation.php:329 +#: src/Content/Conversation.php:335 msgid "Visible to everybody" msgstr "" -#: src/Content/Conversation.php:330 src/Module/Item/Compose.php:200 -#: src/Object/Post.php:1099 +#: src/Content/Conversation.php:336 src/Module/Item/Compose.php:200 +#: src/Object/Post.php:1107 msgid "Please enter a image/video/audio/webpage URL:" msgstr "" -#: src/Content/Conversation.php:331 +#: src/Content/Conversation.php:337 msgid "Tag term:" msgstr "" -#: src/Content/Conversation.php:332 src/Module/Filer/SaveTag.php:73 +#: src/Content/Conversation.php:338 src/Module/Filer/SaveTag.php:73 msgid "Save to Folder:" msgstr "" -#: src/Content/Conversation.php:333 +#: src/Content/Conversation.php:339 msgid "Where are you right now?" msgstr "" -#: src/Content/Conversation.php:334 +#: src/Content/Conversation.php:340 msgid "Delete item(s)?" msgstr "" -#: src/Content/Conversation.php:346 src/Module/Item/Compose.php:175 +#: src/Content/Conversation.php:352 src/Module/Item/Compose.php:175 msgid "Created at" msgstr "" -#: src/Content/Conversation.php:356 +#: src/Content/Conversation.php:362 msgid "New Post" msgstr "" -#: src/Content/Conversation.php:359 +#: src/Content/Conversation.php:365 msgid "Share" msgstr "" -#: src/Content/Conversation.php:362 src/Module/Post/Edit.php:132 +#: src/Content/Conversation.php:368 src/Module/Post/Edit.php:132 msgid "upload photo" msgstr "" -#: src/Content/Conversation.php:363 src/Module/Post/Edit.php:133 +#: src/Content/Conversation.php:369 src/Module/Post/Edit.php:133 msgid "Attach file" msgstr "" -#: src/Content/Conversation.php:364 src/Module/Post/Edit.php:134 +#: src/Content/Conversation.php:370 src/Module/Post/Edit.php:134 msgid "attach file" msgstr "" -#: src/Content/Conversation.php:365 src/Module/Item/Compose.php:190 -#: src/Module/Post/Edit.php:171 src/Object/Post.php:1089 +#: src/Content/Conversation.php:371 src/Module/Item/Compose.php:190 +#: src/Module/Post/Edit.php:171 src/Object/Post.php:1097 msgid "Bold" msgstr "" -#: src/Content/Conversation.php:366 src/Module/Item/Compose.php:191 -#: src/Module/Post/Edit.php:172 src/Object/Post.php:1090 +#: src/Content/Conversation.php:372 src/Module/Item/Compose.php:191 +#: src/Module/Post/Edit.php:172 src/Object/Post.php:1098 msgid "Italic" msgstr "" -#: src/Content/Conversation.php:367 src/Module/Item/Compose.php:192 -#: src/Module/Post/Edit.php:173 src/Object/Post.php:1091 +#: src/Content/Conversation.php:373 src/Module/Item/Compose.php:192 +#: src/Module/Post/Edit.php:173 src/Object/Post.php:1099 msgid "Underline" msgstr "" -#: src/Content/Conversation.php:368 src/Module/Item/Compose.php:193 -#: src/Module/Post/Edit.php:174 src/Object/Post.php:1093 +#: src/Content/Conversation.php:374 src/Module/Item/Compose.php:193 +#: src/Module/Post/Edit.php:174 src/Object/Post.php:1101 msgid "Quote" msgstr "" -#: src/Content/Conversation.php:369 src/Module/Item/Compose.php:194 -#: src/Module/Post/Edit.php:175 src/Object/Post.php:1094 +#: src/Content/Conversation.php:375 src/Module/Item/Compose.php:194 +#: src/Module/Post/Edit.php:175 src/Object/Post.php:1102 msgid "Add emojis" msgstr "" -#: src/Content/Conversation.php:370 src/Module/Item/Compose.php:195 -#: src/Object/Post.php:1092 +#: src/Content/Conversation.php:376 src/Module/Item/Compose.php:195 +#: src/Object/Post.php:1100 msgid "Content Warning" msgstr "" -#: src/Content/Conversation.php:371 src/Module/Item/Compose.php:196 -#: src/Module/Post/Edit.php:176 src/Object/Post.php:1095 +#: src/Content/Conversation.php:377 src/Module/Item/Compose.php:196 +#: src/Module/Post/Edit.php:176 src/Object/Post.php:1103 msgid "Code" msgstr "" -#: src/Content/Conversation.php:372 src/Module/Item/Compose.php:197 -#: src/Object/Post.php:1096 +#: src/Content/Conversation.php:378 src/Module/Item/Compose.php:197 +#: src/Object/Post.php:1104 msgid "Image" msgstr "" -#: src/Content/Conversation.php:373 src/Module/Item/Compose.php:198 -#: src/Module/Post/Edit.php:177 src/Object/Post.php:1097 +#: src/Content/Conversation.php:379 src/Module/Item/Compose.php:198 +#: src/Module/Post/Edit.php:177 src/Object/Post.php:1105 msgid "Link" msgstr "" -#: src/Content/Conversation.php:374 src/Module/Item/Compose.php:199 -#: src/Module/Post/Edit.php:178 src/Object/Post.php:1098 +#: src/Content/Conversation.php:380 src/Module/Item/Compose.php:199 +#: src/Module/Post/Edit.php:178 src/Object/Post.php:1106 msgid "Link or Media" msgstr "" -#: src/Content/Conversation.php:375 +#: src/Content/Conversation.php:381 msgid "Video" msgstr "" -#: src/Content/Conversation.php:376 src/Module/Item/Compose.php:202 +#: src/Content/Conversation.php:382 src/Module/Item/Compose.php:202 #: src/Module/Post/Edit.php:141 msgid "Set your location" msgstr "" -#: src/Content/Conversation.php:377 src/Module/Post/Edit.php:142 +#: src/Content/Conversation.php:383 src/Module/Post/Edit.php:142 msgid "set location" msgstr "" -#: src/Content/Conversation.php:378 src/Module/Post/Edit.php:143 +#: src/Content/Conversation.php:384 src/Module/Post/Edit.php:143 msgid "Clear browser location" msgstr "" -#: src/Content/Conversation.php:379 src/Module/Post/Edit.php:144 +#: src/Content/Conversation.php:385 src/Module/Post/Edit.php:144 msgid "clear location" msgstr "" -#: src/Content/Conversation.php:381 src/Module/Item/Compose.php:207 +#: src/Content/Conversation.php:387 src/Module/Item/Compose.php:207 #: src/Module/Post/Edit.php:157 msgid "Set title" msgstr "" -#: src/Content/Conversation.php:383 src/Module/Item/Compose.php:208 +#: src/Content/Conversation.php:389 src/Module/Item/Compose.php:208 #: src/Module/Post/Edit.php:159 msgid "Categories (comma-separated list)" msgstr "" -#: src/Content/Conversation.php:388 src/Module/Item/Compose.php:224 +#: src/Content/Conversation.php:394 src/Module/Item/Compose.php:224 msgid "Scheduled at" msgstr "" -#: src/Content/Conversation.php:393 src/Module/Post/Edit.php:146 +#: src/Content/Conversation.php:399 src/Module/Post/Edit.php:146 msgid "Permission settings" msgstr "" -#: src/Content/Conversation.php:403 src/Module/Post/Edit.php:155 +#: src/Content/Conversation.php:409 src/Module/Post/Edit.php:155 msgid "Public post" msgstr "" -#: src/Content/Conversation.php:417 src/Content/Widget/VCard.php:120 -#: src/Model/Profile.php:469 src/Module/Admin/Logs/View.php:92 +#: src/Content/Conversation.php:423 src/Content/Widget/VCard.php:120 +#: src/Model/Profile.php:467 src/Module/Admin/Logs/View.php:92 #: src/Module/Post/Edit.php:181 msgid "Message" msgstr "" -#: src/Content/Conversation.php:418 src/Module/Post/Edit.php:182 +#: src/Content/Conversation.php:424 src/Module/Post/Edit.php:182 #: src/Module/Settings/TwoFactor/Trusted.php:140 msgid "Browser" msgstr "" -#: src/Content/Conversation.php:420 src/Module/Post/Edit.php:185 +#: src/Content/Conversation.php:426 src/Module/Post/Edit.php:185 msgid "Open Compose page" msgstr "" -#: src/Content/Conversation.php:569 +#: src/Content/Conversation.php:581 msgid "remove" msgstr "" -#: src/Content/Conversation.php:573 +#: src/Content/Conversation.php:585 msgid "Delete Selected Items" msgstr "" -#: src/Content/Conversation.php:728 src/Content/Conversation.php:731 -#: src/Content/Conversation.php:734 src/Content/Conversation.php:737 -#: src/Content/Conversation.php:740 +#: src/Content/Conversation.php:740 src/Content/Conversation.php:743 +#: src/Content/Conversation.php:746 src/Content/Conversation.php:749 +#: src/Content/Conversation.php:752 #, php-format msgid "You had been addressed (%s)." msgstr "" -#: src/Content/Conversation.php:743 +#: src/Content/Conversation.php:755 #, php-format msgid "You are following %s." msgstr "" -#: src/Content/Conversation.php:746 +#: src/Content/Conversation.php:760 +#, php-format +msgid "You subscribed to %s." +msgstr "" + +#: src/Content/Conversation.php:762 msgid "You subscribed to one or more tags in this post." msgstr "" -#: src/Content/Conversation.php:765 +#: src/Content/Conversation.php:782 #, php-format msgid "%s reshared this." msgstr "" -#: src/Content/Conversation.php:767 +#: src/Content/Conversation.php:784 msgid "Reshared" msgstr "" -#: src/Content/Conversation.php:767 +#: src/Content/Conversation.php:784 #, php-format msgid "Reshared by %s <%s>" msgstr "" -#: src/Content/Conversation.php:770 +#: src/Content/Conversation.php:787 #, php-format msgid "%s is participating in this thread." msgstr "" -#: src/Content/Conversation.php:773 +#: src/Content/Conversation.php:790 msgid "Stored for general reasons" msgstr "" -#: src/Content/Conversation.php:776 +#: src/Content/Conversation.php:793 msgid "Global post" msgstr "" -#: src/Content/Conversation.php:779 +#: src/Content/Conversation.php:796 msgid "Sent via an relay server" msgstr "" -#: src/Content/Conversation.php:779 +#: src/Content/Conversation.php:796 #, php-format msgid "Sent via the relay server %s <%s>" msgstr "" -#: src/Content/Conversation.php:782 +#: src/Content/Conversation.php:799 msgid "Fetched" msgstr "" -#: src/Content/Conversation.php:782 +#: src/Content/Conversation.php:799 #, php-format msgid "Fetched because of %s <%s>" msgstr "" -#: src/Content/Conversation.php:785 +#: src/Content/Conversation.php:802 msgid "Stored because of a child post to complete this thread." msgstr "" -#: src/Content/Conversation.php:788 +#: src/Content/Conversation.php:805 msgid "Local delivery" msgstr "" -#: src/Content/Conversation.php:791 +#: src/Content/Conversation.php:808 msgid "Stored because of your activity (like, comment, star, ...)" msgstr "" -#: src/Content/Conversation.php:794 +#: src/Content/Conversation.php:811 msgid "Distributed" msgstr "" -#: src/Content/Conversation.php:797 +#: src/Content/Conversation.php:814 msgid "Pushed to us" msgstr "" -#: src/Content/Conversation.php:1452 src/Object/Post.php:248 +#: src/Content/Conversation.php:1477 src/Object/Post.php:247 msgid "Pinned item" msgstr "" -#: src/Content/Conversation.php:1468 src/Object/Post.php:515 -#: src/Object/Post.php:516 +#: src/Content/Conversation.php:1494 src/Object/Post.php:521 +#: src/Object/Post.php:522 #, php-format msgid "View %s's profile @ %s" msgstr "" -#: src/Content/Conversation.php:1481 src/Object/Post.php:503 +#: src/Content/Conversation.php:1507 src/Object/Post.php:509 msgid "Categories:" msgstr "" -#: src/Content/Conversation.php:1482 src/Object/Post.php:504 +#: src/Content/Conversation.php:1508 src/Object/Post.php:510 msgid "Filed under:" msgstr "" -#: src/Content/Conversation.php:1490 src/Object/Post.php:529 +#: src/Content/Conversation.php:1516 src/Object/Post.php:535 #, php-format msgid "%s from %s" msgstr "" -#: src/Content/Conversation.php:1506 +#: src/Content/Conversation.php:1532 msgid "View in context" msgstr "" @@ -1607,8 +1625,8 @@ msgid "" msgstr "" #: src/Content/GroupManager.php:152 src/Content/Nav.php:276 -#: src/Content/Text/HTML.php:880 src/Content/Widget.php:541 -#: src/Model/User.php:1254 +#: src/Content/Text/HTML.php:880 src/Content/Widget.php:537 +#: src/Model/User.php:1255 msgid "Groups" msgstr "" @@ -1616,12 +1634,12 @@ msgstr "" msgid "External link to group" msgstr "" -#: src/Content/GroupManager.php:158 src/Content/Widget.php:516 +#: src/Content/GroupManager.php:158 src/Content/Widget.php:512 msgid "show less" msgstr "" -#: src/Content/GroupManager.php:159 src/Content/Widget.php:414 -#: src/Content/Widget.php:517 +#: src/Content/GroupManager.php:159 src/Content/Widget.php:410 +#: src/Content/Widget.php:513 msgid "show more" msgstr "" @@ -1629,88 +1647,93 @@ msgstr "" msgid "Create new group" msgstr "" -#: src/Content/Item.php:329 src/Model/Item.php:2993 +#: src/Content/Item.php:331 src/Model/Item.php:3002 msgid "event" msgstr "" -#: src/Content/Item.php:332 src/Content/Item.php:342 +#: src/Content/Item.php:334 src/Content/Item.php:344 msgid "status" msgstr "" -#: src/Content/Item.php:338 src/Model/Item.php:2995 +#: src/Content/Item.php:340 src/Model/Item.php:3004 #: src/Module/Post/Tag/Add.php:123 msgid "photo" msgstr "" -#: src/Content/Item.php:352 src/Module/Post/Tag/Add.php:141 +#: src/Content/Item.php:354 src/Module/Post/Tag/Add.php:141 #, php-format msgid "%1$s tagged %2$s's %3$s with %4$s" msgstr "" -#: src/Content/Item.php:421 view/theme/frio/theme.php:262 +#: src/Content/Item.php:428 view/theme/frio/theme.php:262 msgid "Follow Thread" msgstr "" -#: src/Content/Item.php:422 src/Model/Contact.php:1205 +#: src/Content/Item.php:429 src/Model/Contact.php:1211 msgid "View Status" msgstr "" -#: src/Content/Item.php:423 src/Content/Item.php:443 src/Model/Contact.php:1154 -#: src/Model/Contact.php:1197 src/Model/Contact.php:1206 -#: src/Module/Directory.php:157 src/Module/Settings/Profile/Index.php:233 +#: src/Content/Item.php:430 src/Content/Item.php:451 src/Model/Contact.php:1160 +#: src/Model/Contact.php:1203 src/Model/Contact.php:1212 +#: src/Module/Directory.php:157 src/Module/Settings/Profile/Index.php:259 msgid "View Profile" msgstr "" -#: src/Content/Item.php:424 src/Model/Contact.php:1207 +#: src/Content/Item.php:431 src/Model/Contact.php:1213 msgid "View Photos" msgstr "" -#: src/Content/Item.php:425 src/Model/Contact.php:1198 -#: src/Model/Contact.php:1208 +#: src/Content/Item.php:432 src/Model/Contact.php:1204 +#: src/Model/Contact.php:1214 msgid "Network Posts" msgstr "" -#: src/Content/Item.php:426 src/Model/Contact.php:1199 -#: src/Model/Contact.php:1209 +#: src/Content/Item.php:433 src/Model/Contact.php:1205 +#: src/Model/Contact.php:1215 msgid "View Contact" msgstr "" -#: src/Content/Item.php:427 src/Model/Contact.php:1210 +#: src/Content/Item.php:434 src/Model/Contact.php:1216 msgid "Send PM" msgstr "" -#: src/Content/Item.php:428 src/Module/Contact.php:468 -#: src/Module/Contact/Profile.php:477 +#: src/Content/Item.php:435 src/Module/Contact.php:468 +#: src/Module/Contact/Profile.php:498 #: src/Module/Moderation/Blocklist/Contact.php:116 #: src/Module/Moderation/Users/Active.php:137 #: src/Module/Moderation/Users/Index.php:152 msgid "Block" msgstr "" -#: src/Content/Item.php:429 src/Module/Contact.php:469 -#: src/Module/Contact/Profile.php:485 +#: src/Content/Item.php:436 src/Module/Contact.php:469 +#: src/Module/Contact/Profile.php:506 #: src/Module/Notifications/Introductions.php:134 #: src/Module/Notifications/Introductions.php:206 #: src/Module/Notifications/Notification.php:89 msgid "Ignore" msgstr "" -#: src/Content/Item.php:430 src/Module/Contact.php:470 -#: src/Module/Contact/Profile.php:493 +#: src/Content/Item.php:437 src/Module/Contact.php:470 +#: src/Module/Contact/Profile.php:514 msgid "Collapse" msgstr "" -#: src/Content/Item.php:434 src/Object/Post.php:484 +#: src/Content/Item.php:438 src/Object/Post.php:288 +#, php-format +msgid "Ignore %s server" +msgstr "" + +#: src/Content/Item.php:442 src/Object/Post.php:490 msgid "Languages" msgstr "" -#: src/Content/Item.php:440 src/Content/Widget.php:80 -#: src/Model/Contact.php:1200 src/Model/Contact.php:1211 +#: src/Content/Item.php:448 src/Content/Widget.php:80 +#: src/Model/Contact.php:1206 src/Model/Contact.php:1217 #: src/Module/Contact/Follow.php:167 view/theme/vier/theme.php:195 msgid "Connect/Follow" msgstr "" -#: src/Content/Item.php:874 +#: src/Content/Item.php:882 msgid "Unable to fetch user." msgstr "" @@ -1758,7 +1781,7 @@ msgstr "" #: src/Content/Nav.php:228 src/Module/BaseProfile.php:49 #: src/Module/BaseSettings.php:100 src/Module/Contact.php:504 -#: src/Module/Contact/Profile.php:392 src/Module/Profile/Profile.php:268 +#: src/Module/Contact/Profile.php:413 src/Module/Profile/Profile.php:268 #: src/Module/Welcome.php:57 view/theme/frio/theme.php:230 msgid "Profile" msgstr "" @@ -1961,7 +1984,7 @@ msgid "Manage other pages" msgstr "" #: src/Content/Nav.php:325 src/Module/Admin/Addons/Details.php:114 -#: src/Module/Admin/Themes/Details.php:93 src/Module/BaseSettings.php:170 +#: src/Module/Admin/Themes/Details.php:93 src/Module/BaseSettings.php:177 #: src/Module/Welcome.php:52 view/theme/frio/theme.php:242 msgid "Settings" msgstr "" @@ -2043,8 +2066,8 @@ msgid "" "%2$s %3$s" msgstr "" -#: src/Content/Text/BBCode.php:939 src/Model/Item.php:3735 -#: src/Model/Item.php:3741 src/Model/Item.php:3742 +#: src/Content/Text/BBCode.php:939 src/Model/Item.php:3744 +#: src/Model/Item.php:3750 src/Model/Item.php:3751 msgid "Link to source" msgstr "" @@ -2060,11 +2083,11 @@ msgstr "" msgid "Encrypted content" msgstr "" -#: src/Content/Text/BBCode.php:1901 +#: src/Content/Text/BBCode.php:1897 msgid "Invalid source protocol" msgstr "" -#: src/Content/Text/BBCode.php:1920 +#: src/Content/Text/BBCode.php:1916 msgid "Invalid link protocol" msgstr "" @@ -2077,7 +2100,7 @@ msgid "The end" msgstr "" #: src/Content/Text/HTML.php:859 src/Content/Widget/VCard.php:116 -#: src/Model/Profile.php:463 src/Module/Contact/Profile.php:437 +#: src/Model/Profile.php:461 src/Module/Contact/Profile.php:458 msgid "Follow" msgstr "" @@ -2147,80 +2170,80 @@ msgstr "" msgid "Local Directory" msgstr "" -#: src/Content/Widget.php:219 src/Model/Circle.php:600 +#: src/Content/Widget.php:215 src/Model/Circle.php:600 #: src/Module/Contact.php:401 src/Module/Welcome.php:76 msgid "Circles" msgstr "" -#: src/Content/Widget.php:221 +#: src/Content/Widget.php:217 msgid "Everyone" msgstr "" -#: src/Content/Widget.php:246 src/Module/Contact.php:424 +#: src/Content/Widget.php:242 src/Module/Contact.php:424 msgid "No relationship" msgstr "" -#: src/Content/Widget.php:251 +#: src/Content/Widget.php:247 msgid "Relationships" msgstr "" -#: src/Content/Widget.php:253 src/Module/Circle.php:292 +#: src/Content/Widget.php:249 src/Module/Circle.php:292 #: src/Module/Contact.php:345 msgid "All Contacts" msgstr "" -#: src/Content/Widget.php:292 +#: src/Content/Widget.php:288 msgid "Protocols" msgstr "" -#: src/Content/Widget.php:294 +#: src/Content/Widget.php:290 msgid "All Protocols" msgstr "" -#: src/Content/Widget.php:322 +#: src/Content/Widget.php:318 msgid "Saved Folders" msgstr "" -#: src/Content/Widget.php:324 src/Content/Widget.php:355 +#: src/Content/Widget.php:320 src/Content/Widget.php:351 msgid "Everything" msgstr "" -#: src/Content/Widget.php:353 +#: src/Content/Widget.php:349 msgid "Categories" msgstr "" -#: src/Content/Widget.php:410 +#: src/Content/Widget.php:406 #, php-format msgid "%d contact in common" msgid_plural "%d contacts in common" msgstr[0] "" msgstr[1] "" -#: src/Content/Widget.php:510 +#: src/Content/Widget.php:506 msgid "Archives" msgstr "" -#: src/Content/Widget.php:518 +#: src/Content/Widget.php:514 msgid "On this date" msgstr "" -#: src/Content/Widget.php:538 +#: src/Content/Widget.php:534 msgid "Persons" msgstr "" -#: src/Content/Widget.php:539 +#: src/Content/Widget.php:535 msgid "Organisations" msgstr "" -#: src/Content/Widget.php:540 src/Model/Contact.php:1675 +#: src/Content/Widget.php:536 src/Model/Contact.php:1681 msgid "News" msgstr "" -#: src/Content/Widget.php:546 src/Module/Settings/Account.php:454 +#: src/Content/Widget.php:542 src/Module/Settings/Account.php:454 msgid "Account Types" msgstr "" -#: src/Content/Widget.php:548 src/Module/Moderation/BaseUsers.php:69 +#: src/Content/Widget.php:544 src/Module/Moderation/BaseUsers.php:69 msgid "All" msgstr "" @@ -2270,32 +2293,32 @@ msgstr[1] "" msgid "More Trending Tags" msgstr "" -#: src/Content/Widget/VCard.php:109 src/Model/Profile.php:378 -#: src/Module/Contact/Profile.php:381 src/Module/Profile/Profile.php:199 +#: src/Content/Widget/VCard.php:109 src/Model/Profile.php:376 +#: src/Module/Contact/Profile.php:402 src/Module/Profile/Profile.php:199 msgid "XMPP:" msgstr "" -#: src/Content/Widget/VCard.php:110 src/Model/Profile.php:379 -#: src/Module/Contact/Profile.php:383 src/Module/Profile/Profile.php:203 +#: src/Content/Widget/VCard.php:110 src/Model/Profile.php:377 +#: src/Module/Contact/Profile.php:404 src/Module/Profile/Profile.php:203 msgid "Matrix:" msgstr "" #: src/Content/Widget/VCard.php:111 src/Model/Event.php:82 #: src/Model/Event.php:109 src/Model/Event.php:471 src/Model/Event.php:963 -#: src/Model/Profile.php:373 src/Module/Contact/Profile.php:379 +#: src/Model/Profile.php:371 src/Module/Contact/Profile.php:400 #: src/Module/Directory.php:147 src/Module/Notifications/Introductions.php:187 #: src/Module/Profile/Profile.php:221 msgid "Location:" msgstr "" -#: src/Content/Widget/VCard.php:114 src/Model/Profile.php:476 +#: src/Content/Widget/VCard.php:114 src/Model/Profile.php:474 #: src/Module/Notifications/Introductions.php:201 msgid "Network:" msgstr "" -#: src/Content/Widget/VCard.php:118 src/Model/Contact.php:1201 -#: src/Model/Contact.php:1212 src/Model/Profile.php:465 -#: src/Module/Contact/Profile.php:429 +#: src/Content/Widget/VCard.php:118 src/Model/Contact.php:1207 +#: src/Model/Contact.php:1218 src/Model/Profile.php:463 +#: src/Module/Contact/Profile.php:450 msgid "Unfollow" msgstr "" @@ -3047,17 +3070,17 @@ msgstr "" msgid "Edit circles" msgstr "" -#: src/Model/Contact.php:1218 src/Module/Moderation/Users/Pending.php:102 +#: src/Model/Contact.php:1224 src/Module/Moderation/Users/Pending.php:102 #: src/Module/Notifications/Introductions.php:132 #: src/Module/Notifications/Introductions.php:204 msgid "Approve" msgstr "" -#: src/Model/Contact.php:1671 +#: src/Model/Contact.php:1677 msgid "Organisation" msgstr "" -#: src/Model/Contact.php:1679 +#: src/Model/Contact.php:1685 msgid "Group" msgstr "" @@ -3065,7 +3088,7 @@ msgstr "" msgid "Disallowed profile URL." msgstr "" -#: src/Model/Contact.php:2993 src/Module/Friendica.php:102 +#: src/Model/Contact.php:2993 src/Module/Friendica.php:101 msgid "Blocked domain" msgstr "" @@ -3227,81 +3250,81 @@ msgstr "" msgid "Happy Birthday %s" msgstr "" -#: src/Model/Item.php:2056 +#: src/Model/Item.php:2061 #, php-format msgid "Detected languages in this post:\\n%s" msgstr "" -#: src/Model/Item.php:2997 +#: src/Model/Item.php:3006 msgid "activity" msgstr "" -#: src/Model/Item.php:2999 +#: src/Model/Item.php:3008 msgid "comment" msgstr "" -#: src/Model/Item.php:3002 src/Module/Post/Tag/Add.php:123 +#: src/Model/Item.php:3011 src/Module/Post/Tag/Add.php:123 msgid "post" msgstr "" -#: src/Model/Item.php:3172 +#: src/Model/Item.php:3181 #, php-format msgid "%s is blocked" msgstr "" -#: src/Model/Item.php:3174 +#: src/Model/Item.php:3183 #, php-format msgid "%s is ignored" msgstr "" -#: src/Model/Item.php:3176 +#: src/Model/Item.php:3185 #, php-format msgid "Content from %s is collapsed" msgstr "" -#: src/Model/Item.php:3180 +#: src/Model/Item.php:3189 #, php-format msgid "Content warning: %s" msgstr "" -#: src/Model/Item.php:3642 +#: src/Model/Item.php:3651 msgid "bytes" msgstr "" -#: src/Model/Item.php:3673 +#: src/Model/Item.php:3682 #, php-format msgid "%2$s (%3$d%%, %1$d vote)" msgid_plural "%2$s (%3$d%%, %1$d votes)" msgstr[0] "" msgstr[1] "" -#: src/Model/Item.php:3675 +#: src/Model/Item.php:3684 #, php-format msgid "%2$s (%1$d vote)" msgid_plural "%2$s (%1$d votes)" msgstr[0] "" msgstr[1] "" -#: src/Model/Item.php:3680 +#: src/Model/Item.php:3689 #, php-format msgid "%d voter. Poll end: %s" msgid_plural "%d voters. Poll end: %s" msgstr[0] "" msgstr[1] "" -#: src/Model/Item.php:3682 +#: src/Model/Item.php:3691 #, php-format msgid "%d voter." msgid_plural "%d voters." msgstr[0] "" msgstr[1] "" -#: src/Model/Item.php:3684 +#: src/Model/Item.php:3693 #, php-format msgid "Poll end: %s" msgstr "" -#: src/Model/Item.php:3718 src/Model/Item.php:3719 +#: src/Model/Item.php:3727 src/Model/Item.php:3728 msgid "View on separate page" msgstr "" @@ -3309,295 +3332,295 @@ msgstr "" msgid "[no subject]" msgstr "" -#: src/Model/Photo.php:1184 src/Module/Media/Photo/Upload.php:170 +#: src/Model/Photo.php:1190 src/Module/Media/Photo/Upload.php:170 msgid "Wall Photos" msgstr "" -#: src/Model/Profile.php:361 src/Module/Profile/Profile.php:283 +#: src/Model/Profile.php:359 src/Module/Profile/Profile.php:283 #: src/Module/Profile/Profile.php:285 msgid "Edit profile" msgstr "" -#: src/Model/Profile.php:363 +#: src/Model/Profile.php:361 msgid "Change profile photo" msgstr "" -#: src/Model/Profile.php:376 src/Module/Directory.php:152 +#: src/Model/Profile.php:374 src/Module/Directory.php:152 #: src/Module/Profile/Profile.php:209 msgid "Homepage:" msgstr "" -#: src/Model/Profile.php:377 src/Module/Contact/Profile.php:385 +#: src/Model/Profile.php:375 src/Module/Contact/Profile.php:406 #: src/Module/Notifications/Introductions.php:189 msgid "About:" msgstr "" -#: src/Model/Profile.php:467 +#: src/Model/Profile.php:465 msgid "Atom feed" msgstr "" -#: src/Model/Profile.php:474 +#: src/Model/Profile.php:472 msgid "This website has been verified to belong to the same person." msgstr "" -#: src/Model/Profile.php:511 +#: src/Model/Profile.php:509 msgid "F d" msgstr "" -#: src/Model/Profile.php:575 src/Model/Profile.php:664 +#: src/Model/Profile.php:573 src/Model/Profile.php:662 msgid "[today]" msgstr "" -#: src/Model/Profile.php:584 +#: src/Model/Profile.php:582 msgid "Birthday Reminders" msgstr "" -#: src/Model/Profile.php:585 +#: src/Model/Profile.php:583 msgid "Birthdays this week:" msgstr "" -#: src/Model/Profile.php:613 +#: src/Model/Profile.php:611 msgid "g A l F d" msgstr "" -#: src/Model/Profile.php:651 +#: src/Model/Profile.php:649 msgid "[No description]" msgstr "" -#: src/Model/Profile.php:677 +#: src/Model/Profile.php:675 msgid "Event Reminders" msgstr "" -#: src/Model/Profile.php:678 +#: src/Model/Profile.php:676 msgid "Upcoming events the next 7 days:" msgstr "" -#: src/Model/Profile.php:875 +#: src/Model/Profile.php:873 #, php-format msgid "OpenWebAuth: %1$s welcomes %2$s" msgstr "" -#: src/Model/Profile.php:1015 +#: src/Model/Profile.php:1013 msgid "Hometown:" msgstr "" -#: src/Model/Profile.php:1016 +#: src/Model/Profile.php:1014 msgid "Marital Status:" msgstr "" -#: src/Model/Profile.php:1017 +#: src/Model/Profile.php:1015 msgid "With:" msgstr "" -#: src/Model/Profile.php:1018 +#: src/Model/Profile.php:1016 msgid "Since:" msgstr "" -#: src/Model/Profile.php:1019 +#: src/Model/Profile.php:1017 msgid "Sexual Preference:" msgstr "" -#: src/Model/Profile.php:1020 +#: src/Model/Profile.php:1018 msgid "Political Views:" msgstr "" -#: src/Model/Profile.php:1021 +#: src/Model/Profile.php:1019 msgid "Religious Views:" msgstr "" -#: src/Model/Profile.php:1022 +#: src/Model/Profile.php:1020 msgid "Likes:" msgstr "" -#: src/Model/Profile.php:1023 +#: src/Model/Profile.php:1021 msgid "Dislikes:" msgstr "" -#: src/Model/Profile.php:1024 +#: src/Model/Profile.php:1022 msgid "Title/Description:" msgstr "" -#: src/Model/Profile.php:1025 src/Module/Admin/Summary.php:197 +#: src/Model/Profile.php:1023 src/Module/Admin/Summary.php:197 #: src/Module/Moderation/Report/Create.php:280 #: src/Module/Moderation/Summary.php:77 msgid "Summary" msgstr "" -#: src/Model/Profile.php:1026 +#: src/Model/Profile.php:1024 msgid "Musical interests" msgstr "" -#: src/Model/Profile.php:1027 +#: src/Model/Profile.php:1025 msgid "Books, literature" msgstr "" -#: src/Model/Profile.php:1028 +#: src/Model/Profile.php:1026 msgid "Television" msgstr "" -#: src/Model/Profile.php:1029 +#: src/Model/Profile.php:1027 msgid "Film/dance/culture/entertainment" msgstr "" -#: src/Model/Profile.php:1030 +#: src/Model/Profile.php:1028 msgid "Hobbies/Interests" msgstr "" -#: src/Model/Profile.php:1031 +#: src/Model/Profile.php:1029 msgid "Love/romance" msgstr "" -#: src/Model/Profile.php:1032 +#: src/Model/Profile.php:1030 msgid "Work/employment" msgstr "" -#: src/Model/Profile.php:1033 +#: src/Model/Profile.php:1031 msgid "School/education" msgstr "" -#: src/Model/Profile.php:1034 +#: src/Model/Profile.php:1032 msgid "Contact information and Social Networks" msgstr "" -#: src/Model/User.php:225 src/Model/User.php:1167 +#: src/Model/User.php:226 src/Model/User.php:1168 msgid "SERIOUS ERROR: Generation of security keys failed." msgstr "" -#: src/Model/User.php:601 src/Model/User.php:634 +#: src/Model/User.php:602 src/Model/User.php:635 msgid "Login failed" msgstr "" -#: src/Model/User.php:666 +#: src/Model/User.php:667 msgid "Not enough information to authenticate" msgstr "" -#: src/Model/User.php:787 +#: src/Model/User.php:788 msgid "Password can't be empty" msgstr "" -#: src/Model/User.php:829 +#: src/Model/User.php:830 msgid "Empty passwords are not allowed." msgstr "" -#: src/Model/User.php:833 +#: src/Model/User.php:834 msgid "" "The new password has been exposed in a public data dump, please choose " "another." msgstr "" -#: src/Model/User.php:837 +#: src/Model/User.php:838 msgid "The password length is limited to 72 characters." msgstr "" -#: src/Model/User.php:841 +#: src/Model/User.php:842 msgid "The password can't contain white spaces nor accentuated letters" msgstr "" -#: src/Model/User.php:1050 +#: src/Model/User.php:1051 msgid "Passwords do not match. Password unchanged." msgstr "" -#: src/Model/User.php:1057 +#: src/Model/User.php:1058 msgid "An invitation is required." msgstr "" -#: src/Model/User.php:1061 +#: src/Model/User.php:1062 msgid "Invitation could not be verified." msgstr "" -#: src/Model/User.php:1069 +#: src/Model/User.php:1070 msgid "Invalid OpenID url" msgstr "" -#: src/Model/User.php:1082 src/Security/Authentication.php:241 +#: src/Model/User.php:1083 src/Security/Authentication.php:241 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:1082 src/Security/Authentication.php:241 +#: src/Model/User.php:1083 src/Security/Authentication.php:241 msgid "The error message was:" msgstr "" -#: src/Model/User.php:1088 +#: src/Model/User.php:1089 msgid "Please enter the required information." msgstr "" -#: src/Model/User.php:1102 +#: src/Model/User.php:1103 #, 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:1109 +#: src/Model/User.php:1110 #, 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:1113 +#: src/Model/User.php:1114 #, 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:1121 +#: src/Model/User.php:1122 msgid "That doesn't appear to be your full (First Last) name." msgstr "" -#: src/Model/User.php:1126 +#: src/Model/User.php:1127 msgid "Your email domain is not among those allowed on this site." msgstr "" -#: src/Model/User.php:1130 +#: src/Model/User.php:1131 msgid "Not a valid email address." msgstr "" -#: src/Model/User.php:1133 +#: src/Model/User.php:1134 msgid "The nickname was blocked from registration by the nodes admin." msgstr "" -#: src/Model/User.php:1137 src/Model/User.php:1143 +#: src/Model/User.php:1138 src/Model/User.php:1144 msgid "Cannot use that email." msgstr "" -#: src/Model/User.php:1149 +#: src/Model/User.php:1150 msgid "Your nickname can only contain a-z, 0-9 and _." msgstr "" -#: src/Model/User.php:1157 src/Model/User.php:1214 +#: src/Model/User.php:1158 src/Model/User.php:1215 msgid "Nickname is already registered. Please choose another." msgstr "" -#: src/Model/User.php:1201 src/Model/User.php:1205 +#: src/Model/User.php:1202 src/Model/User.php:1206 msgid "An error occurred during registration. Please try again." msgstr "" -#: src/Model/User.php:1228 +#: src/Model/User.php:1229 msgid "An error occurred creating your default profile. Please try again." msgstr "" -#: src/Model/User.php:1235 +#: src/Model/User.php:1236 msgid "An error occurred creating your self contact. Please try again." msgstr "" -#: src/Model/User.php:1240 +#: src/Model/User.php:1241 msgid "Friends" msgstr "" -#: src/Model/User.php:1244 +#: src/Model/User.php:1245 msgid "" "An error occurred creating your default contact circle. Please try again." msgstr "" -#: src/Model/User.php:1288 +#: src/Model/User.php:1289 msgid "Profile Photos" msgstr "" -#: src/Model/User.php:1483 +#: src/Model/User.php:1469 #, php-format msgid "" "\n" @@ -3605,7 +3628,7 @@ msgid "" "\t\t\tthe administrator of %2$s has set up an account for you." msgstr "" -#: src/Model/User.php:1486 +#: src/Model/User.php:1472 #, php-format msgid "" "\n" @@ -3643,12 +3666,12 @@ msgid "" "\t\tThank you and welcome to %4$s." msgstr "" -#: src/Model/User.php:1519 src/Model/User.php:1626 +#: src/Model/User.php:1505 src/Model/User.php:1612 #, php-format msgid "Registration details for %s" msgstr "" -#: src/Model/User.php:1539 +#: src/Model/User.php:1525 #, php-format msgid "" "\n" @@ -3664,12 +3687,12 @@ msgid "" "\t\t" msgstr "" -#: src/Model/User.php:1558 +#: src/Model/User.php:1544 #, php-format msgid "Registration at %s" msgstr "" -#: src/Model/User.php:1582 +#: src/Model/User.php:1568 #, php-format msgid "" "\n" @@ -3678,7 +3701,7 @@ msgid "" "\t\t\t" msgstr "" -#: src/Model/User.php:1590 +#: src/Model/User.php:1576 #, php-format msgid "" "\n" @@ -5039,7 +5062,7 @@ msgid "" "received." msgstr "" -#: src/Module/Admin/Site.php:513 src/Module/Contact/Profile.php:286 +#: src/Module/Admin/Site.php:513 src/Module/Contact/Profile.php:305 #: src/Module/Settings/TwoFactor/Index.php:125 msgid "Disabled" msgstr "" @@ -5628,11 +5651,15 @@ msgstr "" msgid "Connected apps" msgstr "" -#: src/Module/BaseSettings.php:155 src/Module/Settings/UserExport.php:98 +#: src/Module/BaseSettings.php:155 +msgid "Remote servers" +msgstr "" + +#: src/Module/BaseSettings.php:162 src/Module/Settings/UserExport.php:98 msgid "Export personal data" msgstr "" -#: src/Module/BaseSettings.php:162 +#: src/Module/BaseSettings.php:169 msgid "Remove account" msgstr "" @@ -5778,8 +5805,8 @@ msgstr "" #: src/Module/Contact/Conversations.php:89 #: src/Module/Contact/Conversations.php:94 src/Module/Contact/Media.php:43 #: src/Module/Contact/Posts.php:78 src/Module/Contact/Posts.php:83 -#: src/Module/Contact/Posts.php:88 src/Module/Contact/Profile.php:142 -#: src/Module/Contact/Profile.php:147 src/Module/Contact/Profile.php:152 +#: src/Module/Contact/Posts.php:88 src/Module/Contact/Profile.php:150 +#: src/Module/Contact/Profile.php:155 src/Module/Contact/Profile.php:160 #: src/Module/Contact/Redir.php:94 src/Module/Contact/Redir.php:140 #: src/Module/FriendSuggest.php:71 src/Module/FriendSuggest.php:109 msgid "Contact not found." @@ -5888,7 +5915,7 @@ msgid "Only show blocked contacts" msgstr "" #: src/Module/Contact.php:369 src/Module/Contact.php:441 -#: src/Object/Post.php:362 +#: src/Module/Settings/Server/Index.php:107 src/Object/Post.php:368 msgid "Ignored" msgstr "" @@ -5937,18 +5964,18 @@ msgstr "" msgid "Update" msgstr "" -#: src/Module/Contact.php:468 src/Module/Contact/Profile.php:477 +#: src/Module/Contact.php:468 src/Module/Contact/Profile.php:498 #: src/Module/Moderation/Blocklist/Contact.php:117 #: src/Module/Moderation/Users/Blocked.php:138 #: src/Module/Moderation/Users/Index.php:154 msgid "Unblock" msgstr "" -#: src/Module/Contact.php:469 src/Module/Contact/Profile.php:485 +#: src/Module/Contact.php:469 src/Module/Contact/Profile.php:506 msgid "Unignore" msgstr "" -#: src/Module/Contact.php:470 src/Module/Contact/Profile.php:493 +#: src/Module/Contact.php:470 src/Module/Contact/Profile.php:514 msgid "Uncollapse" msgstr "" @@ -6000,7 +6027,7 @@ msgstr "" msgid "Pending incoming contact request" msgstr "" -#: src/Module/Contact.php:627 src/Module/Contact/Profile.php:346 +#: src/Module/Contact.php:627 src/Module/Contact/Profile.php:365 #, php-format msgid "Visit %s's profile [%s]" msgstr "" @@ -6135,7 +6162,7 @@ msgstr "" msgid "Your Identity Address:" msgstr "" -#: src/Module/Contact/Follow.php:170 src/Module/Contact/Profile.php:375 +#: src/Module/Contact/Follow.php:170 src/Module/Contact/Profile.php:396 #: src/Module/Contact/Unfollow.php:129 #: src/Module/Moderation/Blocklist/Contact.php:133 #: src/Module/Notifications/Introductions.php:129 @@ -6143,7 +6170,7 @@ msgstr "" msgid "Profile URL" msgstr "" -#: src/Module/Contact/Follow.php:171 src/Module/Contact/Profile.php:387 +#: src/Module/Contact/Follow.php:171 src/Module/Contact/Profile.php:408 #: src/Module/Notifications/Introductions.php:191 #: src/Module/Profile/Profile.php:234 msgid "Tags:" @@ -6182,249 +6209,257 @@ msgstr "" msgid "Profile Match" msgstr "" -#: src/Module/Contact/Profile.php:128 +#: src/Module/Contact/Profile.php:136 msgid "Failed to update contact record." msgstr "" -#: src/Module/Contact/Profile.php:178 +#: src/Module/Contact/Profile.php:186 msgid "Contact has been unblocked" msgstr "" -#: src/Module/Contact/Profile.php:182 +#: src/Module/Contact/Profile.php:190 msgid "Contact has been blocked" msgstr "" -#: src/Module/Contact/Profile.php:194 +#: src/Module/Contact/Profile.php:202 msgid "Contact has been unignored" msgstr "" -#: src/Module/Contact/Profile.php:198 +#: src/Module/Contact/Profile.php:206 msgid "Contact has been ignored" msgstr "" -#: src/Module/Contact/Profile.php:210 +#: src/Module/Contact/Profile.php:218 msgid "Contact has been uncollapsed" msgstr "" -#: src/Module/Contact/Profile.php:214 +#: src/Module/Contact/Profile.php:222 msgid "Contact has been collapsed" msgstr "" -#: src/Module/Contact/Profile.php:242 +#: src/Module/Contact/Profile.php:250 #, php-format msgid "You are mutual friends with %s" msgstr "" -#: src/Module/Contact/Profile.php:243 +#: src/Module/Contact/Profile.php:251 #, php-format msgid "You are sharing with %s" msgstr "" -#: src/Module/Contact/Profile.php:244 +#: src/Module/Contact/Profile.php:252 #, php-format msgid "%s is sharing with you" msgstr "" -#: src/Module/Contact/Profile.php:260 +#: src/Module/Contact/Profile.php:268 msgid "Private communications are not available for this contact." msgstr "" -#: src/Module/Contact/Profile.php:262 +#: src/Module/Contact/Profile.php:278 +msgid "This contact is on a server you ignored." +msgstr "" + +#: src/Module/Contact/Profile.php:281 msgid "Never" msgstr "" -#: src/Module/Contact/Profile.php:265 +#: src/Module/Contact/Profile.php:284 msgid "(Update was not successful)" msgstr "" -#: src/Module/Contact/Profile.php:265 +#: src/Module/Contact/Profile.php:284 msgid "(Update was successful)" msgstr "" -#: src/Module/Contact/Profile.php:267 src/Module/Contact/Profile.php:448 +#: src/Module/Contact/Profile.php:286 src/Module/Contact/Profile.php:469 msgid "Suggest friends" msgstr "" -#: src/Module/Contact/Profile.php:271 +#: src/Module/Contact/Profile.php:290 #, php-format msgid "Network type: %s" msgstr "" -#: src/Module/Contact/Profile.php:276 +#: src/Module/Contact/Profile.php:295 msgid "Communications lost with this contact!" msgstr "" -#: src/Module/Contact/Profile.php:282 +#: src/Module/Contact/Profile.php:301 msgid "Fetch further information for feeds" msgstr "" -#: src/Module/Contact/Profile.php:284 +#: src/Module/Contact/Profile.php:303 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:287 +#: src/Module/Contact/Profile.php:306 msgid "Fetch information" msgstr "" -#: src/Module/Contact/Profile.php:288 +#: src/Module/Contact/Profile.php:307 msgid "Fetch keywords" msgstr "" -#: src/Module/Contact/Profile.php:289 +#: src/Module/Contact/Profile.php:308 msgid "Fetch information and keywords" msgstr "" -#: src/Module/Contact/Profile.php:299 src/Module/Contact/Profile.php:304 -#: src/Module/Contact/Profile.php:309 src/Module/Contact/Profile.php:315 +#: src/Module/Contact/Profile.php:318 src/Module/Contact/Profile.php:323 +#: src/Module/Contact/Profile.php:328 src/Module/Contact/Profile.php:334 msgid "No mirroring" msgstr "" -#: src/Module/Contact/Profile.php:300 src/Module/Contact/Profile.php:310 -#: src/Module/Contact/Profile.php:316 +#: src/Module/Contact/Profile.php:319 src/Module/Contact/Profile.php:329 +#: src/Module/Contact/Profile.php:335 msgid "Mirror as my own posting" msgstr "" -#: src/Module/Contact/Profile.php:305 src/Module/Contact/Profile.php:311 +#: src/Module/Contact/Profile.php:324 src/Module/Contact/Profile.php:330 msgid "Native reshare" msgstr "" -#: src/Module/Contact/Profile.php:328 +#: src/Module/Contact/Profile.php:347 msgid "Contact Information / Notes" msgstr "" -#: src/Module/Contact/Profile.php:329 +#: src/Module/Contact/Profile.php:348 msgid "Contact Settings" msgstr "" -#: src/Module/Contact/Profile.php:337 +#: src/Module/Contact/Profile.php:356 msgid "Contact" msgstr "" -#: src/Module/Contact/Profile.php:341 +#: src/Module/Contact/Profile.php:360 msgid "Their personal note" msgstr "" -#: src/Module/Contact/Profile.php:343 +#: src/Module/Contact/Profile.php:362 msgid "Edit contact notes" msgstr "" -#: src/Module/Contact/Profile.php:347 +#: src/Module/Contact/Profile.php:366 msgid "Block/Unblock contact" msgstr "" -#: src/Module/Contact/Profile.php:348 +#: src/Module/Contact/Profile.php:367 #: src/Module/Moderation/Report/Create.php:293 msgid "Ignore contact" msgstr "" -#: src/Module/Contact/Profile.php:349 +#: src/Module/Contact/Profile.php:368 msgid "View conversations" msgstr "" -#: src/Module/Contact/Profile.php:354 +#: src/Module/Contact/Profile.php:373 msgid "Last update:" msgstr "" -#: src/Module/Contact/Profile.php:356 +#: src/Module/Contact/Profile.php:375 msgid "Update public posts" msgstr "" -#: src/Module/Contact/Profile.php:358 src/Module/Contact/Profile.php:458 +#: src/Module/Contact/Profile.php:377 src/Module/Contact/Profile.php:479 msgid "Update now" msgstr "" -#: src/Module/Contact/Profile.php:360 +#: src/Module/Contact/Profile.php:379 msgid "Awaiting connection acknowledge" msgstr "" -#: src/Module/Contact/Profile.php:361 +#: src/Module/Contact/Profile.php:380 msgid "Currently blocked" msgstr "" -#: src/Module/Contact/Profile.php:362 +#: src/Module/Contact/Profile.php:381 msgid "Currently ignored" msgstr "" -#: src/Module/Contact/Profile.php:363 +#: src/Module/Contact/Profile.php:382 msgid "Currently collapsed" msgstr "" -#: src/Module/Contact/Profile.php:364 +#: src/Module/Contact/Profile.php:383 msgid "Currently archived" msgstr "" -#: src/Module/Contact/Profile.php:367 +#: src/Module/Contact/Profile.php:386 +msgid "Manage remote servers" +msgstr "" + +#: src/Module/Contact/Profile.php:388 #: src/Module/Notifications/Introductions.php:192 msgid "Hide this contact from others" msgstr "" -#: src/Module/Contact/Profile.php:367 +#: src/Module/Contact/Profile.php:388 msgid "" "Replies/likes to your public posts may still be visible" msgstr "" -#: src/Module/Contact/Profile.php:368 +#: src/Module/Contact/Profile.php:389 msgid "Notification for new posts" msgstr "" -#: src/Module/Contact/Profile.php:368 +#: src/Module/Contact/Profile.php:389 msgid "Send a notification of every new post of this contact" msgstr "" -#: src/Module/Contact/Profile.php:370 +#: src/Module/Contact/Profile.php:391 msgid "Keyword Deny List" msgstr "" -#: src/Module/Contact/Profile.php:370 +#: src/Module/Contact/Profile.php:391 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:388 +#: src/Module/Contact/Profile.php:409 #: src/Module/Settings/TwoFactor/Index.php:139 msgid "Actions" msgstr "" -#: src/Module/Contact/Profile.php:390 +#: src/Module/Contact/Profile.php:411 #: src/Module/Settings/TwoFactor/Index.php:119 view/theme/frio/theme.php:229 msgid "Status" msgstr "" -#: src/Module/Contact/Profile.php:396 +#: src/Module/Contact/Profile.php:417 msgid "Mirror postings from this contact" msgstr "" -#: src/Module/Contact/Profile.php:398 +#: src/Module/Contact/Profile.php:419 msgid "" "Mark this contact as remote_self, this will cause friendica to repost new " "entries from this contact." msgstr "" -#: src/Module/Contact/Profile.php:468 +#: src/Module/Contact/Profile.php:489 msgid "Refetch contact data" msgstr "" -#: src/Module/Contact/Profile.php:479 +#: src/Module/Contact/Profile.php:500 msgid "Toggle Blocked status" msgstr "" -#: src/Module/Contact/Profile.php:487 +#: src/Module/Contact/Profile.php:508 msgid "Toggle Ignored status" msgstr "" -#: src/Module/Contact/Profile.php:495 +#: src/Module/Contact/Profile.php:516 msgid "Toggle Collapsed status" msgstr "" -#: src/Module/Contact/Profile.php:502 src/Module/Contact/Revoke.php:106 +#: src/Module/Contact/Profile.php:523 src/Module/Contact/Revoke.php:106 msgid "Revoke Follow" msgstr "" -#: src/Module/Contact/Profile.php:504 +#: src/Module/Contact/Profile.php:525 msgid "Revoke the follow from this contact" msgstr "" @@ -6564,7 +6599,7 @@ msgid "Sort by post creation date" msgstr "" #: src/Module/Conversation/Network.php:281 -#: src/Module/Settings/Profile/Index.php:235 +#: src/Module/Settings/Profile/Index.php:260 msgid "Personal" msgstr "" @@ -6572,7 +6607,7 @@ msgstr "" msgid "Posts that mention or involve you" msgstr "" -#: src/Module/Conversation/Network.php:289 src/Object/Post.php:374 +#: src/Module/Conversation/Network.php:289 src/Object/Post.php:380 msgid "Starred" msgstr "" @@ -6796,7 +6831,7 @@ msgid "Twitter Source / Tweet URL (requires API key)" msgstr "" #: src/Module/Debug/Feed.php:52 src/Module/Filer/SaveTag.php:47 -#: src/Module/Settings/Profile/Index.php:144 +#: src/Module/Settings/Profile/Index.php:177 msgid "You must be logged in to use this module" msgstr "" @@ -6938,42 +6973,42 @@ msgstr "" msgid "Read about the Terms of Service of this node." msgstr "" -#: src/Module/Friendica.php:100 +#: src/Module/Friendica.php:99 msgid "On this server the following remote servers are blocked." msgstr "" -#: src/Module/Friendica.php:103 +#: src/Module/Friendica.php:102 #: src/Module/Moderation/Blocklist/Server/Index.php:87 #: src/Module/Moderation/Blocklist/Server/Index.php:111 msgid "Reason for the block" msgstr "" -#: src/Module/Friendica.php:105 +#: src/Module/Friendica.php:104 msgid "Download this list in CSV format" msgstr "" -#: src/Module/Friendica.php:119 +#: src/Module/Friendica.php:118 #, php-format msgid "" "This is Friendica, version %s that is running at the web location %s. The " "database version is %s, the post update version is %s." msgstr "" -#: src/Module/Friendica.php:124 +#: src/Module/Friendica.php:123 msgid "" "Please visit Friendi.ca to learn more " "about the Friendica project." msgstr "" -#: src/Module/Friendica.php:125 +#: src/Module/Friendica.php:124 msgid "Bug reports and issues: please visit" msgstr "" -#: src/Module/Friendica.php:125 +#: src/Module/Friendica.php:124 msgid "the bugtracker at github" msgstr "" -#: src/Module/Friendica.php:126 +#: src/Module/Friendica.php:125 msgid "" "Suggestions, praise, etc. - please email \"info\" at \"friendi - dot - ca" msgstr "" @@ -7288,10 +7323,6 @@ msgid "" "Theme Customization settings." msgstr "" -#: src/Module/Item/Display.php:136 src/Module/Update/Display.php:55 -msgid "The requested item doesn't exist or has been deleted." -msgstr "" - #: src/Module/Item/Feed.php:86 msgid "The feed for this item is unavailable." msgstr "" @@ -7550,6 +7581,8 @@ msgid "Matching known servers" msgstr "" #: src/Module/Moderation/Blocklist/Server/Add.php:130 +#: src/Module/Settings/Server/Action.php:76 +#: src/Module/Settings/Server/Index.php:106 msgid "Server Name" msgstr "" @@ -8520,21 +8553,21 @@ msgstr "" msgid "Attributed To: %s
" msgstr "" -#: src/Module/Photo.php:129 +#: src/Module/Photo.php:130 msgid "The Photo is not available." msgstr "" -#: src/Module/Photo.php:154 +#: src/Module/Photo.php:155 #, php-format msgid "The Photo with id %s is not available." msgstr "" -#: src/Module/Photo.php:191 +#: src/Module/Photo.php:192 #, php-format msgid "Invalid external resource with url %s." msgstr "" -#: src/Module/Photo.php:193 +#: src/Module/Photo.php:194 #, php-format msgid "Invalid photo with id %s." msgstr "" @@ -8586,20 +8619,20 @@ msgstr "" #: src/Module/Profile/Conversations.php:106 #: src/Module/Profile/Conversations.php:109 src/Module/Profile/Profile.php:351 -#: src/Module/Profile/Profile.php:354 src/Protocol/Feed.php:1090 +#: src/Module/Profile/Profile.php:354 src/Protocol/Feed.php:1098 #: src/Protocol/OStatus.php:1009 #, php-format msgid "%s's timeline" msgstr "" #: src/Module/Profile/Conversations.php:107 src/Module/Profile/Profile.php:352 -#: src/Protocol/Feed.php:1094 src/Protocol/OStatus.php:1014 +#: src/Protocol/Feed.php:1102 src/Protocol/OStatus.php:1014 #, php-format msgid "%s's posts" msgstr "" #: src/Module/Profile/Conversations.php:108 src/Module/Profile/Profile.php:353 -#: src/Protocol/Feed.php:1097 src/Protocol/OStatus.php:1018 +#: src/Protocol/Feed.php:1105 src/Protocol/OStatus.php:1018 #, php-format msgid "%s's comments" msgstr "" @@ -8644,7 +8677,7 @@ msgid "" "\"btn btn-sm pull-right\">Cancel" msgstr "" -#: src/Module/Profile/Profile.php:167 src/Module/Settings/Account.php:576 +#: src/Module/Profile/Profile.php:167 msgid "Full Name:" msgstr "" @@ -8664,12 +8697,12 @@ msgstr "" msgid "Birthday:" msgstr "" -#: src/Module/Profile/Profile.php:190 src/Module/Settings/Profile/Index.php:253 +#: src/Module/Profile/Profile.php:190 src/Module/Settings/Profile/Index.php:291 #: src/Util/Temporal.php:170 msgid "Age: " msgstr "" -#: src/Module/Profile/Profile.php:190 src/Module/Settings/Profile/Index.php:253 +#: src/Module/Profile/Profile.php:190 src/Module/Settings/Profile/Index.php:291 #: src/Util/Temporal.php:170 #, php-format msgid "%d year old" @@ -8677,7 +8710,7 @@ msgid_plural "%d years old" msgstr[0] "" msgstr[1] "" -#: src/Module/Profile/Profile.php:195 src/Module/Settings/Profile/Index.php:246 +#: src/Module/Profile/Profile.php:195 src/Module/Settings/Profile/Index.php:284 msgid "Description:" msgstr "" @@ -9362,6 +9395,11 @@ msgstr "" msgid "Basic Settings" msgstr "" +#: src/Module/Settings/Account.php:576 +#: src/Module/Settings/Profile/Index.php:283 +msgid "Display name:" +msgstr "" + #: src/Module/Settings/Account.php:577 msgid "Email Address:" msgstr "" @@ -10126,146 +10164,85 @@ msgstr "" msgid "Remove authorization" msgstr "" -#: src/Module/Settings/Profile/Index.php:84 -msgid "Profile Name is required." +#: src/Module/Settings/Profile/Index.php:116 +msgid "Display Name is required." msgstr "" -#: src/Module/Settings/Profile/Index.php:134 +#: src/Module/Settings/Profile/Index.php:167 msgid "Profile couldn't be updated." msgstr "" -#: src/Module/Settings/Profile/Index.php:175 -#: src/Module/Settings/Profile/Index.php:195 +#: src/Module/Settings/Profile/Index.php:205 +#: src/Module/Settings/Profile/Index.php:226 msgid "Label:" msgstr "" -#: src/Module/Settings/Profile/Index.php:176 -#: src/Module/Settings/Profile/Index.php:196 +#: src/Module/Settings/Profile/Index.php:206 +#: src/Module/Settings/Profile/Index.php:227 msgid "Value:" msgstr "" -#: src/Module/Settings/Profile/Index.php:186 -#: src/Module/Settings/Profile/Index.php:206 +#: src/Module/Settings/Profile/Index.php:217 +#: src/Module/Settings/Profile/Index.php:238 msgid "Field Permissions" msgstr "" -#: src/Module/Settings/Profile/Index.php:187 -#: src/Module/Settings/Profile/Index.php:207 +#: src/Module/Settings/Profile/Index.php:218 +#: src/Module/Settings/Profile/Index.php:239 msgid "(click to open/close)" msgstr "" -#: src/Module/Settings/Profile/Index.php:193 +#: src/Module/Settings/Profile/Index.php:224 msgid "Add a new profile field" msgstr "" -#: src/Module/Settings/Profile/Index.php:216 +#: src/Module/Settings/Profile/Index.php:247 msgid "" "The homepage is verified. A rel=\"me\" link back to your Friendica profile " "page was found on the homepage." msgstr "" -#: src/Module/Settings/Profile/Index.php:218 +#: src/Module/Settings/Profile/Index.php:249 #, php-format msgid "" "To verify your homepage, add a rel=\"me\" link to it, pointing to your " "profile URL (%s)." msgstr "" -#: src/Module/Settings/Profile/Index.php:228 +#: src/Module/Settings/Profile/Index.php:255 msgid "Profile Actions" msgstr "" -#: src/Module/Settings/Profile/Index.php:229 +#: src/Module/Settings/Profile/Index.php:256 msgid "Edit Profile Details" msgstr "" -#: src/Module/Settings/Profile/Index.php:231 +#: src/Module/Settings/Profile/Index.php:258 msgid "Change Profile Photo" msgstr "" -#: src/Module/Settings/Profile/Index.php:236 +#: src/Module/Settings/Profile/Index.php:261 msgid "Profile picture" msgstr "" -#: src/Module/Settings/Profile/Index.php:237 +#: src/Module/Settings/Profile/Index.php:262 msgid "Location" msgstr "" -#: src/Module/Settings/Profile/Index.php:238 src/Util/Temporal.php:97 +#: src/Module/Settings/Profile/Index.php:263 src/Util/Temporal.php:97 #: src/Util/Temporal.php:99 msgid "Miscellaneous" msgstr "" -#: src/Module/Settings/Profile/Index.php:239 +#: src/Module/Settings/Profile/Index.php:264 msgid "Custom Profile Fields" msgstr "" -#: src/Module/Settings/Profile/Index.php:241 src/Module/Welcome.php:58 +#: src/Module/Settings/Profile/Index.php:265 src/Module/Welcome.php:58 msgid "Upload Profile Photo" msgstr "" -#: src/Module/Settings/Profile/Index.php:245 -msgid "Display name:" -msgstr "" - -#: src/Module/Settings/Profile/Index.php:248 -msgid "Street Address:" -msgstr "" - -#: src/Module/Settings/Profile/Index.php:249 -msgid "Locality/City:" -msgstr "" - -#: src/Module/Settings/Profile/Index.php:250 -msgid "Region/State:" -msgstr "" - -#: src/Module/Settings/Profile/Index.php:251 -msgid "Postal/Zip Code:" -msgstr "" - -#: src/Module/Settings/Profile/Index.php:252 -msgid "Country:" -msgstr "" - -#: src/Module/Settings/Profile/Index.php:254 -msgid "XMPP (Jabber) address:" -msgstr "" - -#: src/Module/Settings/Profile/Index.php:254 -msgid "The XMPP address will be published so that people can follow you there." -msgstr "" - -#: src/Module/Settings/Profile/Index.php:255 -msgid "Matrix (Element) address:" -msgstr "" - -#: src/Module/Settings/Profile/Index.php:255 -msgid "" -"The Matrix address will be published so that people can follow you there." -msgstr "" - -#: src/Module/Settings/Profile/Index.php:256 -msgid "Homepage URL:" -msgstr "" - -#: src/Module/Settings/Profile/Index.php:257 -msgid "Public Keywords:" -msgstr "" - -#: src/Module/Settings/Profile/Index.php:257 -msgid "(Used for suggesting potential friends, can be seen by others)" -msgstr "" - -#: src/Module/Settings/Profile/Index.php:258 -msgid "Private Keywords:" -msgstr "" - -#: src/Module/Settings/Profile/Index.php:258 -msgid "(Used for searching profiles, never shown to others)" -msgstr "" - -#: src/Module/Settings/Profile/Index.php:259 +#: src/Module/Settings/Profile/Index.php:266 #, php-format msgid "" "

Custom fields appear on your profile page.

\n" @@ -10276,6 +10253,63 @@ msgid "" "contacts or the Friendica contacts in the selected circles.

" msgstr "" +#: src/Module/Settings/Profile/Index.php:286 +msgid "Street Address:" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:287 +msgid "Locality/City:" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:288 +msgid "Region/State:" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:289 +msgid "Postal/Zip Code:" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:290 +msgid "Country:" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:292 +msgid "XMPP (Jabber) address:" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:292 +msgid "The XMPP address will be published so that people can follow you there." +msgstr "" + +#: src/Module/Settings/Profile/Index.php:293 +msgid "Matrix (Element) address:" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:293 +msgid "" +"The Matrix address will be published so that people can follow you there." +msgstr "" + +#: src/Module/Settings/Profile/Index.php:294 +msgid "Homepage URL:" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:295 +msgid "Public Keywords:" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:295 +msgid "(Used for suggesting potential friends, can be seen by others)" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:296 +msgid "Private Keywords:" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:296 +msgid "(Used for searching profiles, never shown to others)" +msgstr "" + #: src/Module/Settings/Profile/Photo/Crop.php:107 #: src/Module/Settings/Profile/Photo/Crop.php:125 #: src/Module/Settings/Profile/Photo/Crop.php:143 @@ -10386,6 +10420,42 @@ msgstr "" msgid "Please enter your password for verification:" msgstr "" +#: src/Module/Settings/Server/Action.php:60 +msgid "Do you want to ignore this server?" +msgstr "" + +#: src/Module/Settings/Server/Action.php:64 +msgid "Do you want to unignore this server?" +msgstr "" + +#: src/Module/Settings/Server/Action.php:74 +#: src/Module/Settings/Server/Index.php:104 +msgid "Remote server settings" +msgstr "" + +#: src/Module/Settings/Server/Action.php:77 +msgid "Server URL" +msgstr "" + +#: src/Module/Settings/Server/Index.php:78 +msgid "Settings saved" +msgstr "" + +#: src/Module/Settings/Server/Index.php:105 +msgid "" +"Here you can find all the remote servers you have taken individual " +"moderation actions against. For a list of servers your node has blocked, " +"please check out the Information page." +msgstr "" + +#: src/Module/Settings/Server/Index.php:110 +msgid "Delete all your settings for the remote server" +msgstr "" + +#: src/Module/Settings/Server/Index.php:111 +msgid "Save changes" +msgstr "" + #: src/Module/Settings/TwoFactor/AppSpecific.php:66 #: src/Module/Settings/TwoFactor/Recovery.php:64 #: src/Module/Settings/TwoFactor/Trusted.php:67 @@ -10706,22 +10776,41 @@ msgid "" "e.g. Mastodon." msgstr "" +#: src/Module/Special/DisplayNotFound.php:35 +msgid "The top-level post isn't visible." +msgstr "" + +#: src/Module/Special/DisplayNotFound.php:36 +msgid "The top-level post was deleted." +msgstr "" + #: src/Module/Special/DisplayNotFound.php:37 -msgid "Not Found" +msgid "" +"This node has blocked the top-level author or the author of the shared post." msgstr "" #: src/Module/Special/DisplayNotFound.php:38 msgid "" -"

Unfortunately, the requested conversation isn't available to you.

\n" -"

Possible reasons include:

\n" -"" +"You have ignored or blocked the top-level author or the author of the shared " +"post." +msgstr "" + +#: src/Module/Special/DisplayNotFound.php:39 +msgid "" +"You have ignored the top-level author's server or the shared post author's " +"server." +msgstr "" + +#: src/Module/Special/DisplayNotFound.php:45 +msgid "Conversation Not Found" +msgstr "" + +#: src/Module/Special/DisplayNotFound.php:46 +msgid "Unfortunately, the requested conversation isn't available to you." +msgstr "" + +#: src/Module/Special/DisplayNotFound.php:47 +msgid "Possible reasons include:" msgstr "" #: src/Module/Special/HTTPException.php:78 @@ -10776,6 +10865,10 @@ msgstr "" msgid "Parameter uri_id is missing." msgstr "" +#: src/Module/Update/Display.php:55 +msgid "The requested item doesn't exist or has been deleted." +msgstr "" + #: src/Module/User/Import.php:103 msgid "User imports on closed servers can only be done by an administrator." msgstr "" @@ -11486,27 +11579,27 @@ msgstr "" msgid "%s posted an update." msgstr "" -#: src/Object/Post.php:139 +#: src/Object/Post.php:138 msgid "Private Message" msgstr "" -#: src/Object/Post.php:143 +#: src/Object/Post.php:142 msgid "Public Message" msgstr "" -#: src/Object/Post.php:147 +#: src/Object/Post.php:146 msgid "Unlisted Message" msgstr "" -#: src/Object/Post.php:182 +#: src/Object/Post.php:181 msgid "This entry was edited" msgstr "" -#: src/Object/Post.php:210 +#: src/Object/Post.php:209 msgid "Connector Message" msgstr "" -#: src/Object/Post.php:226 src/Object/Post.php:228 +#: src/Object/Post.php:225 src/Object/Post.php:227 msgid "Edit" msgstr "" @@ -11537,207 +11630,207 @@ msgstr "" msgid "Report post" msgstr "" -#: src/Object/Post.php:287 +#: src/Object/Post.php:293 msgid "Save to folder" msgstr "" -#: src/Object/Post.php:327 +#: src/Object/Post.php:333 msgid "I will attend" msgstr "" -#: src/Object/Post.php:327 +#: src/Object/Post.php:333 msgid "I will not attend" msgstr "" -#: src/Object/Post.php:327 +#: src/Object/Post.php:333 msgid "I might attend" msgstr "" -#: src/Object/Post.php:357 +#: src/Object/Post.php:363 msgid "Ignore thread" msgstr "" -#: src/Object/Post.php:358 +#: src/Object/Post.php:364 msgid "Unignore thread" msgstr "" -#: src/Object/Post.php:359 +#: src/Object/Post.php:365 msgid "Toggle ignore status" msgstr "" -#: src/Object/Post.php:369 +#: src/Object/Post.php:375 msgid "Add star" msgstr "" -#: src/Object/Post.php:370 +#: src/Object/Post.php:376 msgid "Remove star" msgstr "" -#: src/Object/Post.php:371 +#: src/Object/Post.php:377 msgid "Toggle star status" msgstr "" -#: src/Object/Post.php:382 +#: src/Object/Post.php:388 msgid "Pin" msgstr "" -#: src/Object/Post.php:383 +#: src/Object/Post.php:389 msgid "Unpin" msgstr "" -#: src/Object/Post.php:384 +#: src/Object/Post.php:390 msgid "Toggle pin status" msgstr "" -#: src/Object/Post.php:387 +#: src/Object/Post.php:393 msgid "Pinned" msgstr "" -#: src/Object/Post.php:392 +#: src/Object/Post.php:398 msgid "Add tag" msgstr "" -#: src/Object/Post.php:405 +#: src/Object/Post.php:411 msgid "Quote share this" msgstr "" -#: src/Object/Post.php:405 +#: src/Object/Post.php:411 msgid "Quote Share" msgstr "" -#: src/Object/Post.php:408 +#: src/Object/Post.php:414 msgid "Reshare this" msgstr "" -#: src/Object/Post.php:408 +#: src/Object/Post.php:414 msgid "Reshare" msgstr "" -#: src/Object/Post.php:409 +#: src/Object/Post.php:415 msgid "Cancel your Reshare" msgstr "" -#: src/Object/Post.php:409 +#: src/Object/Post.php:415 msgid "Unshare" msgstr "" -#: src/Object/Post.php:460 +#: src/Object/Post.php:466 #, php-format msgid "%s (Received %s)" msgstr "" -#: src/Object/Post.php:466 +#: src/Object/Post.php:472 msgid "Comment this item on your system" msgstr "" -#: src/Object/Post.php:466 +#: src/Object/Post.php:472 msgid "Remote comment" msgstr "" -#: src/Object/Post.php:488 +#: src/Object/Post.php:494 msgid "Share via ..." msgstr "" -#: src/Object/Post.php:488 +#: src/Object/Post.php:494 msgid "Share via external services" msgstr "" -#: src/Object/Post.php:517 +#: src/Object/Post.php:523 msgid "to" msgstr "" -#: src/Object/Post.php:518 +#: src/Object/Post.php:524 msgid "via" msgstr "" -#: src/Object/Post.php:519 +#: src/Object/Post.php:525 msgid "Wall-to-Wall" msgstr "" -#: src/Object/Post.php:520 +#: src/Object/Post.php:526 msgid "via Wall-To-Wall:" msgstr "" -#: src/Object/Post.php:566 +#: src/Object/Post.php:573 #, php-format msgid "Reply to %s" msgstr "" -#: src/Object/Post.php:569 +#: src/Object/Post.php:576 msgid "More" msgstr "" -#: src/Object/Post.php:587 +#: src/Object/Post.php:595 msgid "Notifier task is pending" msgstr "" -#: src/Object/Post.php:588 +#: src/Object/Post.php:596 msgid "Delivery to remote servers is pending" msgstr "" -#: src/Object/Post.php:589 +#: src/Object/Post.php:597 msgid "Delivery to remote servers is underway" msgstr "" -#: src/Object/Post.php:590 +#: src/Object/Post.php:598 msgid "Delivery to remote servers is mostly done" msgstr "" -#: src/Object/Post.php:591 +#: src/Object/Post.php:599 msgid "Delivery to remote servers is done" msgstr "" -#: src/Object/Post.php:611 +#: src/Object/Post.php:619 #, php-format msgid "%d comment" msgid_plural "%d comments" msgstr[0] "" msgstr[1] "" -#: src/Object/Post.php:612 +#: src/Object/Post.php:620 msgid "Show more" msgstr "" -#: src/Object/Post.php:613 +#: src/Object/Post.php:621 msgid "Show fewer" msgstr "" -#: src/Object/Post.php:649 +#: src/Object/Post.php:657 #, php-format msgid "Reshared by: %s" msgstr "" -#: src/Object/Post.php:654 +#: src/Object/Post.php:662 #, php-format msgid "Viewed by: %s" msgstr "" -#: src/Object/Post.php:659 +#: src/Object/Post.php:667 #, php-format msgid "Liked by: %s" msgstr "" -#: src/Object/Post.php:664 +#: src/Object/Post.php:672 #, php-format msgid "Disliked by: %s" msgstr "" -#: src/Object/Post.php:669 +#: src/Object/Post.php:677 #, php-format msgid "Attended by: %s" msgstr "" -#: src/Object/Post.php:674 +#: src/Object/Post.php:682 #, php-format msgid "Maybe attended by: %s" msgstr "" -#: src/Object/Post.php:679 +#: src/Object/Post.php:687 #, php-format msgid "Not attended by: %s" msgstr "" -#: src/Object/Post.php:684 +#: src/Object/Post.php:692 #, php-format msgid "Reacted with %s by: %s" msgstr "" diff --git a/view/templates/admin/federation.tpl b/view/templates/admin/federation.tpl index dbee2ec3e8..8f8d70cd2b 100644 --- a/view/templates/admin/federation.tpl +++ b/view/templates/admin/federation.tpl @@ -57,7 +57,7 @@ {{if $c[0]['total'] > 0}} {{$c[0]['platform']}} - {{$c[0]['total']}} + {{$c[0]['total']}} {{$c[0]['network']}} diff --git a/view/templates/settings/profile/index.tpl b/view/templates/settings/profile/index.tpl index 69812c5a89..64c9daee02 100644 --- a/view/templates/settings/profile/index.tpl +++ b/view/templates/settings/profile/index.tpl @@ -1,121 +1,131 @@ -

{{$banner}}

+ -{{$default nofilter}} +

{{$l10n.banner}}

-
-
+ + + + +
+

{{$l10n.picture_section}} »

+ +
+
+ +
-
- - -
-
-
- - -
-
-
- {{$dob nofilter}} -
-
- {{$hide_friends nofilter}} -
- -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
- -
-
-
- - -
-
{{$homepage.3}}
-
-
- - -
-
{{$xmpp.3}}
-
-
- - -
-
{{$matrix.3}}
-
-
- - -
-
{{$pub_keywords.3}}
-
-
- - -
-
{{$prv_keywords.3}}
-
-
- -
-
+ +
+

{{$l10n.personal_section}} »

+ + +
+

{{$l10n.location_section}} »

+ +
+ +
+

{{$l10n.custom_fields_section}} »

+
-
- -

{{$banner}}

- - - - -
-
- - - -
-

{{$lbl_picture_section}} »

- -
-
- -
- - - -
-

{{$lbl_personal_section}} »

- -
- -
-

{{$lbl_location_section}} »

- -
- -
-

{{$lbl_custom_fields_section}} »

- -
-
-
-