mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-10-22 19:42:13 +00:00
core: improve message forwarding to better manage support scopes (#6056)
* core: test forwarding in support scope * wip * test * add to test * comment * rework forwarding * fixes * refactor tests * narrow * forwardMsgs * support mem * unfocus tests * fix, tests * plans * add test * comment * add scope to reaction and deletion, refactor * fix del * refactor * query plans --------- Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
This commit is contained in:
1 parent
f3454f1f90
commit
8094078bee
8 files changed
+695
-241
No files matched your search
@@ -60,6 +60,8 @@ module Simplex.Chat.Store.Groups
|
||||
getMentionedMemberByMemberId,
|
||||
getGroupMemberById,
|
||||
getGroupMemberByMemberId,
|
||||
getGroupMemberIdViaMemberId,
|
||||
getScopeMemberIdViaMemberId,
|
||||
getGroupMembers,
|
||||
getGroupModerators,
|
||||
getGroupMembersForExpiration,
|
||||
@@ -103,7 +105,10 @@ module Simplex.Chat.Store.Groups
|
||||
getIntroduction,
|
||||
getIntroducedGroupMemberIds,
|
||||
getForwardIntroducedMembers,
|
||||
getForwardIntroducedModerators,
|
||||
getForwardInvitedMembers,
|
||||
getForwardInvitedModerators,
|
||||
getForwardScopeMember,
|
||||
createIntroReMember,
|
||||
createIntroToMemberContact,
|
||||
saveMemberInvitation,
|
||||
@@ -182,7 +187,7 @@ import qualified Simplex.Messaging.Crypto as C
|
||||
import Simplex.Messaging.Crypto.Ratchet (pattern PQEncOff, pattern PQSupportOff)
|
||||
import Simplex.Messaging.Parsers (defaultJSON)
|
||||
import Simplex.Messaging.Protocol (SubscriptionMode (..))
|
||||
import Simplex.Messaging.Util (eitherToMaybe, firstRow', ($>>=), (<$$>))
|
||||
import Simplex.Messaging.Util (eitherToMaybe, firstRow', ($>>), ($>>=), (<$$>))
|
||||
import Simplex.Messaging.Version
|
||||
import UnliftIO.STM
|
||||
#if defined(dbPostgres)
|
||||
@@ -1091,6 +1096,20 @@ getGroupMemberByMemberId db vr user@User {userId} GroupInfo {groupId} memberId =
|
||||
(groupMemberQuery <> " WHERE m.group_id = ? AND m.member_id = ?")
|
||||
(userId, groupId, memberId)
|
||||
|
||||
getScopeMemberIdViaMemberId :: DB.Connection -> User -> GroupInfo -> GroupMember -> MemberId -> ExceptT StoreError IO GroupMemberId
|
||||
getScopeMemberIdViaMemberId db user g@GroupInfo {membership} sender scopeMemberId
|
||||
| scopeMemberId == memberId' membership = pure $ groupMemberId' membership
|
||||
| scopeMemberId == memberId' sender = pure $ groupMemberId' sender
|
||||
| otherwise = getGroupMemberIdViaMemberId db user g scopeMemberId
|
||||
|
||||
getGroupMemberIdViaMemberId :: DB.Connection -> User -> GroupInfo -> MemberId -> ExceptT StoreError IO GroupMemberId
|
||||
getGroupMemberIdViaMemberId db User {userId} GroupInfo {groupId} memberId =
|
||||
ExceptT . firstRow fromOnly (SEGroupMemberNotFoundByMemberId memberId) $
|
||||
DB.query
|
||||
db
|
||||
"SELECT group_member_id FROM group_members WHERE user_id = ? AND group_id = ? AND member_id = ?"
|
||||
(userId, groupId, memberId)
|
||||
|
||||
getGroupMembers :: DB.Connection -> VersionRangeChat -> User -> GroupInfo -> IO [GroupMember]
|
||||
getGroupMembers db vr user@User {userId, userContactId} GroupInfo {groupId} = do
|
||||
map (toContactMember vr user)
|
||||
@@ -1727,6 +1746,26 @@ getForwardIntroducedMembers db vr user invitee highlyAvailable = do
|
||||
WHERE to_group_member_id = ? AND intro_status NOT IN (?,?,?)
|
||||
|]
|
||||
|
||||
-- for support scope we don't need to filter by intro_chat_protocol_version for non highly available client,
|
||||
-- as we will filter moderators supporting this feature by a higher version (as opposed to getForwardIntroducedMembers)
|
||||
getForwardIntroducedModerators :: DB.Connection -> VersionRangeChat -> User -> GroupMember -> IO [GroupMember]
|
||||
getForwardIntroducedModerators db vr user@User {userContactId} invitee = do
|
||||
memberIds <- map fromOnly <$> query
|
||||
rights <$> mapM (runExceptT . getGroupMemberById db vr user) memberIds
|
||||
where
|
||||
mId = groupMemberId' invitee
|
||||
query =
|
||||
DB.query
|
||||
db
|
||||
[sql|
|
||||
SELECT i.re_group_member_id
|
||||
FROM group_member_intros i
|
||||
JOIN group_members m ON m.group_member_id = i.re_group_member_id
|
||||
WHERE i.to_group_member_id = ? AND i.intro_status NOT IN (?,?,?)
|
||||
AND (m.contact_id IS NULL OR m.contact_id != ?) AND m.member_role IN (?,?,?)
|
||||
|]
|
||||
(mId, GMIntroReConnected, GMIntroToConnected, GMIntroConnected, userContactId, GRModerator, GRAdmin, GROwner)
|
||||
|
||||
getForwardInvitedMembers :: DB.Connection -> VersionRangeChat -> User -> GroupMember -> Bool -> IO [GroupMember]
|
||||
getForwardInvitedMembers db vr user forwardMember highlyAvailable = do
|
||||
memberIds <- map fromOnly <$> query
|
||||
@@ -1747,6 +1786,46 @@ getForwardInvitedMembers db vr user forwardMember highlyAvailable = do
|
||||
WHERE re_group_member_id = ? AND intro_status NOT IN (?,?,?)
|
||||
|]
|
||||
|
||||
-- for support scope we don't need to filter by intro_chat_protocol_version for non highly available client,
|
||||
-- as we will filter moderators supporting this feature by a higher version (as opposed to getForwardInvitedMembers)
|
||||
getForwardInvitedModerators :: DB.Connection -> VersionRangeChat -> User -> GroupMember -> IO [GroupMember]
|
||||
getForwardInvitedModerators db vr user@User {userContactId} forwardMember = do
|
||||
memberIds <- map fromOnly <$> query
|
||||
rights <$> mapM (runExceptT . getGroupMemberById db vr user) memberIds
|
||||
where
|
||||
mId = groupMemberId' forwardMember
|
||||
query =
|
||||
DB.query
|
||||
db
|
||||
[sql|
|
||||
SELECT i.to_group_member_id
|
||||
FROM group_member_intros i
|
||||
JOIN group_members m ON m.group_member_id = i.to_group_member_id
|
||||
WHERE i.re_group_member_id = ? AND i.intro_status NOT IN (?,?,?)
|
||||
AND (m.contact_id IS NULL OR m.contact_id != ?) AND m.member_role IN (?,?,?)
|
||||
|]
|
||||
(mId, GMIntroReConnected, GMIntroToConnected, GMIntroConnected, userContactId, GRModerator, GRAdmin, GROwner)
|
||||
|
||||
getForwardScopeMember :: DB.Connection -> VersionRangeChat -> User -> GroupMember -> GroupMemberId -> IO (Maybe GroupMember)
|
||||
getForwardScopeMember db vr user GroupMember {groupMemberId = sendingGMId} scopeGMId = do
|
||||
(introExists_ :: Maybe Int64) <-
|
||||
liftIO $ maybeFirstRow fromOnly $
|
||||
DB.query
|
||||
db
|
||||
[sql|
|
||||
SELECT 1
|
||||
FROM group_member_intros
|
||||
WHERE
|
||||
(
|
||||
(re_group_member_id = ? AND to_group_member_id = ?) OR
|
||||
(re_group_member_id = ? AND to_group_member_id = ?)
|
||||
)
|
||||
AND intro_status NOT IN (?,?,?)
|
||||
LIMIT 1
|
||||
|]
|
||||
(sendingGMId, scopeGMId, scopeGMId, sendingGMId, GMIntroReConnected, GMIntroToConnected, GMIntroConnected)
|
||||
pure introExists_ $>> (eitherToMaybe <$> runExceptT (getGroupMemberById db vr user scopeGMId))
|
||||
|
||||
createIntroReMember :: DB.Connection -> User -> GroupInfo -> GroupMember -> VersionChat -> MemberInfo -> Maybe MemberRestrictions -> (CommandId, ConnId) -> SubscriptionMode -> ExceptT StoreError IO GroupMember
|
||||
createIntroReMember
|
||||
db
|
||||
|
||||
@@ -1041,6 +1041,24 @@ SEARCH g USING INTEGER PRIMARY KEY (rowid=?)
|
||||
SEARCH gp USING INTEGER PRIMARY KEY (rowid=?)
|
||||
SEARCH pu USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
SELECT 1
|
||||
FROM group_member_intros
|
||||
WHERE
|
||||
(
|
||||
(re_group_member_id = ? AND to_group_member_id = ?) OR
|
||||
(re_group_member_id = ? AND to_group_member_id = ?)
|
||||
)
|
||||
AND intro_status NOT IN (?,?,?)
|
||||
LIMIT 1
|
||||
|
||||
Plan:
|
||||
MULTI-INDEX OR
|
||||
INDEX 1
|
||||
SEARCH group_member_intros USING INDEX sqlite_autoindex_group_member_intros_1 (re_group_member_id=? AND to_group_member_id=?)
|
||||
INDEX 2
|
||||
SEARCH group_member_intros USING INDEX sqlite_autoindex_group_member_intros_1 (re_group_member_id=? AND to_group_member_id=?)
|
||||
|
||||
Query:
|
||||
SELECT 1 FROM users
|
||||
WHERE (user_id = ? AND local_display_name = ?)
|
||||
@@ -1334,6 +1352,28 @@ Plan:
|
||||
SEARCH g USING INTEGER PRIMARY KEY (rowid=?)
|
||||
SEARCH i USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
SELECT i.re_group_member_id
|
||||
FROM group_member_intros i
|
||||
JOIN group_members m ON m.group_member_id = i.re_group_member_id
|
||||
WHERE i.to_group_member_id = ? AND i.intro_status NOT IN (?,?,?)
|
||||
AND (m.contact_id IS NULL OR m.contact_id != ?) AND m.member_role IN (?,?,?)
|
||||
|
||||
Plan:
|
||||
SEARCH i USING INDEX idx_group_member_intros_to_group_member_id (to_group_member_id=?)
|
||||
SEARCH m USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
SELECT i.to_group_member_id
|
||||
FROM group_member_intros i
|
||||
JOIN group_members m ON m.group_member_id = i.to_group_member_id
|
||||
WHERE i.re_group_member_id = ? AND i.intro_status NOT IN (?,?,?)
|
||||
AND (m.contact_id IS NULL OR m.contact_id != ?) AND m.member_role IN (?,?,?)
|
||||
|
||||
Plan:
|
||||
SEARCH i USING INDEX idx_group_member_intros_re_group_member_id (re_group_member_id=?)
|
||||
SEARCH m USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
SELECT member_status
|
||||
FROM group_members
|
||||
@@ -3565,6 +3605,15 @@ Query:
|
||||
Plan:
|
||||
SEARCH chat_items USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
UPDATE connections SET conn_status='deleted'
|
||||
WHERE group_member_id IN (SELECT group_member_id FROM group_members WHERE local_display_name = ?)
|
||||
|
||||
Plan:
|
||||
SEARCH connections USING INDEX idx_connections_group_member_id (group_member_id=?)
|
||||
LIST SUBQUERY 1
|
||||
SCAN group_members USING COVERING INDEX idx_group_members_user_id_local_display_name
|
||||
|
||||
Query:
|
||||
UPDATE group_member_intros
|
||||
SET intro_status = ?,
|
||||
@@ -3576,6 +3625,18 @@ Query:
|
||||
Plan:
|
||||
SEARCH group_member_intros USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
UPDATE group_member_intros SET intro_status='fwd'
|
||||
WHERE re_group_member_id IN (SELECT group_member_id FROM group_members WHERE local_display_name = ?)
|
||||
AND to_group_member_id IN (SELECT group_member_id FROM group_members WHERE local_display_name = ?)
|
||||
|
||||
Plan:
|
||||
SEARCH group_member_intros USING INDEX sqlite_autoindex_group_member_intros_1 (re_group_member_id=? AND to_group_member_id=?)
|
||||
LIST SUBQUERY 1
|
||||
SCAN group_members USING COVERING INDEX idx_group_members_user_id_local_display_name
|
||||
LIST SUBQUERY 2
|
||||
SCAN group_members USING COVERING INDEX idx_group_members_user_id_local_display_name
|
||||
|
||||
Query:
|
||||
UPDATE group_members
|
||||
SET contact_id = ?, local_display_name = ?, contact_profile_id = ?, updated_at = ?
|
||||
@@ -5997,10 +6058,6 @@ Query: UPDATE connections SET conn_status = ?, updated_at = ?, conn_req_inv = NU
|
||||
Plan:
|
||||
SEARCH connections USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query: UPDATE connections SET conn_status='deleted' WHERE group_member_id = 3
|
||||
Plan:
|
||||
SEARCH connections USING INDEX idx_connections_group_member_id (group_member_id=?)
|
||||
|
||||
Query: UPDATE connections SET conn_type = ?, group_member_id = ?, updated_at = ? WHERE connection_id = ?
|
||||
Plan:
|
||||
SEARCH connections USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Reference in new issue
Block a user