From a3ba3fb3835213c6fa9dbe373537a50e0f7b0615 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 12 Feb 2022 10:46:17 +0000 Subject: [PATCH 01/44] Simplify author contact fetching --- mod/display.php | 48 ++++++++---------------------------------------- 1 file changed, 8 insertions(+), 40 deletions(-) diff --git a/mod/display.php b/mod/display.php index 1186458198..da41c8656e 100644 --- a/mod/display.php +++ b/mod/display.php @@ -23,7 +23,6 @@ use Friendica\App; use Friendica\Content\Text\BBCode; use Friendica\Content\Widget; use Friendica\Core\Logger; -use Friendica\Core\Protocol; use Friendica\Core\Renderer; use Friendica\Core\Session; use Friendica\Database\DBA; @@ -36,6 +35,7 @@ use Friendica\Module\ActivityPub\Objects; use Friendica\Network\HTTPException; use Friendica\Protocol\ActivityPub; use Friendica\Protocol\DFRN; +use Friendica\Protocol\Diaspora; function display_init(App $a) { @@ -108,55 +108,23 @@ function display_init(App $a) $item = $parent ?: $item; } - $profiledata = display_fetchauthor($item); - - DI::page()['aside'] = Widget\VCard::getHTML($profiledata); + DI::page()['aside'] = Widget\VCard::getHTML(display_fetchauthor($item)); } function display_fetchauthor($item) { - $profiledata = Contact::getByURLForUser($item['author-link'], local_user()); - - // Check for a repeated message - $shared = Item::getShareArray($item); - if (!empty($shared) && empty($shared['comment'])) { - $profiledata = [ - 'uid' => 0, - 'id' => -1, - 'nickname' => '', - 'name' => '', - 'picdate' => '', - 'photo' => '', - 'url' => '', - 'network' => '', - ]; - - if (!empty($shared['author'])) { - $profiledata['name'] = $shared['author']; - } - + if (Diaspora::isReshare($item['body'], true)) { + $shared = Item::getShareArray($item); if (!empty($shared['profile'])) { - $profiledata['url'] = $shared['profile']; + $contact = Contact::getByURLForUser($shared['profile'], local_user()); } - - if (!empty($shared['avatar'])) { - $profiledata['photo'] = $shared['avatar']; - } - - $profiledata['nickname'] = $profiledata['name']; - $profiledata['network'] = Protocol::PHANTOM; - - $profiledata['address'] = ''; - $profiledata['about'] = ''; - - $profiledata = Contact::getByURLForUser($profiledata['url'], local_user()) ?: $profiledata; } - if (!empty($profiledata['photo'])) { - $profiledata['photo'] = DI::baseUrl()->remove($profiledata['photo']); + if (empty($contact)) { + $contact = Contact::getById($item['author-id']); } - return $profiledata; + return $contact; } function display_content(App $a, $update = false, $update_uid = 0) From cdee2b44dbab5a7cffe5c18db773624070bbcd98 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 12 Feb 2022 13:05:56 +0000 Subject: [PATCH 02/44] Avoid thread completion on activities --- src/Protocol/ActivityPub/Processor.php | 20 +++++++++++++++----- src/Protocol/ActivityPub/Receiver.php | 3 +++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/Protocol/ActivityPub/Processor.php b/src/Protocol/ActivityPub/Processor.php index 76f8cdb850..b7ddc09f61 100644 --- a/src/Protocol/ActivityPub/Processor.php +++ b/src/Protocol/ActivityPub/Processor.php @@ -306,7 +306,7 @@ class Processor } else { // Store the original actor in the "causer" fields to enable the check for ignored or blocked contacts $item['causer-link'] = $item['owner-link']; - $item['causer-id'] = $item['owner-id']; + $item['causer-id'] = $item['owner-id']; Logger::info('Use actor as causer.', ['id' => $item['owner-id'], 'actor' => $item['owner-link']]); } @@ -642,10 +642,16 @@ class Processor continue; } - if (!($item['isForum'] ?? false) && ($receiver != 0) && ($item['gravity'] == GRAVITY_PARENT) && - ($item['post-reason'] == Item::PR_BCC) && !Contact::isSharingByURL($activity['author'], $receiver)) { - Logger::info('Top level post via BCC from a non sharer, ignoring', ['uid' => $receiver, 'contact' => $item['contact-id']]); - continue; + if (!($item['isForum'] ?? false) && ($receiver != 0) && ($item['gravity'] == GRAVITY_PARENT) && !Contact::isSharingByURL($activity['author'], $receiver)) { + if ($item['post-reason'] == Item::PR_BCC) { + Logger::info('Top level post via BCC from a non sharer, ignoring', ['uid' => $receiver, 'contact' => $item['contact-id']]); + continue; + } + if (!empty($activity['thread-children-type']) && in_array($activity['thread-children-type'], Receiver::ACTIVITY_TYPES)) { + Logger::info('Top level post from thread completion from a non sharer had been initiated via an activity, ignoring', + ['type' => $activity['thread-children-type'], 'user' => $item['uid'], 'causer' => $item['causer-link'], 'author' => $activity['author'], 'url' => $item['uri']]); + continue; + } } $is_forum = false; @@ -887,6 +893,10 @@ class Processor $ldactivity['thread-completion'] = Contact::getIdForURL($actor); } + if (!empty($child['type'])) { + $ldactivity['thread-children-type'] = $child['type']; + } + if (!empty($relay_actor) && !self::acceptIncomingMessage($ldactivity, $object['id'])) { return ''; } diff --git a/src/Protocol/ActivityPub/Receiver.php b/src/Protocol/ActivityPub/Receiver.php index a28cc96170..3da53a033e 100644 --- a/src/Protocol/ActivityPub/Receiver.php +++ b/src/Protocol/ActivityPub/Receiver.php @@ -515,6 +515,9 @@ class Receiver if (!empty($activity['thread-completion'])) { $object_data['thread-completion'] = $activity['thread-completion']; } + if (!empty($activity['thread-children-type'])) { + $object_data['thread-children-type'] = $activity['thread-children-type']; + } // Internal flag for posts that arrived via relay if (!empty($activity['from-relay'])) { From 6bc69f335368edd985ba312fce810a9a0e33b7fc Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Sat, 12 Feb 2022 18:27:58 +0100 Subject: [PATCH 03/44] Workaround for timing problems / Avoid a notice in the scheduled posts --- src/Object/Api/Mastodon/ScheduledStatus.php | 2 +- src/Util/HTTPSignature.php | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Object/Api/Mastodon/ScheduledStatus.php b/src/Object/Api/Mastodon/ScheduledStatus.php index e93c1c07b3..759cd6e4e0 100644 --- a/src/Object/Api/Mastodon/ScheduledStatus.php +++ b/src/Object/Api/Mastodon/ScheduledStatus.php @@ -71,7 +71,7 @@ class ScheduledStatus extends BaseDataTransferObject 'media_ids' => $media_ids, 'sensitive' => null, 'spoiler_text' => $parameters['item']['title'] ?? '', - 'visibility' => $visibility[$parameters['item']['private']], + 'visibility' => $visibility[$parameters['item']['private'] ?? 1], 'scheduled_at' => $this->scheduled_at, 'poll' => null, 'idempotency' => null, diff --git a/src/Util/HTTPSignature.php b/src/Util/HTTPSignature.php index 7603b622b7..68f6cb1dd7 100644 --- a/src/Util/HTTPSignature.php +++ b/src/Util/HTTPSignature.php @@ -627,7 +627,8 @@ class HTTPSignature if (!empty($created)) { $current = time(); - if ($created > $current) { + // Calculate with a grace period of 60 seconds to avoid slight time differences between the servers + if (($created - 60) > $current) { Logger::notice('Signature created in the future', ['created' => date(DateTimeFormat::MYSQL, $created), 'expired' => date(DateTimeFormat::MYSQL, $expired), 'current' => date(DateTimeFormat::MYSQL, $current)]); return false; } From e394143148c63b73ad719cfb60b517bb20858b74 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 12 Feb 2022 18:38:36 +0000 Subject: [PATCH 04/44] Private forums are now working via ActivityPub --- database.sql | 4 +- doc/database/db_post-thread-user.md | 2 +- mod/item.php | 30 +++----- src/Model/Contact.php | 3 +- src/Model/Group.php | 62 ++++++++++----- src/Model/Item.php | 90 +++++++++------------- src/Module/Api/Twitter/Lists/Ownership.php | 2 +- src/Protocol/ActivityPub/Transmitter.php | 16 +--- src/Protocol/DFRN.php | 13 +--- src/Worker/Delivery.php | 1 - src/Worker/Notifier.php | 24 ------ static/dbstructure.config.php | 2 +- static/dbview.config.php | 2 - 13 files changed, 97 insertions(+), 154 deletions(-) diff --git a/database.sql b/database.sql index ea129109dc..308e2e8a86 100644 --- a/database.sql +++ b/database.sql @@ -1277,7 +1277,7 @@ CREATE TABLE IF NOT EXISTS `post-thread-user` ( `wall` boolean NOT NULL DEFAULT '0' COMMENT 'This item was posted to the wall of uid', `mention` boolean NOT NULL DEFAULT '0' COMMENT '', `pubmail` boolean NOT NULL DEFAULT '0' COMMENT '', - `forum_mode` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '', + `forum_mode` tinyint unsigned NOT NULL DEFAULT 0 COMMENT 'Deprecated', `contact-id` int unsigned NOT NULL DEFAULT 0 COMMENT 'contact.id', `unseen` boolean NOT NULL DEFAULT '1' COMMENT 'post has not been seen', `hidden` boolean NOT NULL DEFAULT '0' COMMENT 'Marker to hide the post from the user', @@ -1612,7 +1612,6 @@ CREATE VIEW `post-user-view` AS SELECT `post-user`.`deleted` AS `deleted`, `post-user`.`origin` AS `origin`, `post-thread-user`.`origin` AS `parent-origin`, - `post-thread-user`.`forum_mode` AS `forum_mode`, `post-thread-user`.`mention` AS `mention`, `post-user`.`global` AS `global`, `post-user`.`network` AS `network`, @@ -1773,7 +1772,6 @@ CREATE VIEW `post-thread-user-view` AS SELECT `post-thread-user`.`unseen` AS `unseen`, `post-user`.`deleted` AS `deleted`, `post-thread-user`.`origin` AS `origin`, - `post-thread-user`.`forum_mode` AS `forum_mode`, `post-thread-user`.`mention` AS `mention`, `post-user`.`global` AS `global`, `post-thread-user`.`network` AS `network`, diff --git a/doc/database/db_post-thread-user.md b/doc/database/db_post-thread-user.md index 7307dc78d6..0b74837411 100644 --- a/doc/database/db_post-thread-user.md +++ b/doc/database/db_post-thread-user.md @@ -24,7 +24,7 @@ Fields | wall | This item was posted to the wall of uid | boolean | NO | | 0 | | | mention | | boolean | NO | | 0 | | | pubmail | | boolean | NO | | 0 | | -| forum_mode | | tinyint unsigned | NO | | 0 | | +| forum_mode | Deprecated | tinyint unsigned | NO | | 0 | | | contact-id | contact.id | int unsigned | NO | | 0 | | | unseen | post has not been seen | boolean | NO | | 1 | | | hidden | Marker to hide the post from the user | boolean | NO | | 0 | | diff --git a/mod/item.php b/mod/item.php index 7cf2e53d49..bc35282e33 100644 --- a/mod/item.php +++ b/mod/item.php @@ -29,7 +29,6 @@ */ use Friendica\App; -use Friendica\Content\Item as ItemHelper; use Friendica\Content\PageInfo; use Friendica\Content\Text\BBCode; use Friendica\Core\Hook; @@ -40,11 +39,11 @@ use Friendica\Core\System; use Friendica\Core\Worker; use Friendica\Database\DBA; use Friendica\DI; -use Friendica\Model\APContact; use Friendica\Model\Attach; use Friendica\Model\Contact; use Friendica\Model\Conversation; use Friendica\Model\FileTag; +use Friendica\Model\Group; use Friendica\Model\Item; use Friendica\Model\ItemURI; use Friendica\Model\Notification; @@ -404,7 +403,7 @@ function item_post(App $a) { } $inform .= 'cid:' . $contact['id']; - if (!$toplevel_item_id || empty($contact['cid']) || ($contact['contact-type'] != Contact::TYPE_COMMUNITY)) { + if ($toplevel_item_id || empty($contact['cid']) || ($contact['contact-type'] != Contact::TYPE_COMMUNITY)) { continue; } @@ -437,26 +436,15 @@ function item_post(App $a) { $postopts = ''; } - if (!$private_forum) { + $str_contact_deny = ''; + $str_group_deny = ''; + + if ($private_forum) { + $str_contact_allow = '<' . $private_id . '>'; + $str_group_allow = '<' . Group::getIdForForum($forum_contact['id']) . '>'; + } else { $str_contact_allow = ''; $str_group_allow = ''; - $str_contact_deny = ''; - $str_group_deny = ''; - } - - if ($private_forum || !APContact::getByURL($forum_contact['url'])) { - $str_group_allow = ''; - $str_contact_deny = ''; - $str_group_deny = ''; - if ($private_forum) { - $str_contact_allow = '<' . $private_id . '>'; - } else { - $str_contact_allow = ''; - } - $contact_id = $private_id; - $contact_record = $forum_contact; - $_REQUEST['origin'] = false; - $wall = 0; } } diff --git a/src/Model/Contact.php b/src/Model/Contact.php index 1b39247f4e..d80827c93f 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -685,7 +685,7 @@ class Contact */ public static function updateSelfFromUserID($uid, $update_avatar = false) { - $fields = ['id', 'name', 'nick', 'location', 'about', 'keywords', 'avatar', 'prvkey', 'pubkey', + $fields = ['id', 'name', 'nick', 'location', 'about', 'keywords', 'avatar', 'prvkey', 'pubkey', 'manually-approve', 'xmpp', 'matrix', 'contact-type', 'forum', 'prv', 'avatar-date', 'url', 'nurl', 'unsearchable', 'photo', 'thumb', 'micro', 'header', 'addr', 'request', 'notify', 'poll', 'confirm', 'poco', 'network']; $self = DBA::selectFirst('contact', $fields, ['uid' => $uid, 'self' => true]); @@ -757,6 +757,7 @@ class Contact $fields['forum'] = $user['page-flags'] == User::PAGE_FLAGS_COMMUNITY; $fields['prv'] = $user['page-flags'] == User::PAGE_FLAGS_PRVGROUP; $fields['unsearchable'] = !$profile['net-publish']; + $fields['manually-approve'] = in_array($user['page-flags'], [User::PAGE_FLAGS_NORMAL, User::PAGE_FLAGS_PRVGROUP]); $update = false; diff --git a/src/Model/Group.php b/src/Model/Group.php index 390ed532e3..b9f4c7f277 100644 --- a/src/Model/Group.php +++ b/src/Model/Group.php @@ -41,7 +41,7 @@ class Group public static function getByUserId($uid, $includesDeleted = false) { - $conditions = ['uid' => $uid]; + $conditions = ['uid' => $uid, 'cid' => null]; if (!$includesDeleted) { $conditions['deleted'] = false; @@ -408,7 +408,7 @@ class Group ] ]; - $stmt = DBA::select('group', [], ['deleted' => 0, 'uid' => $uid], ['order' => ['name']]); + $stmt = DBA::select('group', [], ['deleted' => false, 'uid' => $uid, 'cid' => null], ['order' => ['name']]); while ($group = DBA::fetch($stmt)) { $display_groups[] = [ 'name' => $group['name'], @@ -465,7 +465,7 @@ class Group $member_of = self::getIdsByContactId($cid); } - $stmt = DBA::select('group', [], ['deleted' => 0, 'uid' => local_user()], ['order' => ['name']]); + $stmt = DBA::select('group', [], ['deleted' => false, 'uid' => local_user(), 'cid' => null], ['order' => ['name']]); while ($group = DBA::fetch($stmt)) { $selected = (($group_id == $group['id']) ? ' group-selected' : ''); @@ -522,21 +522,19 @@ class Group } /** - * Fetch the followers of a given contact id and store them as group members + * Fetch the group id for the given contact id * * @param integer $id Contact ID + * @return integer Group IO */ - public static function getMembersForForum(int $id) { - $contact = Contact::getById($id, ['uid', 'url', 'name']); - if (empty($contact)) { - return; + public static function getIdForForum(int $id) + { + Logger::info('Get id for forum id', ['id' => $id]); + $contact = Contact::getById($id, ['uid', 'name', 'contact-type', 'manually-approve']); + if (empty($contact) || ($contact['contact-type'] != Contact::TYPE_COMMUNITY) || !$contact['manually-approve']) { + return 0; } - - $apcontact = APContact::getByURL($contact['url']); - if (empty($apcontact['followers'])) { - return; - } - + $group = DBA::selectFirst('group', ['id'], ['uid' => $contact['uid'], 'cid' => $id]); if (empty($group)) { $fields = [ @@ -549,15 +547,42 @@ class Group } else { $gid = $group['id']; } - + + return $gid; + } + + /** + * Fetch the followers of a given contact id and store them as group members + * + * @param integer $id Contact ID + */ + public static function getMembersForForum(int $id) + { + Logger::info('Update forum members', ['id' => $id]); + + $contact = Contact::getById($id, ['uid', 'url']); + if (empty($contact)) { + return; + } + + $apcontact = APContact::getByURL($contact['url']); + if (empty($apcontact['followers'])) { + return; + } + + $gid = self::getIdForForum($id); + if (empty($gid)) { + return; + } + $group_members = DBA::selectToArray('group_member', ['contact-id'], ['gid' => $gid]); if (!empty($group_members)) { $current = array_unique(array_column($group_members, 'contact-id')); } else { $current = []; } - - foreach (ActivityPub::fetchItems($apcontact['followers']) as $follower) { + + foreach (ActivityPub::fetchItems($apcontact['followers'], $contact['uid']) as $follower) { $id = Contact::getIdForURL($follower); if (!in_array($id, $current)) { DBA::insert('group_member', ['gid' => $gid, 'contact-id' => $id]); @@ -566,7 +591,8 @@ class Group unset($current[$key]); } } - + DBA::delete('group_member', ['gid' => $gid, 'contact-id' => $current]); + Logger::info('Updated forum members', ['id' => $id, 'count' => DBA::count('group_member', ['gid' => $gid])]); } } diff --git a/src/Model/Item.php b/src/Model/Item.php index bf1f2585a1..6749dc2389 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -100,7 +100,7 @@ class Item 'inform', 'deleted', 'extid', 'post-type', 'post-reason', 'gravity', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', 'author-id', 'author-link', 'author-name', 'author-avatar', 'owner-id', 'owner-link', 'contact-uid', - 'signed_text', 'network', 'wall', 'contact-id', 'plink', 'forum_mode', 'origin', + 'signed_text', 'network', 'wall', 'contact-id', 'plink', 'origin', 'thr-parent-id', 'parent-uri-id', 'postopts', 'pubmail', 'event-created', 'event-edited', 'event-start', 'event-finish', 'event-summary', 'event-desc', 'event-location', 'event-type', @@ -114,7 +114,7 @@ class Item 'postopts', 'plink', 'resource-id', 'event-id', 'inform', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', 'post-type', 'post-reason', 'private', 'pubmail', 'visible', 'starred', - 'unseen', 'deleted', 'origin', 'forum_mode', 'mention', 'global', 'network', + 'unseen', 'deleted', 'origin', 'mention', 'global', 'network', 'title', 'content-warning', 'body', 'location', 'coord', 'app', 'rendered-hash', 'rendered-html', 'object-type', 'object', 'target-type', 'target', 'author-id', 'author-link', 'author-name', 'author-avatar', 'author-network', @@ -655,7 +655,7 @@ class Item $fields = ['uid', 'uri', 'parent-uri', 'id', 'deleted', 'uri-id', 'parent-uri-id', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', - 'wall', 'private', 'forum_mode', 'origin', 'author-id']; + 'wall', 'private', 'origin', 'author-id']; $condition = ['uri-id' => $item['thr-parent-id'], 'uid' => $item['uid']]; $params = ['order' => ['id' => false]]; $parent = Post::selectFirst($fields, $condition, $params); @@ -881,10 +881,15 @@ class Item $item['parent-uri'] = $toplevel_parent['uri']; $item['parent-uri-id'] = $toplevel_parent['uri-id']; $item['deleted'] = $toplevel_parent['deleted']; - $item['allow_cid'] = $toplevel_parent['allow_cid']; - $item['allow_gid'] = $toplevel_parent['allow_gid']; - $item['deny_cid'] = $toplevel_parent['deny_cid']; - $item['deny_gid'] = $toplevel_parent['deny_gid']; + + // Reshares have to keep their permissions to allow forums to work + if (!$item['origin'] || ($item['verb'] != Activity::ANNOUNCE)) { + $item['allow_cid'] = $toplevel_parent['allow_cid']; + $item['allow_gid'] = $toplevel_parent['allow_gid']; + $item['deny_cid'] = $toplevel_parent['deny_cid']; + $item['deny_gid'] = $toplevel_parent['deny_gid']; + } + $parent_origin = $toplevel_parent['origin']; // Don't federate received participation messages @@ -905,15 +910,6 @@ class Item $item['private'] = $toplevel_parent['private']; } - /* - * Edge case. We host a public forum that was originally posted to privately. - * The original author commented, but as this is a comment, the permissions - * weren't fixed up so it will still show the comment as private unless we fix it here. - */ - if ((intval($toplevel_parent['forum_mode']) == 1) && ($toplevel_parent['private'] != self::PUBLIC)) { - $item['private'] = self::PUBLIC; - } - // If its a post that originated here then tag the thread as "mention" if ($item['origin'] && $item['uid']) { DBA::update('post-thread-user', ['mention' => true], ['uri-id' => $item['parent-uri-id'], 'uid' => $item['uid']]); @@ -1451,7 +1447,6 @@ class Item unset($item['pinned']); unset($item['ignored']); unset($item['pubmail']); - unset($item['forum_mode']); unset($item['event-id']); unset($item['hidden']); @@ -1928,41 +1923,18 @@ class Item Logger::info('Community post will be distributed', ['uri' => $item['uri'], 'uid' => $uid, 'id' => $item_id, 'uri-id' => $item['uri-id'], 'guid' => $item['guid']]); - self::performActivity($item['id'], 'announce', $uid); + if ($owner['page-flags'] == User::PAGE_FLAGS_PRVGROUP) { + Group::getMembersForForum($owner['id']); - /** - * All the following lines are only needed for private forums and compatibility to older systems without AP support. - * A possible way would be that the followers list of a forum would always be readable by all followers. - * So this would mean that the comment distribution could be done exactly for the intended audience. - * Or possibly we could store the receivers that had been in the "announce" message above and use this. - */ - - // also reset all the privacy bits to the forum default permissions - if ($owner['allow_cid'] || $owner['allow_gid'] || $owner['deny_cid'] || $owner['deny_gid']) { - $private = self::PRIVATE; - } elseif (DI::pConfig()->get($owner['uid'], 'system', 'unlisted')) { - $private = self::UNLISTED; + $allow_cid = '<' . $owner['id'] . '>'; + $allow_gid = '<' . Group::getIdForForum($owner['id']) . '>'; + $deny_cid = ''; + $deny_gid = ''; + self::performActivity($item['id'], 'announce', $uid, $allow_cid, $allow_gid, $deny_cid, $deny_gid); } else { - $private = self::PUBLIC; + self::performActivity($item['id'], 'announce', $uid); } - $permissionSet = DI::permissionSet()->selectOrCreate( - DI::permissionSetFactory()->createFromString( - $owner['uid'], - $owner['allow_cid'], - $owner['allow_gid'], - $owner['deny_cid'], - $owner['deny_gid'] - )); - - $forum_mode = ($owner['page-flags'] == User::PAGE_FLAGS_PRVGROUP) ? 2 : 1; - - $fields = ['wall' => true, 'origin' => true, 'forum_mode' => $forum_mode, 'contact-id' => $owner['id'], - 'owner-id' => Contact::getPublicIdByUserId($uid), 'private' => $private, 'psid' => $permissionSet->id]; - self::update($fields, ['id' => $item['id']]); - - Worker::add(['priority' => PRIORITY_HIGH, 'dont_fork' => true], 'Notifier', Delivery::POST, (int)$item['uri-id'], (int)$item['uid']); - Logger::info('Community post had been distributed', ['uri' => $item['uri'], 'uid' => $uid, 'id' => $item_id, 'uri-id' => $item['uri-id'], 'guid' => $item['guid']]); return false; } @@ -2325,12 +2297,17 @@ class Item * * Toggle activities as like,dislike,attend of an item * - * @param int $item_id + * @param int $item_id * @param string $verb * Activity verb. One of * like, unlike, dislike, undislike, attendyes, unattendyes, * attendno, unattendno, attendmaybe, unattendmaybe, * announce, unannouce + * @param int $uid + * @param string $allow_cid + * @param string $allow_gid + * @param string $deny_cid + * @param string $deny_gid * @return bool * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException @@ -2338,7 +2315,7 @@ class Item * array $arr * 'post_id' => ID of posted item */ - public static function performActivity(int $item_id, string $verb, int $uid) + public static function performActivity(int $item_id, string $verb, int $uid, string $allow_cid = null, string $allow_gid = null, string $deny_cid = null, string $deny_gid = null) { if (empty($uid)) { return false; @@ -2479,6 +2456,11 @@ class Item return true; } + $allow_cid = $allow_cid ?? $item['allow_cid']; + $allow_gid = $allow_gid ?? $item['allow_gid']; + $deny_cid = $deny_cid ?? $item['deny_cid']; + $deny_gid = $deny_gid ?? $item['deny_gid']; + $objtype = $item['resource-id'] ? Activity\ObjectType::IMAGE : Activity\ObjectType::NOTE; $new_item = [ @@ -2499,10 +2481,10 @@ class Item 'body' => $activity, 'verb' => $activity, 'object-type' => $objtype, - 'allow_cid' => $item['allow_cid'], - 'allow_gid' => $item['allow_gid'], - 'deny_cid' => $item['deny_cid'], - 'deny_gid' => $item['deny_gid'], + 'allow_cid' => $allow_cid, + 'allow_gid' => $allow_gid, + 'deny_cid' => $deny_cid, + 'deny_gid' => $deny_gid, 'visible' => 1, 'unseen' => 1, ]; diff --git a/src/Module/Api/Twitter/Lists/Ownership.php b/src/Module/Api/Twitter/Lists/Ownership.php index e5aca1ad5c..c3ff0030b4 100644 --- a/src/Module/Api/Twitter/Lists/Ownership.php +++ b/src/Module/Api/Twitter/Lists/Ownership.php @@ -56,7 +56,7 @@ class Ownership extends BaseApi BaseApi::checkAllowedScope(BaseApi::SCOPE_READ); $uid = BaseApi::getCurrentUserID(); - $groups = $this->dba->select('group', [], ['deleted' => false, 'uid' => $uid]); + $groups = $this->dba->select('group', [], ['deleted' => false, 'uid' => $uid, 'cid' => null]); // loop through all groups $lists = []; diff --git a/src/Protocol/ActivityPub/Transmitter.php b/src/Protocol/ActivityPub/Transmitter.php index aafeee1e29..663862f79d 100644 --- a/src/Protocol/ActivityPub/Transmitter.php +++ b/src/Protocol/ActivityPub/Transmitter.php @@ -184,7 +184,7 @@ class Transmitter // Allow fetching the contact list when the requester is part of the list. if (($owner['page-flags'] == User::PAGE_FLAGS_PRVGROUP) && !empty($requester)) { - $show_contacts = DBA::exists('contact', ['nurl' => Strings::normaliseLink($requester), 'rel' => $rel]); + $show_contacts = DBA::exists('contact', ['nurl' => Strings::normaliseLink($requester), 'uid' => $owner['uid'], 'blocked' => false]); } if (!$show_contacts) { @@ -1079,20 +1079,6 @@ class Transmitter return false; } - // In case of a forum post ensure to return the original post if author and forum are on the same machine - if (($item['gravity'] == GRAVITY_PARENT) && !empty($item['forum_mode'])) { - $author = Contact::getById($item['author-id'], ['nurl']); - if (!empty($author['nurl'])) { - $self = Contact::selectFirst(['uid'], ['nurl' => $author['nurl'], 'self' => true]); - if (!empty($self['uid'])) { - $forum_item = Post::selectFirst(Item::DELIVER_FIELDLIST, ['uri-id' => $item['uri-id'], 'uid' => $self['uid']]); - if (DBA::isResult($forum_item)) { - $item = $forum_item; - } - } - } - } - if (empty($item['uri-id'])) { Logger::warning('Item without uri-id', ['item' => $item]); return false; diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index 94b1b1689d..50faf987aa 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -1557,22 +1557,11 @@ class DFRN // was the top-level post for this action written by somebody on this site? // Specifically, the recipient? - $parent = Post::selectFirst(['forum_mode', 'wall'], + $parent = Post::selectFirst(['wall'], ["`uri` = ? AND `uid` = ?" . $sql_extra, $item["thr-parent"], $importer["importer_uid"]]); $is_a_remote_action = DBA::isResult($parent); - /* - * Does this have the characteristics of a community or private group action? - * If it's an action to a wall post on a community/prvgroup page it's a - * valid community action. Also forum_mode makes it valid for sure. - * If neither, it's not. - */ - if ($is_a_remote_action && $community && (!$parent["forum_mode"]) && (!$parent["wall"])) { - $is_a_remote_action = false; - Logger::notice("not a community action"); - } - if ($is_a_remote_action) { return DFRN::REPLY_RC; } else { diff --git a/src/Worker/Delivery.php b/src/Worker/Delivery.php index 3be49a38fe..c09181d3e6 100644 --- a/src/Worker/Delivery.php +++ b/src/Worker/Delivery.php @@ -46,7 +46,6 @@ class Delivery const DELETION = 'drop'; const POST = 'wall-new'; const POKE = 'poke'; - const UPLINK = 'uplink'; const REMOVAL = 'removeme'; const PROFILEUPDATE = 'profileupdate'; diff --git a/src/Worker/Notifier.php b/src/Worker/Notifier.php index f46b1b0d9a..bfd38fe01f 100644 --- a/src/Worker/Notifier.php +++ b/src/Worker/Notifier.php @@ -223,10 +223,6 @@ class Notifier $relay_to_owner = true; } - if (($cmd === Delivery::UPLINK) && (intval($parent['forum_mode']) == 1) && !$top_level) { - $relay_to_owner = true; - } - // until the 'origin' flag has been in use for several months // we will just use it as a fallback test // later we will be able to use it as the primary test of whether or not to relay. @@ -333,15 +329,6 @@ class Notifier $deny_people = $aclFormatter->expand($parent['deny_cid']); $deny_groups = Group::expand($uid, $aclFormatter->expand($parent['deny_gid'])); - // if our parent is a public forum (forum_mode == 1), uplink to the origional author causing - // a delivery fork. private groups (forum_mode == 2) do not uplink - /// @todo Possibly we should not uplink when the author is the forum itself? - - if ((intval($parent['forum_mode']) == 1) && !$top_level && ($cmd !== Delivery::UPLINK) - && ($target_item['verb'] != Activity::ANNOUNCE)) { - Worker::add($a->getQueueValue('priority'), 'Notifier', Delivery::UPLINK, $post_uriid, $sender_uid); - } - foreach ($items as $item) { $recipients[] = $item['contact-id']; // pull out additional tagged people to notify (if public message) @@ -813,15 +800,4 @@ class Notifier return ['count' => $delivery_queue_count, 'contacts' => $contacts]; } - - /** - * Check if the delivered item is a forum post - * - * @param array $item - * @return boolean - */ - public static function isForumPost(array $item) - { - return ($item['gravity'] == GRAVITY_PARENT) && !empty($item['forum_mode']); - } } diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index 0cf8543718..01419bf2b7 100644 --- a/static/dbstructure.config.php +++ b/static/dbstructure.config.php @@ -1301,7 +1301,7 @@ return [ "wall" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "This item was posted to the wall of uid"], "mention" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], "pubmail" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], - "forum_mode" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""], + "forum_mode" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => "Deprecated"], "contact-id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "foreign" => ["contact" => "id"], "comment" => "contact.id"], "unseen" => ["type" => "boolean", "not null" => "1", "default" => "1", "comment" => "post has not been seen"], "hidden" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Marker to hide the post from the user"], diff --git a/static/dbview.config.php b/static/dbview.config.php index 4188c7726d..014973de26 100644 --- a/static/dbview.config.php +++ b/static/dbview.config.php @@ -91,7 +91,6 @@ "deleted" => ["post-user", "deleted"], "origin" => ["post-user", "origin"], "parent-origin" => ["post-thread-user", "origin"], - "forum_mode" => ["post-thread-user", "forum_mode"], "mention" => ["post-thread-user", "mention"], "global" => ["post-user", "global"], "network" => ["post-user", "network"], @@ -250,7 +249,6 @@ "unseen" => ["post-thread-user", "unseen"], "deleted" => ["post-user", "deleted"], "origin" => ["post-thread-user", "origin"], - "forum_mode" => ["post-thread-user", "forum_mode"], "mention" => ["post-thread-user", "mention"], "global" => ["post-user", "global"], "network" => ["post-thread-user", "network"], From ee3a8ccb3bbb4c214f7410976bd9f6ae95be40f1 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 13 Feb 2022 05:45:06 +0000 Subject: [PATCH 05/44] No notifcations for forum / fetch user for fetching content --- src/Model/Post/UserNotification.php | 6 +++++ src/Protocol/ActivityPub/Receiver.php | 37 ++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/Model/Post/UserNotification.php b/src/Model/Post/UserNotification.php index ad7b9c4904..79499897dd 100644 --- a/src/Model/Post/UserNotification.php +++ b/src/Model/Post/UserNotification.php @@ -33,6 +33,7 @@ use Friendica\Model\Contact; use Friendica\Model\Post; use Friendica\Model\Subscription; use Friendica\Model\Tag; +use Friendica\Model\User; use Friendica\Navigation\Notifications; use Friendica\Network\HTTPException; use Friendica\Protocol\Activity; @@ -176,6 +177,11 @@ class UserNotification return; } + $user = User::getById($uid, ['account-type']); + if (in_array($user['account-type'], [User::ACCOUNT_TYPE_COMMUNITY, User::ACCOUNT_TYPE_RELAY])) { + return; + } + $notification_type = self::TYPE_NONE; if (self::checkShared($item, $uid)) { diff --git a/src/Protocol/ActivityPub/Receiver.php b/src/Protocol/ActivityPub/Receiver.php index 3da53a033e..3d183aec56 100644 --- a/src/Protocol/ActivityPub/Receiver.php +++ b/src/Protocol/ActivityPub/Receiver.php @@ -263,7 +263,19 @@ class Receiver { $id = JsonLD::fetchElement($activity, '@id'); if (!empty($id) && !$trust_source) { - $fetched_activity = ActivityPub::fetchContent($id, $uid ?? 0); + if (empty($uid)) { + $actor = JsonLD::fetchElement($activity, 'as:actor', '@id'); + if (empty($actor)) { + $actor = ''; + } + + // Fetch a user out of the receivers of the message. + $fetch_uid = Receiver::getBestUserForActivity($activity, $actor); + } else { + $fetch_uid = $uid; + } + + $fetched_activity = ActivityPub::fetchContent($id, $fetch_uid); if (!empty($fetched_activity)) { $object = JsonLD::compact($fetched_activity); $fetched_id = JsonLD::fetchElement($object, '@id'); @@ -643,6 +655,29 @@ class Receiver } } + /** + * Fetch a user id from an activity array + * + * @param array $activity + * @param string $actor + * + * @return int user id + */ + private static function getBestUserForActivity(array $activity, string $actor) + { + $uid = 0; + $receivers = self::getReceivers($activity, $actor); + foreach ($receivers as $receiver) { + if ($receiver['type'] == self::TARGET_GLOBAL) { + return 0; + } + if (empty($uid) || ($receiver['type'] == self::TARGET_TO)) { + $uid = $receiver['uid']; + } + } + return $uid; + } + /** * Fetch the receiver list from an activity array * From a5a1c8179059a66886809dcfdfd8eb67f6c24828 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 13 Feb 2022 16:42:43 +0000 Subject: [PATCH 06/44] Fetch the user id when not provided --- src/Protocol/ActivityPub/Receiver.php | 34 ++++++++++----------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/src/Protocol/ActivityPub/Receiver.php b/src/Protocol/ActivityPub/Receiver.php index 3d183aec56..7f08410f69 100644 --- a/src/Protocol/ActivityPub/Receiver.php +++ b/src/Protocol/ActivityPub/Receiver.php @@ -263,17 +263,7 @@ class Receiver { $id = JsonLD::fetchElement($activity, '@id'); if (!empty($id) && !$trust_source) { - if (empty($uid)) { - $actor = JsonLD::fetchElement($activity, 'as:actor', '@id'); - if (empty($actor)) { - $actor = ''; - } - - // Fetch a user out of the receivers of the message. - $fetch_uid = Receiver::getBestUserForActivity($activity, $actor); - } else { - $fetch_uid = $uid; - } + $fetch_uid = $uid ?: self::getBestUserForActivity($activity); $fetched_activity = ActivityPub::fetchContent($id, $fetch_uid); if (!empty($fetched_activity)) { @@ -314,12 +304,12 @@ class Receiver if (empty($activity['thread-completion']) && (empty($reception_types[$uid]) || in_array($reception_types[$uid], [self::TARGET_UNKNOWN, self::TARGET_FOLLOWER, self::TARGET_ANSWER, self::TARGET_GLOBAL]))) { $reception_types[$uid] = self::TARGET_BCC; } - } else { - // We possibly need some user to fetch private content, - // so we fetch the first out ot the list. - $uid = self::getFirstUserFromReceivers($receivers); } + // We possibly need some user to fetch private content, + // so we fetch one out of the receivers if no uid is provided. + $fetch_uid = $uid ?: self::getBestUserForActivity($activity); + $object_id = JsonLD::fetchElement($activity, 'as:object', '@id'); if (empty($object_id)) { Logger::info('No object found'); @@ -331,11 +321,11 @@ class Receiver return []; } - $object_type = self::fetchObjectType($activity, $object_id, $uid); + $object_type = self::fetchObjectType($activity, $object_id, $fetch_uid); // Fetch the activity on Lemmy "Announce" messages (announces of activities) if (($type == 'as:Announce') && in_array($object_type, array_merge(self::ACTIVITY_TYPES, ['as:Delete', 'as:Undo', 'as:Update']))) { - $data = ActivityPub::fetchContent($object_id, $uid); + $data = ActivityPub::fetchContent($object_id, $fetch_uid); if (!empty($data)) { $type = $object_type; $activity = JsonLD::compact($data); @@ -343,7 +333,7 @@ class Receiver // Some variables need to be refetched since the activity changed $actor = JsonLD::fetchElement($activity, 'as:actor', '@id'); $object_id = JsonLD::fetchElement($activity, 'as:object', '@id'); - $object_type = self::fetchObjectType($activity, $object_id, $uid); + $object_type = self::fetchObjectType($activity, $object_id, $fetch_uid); } } @@ -360,7 +350,7 @@ class Receiver // Fetch the content only on activities where this matters // We can receive "#emojiReaction" when fetching content from Hubzilla systems // Always fetch on "Announce" - $object_data = self::fetchObject($object_id, $activity['as:object'], $trust_source && ($type != 'as:Announce'), $uid); + $object_data = self::fetchObject($object_id, $activity['as:object'], $trust_source && ($type != 'as:Announce'), $fetch_uid); if (empty($object_data)) { Logger::info("Object data couldn't be processed"); return []; @@ -408,7 +398,7 @@ class Receiver // An Undo is done on the object of an object, so we need that type as well if (($type == 'as:Undo') && !empty($object_data['object_object'])) { - $object_data['object_object_type'] = self::fetchObjectType([], $object_data['object_object'], $uid); + $object_data['object_object_type'] = self::fetchObjectType([], $object_data['object_object'], $fetch_uid); } } @@ -663,9 +653,11 @@ class Receiver * * @return int user id */ - private static function getBestUserForActivity(array $activity, string $actor) + public static function getBestUserForActivity(array $activity) { $uid = 0; + $actor = JsonLD::fetchElement($activity, 'as:actor', '@id') ?? ''; + $receivers = self::getReceivers($activity, $actor); foreach ($receivers as $receiver) { if ($receiver['type'] == self::TARGET_GLOBAL) { From d404f15312320dbe1f516db7bb91944182ad5d26 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 14 Feb 2022 22:04:33 +0000 Subject: [PATCH 07/44] Improve local forum distribution --- src/Model/Item.php | 52 ++++++++++++++++++++++-- src/Protocol/ActivityPub/Transmitter.php | 31 +++++++++----- 2 files changed, 69 insertions(+), 14 deletions(-) diff --git a/src/Model/Item.php b/src/Model/Item.php index 6749dc2389..fd0dbde2bf 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -1402,9 +1402,15 @@ class Item } if ((($item['gravity'] == GRAVITY_COMMENT) || $is_reshare) && !Post::exists(['uri-id' => $item['thr-parent-id'], 'uid' => $uid])) { - // Only do an auto complete with the source uid "0" to prevent privavy problems + // Fetch the origin user for the post + $origin_uid = self::GetOriginUidForUriId($item['thr-parent-id'], $uid); + if (is_null($origin_uid)) { + Logger::info('Origin item was not found', ['uid' => $uid, 'uri-id' => $item['thr-parent-id']]); + return 0; + } + $causer = $item['causer-id'] ?: $item['author-id']; - $result = self::storeForUserByUriId($item['thr-parent-id'], $uid, ['causer-id' => $causer, 'post-reason' => self::PR_FETCHED]); + $result = self::storeForUserByUriId($item['thr-parent-id'], $uid, ['causer-id' => $causer, 'post-reason' => self::PR_FETCHED], $origin_uid); Logger::info('Fetched thread parent', ['uri-id' => $item['thr-parent-id'], 'uid' => $uid, 'causer' => $causer, 'result' => $result]); } @@ -1413,6 +1419,46 @@ class Item return $stored; } + /** + * Returns the origin uid of a post if the given user is allowed to see it. + * + * @param int $uriid + * @param int $uid + * @return int + */ + private static function GetOriginUidForUriId(int $uriid, int $uid) + { + if (Post::exists(['uri-id' => $uriid, 'uid' => $uid])) { + return $uid; + } + + $post = Post::selectFirst(['uid', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', 'private'], ['uri-id' => $uriid, 'origin' => true]); + if (empty($post)) { + if (Post::exists(['uri-id' => $uriid, 'uid' => 0])) { + return 0; + } else { + return null; + } + } + + if (in_array($post['private'], [Item::PUBLIC, Item::UNLISTED])) { + return $post['uid']; + } + + $pcid = Contact::getPublicIdByUserId($uid); + if (empty($pcid)) { + return null; + } + + foreach (Item::enumeratePermissions($post, true) as $receiver) { + if ($receiver == $pcid) { + return $post['uid']; + } + } + + return null; + } + /** * Store a public item array for the given users * @@ -1928,7 +1974,7 @@ class Item $allow_cid = '<' . $owner['id'] . '>'; $allow_gid = '<' . Group::getIdForForum($owner['id']) . '>'; - $deny_cid = ''; + $deny_cid = ''; $deny_gid = ''; self::performActivity($item['id'], 'announce', $uid, $allow_cid, $allow_gid, $deny_cid, $deny_gid); } else { diff --git a/src/Protocol/ActivityPub/Transmitter.php b/src/Protocol/ActivityPub/Transmitter.php index 663862f79d..7be55898c8 100644 --- a/src/Protocol/ActivityPub/Transmitter.php +++ b/src/Protocol/ActivityPub/Transmitter.php @@ -600,23 +600,32 @@ class Transmitter continue; } - if (!empty($profile = APContact::getByURL($contact['url'], false))) { + $profile = APContact::getByURL($term['url'], false); + if (!empty($profile)) { + if ($term['type'] == Tag::EXCLUSIVE_MENTION) { + $exclusive = true; + if (!empty($profile['followers']) && ($profile['type'] == 'Group')) { + $data['cc'][] = $profile['followers']; + } + } $data['to'][] = $profile['url']; } } } - foreach ($receiver_list as $receiver) { - $contact = DBA::selectFirst('contact', ['url', 'hidden', 'network', 'protocol', 'gsid'], ['id' => $receiver, 'network' => Protocol::FEDERATED]); - if (!DBA::isResult($contact) || !self::isAPContact($contact, $networks)) { - continue; - } + if (!$exclusive) { + foreach ($receiver_list as $receiver) { + $contact = DBA::selectFirst('contact', ['url', 'hidden', 'network', 'protocol', 'gsid'], ['id' => $receiver, 'network' => Protocol::FEDERATED]); + if (!DBA::isResult($contact) || !self::isAPContact($contact, $networks)) { + continue; + } - if (!empty($profile = APContact::getByURL($contact['url'], false))) { - if ($contact['hidden'] || $always_bcc) { - $data['bcc'][] = $profile['url']; - } else { - $data['cc'][] = $profile['url']; + if (!empty($profile = APContact::getByURL($contact['url'], false))) { + if ($contact['hidden'] || $always_bcc) { + $data['bcc'][] = $profile['url']; + } else { + $data['cc'][] = $profile['url']; + } } } } From 2b0518ac04b31fd37e617723d6492149aaa7e06f Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 15 Feb 2022 06:21:46 +0000 Subject: [PATCH 08/44] unset several table fields before distribution --- src/Model/Item.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Model/Item.php b/src/Model/Item.php index fd0dbde2bf..46f41e9a93 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -1485,6 +1485,7 @@ class Item return 0; } + // Data from the "post-user" table unset($item['id']); unset($item['mention']); unset($item['starred']); @@ -1493,10 +1494,14 @@ class Item unset($item['pinned']); unset($item['ignored']); unset($item['pubmail']); - unset($item['event-id']); unset($item['hidden']); unset($item['notification-type']); + unset($item['post-reason']); + + // Data from the "post-delivery-data" table + unset($item['postopts']); + unset($item['inform']); $item['uid'] = $uid; $item['origin'] = 0; From 29d83c0ffb135a0cec8c6ad5fc2a80fbdd96683f Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 15 Feb 2022 07:08:02 +0000 Subject: [PATCH 09/44] Block communication with Diaspora for communities --- src/Model/Item.php | 9 +++++++++ src/Module/Diaspora/Receive.php | 6 ++++++ src/Protocol/Diaspora.php | 7 +------ src/Worker/Notifier.php | 2 +- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/Model/Item.php b/src/Model/Item.php index 46f41e9a93..9c67426344 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -818,6 +818,15 @@ class Item $item['inform'] = trim($item['inform'] ?? ''); $item['file'] = trim($item['file'] ?? ''); + // Communities aren't working with the Diaspora protoccol + if (($uid != 0) && ($item['network'] == Protocol::DIASPORA)) { + $user = User::getById($uid, ['account-type']); + if ($user['account-type'] == Contact::TYPE_COMMUNITY) { + Logger::info('Community posts are not supported via Diaspora'); + return 0; + } + } + // Items cannot be stored before they happen ... if ($item['created'] > DateTimeFormat::utcNow()) { $item['created'] = DateTimeFormat::utcNow(); diff --git a/src/Module/Diaspora/Receive.php b/src/Module/Diaspora/Receive.php index 498d1b13ed..19de0873ff 100644 --- a/src/Module/Diaspora/Receive.php +++ b/src/Module/Diaspora/Receive.php @@ -93,6 +93,12 @@ class Receive extends BaseModule $importer = User::getByGuid($this->parameters['guid']); + if ($importer['account-type'] == User::ACCOUNT_TYPE_COMMUNITY) { + // Communities aren't working with the Diaspora protoccol + // We throw an "accepted" here, so that the sender doesn't repeat the delivery + throw new HTTPException\AcceptedException(); + } + $msg = $this->decodePost(false, $importer['prvkey'] ?? ''); $this->logger->info('Diaspora: Dispatching.'); diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index aba79364f4..ea0b2b6749 100644 --- a/src/Protocol/Diaspora.php +++ b/src/Protocol/Diaspora.php @@ -858,10 +858,6 @@ class Diaspora } elseif (($contact["rel"] == Contact::SHARING) || ($contact["rel"] == Contact::FRIEND)) { // Yes, then it is fine. return true; - // Is it a post to a community? - } elseif (($contact["rel"] == Contact::FOLLOWER) && ($importer['account-type'] == User::ACCOUNT_TYPE_COMMUNITY)) { - // That's good - return true; // Is the message a global user or a comment? } elseif (($importer["uid"] == 0) || $is_comment) { // Messages for the global users and comments are always accepted @@ -3473,9 +3469,8 @@ class Diaspora private static function prependParentAuthorMention($body, $profile_url) { - $profile = Contact::getByURL($profile_url, false, ['addr', 'name', 'contact-type']); + $profile = Contact::getByURL($profile_url, false, ['addr', 'name']); if (!empty($profile['addr']) - && $profile['contact-type'] != Contact::TYPE_COMMUNITY && !strstr($body, $profile['addr']) && !strstr($body, $profile_url) ) { diff --git a/src/Worker/Notifier.php b/src/Worker/Notifier.php index bfd38fe01f..3a5c7f13e1 100644 --- a/src/Worker/Notifier.php +++ b/src/Worker/Notifier.php @@ -153,7 +153,7 @@ class Notifier } // Should the post be transmitted to Diaspora? - $diaspora_delivery = true; + $diaspora_delivery = ($owner['account-type'] != User::ACCOUNT_TYPE_COMMUNITY); // If this is a public conversation, notify the feed hub $public_message = true; From 9ae0234bb5cd66a00cbf5887cbddfa0fa1850125 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Tue, 15 Feb 2022 09:53:24 -0500 Subject: [PATCH 10/44] Use expected order for post medias - This fixes the wrong display order of post pictures --- src/Model/Post/Media.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Model/Post/Media.php b/src/Model/Post/Media.php index 07cad9cf6f..254b88115c 100644 --- a/src/Model/Post/Media.php +++ b/src/Model/Post/Media.php @@ -518,7 +518,7 @@ class Media $condition = DBA::mergeConditions($condition, ['type' => $types]); } - return DBA::selectToArray('post-media', [], $condition); + return DBA::selectToArray('post-media', [], $condition, ['order' => ['id']]); } /** From d019ef57d2f994f449bb48915cdbee27a2d95672 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 15 Feb 2022 15:44:44 +0000 Subject: [PATCH 11/44] Database version increased, code simplified --- database.sql | 2 +- src/Model/Item.php | 13 ++++--------- static/dbstructure.config.php | 2 +- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/database.sql b/database.sql index 308e2e8a86..a36adad015 100644 --- a/database.sql +++ b/database.sql @@ -1,6 +1,6 @@ -- ------------------------------------------ -- Friendica 2022.05-dev (Siberian Iris) --- DB_UPDATE_VERSION 1451 +-- DB_UPDATE_VERSION 1452 -- ------------------------------------------ diff --git a/src/Model/Item.php b/src/Model/Item.php index 9c67426344..96cf5c488c 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -2516,11 +2516,6 @@ class Item return true; } - $allow_cid = $allow_cid ?? $item['allow_cid']; - $allow_gid = $allow_gid ?? $item['allow_gid']; - $deny_cid = $deny_cid ?? $item['deny_cid']; - $deny_gid = $deny_gid ?? $item['deny_gid']; - $objtype = $item['resource-id'] ? Activity\ObjectType::IMAGE : Activity\ObjectType::NOTE; $new_item = [ @@ -2541,10 +2536,10 @@ class Item 'body' => $activity, 'verb' => $activity, 'object-type' => $objtype, - 'allow_cid' => $allow_cid, - 'allow_gid' => $allow_gid, - 'deny_cid' => $deny_cid, - 'deny_gid' => $deny_gid, + 'allow_cid' => $allow_cid ?? $item['allow_cid'], + 'allow_gid' => $allow_gid ?? $item['allow_gid'], + 'deny_cid' => $deny_cid ?? $item['deny_cid'], + 'deny_gid' => $deny_gid ?? $item['deny_gid'], 'visible' => 1, 'unseen' => 1, ]; diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index 01419bf2b7..f7e02b10b9 100644 --- a/static/dbstructure.config.php +++ b/static/dbstructure.config.php @@ -55,7 +55,7 @@ use Friendica\Database\DBA; if (!defined('DB_UPDATE_VERSION')) { - define('DB_UPDATE_VERSION', 1451); + define('DB_UPDATE_VERSION', 1452); } return [ From 99979019bf8782f96caffec002505a02983eacb1 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Tue, 15 Feb 2022 15:40:18 -0500 Subject: [PATCH 12/44] Expand system.accept_only_sharer pconfig value to include previous behavior with likes --- mod/settings.php | 13 ++++++++++++- src/Model/Item.php | 7 ++++++- src/Protocol/ActivityPub/Processor.php | 9 +++++++-- src/Protocol/OStatus.php | 9 ++++++--- view/templates/settings/connectors.tpl | 2 +- view/theme/frio/templates/settings/connectors.tpl | 2 +- 6 files changed, 33 insertions(+), 9 deletions(-) diff --git a/mod/settings.php b/mod/settings.php index 111e523302..6668951e8f 100644 --- a/mod/settings.php +++ b/mod/settings.php @@ -31,6 +31,7 @@ use Friendica\Core\Worker; use Friendica\Database\DBA; use Friendica\DI; use Friendica\Model\Group; +use Friendica\Model\Item; use Friendica\Model\Notification; use Friendica\Model\Profile; use Friendica\Model\User; @@ -570,7 +571,17 @@ function settings_content(App $a) '$ostat_enabled' => $ostat_enabled, '$general_settings' => DI::l10n()->t('General Social Media Settings'), - '$accept_only_sharer' => ['accept_only_sharer', DI::l10n()->t('Accept only top level posts by contacts you follow'), $accept_only_sharer, DI::l10n()->t('The system does an auto completion of threads when a comment arrives. This has got the side effect that you can receive posts that had been started by a non-follower but had been commented by someone you follow. This setting deactivates this behaviour. When activated, you strictly only will receive posts from people you really do follow.')], + '$accept_only_sharer' => [ + 'accept_only_sharer', + DI::l10n()->t('Followed content scope'), + $accept_only_sharer, + DI::l10n()->t('By default, conversations in which your follows participated but didn\'t start will be shown in your timeline. You can turn this behavior off, or expand it to the conversations in which your follows liked a post.'), + [ + Item::COMPLETION_NONE => DI::l10n()->t('Only conversations my follows started'), + Item::COMPLETION_COMMENT => DI::l10n()->t('Conversations my follows started or commented on (default)'), + Item::COMPLETION_LIKE => DI::l10n()->t('Any conversation my follows interacted with, including likes'), + ] + ], '$enable_cw' => ['enable_cw', DI::l10n()->t('Enable Content Warning'), $enable_cw, DI::l10n()->t('Users on networks like Mastodon or Pleroma are able to set a content warning field which collapse their post by default. This enables the automatic collapsing instead of setting the content warning as the post title. Doesn\'t affect any other content filtering you eventually set up.')], '$enable_smart_shortening' => ['enable_smart_shortening', DI::l10n()->t('Enable intelligent shortening'), $enable_smart_shortening, DI::l10n()->t('Normally the system tries to find the best link to add to shortened posts. If disabled, every shortened post will always point to the original friendica post.')], '$simple_shortening' => ['simple_shortening', DI::l10n()->t('Enable simple text shortening'), $simple_shortening, DI::l10n()->t('Normally the system shortens posts at the next line feed. If this option is enabled then the system will shorten the text at the maximum character limit.')], diff --git a/src/Model/Item.php b/src/Model/Item.php index 96cf5c488c..ef3ba01f43 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -74,6 +74,11 @@ class Item const PR_RELAY = 74; const PR_FETCHED = 75; + // system.accept_only_sharer setting values + const COMPLETION_NONE = 1; + const COMPLETION_COMMENT = 0; + const COMPLETION_LIKE = 2; + // Field list that is used to display the items const DISPLAY_FIELDLIST = [ 'uid', 'id', 'parent', 'guid', 'network', 'gravity', @@ -1403,7 +1408,7 @@ class Item $is_reshare = ($item['gravity'] == GRAVITY_ACTIVITY) && ($item['verb'] == Activity::ANNOUNCE); if ((($item['gravity'] == GRAVITY_PARENT) || $is_reshare) && - DI::pConfig()->get($uid, 'system', 'accept_only_sharer') && + DI::pConfig()->get($uid, 'system', 'accept_only_sharer') === self::COMPLETION_NONE && !Contact::isSharingByURL($item['author-link'], $uid) && !Contact::isSharingByURL($item['owner-link'], $uid)) { Logger::info('Contact is not a follower, thread will not be stored', ['author' => $item['author-link'], 'uid' => $uid]); diff --git a/src/Protocol/ActivityPub/Processor.php b/src/Protocol/ActivityPub/Processor.php index b7ddc09f61..f0d7251a90 100644 --- a/src/Protocol/ActivityPub/Processor.php +++ b/src/Protocol/ActivityPub/Processor.php @@ -647,7 +647,12 @@ class Processor Logger::info('Top level post via BCC from a non sharer, ignoring', ['uid' => $receiver, 'contact' => $item['contact-id']]); continue; } - if (!empty($activity['thread-children-type']) && in_array($activity['thread-children-type'], Receiver::ACTIVITY_TYPES)) { + + if ( + !empty($activity['thread-children-type']) + && in_array($activity['thread-children-type'], Receiver::ACTIVITY_TYPES) + && DI::pConfig()->get($receiver, 'system', 'accept_only_sharer', Item::COMPLETION_COMMENT) !== Item::COMPLETION_LIKE + ) { Logger::info('Top level post from thread completion from a non sharer had been initiated via an activity, ignoring', ['type' => $activity['thread-children-type'], 'user' => $item['uid'], 'causer' => $item['causer-link'], 'author' => $activity['author'], 'url' => $item['uri']]); continue; @@ -663,7 +668,7 @@ class Processor } } - if (!$is_forum && DI::pConfig()->get($receiver, 'system', 'accept_only_sharer', false) && ($receiver != 0) && ($item['gravity'] == GRAVITY_PARENT)) { + if (!$is_forum && DI::pConfig()->get($receiver, 'system', 'accept_only_sharer', Item::COMPLETION_COMMENT) === Item::COMPLETION_NONE && ($receiver != 0) && ($item['gravity'] == GRAVITY_PARENT)) { $skip = !Contact::isSharingByURL($activity['author'], $receiver); if ($skip && (($activity['type'] == 'as:Announce') || ($item['isForum'] ?? false))) { diff --git a/src/Protocol/OStatus.php b/src/Protocol/OStatus.php index 86716e9937..2b3d7cb121 100644 --- a/src/Protocol/OStatus.php +++ b/src/Protocol/OStatus.php @@ -494,19 +494,22 @@ class OStatus if ($initialize && (count(self::$itemlist) > 0)) { if (self::$itemlist[0]['uri'] == self::$itemlist[0]['thr-parent']) { + $uid = self::$itemlist[0]['uid']; // We will import it everytime, when it is started by our contacts - $valid = Contact::isSharingByURL(self::$itemlist[0]['author-link'], self::$itemlist[0]['uid']); + $valid = Contact::isSharingByURL(self::$itemlist[0]['author-link'], $uid); if (!$valid) { // If not, then it depends on this setting - $valid = ((self::$itemlist[0]['uid'] == 0) || !DI::pConfig()->get(self::$itemlist[0]['uid'], 'system', 'accept_only_sharer', false)); + $valid = !$uid || DI::pConfig()->get($uid, 'system', 'accept_only_sharer', Item::COMPLETION_COMMENT) !== Item::COMPLETION_NONE; + if ($valid) { Logger::info("Item with uri ".self::$itemlist[0]['uri']." will be imported due to the system settings."); } } else { Logger::info("Item with uri ".self::$itemlist[0]['uri']." belongs to a contact (".self::$itemlist[0]['contact-id']."). It will be imported."); } - if ($valid) { + + if ($valid && DI::pConfig()->get($uid, 'system', 'accept_only_sharer', Item::COMPLETION_COMMENT) !== Item::COMPLETION_LIKE) { // Never post a thread when the only interaction by our contact was a like $valid = false; $verbs = [Activity::POST, Activity::SHARE]; diff --git a/view/templates/settings/connectors.tpl b/view/templates/settings/connectors.tpl index 0479e99d90..8010cc982d 100644 --- a/view/templates/settings/connectors.tpl +++ b/view/templates/settings/connectors.tpl @@ -11,7 +11,7 @@
- {{include file="field_checkbox.tpl" field=$accept_only_sharer}} + {{include file="field_select.tpl" field=$accept_only_sharer}} {{include file="field_checkbox.tpl" field=$enable_cw}} From 785ea0325ec8cec2520794a96c800e29e7793d6e Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Tue, 15 Feb 2022 15:54:12 -0500 Subject: [PATCH 13/44] Updated main translation file after changing several strings --- view/lang/C/messages.po | 490 ++++++++++++++++++++-------------------- 1 file changed, 250 insertions(+), 240 deletions(-) diff --git a/view/lang/C/messages.po b/view/lang/C/messages.po index af98956ecb..2c94f270ca 100644 --- a/view/lang/C/messages.po +++ b/view/lang/C/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 2022.05-dev\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-02-10 09:02+0100\n" +"POT-Creation-Date: 2022-02-15 15:52-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -36,7 +36,7 @@ msgstr "" msgid "User not found." msgstr "" -#: mod/cal.php:120 mod/display.php:270 src/Module/Profile/Profile.php:94 +#: mod/cal.php:120 mod/display.php:238 src/Module/Profile/Profile.php:94 #: src/Module/Profile/Profile.php:109 src/Module/Profile/Status.php:109 #: src/Module/Update/Profile.php:56 msgid "Access to this profile has been restricted." @@ -103,25 +103,25 @@ msgstr "" msgid "calendar" msgstr "" -#: mod/display.php:165 mod/photos.php:808 +#: mod/display.php:133 mod/photos.php:808 #: src/Module/Conversation/Community.php:175 src/Module/Directory.php:48 #: src/Module/Search/Index.php:49 msgid "Public access denied." msgstr "" -#: mod/display.php:221 mod/display.php:295 +#: mod/display.php:189 mod/display.php:263 msgid "The requested item doesn't exist or has been deleted." msgstr "" -#: mod/display.php:375 +#: mod/display.php:343 msgid "The feed for this item is unavailable." msgstr "" #: mod/editpost.php:38 mod/events.php:220 mod/follow.php:56 mod/follow.php:130 -#: mod/item.php:185 mod/item.php:190 mod/item.php:930 mod/message.php:69 +#: mod/item.php:184 mod/item.php:189 mod/item.php:918 mod/message.php:69 #: mod/message.php:111 mod/notes.php:44 mod/ostatus_subscribe.php:32 #: mod/photos.php:160 mod/photos.php:897 mod/repair_ostatus.php:31 -#: mod/settings.php:46 mod/settings.php:56 mod/settings.php:412 +#: mod/settings.php:47 mod/settings.php:57 mod/settings.php:413 #: mod/suggest.php:34 mod/uimport.php:33 mod/unfollow.php:35 #: mod/unfollow.php:50 mod/unfollow.php:82 mod/wall_attach.php:68 #: mod/wall_attach.php:71 mod/wall_upload.php:90 mod/wall_upload.php:93 @@ -465,7 +465,7 @@ msgid "OStatus support is disabled. Contact can't be added." msgstr "" #: mod/follow.php:138 src/Content/Item.php:452 src/Content/Widget.php:76 -#: src/Model/Contact.php:1056 src/Model/Contact.php:1068 +#: src/Model/Contact.php:1057 src/Model/Contact.php:1069 #: view/theme/vier/theme.php:172 msgid "Connect/Follow" msgstr "" @@ -510,27 +510,27 @@ msgstr "" msgid "The contact could not be added." msgstr "" -#: mod/item.php:135 mod/item.php:139 +#: mod/item.php:134 mod/item.php:138 msgid "Unable to locate original post." msgstr "" -#: mod/item.php:341 mod/item.php:346 +#: mod/item.php:340 mod/item.php:345 msgid "Empty post discarded." msgstr "" -#: mod/item.php:736 +#: mod/item.php:724 msgid "Post updated." msgstr "" -#: mod/item.php:746 mod/item.php:751 +#: mod/item.php:734 mod/item.php:739 msgid "Item wasn't stored." msgstr "" -#: mod/item.php:762 +#: mod/item.php:750 msgid "Item couldn't be fetched." msgstr "" -#: mod/item.php:908 src/Module/Admin/Themes/Details.php:39 +#: mod/item.php:896 src/Module/Admin/Themes/Details.php:39 #: src/Module/Admin/Themes/Index.php:59 src/Module/Debug/ItemBody.php:41 #: src/Module/Debug/ItemBody.php:56 msgid "Item not found." @@ -1079,7 +1079,7 @@ msgstr "" msgid "Select" msgstr "" -#: mod/photos.php:1431 mod/settings.php:596 src/Content/Conversation.php:616 +#: mod/photos.php:1431 mod/settings.php:607 src/Content/Conversation.php:616 #: src/Module/Admin/Users/Active.php:139 src/Module/Admin/Users/Blocked.php:140 #: src/Module/Admin/Users/Index.php:153 msgid "Delete" @@ -1183,75 +1183,75 @@ msgid_plural "Errors" msgstr[0] "" msgstr[1] "" -#: mod/settings.php:128 +#: mod/settings.php:129 msgid "Failed to connect with email account using the settings provided." msgstr "" -#: mod/settings.php:158 +#: mod/settings.php:159 msgid "Contact CSV file upload error" msgstr "" -#: mod/settings.php:177 +#: mod/settings.php:178 msgid "Importing Contacts done" msgstr "" -#: mod/settings.php:190 +#: mod/settings.php:191 msgid "Relocate message has been send to your contacts" msgstr "" -#: mod/settings.php:202 +#: mod/settings.php:203 msgid "Passwords do not match." msgstr "" -#: mod/settings.php:210 src/Console/User.php:210 +#: mod/settings.php:211 src/Console/User.php:210 msgid "Password update failed. Please try again." msgstr "" -#: mod/settings.php:213 src/Console/User.php:213 +#: mod/settings.php:214 src/Console/User.php:213 msgid "Password changed." msgstr "" -#: mod/settings.php:216 +#: mod/settings.php:217 msgid "Password unchanged." msgstr "" -#: mod/settings.php:304 +#: mod/settings.php:305 msgid "Please use a shorter name." msgstr "" -#: mod/settings.php:307 +#: mod/settings.php:308 msgid "Name too short." msgstr "" -#: mod/settings.php:316 +#: mod/settings.php:317 msgid "Wrong Password." msgstr "" -#: mod/settings.php:321 +#: mod/settings.php:322 msgid "Invalid email." msgstr "" -#: mod/settings.php:327 +#: mod/settings.php:328 msgid "Cannot change to that email." msgstr "" -#: mod/settings.php:368 +#: mod/settings.php:369 msgid "Private forum has no privacy permissions. Using default privacy group." msgstr "" -#: mod/settings.php:371 +#: mod/settings.php:372 msgid "Private forum has no privacy permissions and no default privacy group." msgstr "" -#: mod/settings.php:390 +#: mod/settings.php:391 msgid "Settings were not updated." msgstr "" -#: mod/settings.php:431 +#: mod/settings.php:432 msgid "Connected Apps" msgstr "" -#: mod/settings.php:432 src/Module/Admin/Blocklist/Contact.php:106 +#: mod/settings.php:433 src/Module/Admin/Blocklist/Contact.php:106 #: src/Module/Admin/Users/Active.php:129 src/Module/Admin/Users/Blocked.php:130 #: src/Module/Admin/Users/Create.php:71 src/Module/Admin/Users/Deleted.php:88 #: src/Module/Admin/Users/Index.php:142 src/Module/Admin/Users/Index.php:162 @@ -1259,20 +1259,20 @@ msgstr "" msgid "Name" msgstr "" -#: mod/settings.php:433 src/Content/Nav.php:212 +#: mod/settings.php:434 src/Content/Nav.php:212 msgid "Home Page" msgstr "" -#: mod/settings.php:434 src/Module/Admin/Queue.php:78 +#: mod/settings.php:435 src/Module/Admin/Queue.php:78 msgid "Created" msgstr "" -#: mod/settings.php:435 +#: mod/settings.php:436 msgid "Remove authorization" msgstr "" -#: mod/settings.php:461 mod/settings.php:493 mod/settings.php:524 -#: mod/settings.php:598 mod/settings.php:735 +#: mod/settings.php:462 mod/settings.php:494 mod/settings.php:525 +#: mod/settings.php:609 mod/settings.php:746 #: src/Module/Admin/Addons/Index.php:69 src/Module/Admin/Features.php:87 #: src/Module/Admin/Logs/Settings.php:81 src/Module/Admin/Site.php:501 #: src/Module/Admin/Themes/Index.php:113 src/Module/Admin/Tos.php:83 @@ -1280,73 +1280,83 @@ msgstr "" msgid "Save Settings" msgstr "" -#: mod/settings.php:469 +#: mod/settings.php:470 msgid "Addon Settings" msgstr "" -#: mod/settings.php:470 +#: mod/settings.php:471 msgid "No Addon settings configured" msgstr "" -#: mod/settings.php:491 +#: mod/settings.php:492 msgid "Additional Features" msgstr "" -#: mod/settings.php:529 +#: mod/settings.php:530 msgid "Diaspora (Socialhome, Hubzilla)" msgstr "" -#: mod/settings.php:529 mod/settings.php:530 +#: mod/settings.php:530 mod/settings.php:531 msgid "enabled" msgstr "" -#: mod/settings.php:529 mod/settings.php:530 +#: mod/settings.php:530 mod/settings.php:531 msgid "disabled" msgstr "" -#: mod/settings.php:529 mod/settings.php:530 +#: mod/settings.php:530 mod/settings.php:531 #, php-format msgid "Built-in support for %s connectivity is %s" msgstr "" -#: mod/settings.php:530 +#: mod/settings.php:531 msgid "OStatus (GNU Social)" msgstr "" -#: mod/settings.php:556 +#: mod/settings.php:557 msgid "Email access is disabled on this site." msgstr "" -#: mod/settings.php:561 mod/settings.php:596 +#: mod/settings.php:562 mod/settings.php:607 msgid "None" msgstr "" -#: mod/settings.php:567 src/Module/BaseSettings.php:78 +#: mod/settings.php:568 src/Module/BaseSettings.php:78 msgid "Social Networks" msgstr "" -#: mod/settings.php:572 +#: mod/settings.php:573 msgid "General Social Media Settings" msgstr "" -#: mod/settings.php:573 -msgid "Accept only top level posts by contacts you follow" +#: mod/settings.php:576 +msgid "Followed content scope" msgstr "" -#: mod/settings.php:573 +#: mod/settings.php:578 msgid "" -"The system does an auto completion of threads when a comment arrives. This " -"has got the side effect that you can receive posts that had been started by " -"a non-follower but had been commented by someone you follow. This setting " -"deactivates this behaviour. When activated, you strictly only will receive " -"posts from people you really do follow." +"By default, conversations in which your follows participated but didn't " +"start will be shown in your timeline. You can turn this behavior off, or " +"expand it to the conversations in which your follows liked a post." msgstr "" -#: mod/settings.php:574 +#: mod/settings.php:580 +msgid "Only conversations my follows started" +msgstr "" + +#: mod/settings.php:581 +msgid "Conversations my follows started or commented on (default)" +msgstr "" + +#: mod/settings.php:582 +msgid "Any conversation my follows interacted with, including likes" +msgstr "" + +#: mod/settings.php:585 msgid "Enable Content Warning" msgstr "" -#: mod/settings.php:574 +#: mod/settings.php:585 msgid "" "Users on networks like Mastodon or Pleroma are able to set a content warning " "field which collapse their post by default. This enables the automatic " @@ -1354,222 +1364,222 @@ msgid "" "affect any other content filtering you eventually set up." msgstr "" -#: mod/settings.php:575 +#: mod/settings.php:586 msgid "Enable intelligent shortening" msgstr "" -#: mod/settings.php:575 +#: mod/settings.php:586 msgid "" "Normally the system tries to find the best link to add to shortened posts. " "If disabled, every shortened post will always point to the original " "friendica post." msgstr "" -#: mod/settings.php:576 +#: mod/settings.php:587 msgid "Enable simple text shortening" msgstr "" -#: mod/settings.php:576 +#: mod/settings.php:587 msgid "" "Normally the system shortens posts at the next line feed. If this option is " "enabled then the system will shorten the text at the maximum character limit." msgstr "" -#: mod/settings.php:577 +#: mod/settings.php:588 msgid "Attach the link title" msgstr "" -#: mod/settings.php:577 +#: mod/settings.php:588 msgid "" "When activated, the title of the attached link will be added as a title on " "posts to Diaspora. This is mostly helpful with \"remote-self\" contacts that " "share feed content." msgstr "" -#: mod/settings.php:578 +#: mod/settings.php:589 msgid "Your legacy ActivityPub/GNU Social account" msgstr "" -#: mod/settings.php:578 +#: mod/settings.php:589 msgid "" "If you enter your old account name from an ActivityPub based system or your " "GNU Social/Statusnet account name here (in the format user@domain.tld), your " "contacts will be added automatically. The field will be emptied when done." msgstr "" -#: mod/settings.php:581 +#: mod/settings.php:592 msgid "Repair OStatus subscriptions" msgstr "" -#: mod/settings.php:585 +#: mod/settings.php:596 msgid "Email/Mailbox Setup" msgstr "" -#: mod/settings.php:586 +#: mod/settings.php:597 msgid "" "If you wish to communicate with email contacts using this service " "(optional), please specify how to connect to your mailbox." msgstr "" -#: mod/settings.php:587 +#: mod/settings.php:598 msgid "Last successful email check:" msgstr "" -#: mod/settings.php:589 +#: mod/settings.php:600 msgid "IMAP server name:" msgstr "" -#: mod/settings.php:590 +#: mod/settings.php:601 msgid "IMAP port:" msgstr "" -#: mod/settings.php:591 +#: mod/settings.php:602 msgid "Security:" msgstr "" -#: mod/settings.php:592 +#: mod/settings.php:603 msgid "Email login name:" msgstr "" -#: mod/settings.php:593 +#: mod/settings.php:604 msgid "Email password:" msgstr "" -#: mod/settings.php:594 +#: mod/settings.php:605 msgid "Reply-to address:" msgstr "" -#: mod/settings.php:595 +#: mod/settings.php:606 msgid "Send public posts to all email contacts:" msgstr "" -#: mod/settings.php:596 +#: mod/settings.php:607 msgid "Action after import:" msgstr "" -#: mod/settings.php:596 src/Content/Nav.php:280 +#: mod/settings.php:607 src/Content/Nav.php:280 msgid "Mark as seen" msgstr "" -#: mod/settings.php:596 +#: mod/settings.php:607 msgid "Move to folder" msgstr "" -#: mod/settings.php:597 +#: mod/settings.php:608 msgid "Move to folder:" msgstr "" -#: mod/settings.php:611 +#: mod/settings.php:622 msgid "Unable to find your profile. Please contact your admin." msgstr "" -#: mod/settings.php:649 src/Content/Widget.php:526 +#: mod/settings.php:660 src/Content/Widget.php:526 msgid "Account Types" msgstr "" -#: mod/settings.php:650 +#: mod/settings.php:661 msgid "Personal Page Subtypes" msgstr "" -#: mod/settings.php:651 +#: mod/settings.php:662 msgid "Community Forum Subtypes" msgstr "" -#: mod/settings.php:658 src/Module/Admin/BaseUsers.php:107 +#: mod/settings.php:669 src/Module/Admin/BaseUsers.php:107 msgid "Personal Page" msgstr "" -#: mod/settings.php:659 +#: mod/settings.php:670 msgid "Account for a personal profile." msgstr "" -#: mod/settings.php:662 src/Module/Admin/BaseUsers.php:108 +#: mod/settings.php:673 src/Module/Admin/BaseUsers.php:108 msgid "Organisation Page" msgstr "" -#: mod/settings.php:663 +#: mod/settings.php:674 msgid "" "Account for an organisation that automatically approves contact requests as " "\"Followers\"." msgstr "" -#: mod/settings.php:666 src/Module/Admin/BaseUsers.php:109 +#: mod/settings.php:677 src/Module/Admin/BaseUsers.php:109 msgid "News Page" msgstr "" -#: mod/settings.php:667 +#: mod/settings.php:678 msgid "" "Account for a news reflector that automatically approves contact requests as " "\"Followers\"." msgstr "" -#: mod/settings.php:670 src/Module/Admin/BaseUsers.php:110 +#: mod/settings.php:681 src/Module/Admin/BaseUsers.php:110 msgid "Community Forum" msgstr "" -#: mod/settings.php:671 +#: mod/settings.php:682 msgid "Account for community discussions." msgstr "" -#: mod/settings.php:674 src/Module/Admin/BaseUsers.php:100 +#: mod/settings.php:685 src/Module/Admin/BaseUsers.php:100 msgid "Normal Account Page" msgstr "" -#: mod/settings.php:675 +#: mod/settings.php:686 msgid "" "Account for a regular personal profile that requires manual approval of " "\"Friends\" and \"Followers\"." msgstr "" -#: mod/settings.php:678 src/Module/Admin/BaseUsers.php:101 +#: mod/settings.php:689 src/Module/Admin/BaseUsers.php:101 msgid "Soapbox Page" msgstr "" -#: mod/settings.php:679 +#: mod/settings.php:690 msgid "" "Account for a public profile that automatically approves contact requests as " "\"Followers\"." msgstr "" -#: mod/settings.php:682 src/Module/Admin/BaseUsers.php:102 +#: mod/settings.php:693 src/Module/Admin/BaseUsers.php:102 msgid "Public Forum" msgstr "" -#: mod/settings.php:683 +#: mod/settings.php:694 msgid "Automatically approves all contact requests." msgstr "" -#: mod/settings.php:686 src/Module/Admin/BaseUsers.php:103 +#: mod/settings.php:697 src/Module/Admin/BaseUsers.php:103 msgid "Automatic Friend Page" msgstr "" -#: mod/settings.php:687 +#: mod/settings.php:698 msgid "" "Account for a popular profile that automatically approves contact requests " "as \"Friends\"." msgstr "" -#: mod/settings.php:690 +#: mod/settings.php:701 msgid "Private Forum [Experimental]" msgstr "" -#: mod/settings.php:691 +#: mod/settings.php:702 msgid "Requires manual approval of contact requests." msgstr "" -#: mod/settings.php:702 +#: mod/settings.php:713 msgid "OpenID:" msgstr "" -#: mod/settings.php:702 +#: mod/settings.php:713 msgid "(Optional) Allow this OpenID to login to this account." msgstr "" -#: mod/settings.php:710 +#: mod/settings.php:721 msgid "Publish your profile in your local site directory?" msgstr "" -#: mod/settings.php:710 +#: mod/settings.php:721 #, php-format msgid "" "Your profile will be published in this node's local " @@ -1577,115 +1587,115 @@ msgid "" "system settings." msgstr "" -#: mod/settings.php:716 +#: mod/settings.php:727 #, php-format msgid "" "Your profile will also be published in the global friendica directories (e." "g. %s)." msgstr "" -#: mod/settings.php:722 +#: mod/settings.php:733 #, php-format msgid "Your Identity Address is '%s' or '%s'." msgstr "" -#: mod/settings.php:733 +#: mod/settings.php:744 msgid "Account Settings" msgstr "" -#: mod/settings.php:741 +#: mod/settings.php:752 msgid "Password Settings" msgstr "" -#: mod/settings.php:742 src/Module/Register.php:162 +#: mod/settings.php:753 src/Module/Register.php:162 msgid "New Password:" msgstr "" -#: mod/settings.php:742 +#: mod/settings.php:753 msgid "" "Allowed characters are a-z, A-Z, 0-9 and special characters except white " "spaces, accentuated letters and colon (:)." msgstr "" -#: mod/settings.php:743 src/Module/Register.php:163 +#: mod/settings.php:754 src/Module/Register.php:163 msgid "Confirm:" msgstr "" -#: mod/settings.php:743 +#: mod/settings.php:754 msgid "Leave password fields blank unless changing" msgstr "" -#: mod/settings.php:744 +#: mod/settings.php:755 msgid "Current Password:" msgstr "" -#: mod/settings.php:744 +#: mod/settings.php:755 msgid "Your current password to confirm the changes" msgstr "" -#: mod/settings.php:745 +#: mod/settings.php:756 msgid "Password:" msgstr "" -#: mod/settings.php:745 +#: mod/settings.php:756 msgid "Your current password to confirm the changes of the email address" msgstr "" -#: mod/settings.php:748 +#: mod/settings.php:759 msgid "Delete OpenID URL" msgstr "" -#: mod/settings.php:750 +#: mod/settings.php:761 msgid "Basic Settings" msgstr "" -#: mod/settings.php:751 src/Module/Profile/Profile.php:144 +#: mod/settings.php:762 src/Module/Profile/Profile.php:144 msgid "Full Name:" msgstr "" -#: mod/settings.php:752 +#: mod/settings.php:763 msgid "Email Address:" msgstr "" -#: mod/settings.php:753 +#: mod/settings.php:764 msgid "Your Timezone:" msgstr "" -#: mod/settings.php:754 +#: mod/settings.php:765 msgid "Your Language:" msgstr "" -#: mod/settings.php:754 +#: mod/settings.php:765 msgid "" "Set the language we use to show you friendica interface and to send you " "emails" msgstr "" -#: mod/settings.php:755 +#: mod/settings.php:766 msgid "Default Post Location:" msgstr "" -#: mod/settings.php:756 +#: mod/settings.php:767 msgid "Use Browser Location:" msgstr "" -#: mod/settings.php:758 +#: mod/settings.php:769 msgid "Security and Privacy Settings" msgstr "" -#: mod/settings.php:760 +#: mod/settings.php:771 msgid "Maximum Friend Requests/Day:" msgstr "" -#: mod/settings.php:760 mod/settings.php:770 +#: mod/settings.php:771 mod/settings.php:781 msgid "(to prevent spam abuse)" msgstr "" -#: mod/settings.php:762 +#: mod/settings.php:773 msgid "Allow your profile to be searchable globally?" msgstr "" -#: mod/settings.php:762 +#: mod/settings.php:773 msgid "" "Activate this setting if you want others to easily find and follow you. Your " "profile will be searchable on remote systems. This setting also determines " @@ -1693,43 +1703,43 @@ msgid "" "indexed or not." msgstr "" -#: mod/settings.php:763 +#: mod/settings.php:774 msgid "Hide your contact/friend list from viewers of your profile?" msgstr "" -#: mod/settings.php:763 +#: mod/settings.php:774 msgid "" "A list of your contacts is displayed on your profile page. Activate this " "option to disable the display of your contact list." msgstr "" -#: mod/settings.php:764 +#: mod/settings.php:775 msgid "Hide your profile details from anonymous viewers?" msgstr "" -#: mod/settings.php:764 +#: mod/settings.php:775 msgid "" "Anonymous visitors will only see your profile picture, your display name and " "the nickname you are using on your profile page. Your public posts and " "replies will still be accessible by other means." msgstr "" -#: mod/settings.php:765 +#: mod/settings.php:776 msgid "Make public posts unlisted" msgstr "" -#: mod/settings.php:765 +#: mod/settings.php:776 msgid "" "Your public posts will not appear on the community pages or in search " "results, nor be sent to relay servers. However they can still appear on " "public feeds on remote servers." msgstr "" -#: mod/settings.php:766 +#: mod/settings.php:777 msgid "Make all posted pictures accessible" msgstr "" -#: mod/settings.php:766 +#: mod/settings.php:777 msgid "" "This option makes every posted picture accessible via the direct link. This " "is a workaround for the problem that most other networks can't handle " @@ -1737,221 +1747,221 @@ msgid "" "public on your photo albums though." msgstr "" -#: mod/settings.php:767 +#: mod/settings.php:778 msgid "Allow friends to post to your profile page?" msgstr "" -#: mod/settings.php:767 +#: mod/settings.php:778 msgid "" "Your contacts may write posts on your profile wall. These posts will be " "distributed to your contacts" msgstr "" -#: mod/settings.php:768 +#: mod/settings.php:779 msgid "Allow friends to tag your posts?" msgstr "" -#: mod/settings.php:768 +#: mod/settings.php:779 msgid "Your contacts can add additional tags to your posts." msgstr "" -#: mod/settings.php:769 +#: mod/settings.php:780 msgid "Permit unknown people to send you private mail?" msgstr "" -#: mod/settings.php:769 +#: mod/settings.php:780 msgid "" "Friendica network users may send you private messages even if they are not " "in your contact list." msgstr "" -#: mod/settings.php:770 +#: mod/settings.php:781 msgid "Maximum private messages per day from unknown people:" msgstr "" -#: mod/settings.php:772 +#: mod/settings.php:783 msgid "Default Post Permissions" msgstr "" -#: mod/settings.php:776 +#: mod/settings.php:787 msgid "Expiration settings" msgstr "" -#: mod/settings.php:777 +#: mod/settings.php:788 msgid "Automatically expire posts after this many days:" msgstr "" -#: mod/settings.php:777 +#: mod/settings.php:788 msgid "If empty, posts will not expire. Expired posts will be deleted" msgstr "" -#: mod/settings.php:778 +#: mod/settings.php:789 msgid "Expire posts" msgstr "" -#: mod/settings.php:778 +#: mod/settings.php:789 msgid "When activated, posts and comments will be expired." msgstr "" -#: mod/settings.php:779 +#: mod/settings.php:790 msgid "Expire personal notes" msgstr "" -#: mod/settings.php:779 +#: mod/settings.php:790 msgid "" "When activated, the personal notes on your profile page will be expired." msgstr "" -#: mod/settings.php:780 +#: mod/settings.php:791 msgid "Expire starred posts" msgstr "" -#: mod/settings.php:780 +#: mod/settings.php:791 msgid "" "Starring posts keeps them from being expired. That behaviour is overwritten " "by this setting." msgstr "" -#: mod/settings.php:781 +#: mod/settings.php:792 msgid "Expire photos" msgstr "" -#: mod/settings.php:781 +#: mod/settings.php:792 msgid "When activated, photos will be expired." msgstr "" -#: mod/settings.php:782 +#: mod/settings.php:793 msgid "Only expire posts by others" msgstr "" -#: mod/settings.php:782 +#: mod/settings.php:793 msgid "" "When activated, your own posts never expire. Then the settings above are " "only valid for posts you received." msgstr "" -#: mod/settings.php:785 +#: mod/settings.php:796 msgid "Notification Settings" msgstr "" -#: mod/settings.php:786 +#: mod/settings.php:797 msgid "Send a notification email when:" msgstr "" -#: mod/settings.php:787 +#: mod/settings.php:798 msgid "You receive an introduction" msgstr "" -#: mod/settings.php:788 +#: mod/settings.php:799 msgid "Your introductions are confirmed" msgstr "" -#: mod/settings.php:789 +#: mod/settings.php:800 msgid "Someone writes on your profile wall" msgstr "" -#: mod/settings.php:790 +#: mod/settings.php:801 msgid "Someone writes a followup comment" msgstr "" -#: mod/settings.php:791 +#: mod/settings.php:802 msgid "You receive a private message" msgstr "" -#: mod/settings.php:792 +#: mod/settings.php:803 msgid "You receive a friend suggestion" msgstr "" -#: mod/settings.php:793 +#: mod/settings.php:804 msgid "You are tagged in a post" msgstr "" -#: mod/settings.php:794 +#: mod/settings.php:805 msgid "You are poked/prodded/etc. in a post" msgstr "" -#: mod/settings.php:796 +#: mod/settings.php:807 msgid "Create a desktop notification when:" msgstr "" -#: mod/settings.php:797 +#: mod/settings.php:808 msgid "Someone liked your content" msgstr "" -#: mod/settings.php:798 +#: mod/settings.php:809 msgid "Someone shared your content" msgstr "" -#: mod/settings.php:800 +#: mod/settings.php:811 msgid "Activate desktop notifications" msgstr "" -#: mod/settings.php:800 +#: mod/settings.php:811 msgid "Show desktop popup on new notifications" msgstr "" -#: mod/settings.php:802 +#: mod/settings.php:813 msgid "Text-only notification emails" msgstr "" -#: mod/settings.php:804 +#: mod/settings.php:815 msgid "Send text only notification emails, without the html part" msgstr "" -#: mod/settings.php:806 +#: mod/settings.php:817 msgid "Show detailled notifications" msgstr "" -#: mod/settings.php:808 +#: mod/settings.php:819 msgid "" "Per default, notifications are condensed to a single notification per item. " "When enabled every notification is displayed." msgstr "" -#: mod/settings.php:810 +#: mod/settings.php:821 msgid "Show notifications of ignored contacts" msgstr "" -#: mod/settings.php:812 +#: mod/settings.php:823 msgid "" "You don't see posts from ignored contacts. But you still see their comments. " "This setting controls if you want to still receive regular notifications " "that are caused by ignored contacts or not." msgstr "" -#: mod/settings.php:814 +#: mod/settings.php:825 msgid "Advanced Account/Page Type Settings" msgstr "" -#: mod/settings.php:815 +#: mod/settings.php:826 msgid "Change the behaviour of this account for special situations" msgstr "" -#: mod/settings.php:818 +#: mod/settings.php:829 msgid "Import Contacts" msgstr "" -#: mod/settings.php:819 +#: mod/settings.php:830 msgid "" "Upload a CSV file that contains the handle of your followed accounts in the " "first column you exported from the old account." msgstr "" -#: mod/settings.php:820 +#: mod/settings.php:831 msgid "Upload File" msgstr "" -#: mod/settings.php:822 +#: mod/settings.php:833 msgid "Relocate" msgstr "" -#: mod/settings.php:823 +#: mod/settings.php:834 msgid "" "If you have moved this profile from another server, and some of your " "contacts don't receive your updates, try pushing this button." msgstr "" -#: mod/settings.php:824 +#: mod/settings.php:835 msgid "Resend relocate message to contacts" msgstr "" @@ -1965,7 +1975,7 @@ msgstr "" msgid "Friend Suggestions" msgstr "" -#: mod/tagger.php:78 src/Content/Item.php:335 src/Model/Item.php:2620 +#: mod/tagger.php:78 src/Content/Item.php:335 src/Model/Item.php:2662 msgid "photo" msgstr "" @@ -2719,7 +2729,7 @@ msgstr "" msgid "%1$s poked %2$s" msgstr "" -#: src/Content/Item.php:327 src/Model/Item.php:2618 +#: src/Content/Item.php:327 src/Model/Item.php:2660 msgid "event" msgstr "" @@ -2727,31 +2737,31 @@ msgstr "" msgid "Follow Thread" msgstr "" -#: src/Content/Item.php:432 src/Model/Contact.php:1061 +#: src/Content/Item.php:432 src/Model/Contact.php:1062 msgid "View Status" msgstr "" -#: src/Content/Item.php:433 src/Content/Item.php:455 src/Model/Contact.php:995 -#: src/Model/Contact.php:1053 src/Model/Contact.php:1062 +#: src/Content/Item.php:433 src/Content/Item.php:455 src/Model/Contact.php:996 +#: src/Model/Contact.php:1054 src/Model/Contact.php:1063 #: src/Module/Directory.php:157 src/Module/Settings/Profile/Index.php:225 msgid "View Profile" msgstr "" -#: src/Content/Item.php:434 src/Model/Contact.php:1063 +#: src/Content/Item.php:434 src/Model/Contact.php:1064 msgid "View Photos" msgstr "" -#: src/Content/Item.php:435 src/Model/Contact.php:1054 -#: src/Model/Contact.php:1064 +#: src/Content/Item.php:435 src/Model/Contact.php:1055 +#: src/Model/Contact.php:1065 msgid "Network Posts" msgstr "" -#: src/Content/Item.php:436 src/Model/Contact.php:1055 -#: src/Model/Contact.php:1065 +#: src/Content/Item.php:436 src/Model/Contact.php:1056 +#: src/Model/Contact.php:1066 msgid "View Contact" msgstr "" -#: src/Content/Item.php:437 src/Model/Contact.php:1066 +#: src/Content/Item.php:437 src/Model/Contact.php:1067 msgid "Send PM" msgstr "" @@ -2774,7 +2784,7 @@ msgstr "" msgid "Languages" msgstr "" -#: src/Content/Item.php:447 src/Model/Contact.php:1067 +#: src/Content/Item.php:447 src/Model/Contact.php:1068 msgid "Poke" msgstr "" @@ -3070,8 +3080,8 @@ msgid "" "%2$s %3$s" msgstr "" -#: src/Content/Text/BBCode.php:1185 src/Model/Item.php:3149 -#: src/Model/Item.php:3155 src/Model/Item.php:3156 +#: src/Content/Text/BBCode.php:1185 src/Model/Item.php:3191 +#: src/Model/Item.php:3197 src/Model/Item.php:3198 msgid "Link to source" msgstr "" @@ -3226,7 +3236,7 @@ msgstr "" msgid "Organisations" msgstr "" -#: src/Content/Widget.php:522 src/Model/Contact.php:1471 +#: src/Content/Widget.php:522 src/Model/Contact.php:1472 msgid "News" msgstr "" @@ -4049,81 +4059,81 @@ msgstr "" msgid "Legacy module file not found: %s" msgstr "" -#: src/Model/Contact.php:1057 src/Model/Contact.php:1069 +#: src/Model/Contact.php:1058 src/Model/Contact.php:1070 msgid "UnFollow" msgstr "" -#: src/Model/Contact.php:1075 src/Module/Admin/Users/Pending.php:107 +#: src/Model/Contact.php:1076 src/Module/Admin/Users/Pending.php:107 #: src/Module/Notifications/Introductions.php:130 #: src/Module/Notifications/Introductions.php:202 msgid "Approve" msgstr "" -#: src/Model/Contact.php:1467 +#: src/Model/Contact.php:1468 msgid "Organisation" msgstr "" -#: src/Model/Contact.php:1475 +#: src/Model/Contact.php:1476 msgid "Forum" msgstr "" -#: src/Model/Contact.php:2410 +#: src/Model/Contact.php:2411 msgid "Disallowed profile URL." msgstr "" -#: src/Model/Contact.php:2415 src/Module/Friendica.php:81 +#: src/Model/Contact.php:2416 src/Module/Friendica.php:81 msgid "Blocked domain" msgstr "" -#: src/Model/Contact.php:2420 +#: src/Model/Contact.php:2421 msgid "Connect URL missing." msgstr "" -#: src/Model/Contact.php:2429 +#: src/Model/Contact.php:2430 msgid "" "The contact could not be added. Please check the relevant network " "credentials in your Settings -> Social Networks page." msgstr "" -#: src/Model/Contact.php:2466 +#: src/Model/Contact.php:2467 msgid "The profile address specified does not provide adequate information." msgstr "" -#: src/Model/Contact.php:2468 +#: src/Model/Contact.php:2469 msgid "No compatible communication protocols or feeds were discovered." msgstr "" -#: src/Model/Contact.php:2471 +#: src/Model/Contact.php:2472 msgid "An author or name was not found." msgstr "" -#: src/Model/Contact.php:2474 +#: src/Model/Contact.php:2475 msgid "No browser URL could be matched to this address." msgstr "" -#: src/Model/Contact.php:2477 +#: src/Model/Contact.php:2478 msgid "" "Unable to match @-style Identity Address with a known protocol or email " "contact." msgstr "" -#: src/Model/Contact.php:2478 +#: src/Model/Contact.php:2479 msgid "Use mailto: in front of address to force email check." msgstr "" -#: src/Model/Contact.php:2484 +#: src/Model/Contact.php:2485 msgid "" "The profile address specified belongs to a network which has been disabled " "on this site." msgstr "" -#: src/Model/Contact.php:2489 +#: src/Model/Contact.php:2490 msgid "" "Limited profile. This person will be unable to receive direct/personal " "notifications from you." msgstr "" -#: src/Model/Contact.php:2548 +#: src/Model/Contact.php:2549 msgid "Unable to retrieve contact information." msgstr "" @@ -4243,33 +4253,33 @@ msgstr "" msgid "Edit groups" msgstr "" -#: src/Model/Item.php:1691 +#: src/Model/Item.php:1751 #, php-format msgid "Detected languages in this post:\\n%s" msgstr "" -#: src/Model/Item.php:2622 +#: src/Model/Item.php:2664 msgid "activity" msgstr "" -#: src/Model/Item.php:2624 +#: src/Model/Item.php:2666 msgid "comment" msgstr "" -#: src/Model/Item.php:2627 +#: src/Model/Item.php:2669 msgid "post" msgstr "" -#: src/Model/Item.php:2764 +#: src/Model/Item.php:2806 #, php-format msgid "Content warning: %s" msgstr "" -#: src/Model/Item.php:3114 +#: src/Model/Item.php:3156 msgid "bytes" msgstr "" -#: src/Model/Item.php:3143 src/Model/Item.php:3144 +#: src/Model/Item.php:3185 src/Model/Item.php:3186 msgid "View on separate page" msgstr "" @@ -8651,19 +8661,19 @@ msgstr "" #: src/Module/Profile/Profile.php:326 src/Module/Profile/Profile.php:329 #: src/Module/Profile/Status.php:65 src/Module/Profile/Status.php:68 -#: src/Protocol/Feed.php:990 src/Protocol/OStatus.php:1242 +#: src/Protocol/Feed.php:990 src/Protocol/OStatus.php:1245 #, php-format msgid "%s's timeline" msgstr "" #: src/Module/Profile/Profile.php:327 src/Module/Profile/Status.php:66 -#: src/Protocol/Feed.php:994 src/Protocol/OStatus.php:1246 +#: src/Protocol/Feed.php:994 src/Protocol/OStatus.php:1249 #, php-format msgid "%s's posts" msgstr "" #: src/Module/Profile/Profile.php:328 src/Module/Profile/Status.php:67 -#: src/Protocol/Feed.php:997 src/Protocol/OStatus.php:1249 +#: src/Protocol/Feed.php:997 src/Protocol/OStatus.php:1252 #, php-format msgid "%s's comments" msgstr "" @@ -10593,21 +10603,21 @@ msgstr "" msgid "Show fewer" msgstr "" -#: src/Protocol/OStatus.php:1645 +#: src/Protocol/OStatus.php:1648 #, php-format msgid "%s is now following %s." msgstr "" -#: src/Protocol/OStatus.php:1646 +#: src/Protocol/OStatus.php:1649 msgid "following" msgstr "" -#: src/Protocol/OStatus.php:1649 +#: src/Protocol/OStatus.php:1652 #, php-format msgid "%s stopped following %s." msgstr "" -#: src/Protocol/OStatus.php:1650 +#: src/Protocol/OStatus.php:1653 msgid "stopped following" msgstr "" @@ -10726,7 +10736,7 @@ msgstr "" msgid "%1$d %2$s ago" msgstr "" -#: src/Worker/Delivery.php:525 +#: src/Worker/Delivery.php:524 msgid "(no subject)" msgstr "" From 3b6c40e2e6ad59f09daef08cf09366c844edd23a Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Tue, 15 Feb 2022 15:59:35 -0500 Subject: [PATCH 14/44] Check the existence of the `uid` field before accessing it in Module\Photo - Address https://github.com/friendica/friendica/issues/11218#issuecomment-1039512291 --- src/Module/Photo.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Module/Photo.php b/src/Module/Photo.php index c67520b554..3d3110fd8b 100644 --- a/src/Module/Photo.php +++ b/src/Module/Photo.php @@ -288,9 +288,10 @@ class Photo extends BaseModule } } - If (($contact['uid'] != 0) && empty($contact['photo']) && empty($contact['avatar'])) { + if (!empty($contact['uid']) && empty($contact['photo']) && empty($contact['avatar'])) { $contact = Contact::getByURL($contact['url'], false, ['avatar', 'photo', 'xmpp', 'addr']); } + if (!empty($contact['photo']) && !empty($contact['avatar'])) { // Fetch photo directly $resourceid = MPhoto::ridFromURI($contact['photo']); From 4e58c6981cf1e57ed0d07dfb174b6f27ef0736e3 Mon Sep 17 00:00:00 2001 From: Philipp Date: Tue, 15 Feb 2022 23:04:43 +0100 Subject: [PATCH 15/44] Don't use empty, but not null values for redis password and port --- src/Core/Cache/Type/RedisCache.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Core/Cache/Type/RedisCache.php b/src/Core/Cache/Type/RedisCache.php index a58936cfc9..a3a5cf7c84 100644 --- a/src/Core/Cache/Type/RedisCache.php +++ b/src/Core/Cache/Type/RedisCache.php @@ -59,13 +59,13 @@ class RedisCache extends AbstractCache implements ICanCacheInMemory $redis_pw = $config->get('system', 'redis_password'); $redis_db = $config->get('system', 'redis_db', 0); - if (isset($redis_port) && !@$this->redis->connect($redis_host, $redis_port)) { + if (!empty($redis_port) && !@$this->redis->connect($redis_host, $redis_port)) { throw new CachePersistenceException('Expected Redis server at ' . $redis_host . ':' . $redis_port . ' isn\'t available'); } elseif (!@$this->redis->connect($redis_host)) { throw new CachePersistenceException('Expected Redis server at ' . $redis_host . ' isn\'t available'); } - if (isset($redis_pw) && !$this->redis->auth($redis_pw)) { + if (!empty($redis_pw) && !$this->redis->auth($redis_pw)) { throw new CachePersistenceException('Cannot authenticate redis server at ' . $redis_host . ':' . $redis_port); } From be240ca5000fa1bd3dd316d2dc7ad34ac53aa4d8 Mon Sep 17 00:00:00 2001 From: Philipp Date: Tue, 15 Feb 2022 23:10:41 +0100 Subject: [PATCH 16/44] Config Console Show 'NULL' for null-values --- src/Console/Config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Console/Config.php b/src/Console/Config.php index 0a38f607f4..e32983a68a 100644 --- a/src/Console/Config.php +++ b/src/Console/Config.php @@ -151,7 +151,7 @@ HELP; $this->out("{$cat}.{$key}[{$k}] => " . (is_array($v) ? implode(', ', $v) : $v)); } } else { - $this->out("{$cat}.{$key} => " . $value); + $this->out("{$cat}.{$key} => " . ($value ?? 'NULL')); } } From c4e40734df1ff39a4f5be5deeae57db5a39df973 Mon Sep 17 00:00:00 2001 From: Philipp Date: Tue, 15 Feb 2022 23:17:40 +0100 Subject: [PATCH 17/44] adapt test --- tests/src/Console/ConfigConsoleTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/src/Console/ConfigConsoleTest.php b/tests/src/Console/ConfigConsoleTest.php index dd7925ed92..eae6227251 100644 --- a/tests/src/Console/ConfigConsoleTest.php +++ b/tests/src/Console/ConfigConsoleTest.php @@ -102,7 +102,7 @@ class ConfigConsoleTest extends ConsoleTest $console->setArgument(0, 'config'); $console->setArgument(1, 'test'); $txt = $this->dumpExecute($console); - self::assertEquals("config.test => \n", $txt); + self::assertEquals("config.test => NULL\n", $txt); } public function testSetArrayValue() From 33edfc6a5fd86ddb7486b36a66fa27f00edbb634 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 15 Feb 2022 23:51:13 +0000 Subject: [PATCH 18/44] Fix for private communities --- src/Model/Item.php | 36 +++++++++++++++++++----------- src/Module/ActivityPub/Objects.php | 25 ++++++--------------- 2 files changed, 30 insertions(+), 31 deletions(-) diff --git a/src/Model/Item.php b/src/Model/Item.php index 96cf5c488c..69a967b2c4 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -1442,26 +1442,36 @@ class Item } $post = Post::selectFirst(['uid', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', 'private'], ['uri-id' => $uriid, 'origin' => true]); - if (empty($post)) { - if (Post::exists(['uri-id' => $uriid, 'uid' => 0])) { - return 0; - } else { + if (!empty($post)) { + if (in_array($post['private'], [Item::PUBLIC, Item::UNLISTED])) { + return $post['uid']; + } + + $pcid = Contact::getPublicIdByUserId($uid); + if (empty($pcid)) { return null; } - } - if (in_array($post['private'], [Item::PUBLIC, Item::UNLISTED])) { - return $post['uid']; - } + foreach (Item::enumeratePermissions($post, true) as $receiver) { + if ($receiver == $pcid) { + return $post['uid']; + } + } - $pcid = Contact::getPublicIdByUserId($uid); - if (empty($pcid)) { return null; } - foreach (Item::enumeratePermissions($post, true) as $receiver) { - if ($receiver == $pcid) { - return $post['uid']; + if (Post::exists(['uri-id' => $uriid, 'uid' => 0])) { + return 0; + } + + // When the post belongs to a a forum then all forum users are allowed to access it + foreach (Tag::getByURIId($uriid, [Tag::EXCLUSIVE_MENTION]) as $tag) { + if (DBA::exists('contact', ['uid' => $uid, 'nurl' => Strings::normaliseLink($tag['url']), 'contact-type' => Contact::TYPE_COMMUNITY])) { + $target_uid = User::getIdForURL($tag['url']); + if (!empty($target_uid)) { + return $target_uid; + } } } diff --git a/src/Module/ActivityPub/Objects.php b/src/Module/ActivityPub/Objects.php index c085d86836..0a523ea435 100644 --- a/src/Module/ActivityPub/Objects.php +++ b/src/Module/ActivityPub/Objects.php @@ -70,9 +70,7 @@ class Objects extends BaseModule } } - $item = Post::selectFirst(['id', 'uid', 'origin', 'author-link', 'changed', 'private', 'psid', 'gravity', 'deleted', 'parent-uri-id'], - ['uri-id' => $itemuri['id']], ['order' => ['origin' => true]]); - + $item = Post::selectFirst([], ['uri-id' => $itemuri['id'], 'origin' => true]); if (!DBA::isResult($item)) { throw new HTTPException\NotFoundException(); } @@ -81,25 +79,16 @@ class Objects extends BaseModule if (!$validated) { $requester = HTTPSignature::getSigner('', $_SERVER); - if (!empty($requester) && $item['origin']) { - $requester_id = Contact::getIdForURL($requester, $item['uid']); - if (!empty($requester_id)) { - $permissionSets = DI::permissionSet()->selectByContactId($requester_id, $item['uid']); - $psids = array_merge($permissionSets->column('id'), [PermissionSet::PUBLIC]); - $validated = in_array($item['psid'], $psids); + if (!empty($requester)) { + $receivers = Item::enumeratePermissions($item, false); + + $validated = in_array(Contact::getIdForURL($requester, $item['uid']), $receivers); + if (!$validated) { + $validated = in_array(Contact::getIdForURL($requester), $receivers); } } } - if ($validated) { - // Valid items are original post or posted from this node (including in the case of a forum) - $validated = ($item['origin'] || (parse_url($item['author-link'], PHP_URL_HOST) == parse_url(DI::baseUrl()->get(), PHP_URL_HOST))); - - if (!$validated && $item['deleted']) { - $validated = Post::exists(['origin' => true, 'uri-id' => $item['parent-uri-id']]); - } - } - if (!$validated) { throw new HTTPException\NotFoundException(); } From b703d053ab069459809196e8e9c189086f461f85 Mon Sep 17 00:00:00 2001 From: Tobias Diekershoff Date: Wed, 16 Feb 2022 07:43:02 +0100 Subject: [PATCH 19/44] Note about breaking changes in private forums This adds a note/reminder to the CHANGELOG file about the breaking changes introduced in this version regarding the _private forums_. --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 96638b7e05..41929396c3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,6 @@ Version 2022.05 (unreleased) Friendica Core + Breaking: The distribution of _private forums_ was moved to ActivityPub, making them incompatible with older versions of Friendica [annando] Friendica Addons From 9ac24a0f362f16ff0ec30b05aaebf06516788e8a Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 16 Feb 2022 22:56:55 +0000 Subject: [PATCH 20/44] More rework to make private communities working --- mod/settings.php | 26 +++++++----- src/Model/Item.php | 30 ++++--------- src/Module/ActivityPub/Objects.php | 1 + src/Protocol/ActivityPub/Receiver.php | 9 ++++ src/Protocol/ActivityPub/Transmitter.php | 42 ++++++++++--------- src/Worker/Notifier.php | 15 ++++--- view/templates/settings/settings.tpl | 12 +++--- .../frio/templates/settings/settings.tpl | 11 ++--- 8 files changed, 79 insertions(+), 67 deletions(-) diff --git a/mod/settings.php b/mod/settings.php index 111e523302..c18a36704c 100644 --- a/mod/settings.php +++ b/mod/settings.php @@ -239,7 +239,6 @@ function settings_post(App $a) $allow_location = ((!empty($_POST['allow_location']) && (intval($_POST['allow_location']) == 1)) ? 1: 0); $publish = ((!empty($_POST['profile_in_directory']) && (intval($_POST['profile_in_directory']) == 1)) ? 1: 0); $net_publish = ((!empty($_POST['profile_in_netdirectory']) && (intval($_POST['profile_in_netdirectory']) == 1)) ? 1: 0); - $old_visibility = ((!empty($_POST['visibility']) && (intval($_POST['visibility']) == 1)) ? 1 : 0); $account_type = ((!empty($_POST['account-type']) && (intval($_POST['account-type']))) ? intval($_POST['account-type']) : 0); $page_flags = ((!empty($_POST['page-flags']) && (intval($_POST['page-flags']))) ? intval($_POST['page-flags']) : 0); $blockwall = ((!empty($_POST['blockwall']) && (intval($_POST['blockwall']) == 1)) ? 0: 1); // this setting is inverted! @@ -361,16 +360,21 @@ function settings_post(App $a) DI::pConfig()->set(local_user(), 'system', 'unlisted', $unlisted); DI::pConfig()->set(local_user(), 'system', 'accessible-photos', $accessiblephotos); + if ($account_type == User::ACCOUNT_TYPE_COMMUNITY) { + $str_group_allow = ''; + $str_contact_allow = ''; + $str_group_deny = ''; + $str_contact_deny = ''; + + DI::pConfig()->set(local_user(), 'system', 'unlisted', true); + + $blockwall = true; + $blocktags = true; + $hide_friends = true; + } + if ($page_flags == User::PAGE_FLAGS_PRVGROUP) { - $hidewall = 1; - if (!$str_contact_allow && !$str_group_allow && !$str_contact_deny && !$str_group_deny) { - if ($def_gid) { - info(DI::l10n()->t('Private forum has no privacy permissions. Using default privacy group.')); - $str_group_allow = '<' . $def_gid . '>'; - } else { - notice(DI::l10n()->t('Private forum has no privacy permissions and no default privacy group.')); - } - } + $str_group_allow = '<' . Group::FOLLOWERS . '>'; } $fields = ['username' => $username, 'email' => $email, 'timezone' => $timezone, @@ -756,7 +760,7 @@ function settings_content(App $a) '$allowloc' => ['allow_location', DI::l10n()->t('Use Browser Location:'), ($user['allow_location'] == 1), ''], '$h_prv' => DI::l10n()->t('Security and Privacy Settings'), - '$visibility' => $profile['net-publish'], + '$is_community' => ($user['account-type'] == User::ACCOUNT_TYPE_COMMUNITY), '$maxreq' => ['maxreq', DI::l10n()->t('Maximum Friend Requests/Day:'), $maxreq , DI::l10n()->t("\x28to prevent spam abuse\x29")], '$profile_in_dir' => $profile_in_dir, '$profile_in_net_dir' => ['profile_in_netdirectory', DI::l10n()->t('Allow your profile to be searchable globally?'), $profile['net-publish'], DI::l10n()->t("Activate this setting if you want others to easily find and follow you. Your profile will be searchable on remote systems. This setting also determines whether Friendica will inform search engines that your profile should be indexed or not.") . $net_pub_desc], diff --git a/src/Model/Item.php b/src/Model/Item.php index 69a967b2c4..318a8ab511 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -1994,10 +1994,8 @@ class Item Logger::info('Community post will be distributed', ['uri' => $item['uri'], 'uid' => $uid, 'id' => $item_id, 'uri-id' => $item['uri-id'], 'guid' => $item['guid']]); if ($owner['page-flags'] == User::PAGE_FLAGS_PRVGROUP) { - Group::getMembersForForum($owner['id']); - - $allow_cid = '<' . $owner['id'] . '>'; - $allow_gid = '<' . Group::getIdForForum($owner['id']) . '>'; + $allow_cid = ''; + $allow_gid = '<' . Group::FOLLOWERS . '>'; $deny_cid = ''; $deny_gid = ''; self::performActivity($item['id'], 'announce', $uid, $allow_cid, $allow_gid, $deny_cid, $deny_gid); @@ -3210,30 +3208,20 @@ class Item } /** - * Is the given item array a post that is sent as starting post to a forum? + * Does the given uri-id belongs to a post that is sent as starting post to a forum? * - * @param array $item - * @param array $owner + * @param int $uri_id * * @return boolean "true" when it is a forum post */ - public static function isForumPost(array $item, array $owner = []) + public static function isForumPost(int $uri_id) { - if (empty($owner)) { - $owner = User::getOwnerDataById($item['uid']); - if (empty($owner)) { - return false; + foreach (Tag::getByURIId($uri_id, [Tag::EXCLUSIVE_MENTION]) as $tag) { + if (DBA::exists('contact', ['uid' => 0, 'nurl' => Strings::normaliseLink($tag['url']), 'contact-type' => Contact::TYPE_COMMUNITY])) { + return true; } } - - if (($item['author-id'] == $item['owner-id']) || - ($owner['id'] == $item['contact-id']) || - ($item['uri-id'] != $item['parent-uri-id']) || - $item['origin']) { - return false; - } - - return Contact::isForum($item['contact-id']); + return false; } /** diff --git a/src/Module/ActivityPub/Objects.php b/src/Module/ActivityPub/Objects.php index 0a523ea435..f3a37b7dad 100644 --- a/src/Module/ActivityPub/Objects.php +++ b/src/Module/ActivityPub/Objects.php @@ -81,6 +81,7 @@ class Objects extends BaseModule $requester = HTTPSignature::getSigner('', $_SERVER); if (!empty($requester)) { $receivers = Item::enumeratePermissions($item, false); + $receivers[] = $item['contact-id']; $validated = in_array(Contact::getIdForURL($requester, $item['uid']), $receivers); if (!$validated) { diff --git a/src/Protocol/ActivityPub/Receiver.php b/src/Protocol/ActivityPub/Receiver.php index 7f08410f69..003cae0c9f 100644 --- a/src/Protocol/ActivityPub/Receiver.php +++ b/src/Protocol/ActivityPub/Receiver.php @@ -667,6 +667,15 @@ class Receiver $uid = $receiver['uid']; } } + + // When we haven't found any user yet, we just chose a user who most likely could have access to the content + if (empty($uid)) { + $contact = Contact::selectFirst(['uid'], ['nurl' => Strings::normaliseLink($actor), 'rel' => [Contact::SHARING, Contact::FRIEND]]); + if (!empty($contact['uid'])) { + $uid = $contact['uid']; + } + } + return $uid; } diff --git a/src/Protocol/ActivityPub/Transmitter.php b/src/Protocol/ActivityPub/Transmitter.php index 7be55898c8..884f9430f1 100644 --- a/src/Protocol/ActivityPub/Transmitter.php +++ b/src/Protocol/ActivityPub/Transmitter.php @@ -509,28 +509,33 @@ class Transmitter /** * Creates an array of permissions from an item thread * - * @param array $item Item array - * @param boolean $blindcopy addressing via "bcc" or "cc"? - * @param integer $last_id Last item id for adding receivers - * @param boolean $forum_post "true" means that we are sending content to a forum + * @param array $item Item array + * @param boolean $blindcopy addressing via "bcc" or "cc"? + * @param integer $last_id Last item id for adding receivers * * @return array with permission data * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function createPermissionBlockForItem($item, $blindcopy, $last_id = 0, $forum_post = false) + private static function createPermissionBlockForItem($item, $blindcopy, $last_id = 0) { if ($last_id == 0) { $last_id = $item['id']; } $always_bcc = false; + $is_forum = false; + $follower = ''; // Check if we should always deliver our stuff via BCC if (!empty($item['uid'])) { - $profile = User::getOwnerDataById($item['uid']); - if (!empty($profile)) { - $always_bcc = $profile['hide-friends']; + $owner = User::getOwnerDataById($item['uid']); + if (!empty($owner)) { + $always_bcc = $owner['hide-friends']; + $is_forum = ($owner['account-type'] == User::ACCOUNT_TYPE_COMMUNITY) && $owner['manually-approve']; + + $profile = APContact::getByURL($owner['url'], false); + $follower = $profile['followers'] ?? ''; } } @@ -613,7 +618,9 @@ class Transmitter } } - if (!$exclusive) { + if ($is_forum && !$exclusive && !empty($follower)) { + $data['cc'][] = $follower; + } elseif (!$exclusive) { foreach ($receiver_list as $receiver) { $contact = DBA::selectFirst('contact', ['url', 'hidden', 'network', 'protocol', 'gsid'], ['id' => $receiver, 'network' => Protocol::FEDERATED]); if (!DBA::isResult($contact) || !self::isAPContact($contact, $networks)) { @@ -652,9 +659,7 @@ class Transmitter } } elseif (!$exclusive) { // Public thread parent post always are directed to the followers. - // This mustn't be done by posts that are directed to forum servers via the exclusive mention. - // But possibly in that case we could add the "followers" collection of the forum to the message. - if (($item['private'] != Item::PRIVATE) && !$forum_post) { + if ($item['private'] != Item::PRIVATE) { $data['cc'][] = $actor_profile['followers']; } } @@ -820,18 +825,17 @@ class Transmitter /** * Fetches an array of inboxes for the given item and user * - * @param array $item Item array - * @param integer $uid User ID - * @param boolean $personal fetch personal inboxes - * @param integer $last_id Last item id for adding receivers - * @param boolean $forum_post "true" means that we are sending content to a forum + * @param array $item Item array + * @param integer $uid User ID + * @param boolean $personal fetch personal inboxes + * @param integer $last_id Last item id for adding receivers * @return array with inboxes * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function fetchTargetInboxes($item, $uid, $personal = false, $last_id = 0, $forum_post = false) + public static function fetchTargetInboxes($item, $uid, $personal = false, $last_id = 0) { - $permissions = self::createPermissionBlockForItem($item, true, $last_id, $forum_post); + $permissions = self::createPermissionBlockForItem($item, true, $last_id); if (empty($permissions)) { return []; } diff --git a/src/Worker/Notifier.php b/src/Worker/Notifier.php index 3a5c7f13e1..f79b466377 100644 --- a/src/Worker/Notifier.php +++ b/src/Worker/Notifier.php @@ -235,13 +235,13 @@ class Notifier } // Special treatment for forum posts - if (Item::isForumPost($target_item, $owner)) { + if (Item::isForumPost($target_item['uri-id'])) { $relay_to_owner = true; $direct_forum_delivery = true; } // Avoid that comments in a forum thread are sent to OStatus - if (Item::isForumPost($parent, $owner)) { + if (Item::isForumPost($parent['uri-id'])) { $direct_forum_delivery = true; } @@ -729,6 +729,14 @@ class Notifier $uid = $target_item['contact-uid'] ?: $target_item['uid']; + // Update the locally stored follower list when we deliver to a forum + foreach (Tag::getByURIId($target_item['uri-id'], [Tag::EXCLUSIVE_MENTION]) as $tag) { + $target_contact = Contact::getByURL(Strings::normaliseLink($tag['url']), null, [], $uid); + if (($target_contact['contact-type'] == Contact::TYPE_COMMUNITY) && $target_contact['manually-approve']) { + Group::getMembersForForum($target_contact['id']); + } + } + if ($target_item['origin']) { $inboxes = ActivityPub\Transmitter::fetchTargetInboxes($target_item, $uid); @@ -738,9 +746,6 @@ class Notifier } Logger::info('Origin item ' . $target_item['id'] . ' with URL ' . $target_item['uri'] . ' will be distributed.'); - } elseif (Item::isForumPost($target_item, $owner)) { - $inboxes = ActivityPub\Transmitter::fetchTargetInboxes($target_item, $uid, false, 0, true); - Logger::info('Forum item ' . $target_item['id'] . ' with URL ' . $target_item['uri'] . ' will be distributed.'); } elseif (!DBA::exists('conversation', ['item-uri' => $target_item['uri'], 'protocol' => Conversation::PARCEL_ACTIVITYPUB])) { Logger::info('Remote item ' . $target_item['id'] . ' with URL ' . $target_item['uri'] . ' is no AP post. It will not be distributed.'); return ['count' => 0, 'contacts' => []]; diff --git a/view/templates/settings/settings.tpl b/view/templates/settings/settings.tpl index c2ed1a9424..c0e821ac7c 100644 --- a/view/templates/settings/settings.tpl +++ b/view/templates/settings/settings.tpl @@ -39,28 +39,28 @@

{{$h_prv}}

- - - {{include file="field_input.tpl" field=$maxreq}} {{$profile_in_dir nofilter}} {{include file="field_checkbox.tpl" field=$profile_in_net_dir}} - {{include file="field_checkbox.tpl" field=$hide_friends}} + {{if not $is_community}}{{include file="field_checkbox.tpl" field=$hide_friends}}{{/if}} {{include file="field_checkbox.tpl" field=$hide_wall}} - {{include file="field_checkbox.tpl" field=$unlisted}} + {{if not $is_community}}{{include file="field_checkbox.tpl" field=$unlisted}}{{/if}} {{include file="field_checkbox.tpl" field=$accessiblephotos}} + {{if not $is_community}} {{include file="field_checkbox.tpl" field=$blockwall}} {{include file="field_checkbox.tpl" field=$blocktags}} + {{/if}} {{include file="field_checkbox.tpl" field=$unkmail}} {{include file="field_input.tpl" field=$cntunkmail}} {{$group_select nofilter}} - + {{if not $is_community}}

{{$permissions}}

{{$aclselect nofilter}} + {{/if}}
diff --git a/view/theme/frio/templates/settings/settings.tpl b/view/theme/frio/templates/settings/settings.tpl index bf129cc12e..b9e105e886 100644 --- a/view/theme/frio/templates/settings/settings.tpl +++ b/view/theme/frio/templates/settings/settings.tpl @@ -70,28 +70,29 @@
- - - {{include file="field_input.tpl" field=$maxreq}} {{$profile_in_dir nofilter}} {{include file="field_checkbox.tpl" field=$profile_in_net_dir}} - {{include file="field_checkbox.tpl" field=$hide_friends}} + {{if not $is_community}}{{include file="field_checkbox.tpl" field=$hide_friends}}{{/if}} {{include file="field_checkbox.tpl" field=$hide_wall}} - {{include file="field_checkbox.tpl" field=$unlisted}} + {{if not $is_community}}{{include file="field_checkbox.tpl" field=$unlisted}}{{/if}} {{include file="field_checkbox.tpl" field=$accessiblephotos}} + {{if not $is_community}} {{include file="field_checkbox.tpl" field=$blockwall}} {{include file="field_checkbox.tpl" field=$blocktags}} + {{/if}} {{include file="field_checkbox.tpl" field=$unkmail}} {{include file="field_input.tpl" field=$cntunkmail}} {{$group_select nofilter}} + {{if not $is_community}}

{{$permissions}}

{{$aclselect nofilter}} + {{/if}}
- {{if $item.drop.dropping}}{{/if}} + {{if $item.drop && $item.drop.dropping}}{{/if}}
- {{if $item.drop.pagedrop}}{{/if}} + {{if $item.drop && $item.drop.pagedrop}}{{/if}}
diff --git a/view/templates/wall_thread.tpl b/view/templates/wall_thread.tpl index d0e3b51eab..763a68bde6 100644 --- a/view/templates/wall_thread.tpl +++ b/view/templates/wall_thread.tpl @@ -121,9 +121,9 @@
{{/if}}
- {{if $item.drop.dropping}}{{/if}} + {{if $item.drop && $item.drop.dropping}}{{/if}}
- {{if $item.drop.pagedrop}}{{/if}} + {{if $item.drop && $item.drop.pagedrop}}{{/if}}
diff --git a/view/theme/frio/templates/search_item.tpl b/view/theme/frio/templates/search_item.tpl index 2fbff14d78..39e66751f8 100644 --- a/view/theme/frio/templates/search_item.tpl +++ b/view/theme/frio/templates/search_item.tpl @@ -1,6 +1,6 @@ @@ -245,7 +245,7 @@ {{/if}} - {{if $item.drop.dropping}} + {{if $item.drop && $item.drop.dropping}}
  • {{$item.drop.delete}}
  • @@ -270,7 +270,7 @@ {{/if}} - {{if $item.drop.pagedrop}} + {{if $item.drop && $item.drop.pagedrop}} {{/if}} diff --git a/view/theme/frio/templates/wall_thread.tpl b/view/theme/frio/templates/wall_thread.tpl index 8f03cb5c9d..55858d811e 100644 --- a/view/theme/frio/templates/wall_thread.tpl +++ b/view/theme/frio/templates/wall_thread.tpl @@ -336,7 +336,7 @@ as the value of $top_child_total (this is done at the end of this file) {{/if}} {{* Put additional actions in a dropdown menu *}} - {{if $item.menu && ($item.edpost || $item.tagger || $item.filer || $item.pin || $item.star || $item.follow_thread || $item.ignore || $item.drop.dropping)}} + {{if $item.menu && ($item.edpost || $item.tagger || $item.filer || $item.pin || $item.star || $item.follow_thread || $item.ignore || ($item.drop && $item.drop.dropping))}} @@ -385,7 +385,7 @@ as the value of $top_child_total (this is done at the end of this file) {{/if}} - {{if ($item.edpost || $item.tagger || $item.filer || $item.pin || $item.star || $item.follow_thread) && ($item.ignore || $item.drop.dropping)}} + {{if ($item.edpost || $item.tagger || $item.filer || $item.pin || $item.star || $item.follow_thread) && ($item.ignore || ($item.drop && $item.drop.dropping))}} {{/if}} @@ -398,7 +398,7 @@ as the value of $top_child_total (this is done at the end of this file) {{/if}} - {{if $item.drop.dropping}} + {{if $item.drop && $item.drop.dropping}}
  • {{$item.drop.delete}}
  • @@ -429,7 +429,7 @@ as the value of $top_child_total (this is done at the end of this file) {{/if}} - {{if $item.drop.pagedrop}} + {{if $item.drop && $item.drop.pagedrop}} {{/if}} @@ -506,7 +506,7 @@ as the value of $top_child_total (this is done at the end of this file) {{/if}} - {{if $item.edpost || $item.tagger || $item.filer || $item.pin || $item.star || $item.follow_thread || $item.ignore || $item.drop.dropping}} + {{if $item.edpost || $item.tagger || $item.filer || $item.pin || $item.star || $item.follow_thread || $item.ignore || ($item.drop && $item.drop.dropping)}} {{/if}} - {{if $item.drop.pagedrop}} + {{if $item.drop && $item.drop.pagedrop}} {{/if}} diff --git a/view/theme/quattro/templates/search_item.tpl b/view/theme/quattro/templates/search_item.tpl index 903138874a..b5c6af7e75 100644 --- a/view/theme/quattro/templates/search_item.tpl +++ b/view/theme/quattro/templates/search_item.tpl @@ -71,10 +71,10 @@
    - {{if $item.drop.pagedrop}} + {{if $item.drop && $item.drop.pagedrop}} {{/if}} - {{if $item.drop.dropping}} + {{if $item.drop && $item.drop.dropping}} {{$item.drop.delete}} {{/if}} {{if $item.edpost}} diff --git a/view/theme/quattro/templates/wall_item_tag.tpl b/view/theme/quattro/templates/wall_item_tag.tpl index 5f2021b3ef..3aa9d3ad45 100644 --- a/view/theme/quattro/templates/wall_item_tag.tpl +++ b/view/theme/quattro/templates/wall_item_tag.tpl @@ -40,10 +40,10 @@ {{$item.ago}} {{$item.body_html nofilter}}
    - {{if $item.drop.pagedrop}} + {{if $item.drop && $item.drop.pagedrop}} {{/if}} - {{if $item.drop.dropping}} + {{if $item.drop && $item.drop.dropping}} {{$item.drop.delete}} {{/if}}
    diff --git a/view/theme/quattro/templates/wall_thread.tpl b/view/theme/quattro/templates/wall_thread.tpl index 29dae72b43..1382222c1f 100644 --- a/view/theme/quattro/templates/wall_thread.tpl +++ b/view/theme/quattro/templates/wall_thread.tpl @@ -145,10 +145,10 @@
    - {{if $item.drop.pagedrop}} + {{if $item.drop && $item.drop.pagedrop}} {{/if}} - {{if $item.drop.dropping}} + {{if $item.drop && $item.drop.dropping}} {{$item.drop.delete}} {{/if}} {{if $item.edpost}} diff --git a/view/theme/smoothly/templates/search_item.tpl b/view/theme/smoothly/templates/search_item.tpl index 7675c2db17..94d713267b 100644 --- a/view/theme/smoothly/templates/search_item.tpl +++ b/view/theme/smoothly/templates/search_item.tpl @@ -26,9 +26,9 @@
    - {{if $item.drop.dropping}}{{/if}} + {{if $item.drop && $item.drop.dropping}}{{/if}}
    - {{if $item.drop.pagedrop}}{{/if}} + {{if $item.drop && $item.drop.pagedrop}}{{/if}}
    diff --git a/view/theme/smoothly/templates/wall_thread.tpl b/view/theme/smoothly/templates/wall_thread.tpl index 773938f3c5..53602cc8fc 100644 --- a/view/theme/smoothly/templates/wall_thread.tpl +++ b/view/theme/smoothly/templates/wall_thread.tpl @@ -135,12 +135,12 @@ {{/if}}
    - {{if $item.drop.dropping}} + {{if $item.drop && $item.drop.dropping}} {{/if}}
    - {{if $item.drop.pagedrop}} + {{if $item.drop && $item.drop.pagedrop}} {{/if}} diff --git a/view/theme/vier/templates/search_item.tpl b/view/theme/vier/templates/search_item.tpl index 44fb6804d3..2441c80fec 100644 --- a/view/theme/vier/templates/search_item.tpl +++ b/view/theme/vier/templates/search_item.tpl @@ -75,10 +75,10 @@
    - {{if $item.drop.pagedrop}} + {{if $item.drop && $item.drop.pagedrop}} {{/if}} - {{if $item.drop.dropping}} + {{if $item.drop && $item.drop.dropping}} {{$item.drop.delete}} {{/if}} {{if $item.edpost}} diff --git a/view/theme/vier/templates/wall_item_tag.tpl b/view/theme/vier/templates/wall_item_tag.tpl index 01207ab117..c12cb7085f 100644 --- a/view/theme/vier/templates/wall_item_tag.tpl +++ b/view/theme/vier/templates/wall_item_tag.tpl @@ -40,10 +40,10 @@ {{$item.ago}} {{$item.body_html nofilter}}
    - {{if $item.drop.pagedrop}} + {{if $item.drop && $item.drop.pagedrop}} {{/if}} - {{if $item.drop.dropping}} + {{if $item.drop && $item.drop.dropping}} {{$item.drop.delete}} {{/if}}
    diff --git a/view/theme/vier/templates/wall_thread.tpl b/view/theme/vier/templates/wall_thread.tpl index f2bd02e7e7..7d851d0015 100644 --- a/view/theme/vier/templates/wall_thread.tpl +++ b/view/theme/vier/templates/wall_thread.tpl @@ -162,10 +162,10 @@
    - {{if $item.drop.pagedrop}} + {{if $item.drop && $item.drop.pagedrop}} {{/if}} - {{if $item.drop.dropping}} + {{if $item.drop && $item.drop.dropping}} {{$item.drop.delete}} {{/if}} {{if $item.edpost}} From 0209892631892486e4ee000328c7e8e8f15c839c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sun, 20 Feb 2022 14:10:57 +0100 Subject: [PATCH 44/44] Apply suggestions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- src/Model/Group.php | 6 +++++- src/Module/Api/Mastodon/Lists/Accounts.php | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Model/Group.php b/src/Model/Group.php index da77335f12..fa41d26467 100644 --- a/src/Model/Group.php +++ b/src/Model/Group.php @@ -358,14 +358,18 @@ class Group throw new HTTPException\NotFoundException('Group not found.'); } + $contactIds = []; + foreach ($contacts as $cid) { $cdata = Contact::getPublicAndUserContactID($cid, $group['uid']); if (empty($cdata['user'])) { throw new HTTPException\NotFoundException('Invalid contact.'); } - DBA::delete('group_member', ['gid' => $gid, 'contact-id' => $cdata['user']]); + $contactIds[] = $cdata['user']; } + + DBA::delete('group_member', ['gid' => $gid, 'contact-id' => $contactIds]); } /** diff --git a/src/Module/Api/Mastodon/Lists/Accounts.php b/src/Module/Api/Mastodon/Lists/Accounts.php index 8d27207fc4..413cacae29 100644 --- a/src/Module/Api/Mastodon/Lists/Accounts.php +++ b/src/Module/Api/Mastodon/Lists/Accounts.php @@ -45,6 +45,7 @@ class Accounts extends BaseApi if (empty($request['account_ids']) || empty($this->parameters['id'])) { DI::mstdnError()->UnprocessableEntity(); } + return Group::removeMembers($this->parameters['id'], $request['account_ids']); } @@ -59,6 +60,7 @@ class Accounts extends BaseApi if (empty($request['account_ids']) || empty($this->parameters['id'])) { DI::mstdnError()->UnprocessableEntity(); } + return Group::addMembers($this->parameters['id'], $request['account_ids']); }