diff --git a/include/text.php b/include/text.php index 7bed8b4994..3d6bf6a563 100644 --- a/include/text.php +++ b/include/text.php @@ -4,11 +4,11 @@ */ use Friendica\App; -use Friendica\Content\Smilies; use Friendica\Content\Text\BBCode; use Friendica\Core\Protocol; use Friendica\Model\Contact; use Friendica\Model\FileTag; +use Friendica\Model\Group; use Friendica\Util\Strings; /** @@ -20,18 +20,9 @@ use Friendica\Util\Strings; function expand_acl($s) { // turn string array of angle-bracketed elements into numeric array // e.g. "<1><2><3>" => array(1,2,3); - $ret = []; + preg_match_all('/<(' . Group::FOLLOWERS . '|'. Group::MUTUALS . '|[0-9]+)>/', $s, $matches, PREG_PATTERN_ORDER); - if (strlen($s)) { - $t = str_replace('<', '', $s); - $a = explode('>', $t); - foreach ($a as $aa) { - if (intval($aa)) { - $ret[] = intval($aa); - } - } - } - return $ret; + return $matches[1]; } @@ -42,6 +33,8 @@ function expand_acl($s) { function sanitise_acl(&$item) { if (intval($item)) { $item = '<' . intval(Strings::escapeTags(trim($item))) . '>'; + } elseif (in_array($item, [Group::FOLLOWERS, Group::MUTUALS])) { + $item = '<' . $item . '>'; } else { unset($item); } diff --git a/mod/lockview.php b/mod/lockview.php index 35c4b04332..eede1b6a0d 100644 --- a/mod/lockview.php +++ b/mod/lockview.php @@ -6,6 +6,7 @@ use Friendica\App; use Friendica\Core\Hook; use Friendica\Core\L10n; use Friendica\Database\DBA; +use Friendica\Model\Group; use Friendica\Model\Item; function lockview_content(App $a) @@ -67,6 +68,19 @@ function lockview_content(App $a) $l = []; if (count($allowed_groups)) { + $key = array_search(Group::FOLLOWERS, $allowed_groups); + if ($key !== false) { + $l[] = '' . L10n::t('Followers') . ''; + unset($allowed_groups[$key]); + } + + $key = array_search(Group::MUTUALS, $allowed_groups); + if ($key !== false) { + $l[] = '' . L10n::t('Mutuals') . ''; + unset($allowed_groups[$key]); + } + + $r = q("SELECT `name` FROM `group` WHERE `id` IN ( %s )", DBA::escape(implode(', ', $allowed_groups)) ); @@ -89,6 +103,18 @@ function lockview_content(App $a) } if (count($deny_groups)) { + $key = array_search(Group::FOLLOWERS, $deny_groups); + if ($key !== false) { + $l[] = '' . L10n::t('Followers') . ''; + unset($deny_groups[$key]); + } + + $key = array_search(Group::MUTUALS, $deny_groups); + if ($key !== false) { + $l[] = '' . L10n::t('Mutuals') . ''; + unset($deny_groups[$key]); + } + $r = q("SELECT `name` FROM `group` WHERE `id` IN ( %s )", DBA::escape(implode(', ', $deny_groups)) ); diff --git a/mod/network.php b/mod/network.php index 7354667200..fddec60c8d 100644 --- a/mod/network.php +++ b/mod/network.php @@ -643,7 +643,7 @@ function networkThreadedView(App $a, $update, $parent) // NOTREACHED } - $contacts = Group::expand([$gid]); + $contacts = Group::expand(local_user(), [$gid]); if ((is_array($contacts)) && count($contacts)) { $contact_str_self = ''; diff --git a/src/Model/Group.php b/src/Model/Group.php index feff4661ab..5c587ee2a6 100644 --- a/src/Model/Group.php +++ b/src/Model/Group.php @@ -16,9 +16,25 @@ use Friendica\Database\DBA; */ class Group extends BaseObject { + const FOLLOWERS = '~'; + const MUTUALS = '&'; + + public static function getByUserId($uid, $includesDeleted = false) + { + $DB = self::getApp()->getDatabase(); + + $conditions = ['uid' => $uid]; + + if (!$includesDeleted) { + $conditions['deleted'] = false; + } + + $groupsStmt = $DB->select('group', [], $conditions); + + return $DB->toArray($groupsStmt); + } + /** - * - * * @param int $group_id * @return bool * @throws \Exception @@ -300,20 +316,43 @@ class Group extends BaseObject /** * @brief Returns the combined list of contact ids from a group id list * + * @param int $uid * @param array $group_ids * @param boolean $check_dead * @return array * @throws \Exception */ - public static function expand($group_ids, $check_dead = false) + public static function expand($uid, array $group_ids, $check_dead = false) { if (!is_array($group_ids) || !count($group_ids)) { return []; } - $stmt = DBA::select('group_member', ['contact-id'], ['gid' => $group_ids]); - $return = []; + + $key = array_search(self::FOLLOWERS, $group_ids); + if ($key !== false) { + $followersStmt = Contact::select(['id'], ['uid' => $uid, 'rel' => [Contact::FOLLOWER, Contact::FRIEND]]); + + while($follower = DBA::fetch($followersStmt)) { + $return[] = $follower['id']; + } + + unset($group_ids[$key]); + } + + $key = array_search(self::MUTUALS, $group_ids); + if ($key !== false) { + $mutualsStmt = Contact::select(['id'], ['uid' => $uid, 'rel' => [Contact::FRIEND]]); + + while($mutual = DBA::fetch($mutualsStmt)) { + $return[] = $mutual['id']; + } + + unset($group_ids[$key]); + } + + $stmt = DBA::select('group_member', ['contact-id'], ['gid' => $group_ids]); while($group_member = DBA::fetch($stmt)) { $return[] = $group_member['contact-id']; } @@ -332,7 +371,7 @@ class Group extends BaseObject * @param int $gid An optional pre-selected group * @param string $label An optional label of the list * @return string - * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \Exception */ public static function displayGroupSelection($uid, $gid = 0, $label = '') { @@ -377,7 +416,7 @@ class Group extends BaseObject * @param string $group_id * @param int $cid * @return string - * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \Exception */ public static function sidebarWidget($every = 'contact', $each = 'group', $editmode = 'standard', $group_id = '', $cid = 0) { diff --git a/src/Model/Item.php b/src/Model/Item.php index 28f7b436d9..e54dadba5d 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -2799,12 +2799,12 @@ class Item extends BaseObject */ if (self::hasPermissions($photo)) { if ($cid) { - $recips = self::enumeratePermissions($photo); + $recips = self::enumeratePermissions($uid, $photo); if (in_array($cid, $recips)) { $replace = true; } } elseif ($item) { - if (self::samePermissions($item, $photo)) { + if (self::samePermissions($uid, $item, $photo)) { $replace = true; } } @@ -2854,7 +2854,7 @@ class Item extends BaseObject !empty($obj['deny_cid']) || !empty($obj['deny_gid']); } - private static function samePermissions($obj1, $obj2) + private static function samePermissions($uid, $obj1, $obj2) { // first part is easy. Check that these are exactly the same. if (($obj1['allow_cid'] == $obj2['allow_cid']) @@ -2865,8 +2865,8 @@ class Item extends BaseObject } // This is harder. Parse all the permissions and compare the resulting set. - $recipients1 = self::enumeratePermissions($obj1); - $recipients2 = self::enumeratePermissions($obj2); + $recipients1 = self::enumeratePermissions($uid, $obj1); + $recipients2 = self::enumeratePermissions($uid, $obj2); sort($recipients1); sort($recipients2); @@ -2875,12 +2875,12 @@ class Item extends BaseObject } // returns an array of contact-ids that are allowed to see this object - public static function enumeratePermissions($obj) + public static function enumeratePermissions($uid, array $obj) { $allow_people = expand_acl($obj['allow_cid']); - $allow_groups = Group::expand(expand_acl($obj['allow_gid'])); + $allow_groups = Group::expand($uid, expand_acl($obj['allow_gid'])); $deny_people = expand_acl($obj['deny_cid']); - $deny_groups = Group::expand(expand_acl($obj['deny_gid'])); + $deny_groups = Group::expand($uid, expand_acl($obj['deny_gid'])); $recipients = array_unique(array_merge($allow_people, $allow_groups)); $deny = array_unique(array_merge($deny_people, $deny_groups)); $recipients = array_diff($recipients, $deny); diff --git a/src/Protocol/ActivityPub/Transmitter.php b/src/Protocol/ActivityPub/Transmitter.php index b64e746e79..9d8c9de90a 100644 --- a/src/Protocol/ActivityPub/Transmitter.php +++ b/src/Protocol/ActivityPub/Transmitter.php @@ -386,7 +386,7 @@ class Transmitter } } } else { - $receiver_list = Item::enumeratePermissions($item); + $receiver_list = Item::enumeratePermissions($item['uid'], $item); foreach ($terms as $term) { $cid = Contact::getIdForURL($term['url'], $item['uid']); diff --git a/src/Worker/Notifier.php b/src/Worker/Notifier.php index 42ad0afb6d..4efd3e9126 100644 --- a/src/Worker/Notifier.php +++ b/src/Worker/Notifier.php @@ -271,9 +271,9 @@ class Notifier } $allow_people = expand_acl($parent['allow_cid']); - $allow_groups = Group::expand(expand_acl($parent['allow_gid']),true); + $allow_groups = Group::expand($uid, expand_acl($parent['allow_gid']),true); $deny_people = expand_acl($parent['deny_cid']); - $deny_groups = Group::expand(expand_acl($parent['deny_gid'])); + $deny_groups = Group::expand($uid, expand_acl($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