From b857c26999975fc86a8fb1db8a31b4e2a33a0446 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 9 Feb 2022 05:56:12 +0000 Subject: [PATCH 1/5] Use "account-type" instead of "page-flags" --- src/Module/Profile/Status.php | 2 +- src/Module/Settings/Profile/Index.php | 2 +- src/Navigation/Notifications/Repository/Notify.php | 4 ++-- src/Protocol/ActivityPub/Transmitter.php | 12 ++++++------ src/Protocol/DFRN.php | 9 +++------ src/Protocol/Diaspora.php | 2 +- 6 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/Module/Profile/Status.php b/src/Module/Profile/Status.php index 2bb7b6eaa5..1c07281b2f 100644 --- a/src/Module/Profile/Status.php +++ b/src/Module/Profile/Status.php @@ -159,7 +159,7 @@ class Status extends BaseProfile // Does the profile page belong to a forum? // If not then we can improve the performance with an additional condition - $condition2 = ['uid' => $profile['uid'], 'page-flags' => [User::PAGE_FLAGS_COMMUNITY, User::PAGE_FLAGS_PRVGROUP]]; + $condition2 = ['uid' => $profile['uid'], 'account-type' => User::ACCOUNT_TYPE_COMMUNITY]; if (!DBA::exists('user', $condition2)) { $condition = DBA::mergeConditions($condition, ['contact-id' => $profile['id']]); } diff --git a/src/Module/Settings/Profile/Index.php b/src/Module/Settings/Profile/Index.php index adc4fa68db..49130e8c57 100644 --- a/src/Module/Settings/Profile/Index.php +++ b/src/Module/Settings/Profile/Index.php @@ -208,7 +208,7 @@ class Index extends BaseSettings '$baseurl' => DI::baseUrl()->get(true), ]); - $personal_account = !in_array($profile['page-flags'], [User::PAGE_FLAGS_COMMUNITY, User::PAGE_FLAGS_PRVGROUP]); + $personal_account = ($profile['account-type'] != User::ACCOUNT_TYPE_COMMUNITY); $tpl = Renderer::getMarkupTemplate('settings/profile/index.tpl'); $o .= Renderer::replaceMacros($tpl, [ diff --git a/src/Navigation/Notifications/Repository/Notify.php b/src/Navigation/Notifications/Repository/Notify.php index 9b195a753b..6d56258b37 100644 --- a/src/Navigation/Notifications/Repository/Notify.php +++ b/src/Navigation/Notifications/Repository/Notify.php @@ -216,7 +216,7 @@ class Notify extends BaseRepository } // Ensure that the important fields are set at any time - $fields = ['nickname', 'page-flags', 'notify-flags', 'language', 'username', 'email']; + $fields = ['nickname', 'account-type', 'notify-flags', 'language', 'username', 'email']; $user = DBA::selectFirst('user', $fields, ['uid' => $params['uid']]); if (!DBA::isResult($user)) { @@ -225,7 +225,7 @@ class Notify extends BaseRepository } // There is no need to create notifications for forum accounts - if (in_array($user['page-flags'], [Model\User::PAGE_FLAGS_COMMUNITY, Model\User::PAGE_FLAGS_PRVGROUP])) { + if ($user['account-type'] == Model\User::ACCOUNT_TYPE_COMMUNITY) { return false; } diff --git a/src/Protocol/ActivityPub/Transmitter.php b/src/Protocol/ActivityPub/Transmitter.php index 0b7159ec90..31c6d22953 100644 --- a/src/Protocol/ActivityPub/Transmitter.php +++ b/src/Protocol/ActivityPub/Transmitter.php @@ -505,13 +505,13 @@ class Transmitter * @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_mode "true" means that we are sending content to a forum + * @param boolean $forum_post "true" means that we are sending content to a forum * * @return array with permission data * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function createPermissionBlockForItem($item, $blindcopy, $last_id = 0, $forum_mode = false) + private static function createPermissionBlockForItem($item, $blindcopy, $last_id = 0, $forum_post = false) { if ($last_id == 0) { $last_id = $item['id']; @@ -638,7 +638,7 @@ class Transmitter // 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_mode) { + if (($item['private'] != Item::PRIVATE) && !$forum_post) { $data['cc'][] = $actor_profile['followers']; } } @@ -808,14 +808,14 @@ class Transmitter * @param integer $uid User ID * @param boolean $personal fetch personal inboxes * @param integer $last_id Last item id for adding receivers - * @param boolean $forum_mode "true" means that we are sending content to a forum + * @param boolean $forum_post "true" means that we are sending content to a forum * @return array with inboxes * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function fetchTargetInboxes($item, $uid, $personal = false, $last_id = 0, $forum_mode = false) + public static function fetchTargetInboxes($item, $uid, $personal = false, $last_id = 0, $forum_post = false) { - $permissions = self::createPermissionBlockForItem($item, true, $last_id, $forum_mode); + $permissions = self::createPermissionBlockForItem($item, true, $last_id, $forum_post); if (empty($permissions)) { return []; } diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index 3a14a0db9a..833c616ab9 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -1547,7 +1547,7 @@ class DFRN if ($item["thr-parent"] != $item["uri"]) { $community = false; - if ($importer["page-flags"] == User::PAGE_FLAGS_COMMUNITY || $importer["page-flags"] == User::PAGE_FLAGS_PRVGROUP) { + if ($importer['account-type'] == User::ACCOUNT_TYPE_COMMUNITY) { $sql_extra = ""; $community = true; Logger::notice("possible community action"); @@ -2381,14 +2381,11 @@ class DFRN return false; } - $user = DBA::selectFirst('user', ['page-flags', 'nickname'], ['uid' => $uid]); + $user = DBA::selectFirst('user', ['account-type', 'nickname'], ['uid' => $uid]); if (!DBA::isResult($user)) { return false; } - $community_page = ($user['page-flags'] == User::PAGE_FLAGS_COMMUNITY); - $prvgroup = ($user['page-flags'] == User::PAGE_FLAGS_PRVGROUP); - $link = Strings::normaliseLink(DI::baseUrl() . '/profile/' . $user['nickname']); /* @@ -2411,7 +2408,7 @@ class DFRN return false; } - return $community_page || $prvgroup; + return ($user['account-type'] == User::ACCOUNT_TYPE_COMMUNITY); } /** diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index 45879df2ae..aba79364f4 100644 --- a/src/Protocol/Diaspora.php +++ b/src/Protocol/Diaspora.php @@ -859,7 +859,7 @@ class Diaspora // Yes, then it is fine. return true; // Is it a post to a community? - } elseif (($contact["rel"] == Contact::FOLLOWER) && in_array($importer["page-flags"], [User::PAGE_FLAGS_COMMUNITY, User::PAGE_FLAGS_PRVGROUP])) { + } 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? From 9a764516d0c9da99a7dd4fcde252c685b9de0a99 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 9 Feb 2022 06:52:16 +0000 Subject: [PATCH 2/5] Use the "contact-type" instead of "forum" or "prv" --- database.sql | 2 +- src/Content/Widget/VCard.php | 2 +- src/Model/Contact.php | 31 ++++------------------------- src/Model/Profile.php | 2 +- src/Module/Contact.php | 2 +- src/Module/Contact/Hovercard.php | 2 +- src/Module/Contact/Profile.php | 2 +- src/Module/Conversation/Network.php | 2 +- src/Module/Directory.php | 2 +- src/Protocol/DFRN.php | 4 ++-- static/dbstructure.config.php | 2 +- update.php | 9 +++++++++ 12 files changed, 24 insertions(+), 38 deletions(-) diff --git a/database.sql b/database.sql index b7a923618d..4237bcce34 100644 --- a/database.sql +++ b/database.sql @@ -1,6 +1,6 @@ -- ------------------------------------------ -- Friendica 2022.05-dev (Siberian Iris) --- DB_UPDATE_VERSION 1450 +-- DB_UPDATE_VERSION 1451 -- ------------------------------------------ diff --git a/src/Content/Widget/VCard.php b/src/Content/Widget/VCard.php index d230afd303..7f75c6c9c0 100644 --- a/src/Content/Widget/VCard.php +++ b/src/Content/Widget/VCard.php @@ -99,7 +99,7 @@ class VCard '$network_link' => $network_link, '$network_avatar' => $network_avatar, '$network' => DI::l10n()->t('Network:'), - '$account_type' => Contact::getAccountType($contact), + '$account_type' => Contact::getAccountType($contact['contact-type']), '$follow' => DI::l10n()->t('Follow'), '$follow_link' => $follow_link, '$unfollow' => DI::l10n()->t('Unfollow'), diff --git a/src/Model/Contact.php b/src/Model/Contact.php index 0af28a7401..1b39247f4e 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -1457,34 +1457,11 @@ class Contact * * The function can be called with either the user or the contact array * - * @param array $contact contact or user array + * @param int $type type of contact or account * @return string */ - public static function getAccountType(array $contact) + public static function getAccountType(int $type) { - // There are several fields that indicate that the contact or user is a forum - // "page-flags" is a field in the user table, - // "forum" and "prv" are used in the contact table. They stand for User::PAGE_FLAGS_COMMUNITY and User::PAGE_FLAGS_PRVGROUP. - if ((isset($contact['page-flags']) && (intval($contact['page-flags']) == User::PAGE_FLAGS_COMMUNITY)) - || (isset($contact['page-flags']) && (intval($contact['page-flags']) == User::PAGE_FLAGS_PRVGROUP)) - || (isset($contact['forum']) && intval($contact['forum'])) - || (isset($contact['prv']) && intval($contact['prv'])) - || (isset($contact['community']) && intval($contact['community'])) - ) { - $type = self::TYPE_COMMUNITY; - } else { - $type = self::TYPE_PERSON; - } - - // The "contact-type" (contact table) and "account-type" (user table) are more general then the chaos from above. - if (isset($contact["contact-type"])) { - $type = $contact["contact-type"]; - } - - if (isset($contact["account-type"])) { - $type = $contact["account-type"]; - } - switch ($type) { case self::TYPE_ORGANISATION: $account_type = DI::l10n()->t("Organisation"); @@ -2947,7 +2924,7 @@ class Contact */ public static function isForum($contactid) { - $fields = ['contact-type', 'forum', 'prv']; + $fields = ['contact-type']; $condition = ['id' => $contactid]; $contact = DBA::selectFirst('contact', $fields, $condition); if (!DBA::isResult($contact)) { @@ -2955,7 +2932,7 @@ class Contact } // Is it a forum? - return (($contact['contact-type'] == self::TYPE_COMMUNITY) || $contact['forum'] || $contact['prv']); + return ($contact['contact-type'] == self::TYPE_COMMUNITY); } /** diff --git a/src/Model/Profile.php b/src/Model/Profile.php index cb7fa65479..d779355202 100644 --- a/src/Model/Profile.php +++ b/src/Model/Profile.php @@ -362,7 +362,7 @@ class Profile } // Fetch the account type - $account_type = Contact::getAccountType($profile); + $account_type = Contact::getAccountType($profile['account-type']); if (!empty($profile['address']) || !empty($profile['location'])) { $location = DI::l10n()->t('Location:'); diff --git a/src/Module/Contact.php b/src/Module/Contact.php index d571016f19..c7b2870ece 100644 --- a/src/Module/Contact.php +++ b/src/Module/Contact.php @@ -558,7 +558,7 @@ class Contact extends BaseModule 'details' => $contact['location'], 'tags' => $contact['keywords'], 'about' => $contact['about'], - 'account_type' => Model\Contact::getAccountType($contact), + 'account_type' => Model\Contact::getAccountType($contact['contact-type']), 'sparkle' => $sparkle, 'itemurl' => ($contact['addr'] ?? '') ?: $contact['url'], 'network' => ContactSelector::networkToName($contact['network'], $contact['url'], $contact['protocol'], $contact['gsid']), diff --git a/src/Module/Contact/Hovercard.php b/src/Module/Contact/Hovercard.php index ec77a19cb9..cd03e2533a 100644 --- a/src/Module/Contact/Hovercard.php +++ b/src/Module/Contact/Hovercard.php @@ -101,7 +101,7 @@ class Hovercard extends BaseModule 'network_link' => Strings::formatNetworkName($contact['network'], $contact['url']), 'tags' => $contact['keywords'], 'bd' => $contact['bd'] <= DBA::NULL_DATE ? '' : $contact['bd'], - 'account_type' => Contact::getAccountType($contact), + 'account_type' => Contact::getAccountType($contact['contact-type']), 'actions' => $actions, ], ]); diff --git a/src/Module/Contact/Profile.php b/src/Module/Contact/Profile.php index e02a6a3dc6..8ab8dae60e 100644 --- a/src/Module/Contact/Profile.php +++ b/src/Module/Contact/Profile.php @@ -364,7 +364,7 @@ class Profile extends BaseModule '$url' => $url, '$profileurllabel' => $this->t('Profile URL'), '$profileurl' => $contact['url'], - '$account_type' => Contact::getAccountType($contact), + '$account_type' => Contact::getAccountType($contact['contact-type']), '$location' => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['location']), '$location_label' => $this->t('Location:'), '$xmpp' => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['xmpp']), diff --git a/src/Module/Conversation/Network.php b/src/Module/Conversation/Network.php index 908d0a63b4..2978ecbb9d 100644 --- a/src/Module/Conversation/Network.php +++ b/src/Module/Conversation/Network.php @@ -119,7 +119,7 @@ class Network extends BaseModule if (self::$forumContactId) { // If self::$forumContactId belongs to a communitity forum or a privat goup,.add a mention to the status editor - $condition = ["`id` = ? AND (`forum` OR `prv`)", self::$forumContactId]; + $condition = ["`id` = ? AND `contact-type` = ?", self::$forumContactId, Contact::TYPE_COMMUNITY]; $contact = DBA::selectFirst('contact', ['addr'], $condition); if (!empty($contact['addr'])) { $content = '!' . $contact['addr']; diff --git a/src/Module/Directory.php b/src/Module/Directory.php index 3a0a9fa34e..8d7b8611b6 100644 --- a/src/Module/Directory.php +++ b/src/Module/Directory.php @@ -165,7 +165,7 @@ class Directory extends BaseModule 'img_hover' => $contact['name'], 'name' => $contact['name'], 'details' => $details, - 'account_type' => Model\Contact::getAccountType($contact), + 'account_type' => Model\Contact::getAccountType($contact['contact-type']), 'profile' => $profile, 'location' => $location_e, 'tags' => $contact['pub_keywords'], diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index 833c616ab9..94b1b1689d 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -925,9 +925,9 @@ class DFRN foreach ($mentioned as $mention) { $condition = ['uid' => $owner["uid"], 'nurl' => Strings::normaliseLink($mention)]; - $contact = DBA::selectFirst('contact', ['forum', 'prv'], $condition); + $contact = DBA::selectFirst('contact', ['contact-type'], $condition); - if (DBA::isResult($contact) && ($contact["forum"] || $contact["prv"])) { + if (DBA::isResult($contact) && ($contact['contact-type'] == Contact::TYPE_COMMUNITY)) { XML::addElement( $doc, $entry, diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index 2e1a2191c0..014185c92a 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', 1450); + define('DB_UPDATE_VERSION', 1451); } return [ diff --git a/update.php b/update.php index 7b5f6778be..6e9c294c1f 100644 --- a/update.php +++ b/update.php @@ -55,6 +55,7 @@ use Friendica\Model\Notification; use Friendica\Model\Photo; use Friendica\Model\Post; use Friendica\Model\Profile; +use Friendica\Model\User; use Friendica\Security\PermissionSet\Repository\PermissionSet; use Friendica\Worker\Delivery; @@ -1087,3 +1088,11 @@ function update_1446() return Update::SUCCESS; } + +function update_1451() +{ + DBA::update('user', ['account-type' => User::ACCOUNT_TYPE_COMMUNITY], ['page-flags' => [User::PAGE_FLAGS_COMMUNITY, User::PAGE_FLAGS_PRVGROUP]]); + DBA::update('contact', ['contact-type' => Contact::TYPE_COMMUNITY], ["`forum` OR `prv`"]); + + return Update::SUCCESS; +} From 6c156e3bc6eaaffd51ccc894fd8874da138f97d1 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 9 Feb 2022 07:02:06 +0000 Subject: [PATCH 3/5] Set "manually-approve" in the update --- update.php | 1 + 1 file changed, 1 insertion(+) diff --git a/update.php b/update.php index 6e9c294c1f..016fe8a2ec 100644 --- a/update.php +++ b/update.php @@ -1093,6 +1093,7 @@ function update_1451() { DBA::update('user', ['account-type' => User::ACCOUNT_TYPE_COMMUNITY], ['page-flags' => [User::PAGE_FLAGS_COMMUNITY, User::PAGE_FLAGS_PRVGROUP]]); DBA::update('contact', ['contact-type' => Contact::TYPE_COMMUNITY], ["`forum` OR `prv`"]); + DBA::update('contact', ['manually-approve' => true], ['prv' => true]); return Update::SUCCESS; } From 85eab6ebee301dd5351c1659121d341ba36e4764 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 9 Feb 2022 19:44:10 +0000 Subject: [PATCH 4/5] New field for groups that are connected with forums --- database.sql | 5 ++++- doc/database/db_group.md | 17 ++++++++++------- static/dbstructure.config.php | 2 ++ 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/database.sql b/database.sql index 4237bcce34..ea129109dc 100644 --- a/database.sql +++ b/database.sql @@ -644,10 +644,13 @@ CREATE TABLE IF NOT EXISTS `group` ( `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'Owner User id', `visible` boolean NOT NULL DEFAULT '0' COMMENT '1 indicates the member list is not private', `deleted` boolean NOT NULL DEFAULT '0' COMMENT '1 indicates the group has been deleted', + `cid` int unsigned COMMENT 'Contact id of forum. When this field is filled then the members are synced automatically.', `name` varchar(255) NOT NULL DEFAULT '' COMMENT 'human readable name of group', PRIMARY KEY(`id`), INDEX `uid` (`uid`), - FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE + INDEX `cid` (`cid`), + FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE, + FOREIGN KEY (`cid`) REFERENCES `contact` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='privacy groups, group info'; -- diff --git a/doc/database/db_group.md b/doc/database/db_group.md index 1892de3e40..ad7fa4a3dd 100644 --- a/doc/database/db_group.md +++ b/doc/database/db_group.md @@ -6,13 +6,14 @@ privacy groups, group info Fields ------ -| Field | Description | Type | Null | Key | Default | Extra | -| ------- | ------------------------------------------ | ------------------ | ---- | --- | ------- | -------------- | -| id | sequential ID | int unsigned | NO | PRI | NULL | auto_increment | -| uid | Owner User id | mediumint unsigned | NO | | 0 | | -| visible | 1 indicates the member list is not private | boolean | NO | | 0 | | -| deleted | 1 indicates the group has been deleted | boolean | NO | | 0 | | -| name | human readable name of group | varchar(255) | NO | | | | +| Field | Description | Type | Null | Key | Default | Extra | +| ------- | ----------------------------------------------------------------------------------------- | ------------------ | ---- | --- | ------- | -------------- | +| id | sequential ID | int unsigned | NO | PRI | NULL | auto_increment | +| uid | Owner User id | mediumint unsigned | NO | | 0 | | +| visible | 1 indicates the member list is not private | boolean | NO | | 0 | | +| deleted | 1 indicates the group has been deleted | boolean | NO | | 0 | | +| cid | Contact id of forum. When this field is filled then the members are synced automatically. | int unsigned | YES | | NULL | | +| name | human readable name of group | varchar(255) | NO | | | | Indexes ------------ @@ -21,6 +22,7 @@ Indexes | ------- | ------ | | PRIMARY | id | | uid | uid | +| cid | cid | Foreign Keys ------------ @@ -28,5 +30,6 @@ Foreign Keys | Field | Target Table | Target Field | |-------|--------------|--------------| | uid | [user](help/database/db_user) | uid | +| cid | [contact](help/database/db_contact) | id | Return to [database documentation](help/database) diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index 014185c92a..0cf8543718 100644 --- a/static/dbstructure.config.php +++ b/static/dbstructure.config.php @@ -704,11 +704,13 @@ return [ "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "foreign" => ["user" => "uid"], "comment" => "Owner User id"], "visible" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "1 indicates the member list is not private"], "deleted" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "1 indicates the group has been deleted"], + "cid" => ["type" => "int unsigned", "foreign" => ["contact" => "id"], "comment" => "Contact id of forum. When this field is filled then the members are synced automatically."], "name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "human readable name of group"], ], "indexes" => [ "PRIMARY" => ["id"], "uid" => ["uid"], + "cid" => ["cid"], ] ], "group_member" => [ From 5b46b4122688e1c848083843e0d3aa84d6eba7ec Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 9 Feb 2022 21:34:25 +0000 Subject: [PATCH 5/5] New function to add group members from a forum --- src/Model/Group.php | 50 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/Model/Group.php b/src/Model/Group.php index 17e0a18e2e..390ed532e3 100644 --- a/src/Model/Group.php +++ b/src/Model/Group.php @@ -29,6 +29,7 @@ use Friendica\Database\Database; use Friendica\Database\DBA; use Friendica\DI; use Friendica\Network\HTTPException; +use Friendica\Protocol\ActivityPub; /** * functions for interacting with the group database table @@ -519,4 +520,53 @@ class Group return $o; } + + /** + * 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) { + $contact = Contact::getById($id, ['uid', 'url', 'name']); + if (empty($contact)) { + return; + } + + $apcontact = APContact::getByURL($contact['url']); + if (empty($apcontact['followers'])) { + return; + } + + $group = DBA::selectFirst('group', ['id'], ['uid' => $contact['uid'], 'cid' => $id]); + if (empty($group)) { + $fields = [ + 'uid' => $contact['uid'], + 'name' => $contact['name'], + 'cid' => $id, + ]; + DBA::insert('group', $fields); + $gid = DBA::lastInsertId(); + } else { + $gid = $group['id']; + } + + $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) { + $id = Contact::getIdForURL($follower); + if (!in_array($id, $current)) { + DBA::insert('group_member', ['gid' => $gid, 'contact-id' => $id]); + } else { + $key = array_search($id, $current); + unset($current[$key]); + } + } + + DBA::delete('group_member', ['gid' => $gid, 'contact-id' => $current]); + } }