mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-10-23 06:22:43 +00:00
core: chat relays protocol (#6383)
* core: chat relays protocol wip * types, notes * remove file * removal protocol * schema * status * update * recovery * update * formatting * rename * more types * comment * more docs * decrease number of steps * format * correct * update * update protocol * update * typo * todo * update doc * update * update * remove added * update * update * XGrpRelayReady * link to chat relays * update * remove from protocol * update * json * wip * remove comment * wip * update * wip * wip * update * wip * wip * plans * better view * fix * fix * relay acceptance * rework api * add relays to link * comment * active on con, fix send * comments * direct in group plan * prepare * member connection wip * comments * member connection wip * fix forwarding * introduce moderators to new member * enable relay tests * plans * security objectives * refactor * add to threat model * stress test wip * stress test wip * Revert "stress test wip" This reverts commitacde8a1fb3. * Revert "stress test wip" This reverts commit6435808438. * remove stress test * improve output * invert relay fkey * postgres schema * comments * group in progress, remove auto-select relays commented code * comments * corrections * comment * lint * redundant import * core: chat relay request worker (#6509) * update plans * strict tables * core: update group link asynchronously with relay link (#6548) * update simplexmq * docs: connection to chat relays rfc (#6554) * add test for 2 relays (doesn't pass) * create unknown member in same transaction as checking * fix relays choosing different memberId (XContactRelay) * plans, api * use same incognito profile for relays, connect concurrently, save correct link for plan * test * don't duplicate items on group connection * check relay record exists when joining * use mapConcurrently when adding relays, update schemas * fix multi-relay join for postgres (savepoint) * core: async retry connection to chat relays (#6584) * update simplexmq * fix api tests * prefer throwing temp error on connection * check group relays when deleting from configuration * relay_request_err_reason * relay role * rename, fix syntax * plans * rename, style --------- Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
This commit is contained in:
1 parent
2f1816ca32
commit
bd8ba4d5c6
46 files changed
+3198
-739
No files matched your search
@@ -135,21 +135,22 @@ getConnectionEntity db vr user@User {userId, userContactId} agentConnId = do
|
||||
[sql|
|
||||
SELECT
|
||||
-- GroupInfo
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, gp.short_descr, g.local_alias, gp.description, gp.image,
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, gp.short_descr, g.local_alias, gp.description, gp.image, gp.group_link,
|
||||
g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, gp.member_admission,
|
||||
g.created_at, g.updated_at, g.chat_ts, g.user_member_profile_sent_at,
|
||||
g.conn_full_link_to_connect, g.conn_short_link_to_connect, g.conn_link_prepared_connection, g.conn_link_started_connection, g.welcome_shared_msg_id, g.request_shared_msg_id,
|
||||
g.business_chat, g.business_member_id, g.customer_member_id,
|
||||
g.use_relays, g.relay_own_status,
|
||||
g.ui_themes, g.summary_current_members_count, g.custom_data, g.chat_item_ttl, g.members_require_attention, g.via_group_link_uri,
|
||||
-- GroupInfo {membership}
|
||||
mu.group_member_id, mu.group_id, mu.index_in_group, mu.member_id, mu.peer_chat_min_version, mu.peer_chat_max_version, mu.member_role, mu.member_category,
|
||||
mu.member_status, mu.show_messages, mu.member_restriction, mu.is_chat_relay, mu.invited_by, mu.invited_by_group_member_id, mu.local_display_name, mu.contact_id, mu.contact_profile_id, pu.contact_profile_id,
|
||||
mu.member_status, mu.show_messages, mu.member_restriction, mu.invited_by, mu.invited_by_group_member_id, mu.local_display_name, mu.contact_id, mu.contact_profile_id, pu.contact_profile_id,
|
||||
-- GroupInfo {membership = GroupMember {memberProfile}}
|
||||
pu.display_name, pu.full_name, pu.short_descr, pu.image, pu.contact_link, pu.chat_peer_type, pu.local_alias, pu.preferences,
|
||||
mu.created_at, mu.updated_at,
|
||||
mu.support_chat_ts, mu.support_chat_items_unread, mu.support_chat_items_member_attention, mu.support_chat_items_mentions, mu.support_chat_last_msg_from_member_ts,
|
||||
-- from GroupMember
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction, m.is_chat_relay,
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.chat_peer_type, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts
|
||||
|
||||
@@ -161,11 +161,11 @@ getNextDeliveryTasks :: DB.Connection -> GroupInfo -> MessageDeliveryTask -> IO
|
||||
getNextDeliveryTasks db gInfo task =
|
||||
getWorkItems "message delivery task" getTaskIds (getMsgDeliveryTask_ db) (markDeliveryTaskFailed_ db)
|
||||
where
|
||||
GroupInfo {groupId, useRelays} = gInfo
|
||||
GroupInfo {groupId} = gInfo
|
||||
MessageDeliveryTask {jobScope, senderGMId} = task
|
||||
getTaskIds :: IO [Int64]
|
||||
getTaskIds
|
||||
| isTrue useRelays =
|
||||
| useRelays' gInfo =
|
||||
map fromOnly
|
||||
<$> DB.query
|
||||
db
|
||||
|
||||
@@ -30,6 +30,8 @@ module Simplex.Chat.Store.Direct
|
||||
createDirectConnection,
|
||||
createIncognitoProfile,
|
||||
createConnReqConnection,
|
||||
createRelayMemberConnectionAsync,
|
||||
updateConnLinkData,
|
||||
setPreparedGroupStartedConnection,
|
||||
getProfileById,
|
||||
getConnReqContactXContactId,
|
||||
@@ -153,10 +155,12 @@ deletePendingContactConnection db userId connId =
|
||||
|]
|
||||
(userId, connId, ConnContact)
|
||||
|
||||
createConnReqConnection :: DB.Connection -> UserId -> ConnId -> Maybe PreparedChatEntity -> ConnReqContact -> ConnReqUriHash -> Maybe ShortLinkContact -> XContactId -> Maybe Profile -> Maybe GroupLinkId -> SubscriptionMode -> VersionChat -> PQSupport -> IO Connection
|
||||
createConnReqConnection :: DB.Connection -> UserId -> ConnId -> Maybe PreparedChatEntity -> ConnReqContact -> ConnReqUriHash -> Maybe ShortLinkContact -> XContactId -> Maybe IncognitoProfile -> Maybe GroupLinkId -> SubscriptionMode -> VersionChat -> PQSupport -> IO Connection
|
||||
createConnReqConnection db userId acId preparedEntity_ cReq cReqHash sLnk xContactId incognitoProfile groupLinkId subMode chatV pqSup = do
|
||||
currentTs <- getCurrentTime
|
||||
customUserProfileId <- mapM (createIncognitoProfile_ db userId currentTs) incognitoProfile
|
||||
customUserProfileId <- forM incognitoProfile $ \case
|
||||
NewIncognito p -> createIncognitoProfile_ db userId currentTs p
|
||||
ExistingIncognito LocalProfile {profileId = pId} -> pure pId
|
||||
let connStatus = ConnPrepared
|
||||
DB.execute
|
||||
db
|
||||
@@ -175,7 +179,9 @@ createConnReqConnection db userId acId preparedEntity_ cReq cReqHash sLnk xConta
|
||||
)
|
||||
connId <- insertedRowId db
|
||||
case preparedEntity_ of
|
||||
Just (PCEGroup gInfo _) -> updatePreparedGroup gInfo customUserProfileId currentTs
|
||||
-- For relay groups, setPreparedGroupLinkInfo is called before the relay loop
|
||||
Just (PCEGroup gInfo _) | not (useRelays' gInfo) ->
|
||||
setPreparedGroupLinkInfo_ db gInfo cReq cReqHash customUserProfileId currentTs
|
||||
_ -> pure ()
|
||||
pure
|
||||
Connection
|
||||
@@ -213,16 +219,41 @@ createConnReqConnection db userId acId preparedEntity_ cReq cReqHash sLnk xConta
|
||||
Just (PCEContact Contact {contactId}) -> (ConnContact, Just contactId, Nothing, Just contactId)
|
||||
Just (PCEGroup _ GroupMember {groupMemberId}) -> (ConnMember, Nothing, Just groupMemberId, Just groupMemberId)
|
||||
Nothing -> (ConnContact, Nothing, Nothing, Nothing)
|
||||
updatePreparedGroup GroupInfo {groupId, membership} customUserProfileId currentTs = do
|
||||
DB.execute
|
||||
db
|
||||
"UPDATE groups SET via_group_link_uri = ?, via_group_link_uri_hash = ?, conn_link_prepared_connection = ?, updated_at = ? WHERE group_id = ?"
|
||||
(cReq, cReqHash, BI True, currentTs, groupId)
|
||||
when (isJust customUserProfileId) $
|
||||
DB.execute
|
||||
db
|
||||
"UPDATE group_members SET member_profile_id = ?, updated_at = ? WHERE group_member_id = ?"
|
||||
(customUserProfileId, currentTs, groupMemberId' membership)
|
||||
|
||||
createRelayMemberConnectionAsync :: DB.Connection -> User -> GroupInfo -> GroupMember -> ShortLinkContact -> (CommandId, ConnId) -> SubscriptionMode -> IO ()
|
||||
createRelayMemberConnectionAsync db user@User {userId} gInfo GroupMember {groupMemberId} relayLink (cmdId, agentConnId) subMode = do
|
||||
currentTs <- getCurrentTime
|
||||
DB.execute
|
||||
db
|
||||
[sql|
|
||||
INSERT INTO connections (
|
||||
user_id, agent_conn_id, conn_status, conn_type, contact_conn_initiated,
|
||||
group_member_id, via_short_link_contact, custom_user_profile_id, via_group_link,
|
||||
created_at, updated_at, to_subscribe
|
||||
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
|]
|
||||
( (userId, agentConnId, ConnNew, ConnMember, BI True)
|
||||
:. (groupMemberId, relayLink, customUserProfileId_, BI True)
|
||||
:. (currentTs, currentTs, BI (subMode == SMOnlyCreate))
|
||||
)
|
||||
connId <- insertedRowId db
|
||||
setCommandConnId db user cmdId connId
|
||||
where
|
||||
customUserProfileId_ = localProfileId <$> incognitoMembershipProfile gInfo
|
||||
|
||||
updateConnLinkData :: DB.Connection -> User -> Connection -> ConnReqContact -> ConnReqUriHash -> Maybe GroupLinkId -> VersionChat -> PQSupport -> IO ()
|
||||
updateConnLinkData db User {userId} Connection {connId} cReq cReqHash groupLinkId_ chatV pqSup = do
|
||||
currentTs <- getCurrentTime
|
||||
DB.execute
|
||||
db
|
||||
[sql|
|
||||
UPDATE connections
|
||||
SET via_contact_uri = ?, via_contact_uri_hash = ?, group_link_id = ?,
|
||||
conn_chat_version = ?, pq_support = ?, pq_encryption = ?,
|
||||
updated_at = ?
|
||||
WHERE user_id = ? AND connection_id = ?
|
||||
|]
|
||||
(cReq, cReqHash, groupLinkId_, chatV, pqSup, pqSup, currentTs, userId, connId)
|
||||
|
||||
setPreparedGroupStartedConnection :: DB.Connection -> GroupId -> IO ()
|
||||
setPreparedGroupStartedConnection db groupId = do
|
||||
|
||||
@@ -41,7 +41,6 @@ module Simplex.Chat.Store.Groups
|
||||
createGroupRejectedViaLink,
|
||||
setGroupInvitationChatItemId,
|
||||
getGroup,
|
||||
getGroupInfo,
|
||||
getGroupInfoByUserContactLinkConnReq,
|
||||
getGroupInfoViaUserShortLink,
|
||||
getGroupViaShortLinkToConnect,
|
||||
@@ -60,23 +59,38 @@ module Simplex.Chat.Store.Groups
|
||||
getGroupMemberById,
|
||||
getGroupMemberByIndex,
|
||||
getGroupMemberByMemberId,
|
||||
getCreateUnknownGMByMemberId,
|
||||
getGroupMemberIdViaMemberId,
|
||||
getScopeMemberIdViaMemberId,
|
||||
getGroupMembers,
|
||||
getGroupMembersByIndexes,
|
||||
getSupportScopeMembersByIndexes,
|
||||
getGroupModerators,
|
||||
getGroupRelays,
|
||||
getGroupRelayMembers,
|
||||
getGroupMembersForExpiration,
|
||||
getGroupCurrentMembersCount,
|
||||
deleteGroupChatItems,
|
||||
deleteGroupMembers,
|
||||
cleanupHostGroupLinkConn,
|
||||
deleteGroup,
|
||||
getInProgressGroups,
|
||||
getBaseGroupDetails,
|
||||
getContactGroupPreferences,
|
||||
getGroupInvitation,
|
||||
createNewContactMember,
|
||||
createGroupRelayRecord,
|
||||
getGroupRelayById,
|
||||
getGroupRelayByGMId,
|
||||
getGroupRelays,
|
||||
createRelayForOwner,
|
||||
getCreateRelayForMember,
|
||||
createRelayConnection,
|
||||
updateRelayStatus,
|
||||
updateRelayStatusFromTo,
|
||||
setRelayLinkAccepted,
|
||||
setGroupInProgressDone,
|
||||
createRelayRequestGroup,
|
||||
updateRelayOwnStatusFromTo,
|
||||
createNewContactMemberAsync,
|
||||
createJoiningMember,
|
||||
getMemberJoinRequest,
|
||||
@@ -104,6 +118,7 @@ module Simplex.Chat.Store.Groups
|
||||
setMemberVectorRelationConnected,
|
||||
getMemberRelationsVector,
|
||||
createIntroReMember,
|
||||
createIntroReMemberConn,
|
||||
createIntroToMemberContact,
|
||||
getMatchingContacts,
|
||||
getMatchingMembers,
|
||||
@@ -156,6 +171,7 @@ import Data.ByteString (ByteString)
|
||||
import qualified Data.ByteString as B
|
||||
import Data.Char (toLower)
|
||||
import Data.Either (rights)
|
||||
import Data.Functor (($>))
|
||||
import Data.Int (Int64)
|
||||
import Data.List (partition, sortOn)
|
||||
import Data.Maybe (catMaybes, fromMaybe, isJust, isNothing)
|
||||
@@ -165,6 +181,7 @@ import qualified Data.Text as T
|
||||
import Data.Time.Clock (UTCTime (..), getCurrentTime)
|
||||
import Data.Text.Encoding (encodeUtf8)
|
||||
import Simplex.Chat.Messages
|
||||
import Simplex.Chat.Operators
|
||||
import Simplex.Chat.Protocol hiding (Binary)
|
||||
import Simplex.Chat.Store.Direct
|
||||
import Simplex.Chat.Store.Shared
|
||||
@@ -173,7 +190,7 @@ import Simplex.Chat.Types.MemberRelations (IntroductionDirection (..), MemberRel
|
||||
import Simplex.Chat.Types.Preferences
|
||||
import Simplex.Chat.Types.Shared
|
||||
import Simplex.Chat.Types.UITheme
|
||||
import Simplex.Messaging.Agent.Protocol (ConnId, CreatedConnLink (..), UserId)
|
||||
import Simplex.Messaging.Agent.Protocol (ConnId, CreatedConnLink (..), InvitationId, UserId)
|
||||
import Simplex.Messaging.Agent.Store.AgentStore (firstRow, fromOnlyBI, maybeFirstRow)
|
||||
import Simplex.Messaging.Agent.Store.DB (Binary (..), BoolInt (..))
|
||||
import qualified Simplex.Messaging.Agent.Store.DB as DB
|
||||
@@ -191,11 +208,11 @@ import Database.SQLite.Simple (Only (..), Query, (:.) (..))
|
||||
import Database.SQLite.Simple.QQ (sql)
|
||||
#endif
|
||||
|
||||
type MaybeGroupMemberRow = (Maybe GroupMemberId, Maybe GroupId, Maybe Int64, Maybe MemberId, Maybe VersionChat, Maybe VersionChat, Maybe GroupMemberRole, Maybe GroupMemberCategory, Maybe GroupMemberStatus, Maybe BoolInt, Maybe MemberRestrictionStatus, Maybe BoolInt) :. (Maybe Int64, Maybe GroupMemberId, Maybe ContactName, Maybe ContactId, Maybe ProfileId) :. (Maybe ProfileId, Maybe ContactName, Maybe Text, Maybe Text, Maybe ImageData, Maybe ConnLinkContact, Maybe ChatPeerType, Maybe LocalAlias, Maybe Preferences) :. (Maybe UTCTime, Maybe UTCTime) :. (Maybe UTCTime, Maybe Int64, Maybe Int64, Maybe Int64, Maybe UTCTime)
|
||||
type MaybeGroupMemberRow = (Maybe GroupMemberId, Maybe GroupId, Maybe Int64, Maybe MemberId, Maybe VersionChat, Maybe VersionChat, Maybe GroupMemberRole, Maybe GroupMemberCategory, Maybe GroupMemberStatus, Maybe BoolInt, Maybe MemberRestrictionStatus) :. (Maybe Int64, Maybe GroupMemberId, Maybe ContactName, Maybe ContactId, Maybe ProfileId) :. (Maybe ProfileId, Maybe ContactName, Maybe Text, Maybe Text, Maybe ImageData, Maybe ConnLinkContact, Maybe ChatPeerType, Maybe LocalAlias, Maybe Preferences) :. (Maybe UTCTime, Maybe UTCTime) :. (Maybe UTCTime, Maybe Int64, Maybe Int64, Maybe Int64, Maybe UTCTime)
|
||||
|
||||
toMaybeGroupMember :: Int64 -> MaybeGroupMemberRow -> Maybe GroupMember
|
||||
toMaybeGroupMember userContactId ((Just groupMemberId, Just groupId, Just indexInGroup, Just memberId, Just minVer, Just maxVer, Just memberRole, Just memberCategory, Just memberStatus, Just showMessages, memberBlocked', Just isChatRelay) :. (invitedById, invitedByGroupMemberId, Just localDisplayName, memberContactId, Just memberContactProfileId) :. (Just profileId, Just displayName, Just fullName, shortDescr, image, contactLink, peerType, Just localAlias, contactPreferences) :. (Just createdAt, Just updatedAt) :. (supportChatTs, Just supportChatUnread, Just supportChatUnanswered, Just supportChatMentions, supportChatLastMsgFromMemberTs)) =
|
||||
Just $ toGroupMember userContactId ((groupMemberId, groupId, indexInGroup, memberId, minVer, maxVer, memberRole, memberCategory, memberStatus, showMessages, memberBlocked', isChatRelay) :. (invitedById, invitedByGroupMemberId, localDisplayName, memberContactId, memberContactProfileId) :. (profileId, displayName, fullName, shortDescr, image, contactLink, peerType, localAlias, contactPreferences) :. (createdAt, updatedAt) :. (supportChatTs, supportChatUnread, supportChatUnanswered, supportChatMentions, supportChatLastMsgFromMemberTs))
|
||||
toMaybeGroupMember userContactId ((Just groupMemberId, Just groupId, Just indexInGroup, Just memberId, Just minVer, Just maxVer, Just memberRole, Just memberCategory, Just memberStatus, Just showMessages, memberBlocked') :. (invitedById, invitedByGroupMemberId, Just localDisplayName, memberContactId, Just memberContactProfileId) :. (Just profileId, Just displayName, Just fullName, shortDescr, image, contactLink, peerType, Just localAlias, contactPreferences) :. (Just createdAt, Just updatedAt) :. (supportChatTs, Just supportChatUnread, Just supportChatUnanswered, Just supportChatMentions, supportChatLastMsgFromMemberTs)) =
|
||||
Just $ toGroupMember userContactId ((groupMemberId, groupId, indexInGroup, memberId, minVer, maxVer, memberRole, memberCategory, memberStatus, showMessages, memberBlocked') :. (invitedById, invitedByGroupMemberId, localDisplayName, memberContactId, memberContactProfileId) :. (profileId, displayName, fullName, shortDescr, image, contactLink, peerType, localAlias, contactPreferences) :. (createdAt, updatedAt) :. (supportChatTs, supportChatUnread, supportChatUnanswered, supportChatMentions, supportChatLastMsgFromMemberTs))
|
||||
toMaybeGroupMember _ _ = Nothing
|
||||
|
||||
createGroupLink :: DB.Connection -> TVar ChaChaDRG -> User -> GroupInfo -> ConnId -> CreatedLinkContact -> GroupLinkId -> GroupMemberRole -> SubscriptionMode -> ExceptT StoreError IO GroupLink
|
||||
@@ -310,8 +327,8 @@ setGroupLinkShortLink db gLnk@GroupLink {userContactLinkId, connLinkContact = CC
|
||||
pure gLnk {connLinkContact = CCLink connFullLink (Just shortLink), shortLinkDataSet = True, shortLinkLargeDataSet = BoolDef True}
|
||||
|
||||
-- | creates completely new group with a single member - the current user
|
||||
createNewGroup :: DB.Connection -> VersionRangeChat -> TVar ChaChaDRG -> User -> GroupProfile -> Maybe Profile -> ExceptT StoreError IO GroupInfo
|
||||
createNewGroup db vr gVar user@User {userId} groupProfile incognitoProfile = ExceptT $ do
|
||||
createNewGroup :: DB.Connection -> VersionRangeChat -> TVar ChaChaDRG -> User -> GroupProfile -> Maybe Profile -> Bool -> ExceptT StoreError IO GroupInfo
|
||||
createNewGroup db vr gVar user@User {userId} groupProfile incognitoProfile useRelays = ExceptT $ do
|
||||
let GroupProfile {displayName, fullName, shortDescr, description, image, groupPreferences, memberAdmission} = groupProfile
|
||||
fullGroupPreferences = mergeGroupPreferences groupPreferences
|
||||
currentTs <- getCurrentTime
|
||||
@@ -327,11 +344,11 @@ createNewGroup db vr gVar user@User {userId} groupProfile incognitoProfile = Exc
|
||||
db
|
||||
[sql|
|
||||
INSERT INTO groups
|
||||
(local_display_name, user_id, group_profile_id, enable_ntfs,
|
||||
(use_relays, creating_in_progress, local_display_name, user_id, group_profile_id, enable_ntfs,
|
||||
created_at, updated_at, chat_ts, user_member_profile_sent_at)
|
||||
VALUES (?,?,?,?,?,?,?,?)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?)
|
||||
|]
|
||||
(ldn, userId, profileId, BI True, currentTs, currentTs, currentTs, currentTs)
|
||||
(BI useRelays, BI useRelays, ldn, userId, profileId, BI True, currentTs, currentTs, currentTs, currentTs)
|
||||
insertedRowId db
|
||||
memberId <- liftIO $ encodedRandomBytes gVar 12
|
||||
membership <- createContactMemberInv_ db user groupId Nothing user (MemberIdRole (MemberId memberId) GROwner) GCUserMember GSMemCreator IBUser customUserProfileId currentTs vr
|
||||
@@ -339,7 +356,8 @@ createNewGroup db vr gVar user@User {userId} groupProfile incognitoProfile = Exc
|
||||
pure
|
||||
GroupInfo
|
||||
{ groupId,
|
||||
useRelays = BoolDef False,
|
||||
useRelays = BoolDef useRelays,
|
||||
relayOwnStatus = Nothing,
|
||||
localDisplayName = ldn,
|
||||
groupProfile,
|
||||
localAlias = "",
|
||||
@@ -371,9 +389,9 @@ createGroupInvitation db vr user@User {userId} contact@Contact {contactId, activ
|
||||
gInfo@GroupInfo {membership, groupProfile = p'} <- getGroupInfo db vr user gId
|
||||
hostId <- getHostMemberId_ db user gId
|
||||
let GroupMember {groupMemberId, memberId, memberRole} = membership
|
||||
MemberIdRole {memberId = invMemberId, memberRole = memberRole'} = invitedMember
|
||||
liftIO . when (memberId /= invMemberId || memberRole /= memberRole') $
|
||||
DB.execute db "UPDATE group_members SET member_id = ?, member_role = ? WHERE group_member_id = ?" (invMemberId, memberRole', groupMemberId)
|
||||
MemberIdRole {memberId = invMemberId, memberRole = invMemberRole} = invitedMember
|
||||
liftIO . when (memberId /= invMemberId || memberRole /= invMemberRole) $
|
||||
DB.execute db "UPDATE group_members SET member_id = ?, member_role = ? WHERE group_member_id = ?" (invMemberId, invMemberRole, groupMemberId)
|
||||
gInfo' <-
|
||||
if p' == groupProfile
|
||||
then pure gInfo
|
||||
@@ -415,6 +433,7 @@ createGroupInvitation db vr user@User {userId} contact@Contact {contactId, activ
|
||||
( GroupInfo
|
||||
{ groupId,
|
||||
useRelays = BoolDef False,
|
||||
relayOwnStatus = Nothing,
|
||||
localDisplayName,
|
||||
groupProfile,
|
||||
localAlias = "",
|
||||
@@ -498,8 +517,7 @@ createContactMemberInv_ db User {userId, userContactId} groupId invitedByGroupMe
|
||||
memberChatVRange,
|
||||
createdAt,
|
||||
updatedAt = createdAt,
|
||||
supportChat = Nothing,
|
||||
isChatRelay = BoolDef False
|
||||
supportChat = Nothing
|
||||
}
|
||||
where
|
||||
memberChatVRange@(VersionRange minV maxV) = vr
|
||||
@@ -548,13 +566,17 @@ deleteContactCardKeepConn db connId Contact {contactId, profile = LocalProfile {
|
||||
DB.execute db "DELETE FROM contacts WHERE contact_id = ?" (Only contactId)
|
||||
DB.execute db "DELETE FROM contact_profiles WHERE contact_profile_id = ?" (Only profileId)
|
||||
|
||||
createPreparedGroup :: DB.Connection -> VersionRangeChat -> User -> GroupProfile -> Bool -> CreatedLinkContact -> Maybe SharedMsgId -> ExceptT StoreError IO (GroupInfo, GroupMember)
|
||||
createPreparedGroup db vr user@User {userId, userContactId} groupProfile business connLinkToConnect welcomeSharedMsgId = do
|
||||
createPreparedGroup :: DB.Connection -> TVar ChaChaDRG -> VersionRangeChat -> User -> GroupProfile -> Bool -> CreatedLinkContact -> Maybe SharedMsgId -> Bool -> ExceptT StoreError IO (GroupInfo, GroupMember)
|
||||
createPreparedGroup db gVar vr user@User {userId, userContactId} groupProfile business connLinkToConnect welcomeSharedMsgId useRelays = do
|
||||
currentTs <- liftIO getCurrentTime
|
||||
let prepared = Just (connLinkToConnect, welcomeSharedMsgId)
|
||||
(groupId, groupLDN) <- createGroup_ db userId groupProfile prepared Nothing currentTs
|
||||
(groupId, groupLDN) <- createGroup_ db userId groupProfile prepared Nothing useRelays Nothing currentTs
|
||||
hostMemberId <- insertHost_ currentTs groupId groupLDN
|
||||
let userMember = MemberIdRole (MemberId $ encodeUtf8 groupLDN <> "_user_unknown_id") GRMember
|
||||
userMemberId <-
|
||||
if useRelays
|
||||
then liftIO $ MemberId <$> encodedRandomBytes gVar 12
|
||||
else pure $ MemberId $ encodeUtf8 groupLDN <> "_user_unknown_id"
|
||||
let userMember = MemberIdRole userMemberId GRMember
|
||||
membership <- createContactMemberInv_ db user groupId (Just hostMemberId) user userMember GCUserMember GSMemUnknown IBUnknown Nothing currentTs vr
|
||||
hostMember <- getGroupMember db vr user groupId hostMemberId
|
||||
when business $ liftIO $ setGroupBusinessChatInfo groupId membership hostMember
|
||||
@@ -562,8 +584,9 @@ createPreparedGroup db vr user@User {userId, userContactId} groupProfile busines
|
||||
pure (g, hostMember)
|
||||
where
|
||||
insertHost_ currentTs groupId groupLDN = do
|
||||
let memberId = MemberId $ encodeUtf8 groupLDN <> "_host_unknown_id"
|
||||
hostProfile = profileFromName $ nameFromMemberId memberId
|
||||
randHostId <- liftIO $ encodedRandomBytes gVar 12
|
||||
let memberId = MemberId $ encodeUtf8 groupLDN <> "_unknown_host_" <> randHostId
|
||||
hostProfile = profileFromName $ nameFromBS randHostId
|
||||
(localDisplayName, profileId) <- createNewMemberProfile_ db user hostProfile currentTs
|
||||
indexInGroup <- getUpdateNextIndexInGroup_ db groupId
|
||||
liftIO $ do
|
||||
@@ -750,7 +773,7 @@ createGroupViaLink'
|
||||
business
|
||||
membershipStatus = do
|
||||
currentTs <- liftIO getCurrentTime
|
||||
(groupId, _groupLDN) <- createGroup_ db userId groupProfile Nothing business currentTs
|
||||
(groupId, _groupLDN) <- createGroup_ db userId groupProfile Nothing business False Nothing currentTs
|
||||
hostMemberId <- insertHost_ currentTs groupId
|
||||
liftIO $ DB.execute db "UPDATE connections SET conn_type = ?, group_member_id = ?, updated_at = ? WHERE connection_id = ?" (ConnMember, hostMemberId, currentTs, connId)
|
||||
-- using IBUnknown since host is created without contact
|
||||
@@ -776,8 +799,8 @@ createGroupViaLink'
|
||||
)
|
||||
insertedRowId db
|
||||
|
||||
createGroup_ :: DB.Connection -> UserId -> GroupProfile -> Maybe (CreatedLinkContact, Maybe SharedMsgId) -> Maybe BusinessChatInfo -> UTCTime -> ExceptT StoreError IO (GroupId, Text)
|
||||
createGroup_ db userId groupProfile prepared business currentTs = ExceptT $ do
|
||||
createGroup_ :: DB.Connection -> UserId -> GroupProfile -> Maybe (CreatedLinkContact, Maybe SharedMsgId) -> Maybe BusinessChatInfo -> Bool -> Maybe RelayStatus -> UTCTime -> ExceptT StoreError IO (GroupId, Text)
|
||||
createGroup_ db userId groupProfile prepared business useRelays relayOwnStatus currentTs = ExceptT $ do
|
||||
let GroupProfile {displayName, fullName, shortDescr, description, image, groupPreferences, memberAdmission} = groupProfile
|
||||
withLocalDisplayName db userId displayName $ \localDisplayName -> runExceptT $ do
|
||||
liftIO $ do
|
||||
@@ -792,10 +815,10 @@ createGroup_ db userId groupProfile prepared business currentTs = ExceptT $ do
|
||||
INSERT INTO groups
|
||||
(group_profile_id, local_display_name, user_id, enable_ntfs,
|
||||
created_at, updated_at, chat_ts, user_member_profile_sent_at, conn_full_link_to_connect, conn_short_link_to_connect, welcome_shared_msg_id,
|
||||
business_chat, business_member_id, customer_member_id)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
business_chat, business_member_id, customer_member_id, use_relays, relay_own_status)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
|]
|
||||
((profileId, localDisplayName, userId, BI True, currentTs, currentTs, currentTs, currentTs) :. toPreparedGroupRow prepared :. businessChatInfoRow business)
|
||||
((profileId, localDisplayName, userId, BI True, currentTs, currentTs, currentTs, currentTs) :. toPreparedGroupRow prepared :. businessChatInfoRow business :. (BI useRelays, relayOwnStatus))
|
||||
groupId <- insertedRowId db
|
||||
pure (groupId, localDisplayName)
|
||||
|
||||
@@ -903,6 +926,15 @@ deleteGroupProfile_ db userId groupId =
|
||||
|]
|
||||
(userId, groupId)
|
||||
|
||||
getInProgressGroups :: DB.Connection -> VersionRangeChat -> User -> UTCTime -> IO [GroupInfo]
|
||||
getInProgressGroups db vr user@User {userId} createdAtCutoff = do
|
||||
groupIds <- map fromOnly <$>
|
||||
DB.query
|
||||
db
|
||||
"SELECT group_id FROM groups WHERE user_id = ? AND creating_in_progress = 1 AND created_at <= ?"
|
||||
(userId, createdAtCutoff)
|
||||
rights <$> mapM (runExceptT . getGroupInfo db vr user) groupIds
|
||||
|
||||
getBaseGroupDetails :: DB.Connection -> VersionRangeChat -> User -> Maybe ContactId -> Maybe Text -> IO [GroupInfo]
|
||||
getBaseGroupDetails db vr User {userId, userContactId} _contactId_ search_ = do
|
||||
map (toGroupInfo vr userContactId [])
|
||||
@@ -1019,6 +1051,16 @@ getGroupMemberByMemberId db vr user GroupInfo {groupId} memberId =
|
||||
(groupMemberQuery <> " WHERE m.group_id = ? AND m.member_id = ?")
|
||||
(groupId, memberId)
|
||||
|
||||
getCreateUnknownGMByMemberId :: DB.Connection -> VersionRangeChat -> User -> GroupInfo -> MemberId -> Maybe ContactName -> ExceptT StoreError IO (GroupMember, Bool)
|
||||
getCreateUnknownGMByMemberId db vr user gInfo memberId memberName = do
|
||||
liftIO (runExceptT $ getGroupMemberByMemberId db vr user gInfo memberId) >>= \case
|
||||
Right m -> pure (m, False)
|
||||
Left (SEGroupMemberNotFoundByMemberId _) -> do
|
||||
let name = fromMaybe (nameFromMemberId memberId) memberName
|
||||
m <- createNewUnknownGroupMember db vr user gInfo memberId name
|
||||
pure (m, True)
|
||||
Left e -> throwError e
|
||||
|
||||
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
|
||||
@@ -1075,14 +1117,13 @@ getGroupModerators db vr user@User {userId, userContactId} GroupInfo {groupId} =
|
||||
(groupMemberQuery <> " WHERE m.user_id = ? AND m.group_id = ? AND (m.contact_id IS NULL OR m.contact_id != ?) AND m.member_role IN (?,?,?)")
|
||||
(userId, groupId, userContactId, GRModerator, GRAdmin, GROwner)
|
||||
|
||||
-- TODO [channels fwd] retrieve relays based on knowledge about member from protocol, not role (isMemberRelay)
|
||||
getGroupRelays :: DB.Connection -> VersionRangeChat -> User -> GroupInfo -> IO [GroupMember]
|
||||
getGroupRelays db vr user@User {userId, userContactId} GroupInfo {groupId} = do
|
||||
getGroupRelayMembers :: DB.Connection -> VersionRangeChat -> User -> GroupInfo -> IO [GroupMember]
|
||||
getGroupRelayMembers db vr user@User {userId, userContactId} GroupInfo {groupId} = do
|
||||
map (toContactMember vr user)
|
||||
<$> DB.query
|
||||
db
|
||||
(groupMemberQuery <> " WHERE m.user_id = ? AND m.group_id = ? AND m.contact_id IS DISTINCT FROM ? AND m.member_role = ?")
|
||||
(userId, groupId, userContactId, GRAdmin)
|
||||
(userId, groupId, userContactId, GRRelay)
|
||||
|
||||
getGroupMembersForExpiration :: DB.Connection -> VersionRangeChat -> User -> GroupInfo -> IO [GroupMember]
|
||||
getGroupMembersForExpiration db vr user@User {userId, userContactId} GroupInfo {groupId} = do
|
||||
@@ -1166,8 +1207,7 @@ createNewContactMember db gVar User {userId, userContactId} GroupInfo {groupId,
|
||||
memberChatVRange = peerChatVRange,
|
||||
createdAt,
|
||||
updatedAt = createdAt,
|
||||
supportChat = Nothing,
|
||||
isChatRelay = BoolDef False
|
||||
supportChat = Nothing
|
||||
}
|
||||
where
|
||||
insertMember_ = do
|
||||
@@ -1188,6 +1228,241 @@ createNewContactMember db gVar User {userId, userContactId} GroupInfo {groupId,
|
||||
)
|
||||
pure indexInGroup
|
||||
|
||||
createGroupRelayRecord :: DB.Connection -> GroupInfo -> GroupMember -> UserChatRelay -> ExceptT StoreError IO GroupRelay
|
||||
createGroupRelayRecord db GroupInfo {groupId} GroupMember {groupMemberId} UserChatRelay {chatRelayId} = do
|
||||
currentTs <- liftIO getCurrentTime
|
||||
liftIO $
|
||||
DB.execute
|
||||
db
|
||||
[sql|
|
||||
INSERT INTO group_relays
|
||||
(group_id, group_member_id, chat_relay_id, relay_status, created_at, updated_at)
|
||||
VALUES (?,?,?,?,?,?)
|
||||
|]
|
||||
(groupId, groupMemberId, chatRelayId, RSNew, currentTs, currentTs)
|
||||
relayId <- liftIO $ insertedRowId db
|
||||
getGroupRelayById db relayId
|
||||
|
||||
getGroupRelayById :: DB.Connection -> Int64 -> ExceptT StoreError IO GroupRelay
|
||||
getGroupRelayById db relayId =
|
||||
ExceptT . firstRow toGroupRelay (SEGroupRelayNotFound relayId) $
|
||||
DB.query
|
||||
db
|
||||
(groupRelayQuery <> " WHERE group_relay_id = ?")
|
||||
(Only relayId)
|
||||
|
||||
getGroupRelayByGMId :: DB.Connection -> GroupMemberId -> ExceptT StoreError IO GroupRelay
|
||||
getGroupRelayByGMId db groupMemberId =
|
||||
ExceptT . firstRow toGroupRelay (SEGroupRelayNotFoundByMemberId groupMemberId) $
|
||||
DB.query
|
||||
db
|
||||
(groupRelayQuery <> " WHERE group_member_id = ?")
|
||||
(Only groupMemberId)
|
||||
|
||||
getGroupRelays :: DB.Connection -> GroupInfo -> IO [GroupRelay]
|
||||
getGroupRelays db GroupInfo {groupId} =
|
||||
map toGroupRelay
|
||||
<$> DB.query
|
||||
db
|
||||
(groupRelayQuery <> " WHERE group_id = ?")
|
||||
(Only groupId)
|
||||
|
||||
groupRelayQuery :: Query
|
||||
groupRelayQuery =
|
||||
[sql|
|
||||
SELECT group_relay_id, group_member_id, chat_relay_id, relay_status, relay_link
|
||||
FROM group_relays
|
||||
|]
|
||||
|
||||
toGroupRelay :: (Int64, GroupMemberId, Int64, RelayStatus, Maybe ShortLinkContact) -> GroupRelay
|
||||
toGroupRelay (groupRelayId, groupMemberId, userChatRelayId, relayStatus, relayLink) =
|
||||
GroupRelay {groupRelayId, groupMemberId, userChatRelayId, relayStatus, relayLink}
|
||||
|
||||
createRelayForOwner :: DB.Connection -> VersionRangeChat -> TVar ChaChaDRG -> User -> GroupInfo -> UserChatRelay -> ExceptT StoreError IO GroupMember
|
||||
createRelayForOwner db vr gVar user@User {userId, userContactId} GroupInfo {groupId, membership} UserChatRelay {name} = do
|
||||
currentTs <- liftIO getCurrentTime
|
||||
let relayProfile = profileFromName name
|
||||
(localDisplayName, memProfileId) <- createNewMemberProfile_ db user relayProfile currentTs
|
||||
groupMemberId <- createWithRandomId' db gVar $ \memId -> runExceptT $ do
|
||||
indexInGroup <- getUpdateNextIndexInGroup_ db groupId
|
||||
liftIO $
|
||||
DB.execute
|
||||
db
|
||||
[sql|
|
||||
INSERT INTO group_members
|
||||
( group_id, index_in_group, member_id, member_role, member_category, member_status, invited_by, invited_by_group_member_id,
|
||||
user_id, local_display_name, contact_profile_id, created_at, updated_at)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
|]
|
||||
( (groupId, indexInGroup, MemberId memId, GRRelay, GCInviteeMember, GSMemInvited, fromInvitedBy userContactId IBUser, groupMemberId' membership)
|
||||
:. (userId, localDisplayName, memProfileId, currentTs, currentTs)
|
||||
)
|
||||
liftIO $ insertedRowId db
|
||||
getGroupMemberById db vr user groupMemberId
|
||||
|
||||
getCreateRelayForMember :: DB.Connection -> VersionRangeChat -> TVar ChaChaDRG -> User -> GroupInfo -> ShortLinkContact -> ExceptT StoreError IO GroupMember
|
||||
getCreateRelayForMember db vr gVar user@User {userId, userContactId} GroupInfo {groupId, localDisplayName = groupLDN} relayLink =
|
||||
liftIO getGroupMemberByRelayLink >>= maybe createRelayMember pure
|
||||
where
|
||||
getGroupMemberByRelayLink =
|
||||
maybeFirstRow (toContactMember vr user) $
|
||||
DB.query
|
||||
db
|
||||
(groupMemberQuery <> " WHERE m.group_id = ? AND m.relay_link = ?")
|
||||
(groupId, relayLink)
|
||||
createRelayMember = do
|
||||
currentTs <- liftIO getCurrentTime
|
||||
randRelayId <- liftIO $ encodedRandomBytes gVar 12
|
||||
let memberId = MemberId $ encodeUtf8 groupLDN <> "_unknown_relay_" <> randRelayId
|
||||
relayProfile = profileFromName $ nameFromBS randRelayId
|
||||
(localDisplayName, profileId) <- createNewMemberProfile_ db user relayProfile currentTs
|
||||
indexInGroup <- getUpdateNextIndexInGroup_ db groupId
|
||||
groupMemberId <- liftIO $ do
|
||||
DB.execute
|
||||
db
|
||||
[sql|
|
||||
INSERT INTO group_members
|
||||
( group_id, index_in_group, member_id, member_role, member_category, member_status, invited_by,
|
||||
user_id, local_display_name, contact_profile_id, created_at, updated_at, relay_link
|
||||
)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
|]
|
||||
( (groupId, indexInGroup, memberId, GRRelay, GCHostMember, GSMemAccepted, fromInvitedBy userContactId IBUnknown)
|
||||
:. (userId, localDisplayName, profileId, currentTs, currentTs, relayLink)
|
||||
)
|
||||
insertedRowId db
|
||||
getGroupMember db vr user groupId groupMemberId
|
||||
|
||||
createRelayConnection :: DB.Connection -> VersionRangeChat -> User -> Int64 -> ConnId -> ConnStatus -> VersionChat -> SubscriptionMode -> ExceptT StoreError IO Connection
|
||||
createRelayConnection db vr user@User {userId} groupMemberId agentConnId connStatus chatV subMode = do
|
||||
currentTs <- liftIO getCurrentTime
|
||||
liftIO $
|
||||
DB.execute
|
||||
db
|
||||
[sql|
|
||||
INSERT INTO connections (
|
||||
user_id, agent_conn_id, conn_level, conn_status, conn_type,
|
||||
group_member_id, conn_chat_version, to_subscribe, pq_support, pq_encryption,
|
||||
created_at, updated_at
|
||||
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
|]
|
||||
( (userId, agentConnId, 0 :: Int, connStatus, ConnMember)
|
||||
:. (groupMemberId, chatV, BI (subMode == SMOnlyCreate), PQSupportOff, PQSupportOff)
|
||||
:. (currentTs, currentTs)
|
||||
)
|
||||
connId <- liftIO $ insertedRowId db
|
||||
getConnectionById db vr user connId
|
||||
|
||||
updateRelayStatus :: DB.Connection -> GroupRelay -> RelayStatus -> IO GroupRelay
|
||||
updateRelayStatus db relay@GroupRelay {groupRelayId} relayStatus =
|
||||
updateRelayStatus_ db groupRelayId relayStatus $> relay {relayStatus}
|
||||
|
||||
updateRelayStatusFromTo :: DB.Connection -> GroupRelay -> RelayStatus -> RelayStatus -> IO GroupRelay
|
||||
updateRelayStatusFromTo db relay@GroupRelay {groupRelayId} fromStatus toStatus = do
|
||||
maybeFirstRow fromOnly (DB.query db "SELECT relay_status FROM group_relays WHERE group_relay_id = ?" (Only groupRelayId)) >>= \case
|
||||
Just status | status == fromStatus -> updateRelayStatus_ db groupRelayId toStatus $> relay {relayStatus = toStatus}
|
||||
_ -> pure relay
|
||||
|
||||
updateRelayStatus_ :: DB.Connection -> Int64 -> RelayStatus -> IO ()
|
||||
updateRelayStatus_ db relayId relayStatus = do
|
||||
currentTs <- getCurrentTime
|
||||
DB.execute db "UPDATE group_relays SET relay_status = ?, updated_at = ? WHERE group_relay_id = ?" (relayStatus, currentTs, relayId)
|
||||
|
||||
setRelayLinkAccepted :: DB.Connection -> GroupRelay -> ShortLinkContact -> IO GroupRelay
|
||||
setRelayLinkAccepted db relay@GroupRelay {groupRelayId, groupMemberId} relayLink = do
|
||||
currentTs <- getCurrentTime
|
||||
DB.execute
|
||||
db
|
||||
[sql|
|
||||
UPDATE group_relays
|
||||
SET relay_link = ?, relay_status = ?, updated_at = ?
|
||||
WHERE group_relay_id = ?
|
||||
|]
|
||||
(relayLink, RSAccepted, currentTs, groupRelayId)
|
||||
DB.execute
|
||||
db
|
||||
[sql|
|
||||
UPDATE group_members
|
||||
SET relay_link = ?, updated_at = ?
|
||||
WHERE group_member_id = ?
|
||||
|]
|
||||
(relayLink, currentTs, groupMemberId)
|
||||
pure relay {relayStatus = RSAccepted, relayLink = Just relayLink}
|
||||
|
||||
setGroupInProgressDone :: DB.Connection -> GroupInfo -> IO ()
|
||||
setGroupInProgressDone db GroupInfo {groupId} = do
|
||||
currentTs <- getCurrentTime
|
||||
DB.execute
|
||||
db
|
||||
"UPDATE groups SET creating_in_progress = 0, updated_at = ? WHERE group_id = ?"
|
||||
(currentTs, groupId)
|
||||
|
||||
createRelayRequestGroup :: DB.Connection -> VersionRangeChat -> User -> GroupRelayInvitation -> InvitationId -> VersionRangeChat -> ExceptT StoreError IO (GroupInfo, GroupMember)
|
||||
createRelayRequestGroup db vr user@User {userId} GroupRelayInvitation {fromMember, fromMemberProfile, relayMemberId, groupLink} invId reqChatVRange = do
|
||||
currentTs <- liftIO getCurrentTime
|
||||
-- Create group with placeholder profile
|
||||
let Profile {displayName = fromMemberLDN} = fromMemberProfile
|
||||
placeholderProfile = GroupProfile
|
||||
{ displayName = "relay_request_" <> fromMemberLDN,
|
||||
fullName = "",
|
||||
shortDescr = Nothing,
|
||||
description = Nothing,
|
||||
image = Nothing,
|
||||
groupLink = Nothing,
|
||||
groupPreferences = Nothing,
|
||||
memberAdmission = Nothing
|
||||
}
|
||||
(groupId, _groupLDN) <- createGroup_ db userId placeholderProfile Nothing Nothing True (Just RSInvited) currentTs
|
||||
-- Store relay request data for recovery
|
||||
liftIO $ setRelayRequestData_ groupId
|
||||
ownerMemberId <- insertOwner_ currentTs groupId
|
||||
let relayMember = MemberIdRole relayMemberId GRRelay
|
||||
_membership <- createContactMemberInv_ db user groupId (Just ownerMemberId) user relayMember GCUserMember GSMemAccepted IBUnknown Nothing currentTs vr
|
||||
ownerMember <- getGroupMember db vr user groupId ownerMemberId
|
||||
g <- getGroupInfo db vr user groupId
|
||||
pure (g, ownerMember)
|
||||
where
|
||||
setRelayRequestData_ groupId =
|
||||
DB.execute
|
||||
db
|
||||
[sql|
|
||||
UPDATE groups
|
||||
SET relay_request_inv_id = ?,
|
||||
relay_request_group_link = ?,
|
||||
relay_request_peer_chat_min_version = ?,
|
||||
relay_request_peer_chat_max_version = ?
|
||||
WHERE group_id = ?
|
||||
|]
|
||||
(Binary invId, groupLink, minVersion reqChatVRange, maxVersion reqChatVRange, groupId)
|
||||
insertOwner_ currentTs groupId = do
|
||||
let MemberIdRole {memberId, memberRole} = fromMember
|
||||
(localDisplayName, profileId) <- createNewMemberProfile_ db user fromMemberProfile currentTs
|
||||
indexInGroup <- getUpdateNextIndexInGroup_ db groupId
|
||||
liftIO $ do
|
||||
DB.execute
|
||||
db
|
||||
[sql|
|
||||
INSERT INTO group_members
|
||||
( group_id, index_in_group, member_id, member_role, member_category, member_status,
|
||||
user_id, local_display_name, contact_id, contact_profile_id, created_at, updated_at)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
|]
|
||||
( (groupId, indexInGroup, memberId, memberRole, GCHostMember, GSMemAccepted)
|
||||
:. (userId, localDisplayName, Nothing :: (Maybe Int64), profileId, currentTs, currentTs)
|
||||
)
|
||||
insertedRowId db
|
||||
|
||||
updateRelayOwnStatusFromTo :: DB.Connection -> GroupInfo -> RelayStatus -> RelayStatus -> IO GroupInfo
|
||||
updateRelayOwnStatusFromTo db gInfo@GroupInfo {groupId} fromStatus toStatus = do
|
||||
maybeFirstRow fromOnly (DB.query db "SELECT relay_own_status FROM groups WHERE group_id = ?" (Only groupId)) >>= \case
|
||||
Just status | status == fromStatus -> updateRelayOwnStatus_ db gInfo toStatus $> gInfo {relayOwnStatus = Just toStatus}
|
||||
_ -> pure gInfo
|
||||
|
||||
updateRelayOwnStatus_ :: DB.Connection -> GroupInfo -> RelayStatus -> IO ()
|
||||
updateRelayOwnStatus_ db GroupInfo {groupId} relayStatus = do
|
||||
currentTs <- getCurrentTime
|
||||
DB.execute db "UPDATE groups SET relay_own_status = ?, updated_at = ? WHERE group_id = ?" (relayStatus, currentTs, groupId)
|
||||
|
||||
createNewContactMemberAsync :: DB.Connection -> TVar ChaChaDRG -> User -> GroupInfo -> Contact -> GroupMemberRole -> (CommandId, ConnId) -> VersionChat -> VersionRangeChat -> SubscriptionMode -> ExceptT StoreError IO ()
|
||||
createNewContactMemberAsync db gVar user@User {userId, userContactId} GroupInfo {groupId, membership} Contact {contactId, localDisplayName, profile} memberRole (cmdId, agentConnId) chatV peerChatVRange subMode =
|
||||
createWithRandomId' db gVar $ \memId -> runExceptT $ do
|
||||
@@ -1215,7 +1490,7 @@ createNewContactMemberAsync db gVar user@User {userId, userContactId} GroupInfo
|
||||
:. (minV, maxV)
|
||||
)
|
||||
|
||||
createJoiningMember :: DB.Connection -> TVar ChaChaDRG -> User -> GroupInfo -> VersionRangeChat -> Profile -> Maybe XContactId -> Maybe SharedMsgId -> GroupMemberRole -> GroupMemberStatus -> ExceptT StoreError IO (GroupMemberId, MemberId)
|
||||
createJoiningMember :: DB.Connection -> TVar ChaChaDRG -> User -> GroupInfo -> VersionRangeChat -> Profile -> Maybe XContactId -> Maybe MemberId -> Maybe SharedMsgId -> GroupMemberRole -> GroupMemberStatus -> ExceptT StoreError IO (GroupMemberId, MemberId)
|
||||
createJoiningMember
|
||||
db
|
||||
gVar
|
||||
@@ -1224,6 +1499,7 @@ createJoiningMember
|
||||
cReqChatVRange
|
||||
Profile {displayName, fullName, shortDescr, image, contactLink, preferences}
|
||||
cReqXContactId_
|
||||
cReqMemberId_
|
||||
welcomeMsgId_
|
||||
memberRole
|
||||
memberStatus = do
|
||||
@@ -1235,12 +1511,24 @@ createJoiningMember
|
||||
"INSERT INTO contact_profiles (display_name, full_name, short_descr, image, contact_link, user_id, preferences, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?)"
|
||||
(displayName, fullName, shortDescr, image, contactLink, userId, preferences, currentTs, currentTs)
|
||||
profileId <- liftIO $ insertedRowId db
|
||||
createWithRandomId' db gVar $ \memId -> runExceptT $ do
|
||||
insertMember_ ldn profileId (MemberId memId) currentTs
|
||||
groupMemberId <- liftIO $ insertedRowId db
|
||||
pure (groupMemberId, MemberId memId)
|
||||
case cReqMemberId_ of
|
||||
Just memberId -> do
|
||||
checkMemberNotExists memberId
|
||||
insertMember_ ldn profileId memberId currentTs
|
||||
groupMemberId <- liftIO $ insertedRowId db
|
||||
pure (groupMemberId, memberId)
|
||||
Nothing ->
|
||||
createWithRandomId' db gVar $ \memId -> runExceptT $ do
|
||||
insertMember_ ldn profileId (MemberId memId) currentTs
|
||||
groupMemberId <- liftIO $ insertedRowId db
|
||||
pure (groupMemberId, MemberId memId)
|
||||
where
|
||||
VersionRange minV maxV = cReqChatVRange
|
||||
-- TODO [relays] relay: TBC communicate rejection
|
||||
checkMemberNotExists :: MemberId -> ExceptT StoreError IO ()
|
||||
checkMemberNotExists memberId = do
|
||||
exists <- liftIO $ fromOnly . head <$> DB.query db "SELECT EXISTS (SELECT 1 FROM group_members WHERE group_id = ? AND member_id = ?)" (groupId, memberId)
|
||||
when exists $ throwError SEDuplicateMemberId
|
||||
insertMember_ ldn profileId memberId currentTs = do
|
||||
indexInGroup <- getUpdateNextIndexInGroup_ db groupId
|
||||
liftIO $
|
||||
@@ -1488,8 +1776,7 @@ createNewGroupMember db user gInfo invitingMember memInfo@MemberInfo {profile} m
|
||||
memInvitedByGroupMemberId = Just $ groupMemberId' invitingMember,
|
||||
localDisplayName,
|
||||
memContactId = Nothing,
|
||||
memProfileId,
|
||||
isChatRelay = False
|
||||
memProfileId
|
||||
}
|
||||
createNewMember_ db user gInfo newMember currentTs
|
||||
|
||||
@@ -1517,8 +1804,7 @@ createNewMember_
|
||||
memInvitedByGroupMemberId,
|
||||
localDisplayName,
|
||||
memContactId = memberContactId,
|
||||
memProfileId = memberContactProfileId,
|
||||
isChatRelay
|
||||
memProfileId = memberContactProfileId
|
||||
}
|
||||
createdAt = do
|
||||
let invitedById = fromInvitedBy userContactId invitedBy
|
||||
@@ -1531,13 +1817,13 @@ createNewMember_
|
||||
[sql|
|
||||
INSERT INTO group_members
|
||||
(group_id, index_in_group, member_id, member_role, member_category, member_status, member_relations_vector,
|
||||
member_restriction, is_chat_relay, invited_by, invited_by_group_member_id,
|
||||
member_restriction, invited_by, invited_by_group_member_id,
|
||||
user_id, local_display_name, contact_id, contact_profile_id, created_at, updated_at,
|
||||
peer_chat_min_version, peer_chat_max_version)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
|]
|
||||
( (groupId, indexInGroup, memberId, memberRole, memberCategory, memberStatus, Binary B.empty)
|
||||
:. (memRestriction, BI isChatRelay, invitedById, memInvitedByGroupMemberId)
|
||||
:. (memRestriction, invitedById, memInvitedByGroupMemberId)
|
||||
:. (userId, localDisplayName, memberContactId, memberContactProfileId, createdAt, createdAt)
|
||||
:. (minV, maxV)
|
||||
)
|
||||
@@ -1563,8 +1849,7 @@ createNewMember_
|
||||
memberChatVRange,
|
||||
createdAt,
|
||||
updatedAt = createdAt,
|
||||
supportChat = Nothing,
|
||||
isChatRelay = BoolDef isChatRelay
|
||||
supportChat = Nothing
|
||||
}
|
||||
|
||||
checkGroupMemberHasItems :: DB.Connection -> User -> GroupMember -> IO (Maybe ChatItemId)
|
||||
@@ -1669,27 +1954,35 @@ getMemberRelationsVector db GroupMember {groupMemberId} =
|
||||
"SELECT member_relations_vector FROM group_members WHERE group_member_id = ?"
|
||||
(Only groupMemberId)
|
||||
|
||||
createIntroReMember :: DB.Connection -> User -> GroupInfo -> GroupMember -> VersionChat -> MemberInfo -> Maybe MemberRestrictions -> (CommandId, ConnId) -> SubscriptionMode -> ExceptT StoreError IO GroupMember
|
||||
createIntroReMember :: DB.Connection -> User -> GroupInfo -> MemberInfo -> Maybe MemberRestrictions -> ExceptT StoreError IO GroupMember
|
||||
createIntroReMember
|
||||
db
|
||||
user@User {userId}
|
||||
user
|
||||
gInfo
|
||||
memInfo@(MemberInfo _ _ _ memberProfile)
|
||||
memRestrictions_ = do
|
||||
currentTs <- liftIO getCurrentTime
|
||||
(localDisplayName, memProfileId) <- createNewMemberProfile_ db user memberProfile currentTs
|
||||
let memRestriction = restriction <$> memRestrictions_
|
||||
newMember = NewGroupMember {memInfo, memCategory = GCPreMember, memStatus = GSMemIntroduced, memRestriction, memInvitedBy = IBUnknown, memInvitedByGroupMemberId = Nothing, localDisplayName, memContactId = Nothing, memProfileId}
|
||||
createNewMember_ db user gInfo newMember currentTs
|
||||
|
||||
createIntroReMemberConn :: DB.Connection -> User -> GroupMember -> GroupMember -> VersionChat -> MemberInfo -> (CommandId, ConnId) -> SubscriptionMode -> ExceptT StoreError IO GroupMember
|
||||
createIntroReMemberConn
|
||||
db
|
||||
user@User {userId}
|
||||
_host@GroupMember {memberContactId, activeConn}
|
||||
reMember@GroupMember {groupMemberId}
|
||||
chatV
|
||||
memInfo@(MemberInfo _ _ memChatVRange memberProfile)
|
||||
memRestrictions_
|
||||
(MemberInfo _ _ memChatVRange _)
|
||||
(groupCmdId, groupAgentConnId)
|
||||
subMode = do
|
||||
let mcvr = maybe chatInitialVRange fromChatVRange memChatVRange
|
||||
cLevel = 1 + maybe 0 (\Connection {connLevel} -> connLevel) activeConn
|
||||
memRestriction = restriction <$> memRestrictions_
|
||||
currentTs <- liftIO getCurrentTime
|
||||
(localDisplayName, memProfileId) <- createNewMemberProfile_ db user memberProfile currentTs
|
||||
let newMember = NewGroupMember {memInfo, memCategory = GCPreMember, memStatus = GSMemIntroduced, memRestriction, memInvitedBy = IBUnknown, memInvitedByGroupMemberId = Nothing, localDisplayName, memContactId = Nothing, memProfileId, isChatRelay = False}
|
||||
member <- createNewMember_ db user gInfo newMember currentTs
|
||||
conn@Connection {connId = groupConnId} <- liftIO $ createMemberConnection_ db userId (groupMemberId' member) groupAgentConnId chatV mcvr memberContactId cLevel currentTs subMode
|
||||
conn@Connection {connId = groupConnId} <- liftIO $ createMemberConnection_ db userId groupMemberId groupAgentConnId chatV mcvr memberContactId cLevel currentTs subMode
|
||||
liftIO $ setCommandConnId db user groupCmdId groupConnId
|
||||
pure (member :: GroupMember) {activeConn = Just conn}
|
||||
pure (reMember :: GroupMember) {activeConn = Just conn}
|
||||
|
||||
createIntroToMemberContact :: DB.Connection -> User -> GroupMember -> GroupMember -> VersionChat -> VersionRangeChat -> (CommandId, ConnId) -> Maybe (CommandId, ConnId) -> Maybe ProfileId -> SubscriptionMode -> IO ()
|
||||
createIntroToMemberContact db user@User {userId} GroupMember {memberContactId = viaContactId, activeConn} _to@GroupMember {groupMemberId, localDisplayName} chatV mcvr (groupCmdId, groupAgentConnId) directConnIds customUserProfileId subMode = do
|
||||
@@ -1733,7 +2026,7 @@ createMemberConnection_ db userId groupMemberId agentConnId chatV peerChatVRange
|
||||
createConnection_ db userId ConnMember (Just groupMemberId) agentConnId ConnNew chatV peerChatVRange viaContact Nothing Nothing connLevel currentTs subMode PQSupportOff
|
||||
|
||||
updateGroupProfile :: DB.Connection -> User -> GroupInfo -> GroupProfile -> ExceptT StoreError IO GroupInfo
|
||||
updateGroupProfile db user@User {userId} g@GroupInfo {groupId, localDisplayName, groupProfile = GroupProfile {displayName}} p'@GroupProfile {displayName = newName, fullName, shortDescr, description, image, groupPreferences, memberAdmission}
|
||||
updateGroupProfile db user@User {userId} g@GroupInfo {groupId, localDisplayName, groupProfile = GroupProfile {displayName}} p'@GroupProfile {displayName = newName, fullName, shortDescr, description, image, groupLink, groupPreferences, memberAdmission}
|
||||
| displayName == newName = liftIO $ do
|
||||
currentTs <- getCurrentTime
|
||||
updateGroupProfile_ currentTs
|
||||
@@ -1751,14 +2044,16 @@ updateGroupProfile db user@User {userId} g@GroupInfo {groupId, localDisplayName,
|
||||
db
|
||||
[sql|
|
||||
UPDATE group_profiles
|
||||
SET display_name = ?, full_name = ?, short_descr = ?, description = ?, image = ?, preferences = ?, member_admission = ?, updated_at = ?
|
||||
SET display_name = ?, full_name = ?, short_descr = ?, description = ?, image = ?, group_link = ?, preferences = ?, member_admission = ?, updated_at = ?
|
||||
WHERE group_profile_id IN (
|
||||
SELECT group_profile_id
|
||||
FROM groups
|
||||
WHERE user_id = ? AND group_id = ?
|
||||
)
|
||||
|]
|
||||
(newName, fullName, shortDescr, description, image, groupPreferences, memberAdmission, currentTs, userId, groupId)
|
||||
( (newName, fullName, shortDescr, description, image, groupLink)
|
||||
:. (groupPreferences, memberAdmission, currentTs, userId, groupId)
|
||||
)
|
||||
updateGroup_ ldn currentTs = do
|
||||
DB.execute
|
||||
db
|
||||
@@ -1796,23 +2091,14 @@ updateGroupProfileFromMember db user g@GroupInfo {groupId} Profile {displayName
|
||||
DB.query
|
||||
db
|
||||
[sql|
|
||||
SELECT gp.display_name, gp.full_name, gp.short_descr, gp.description, gp.image, gp.preferences, gp.member_admission
|
||||
SELECT gp.display_name, gp.full_name, gp.short_descr, gp.description, gp.image, gp.group_link, gp.preferences, gp.member_admission
|
||||
FROM group_profiles gp
|
||||
JOIN groups g ON gp.group_profile_id = g.group_profile_id
|
||||
WHERE g.group_id = ?
|
||||
|]
|
||||
(Only groupId)
|
||||
toGroupProfile (displayName, fullName, shortDescr, description, image, groupPreferences, memberAdmission) =
|
||||
GroupProfile {displayName, fullName, shortDescr, description, image, groupPreferences, memberAdmission}
|
||||
|
||||
getGroupInfo :: DB.Connection -> VersionRangeChat -> User -> Int64 -> ExceptT StoreError IO GroupInfo
|
||||
getGroupInfo db vr User {userId, userContactId} groupId = ExceptT $ do
|
||||
chatTags <- getGroupChatTags db groupId
|
||||
firstRow (toGroupInfo vr userContactId chatTags) (SEGroupNotFound groupId) $
|
||||
DB.query
|
||||
db
|
||||
(groupInfoQuery <> " WHERE g.group_id = ? AND g.user_id = ? AND mu.contact_id = ?")
|
||||
(groupId, userId, userContactId)
|
||||
toGroupProfile (displayName, fullName, shortDescr, description, image, groupLink, groupPreferences, memberAdmission) =
|
||||
GroupProfile {displayName, fullName, shortDescr, description, image, groupLink, groupPreferences, memberAdmission}
|
||||
|
||||
getGroupInfoByUserContactLinkConnReq :: DB.Connection -> VersionRangeChat -> User -> (ConnReqContact, ConnReqContact) -> IO (Maybe GroupInfo)
|
||||
getGroupInfoByUserContactLinkConnReq db vr user@User {userId} (cReqSchema1, cReqSchema2) = do
|
||||
|
||||
@@ -676,7 +676,7 @@ getChatItemQuote_ db User {userId, userContactId} chatDirection QuotedMsg {msgRe
|
||||
SELECT i.chat_item_id,
|
||||
-- GroupMember
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category,
|
||||
m.member_status, m.show_messages, m.member_restriction, m.is_chat_relay, m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id,
|
||||
m.member_status, m.show_messages, m.member_restriction, m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id,
|
||||
p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.chat_peer_type, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts
|
||||
@@ -889,7 +889,7 @@ findGroupChatPreviews_ db User {userId} pagination clq =
|
||||
baseParams = (userId, userId, CISRcvNew, userId, MCReport_, BI False)
|
||||
getPreviews = case clq of
|
||||
CLQFilters {favorite = False, unread = False} -> do
|
||||
let q = baseQuery <> " WHERE g.user_id = ?"
|
||||
let q = baseQuery <> " WHERE g.user_id = ? AND g.creating_in_progress = 0"
|
||||
p = baseParams :. Only userId
|
||||
queryWithPagination q p
|
||||
CLQFilters {favorite = True, unread = False} -> do
|
||||
@@ -897,7 +897,7 @@ findGroupChatPreviews_ db User {userId} pagination clq =
|
||||
baseQuery
|
||||
<> " "
|
||||
<> [sql|
|
||||
WHERE g.user_id = ?
|
||||
WHERE g.user_id = ? AND g.creating_in_progress = 0
|
||||
AND g.favorite = 1
|
||||
|]
|
||||
p = baseParams :. Only userId
|
||||
@@ -907,7 +907,7 @@ findGroupChatPreviews_ db User {userId} pagination clq =
|
||||
baseQuery
|
||||
<> " "
|
||||
<> [sql|
|
||||
WHERE g.user_id = ?
|
||||
WHERE g.user_id = ? AND g.creating_in_progress = 0
|
||||
AND (g.unread_chat = 1 OR ChatStats.UnreadCount > 0)
|
||||
|]
|
||||
p = baseParams :. Only userId
|
||||
@@ -917,7 +917,7 @@ findGroupChatPreviews_ db User {userId} pagination clq =
|
||||
baseQuery
|
||||
<> " "
|
||||
<> [sql|
|
||||
WHERE g.user_id = ?
|
||||
WHERE g.user_id = ? AND g.creating_in_progress = 0
|
||||
AND (g.favorite = 1
|
||||
OR g.unread_chat = 1 OR ChatStats.UnreadCount > 0)
|
||||
|]
|
||||
@@ -929,7 +929,7 @@ findGroupChatPreviews_ db User {userId} pagination clq =
|
||||
<> " "
|
||||
<> [sql|
|
||||
JOIN group_profiles gp ON gp.group_profile_id = g.group_profile_id
|
||||
WHERE g.user_id = ?
|
||||
WHERE g.user_id = ? AND g.creating_in_progress = 0
|
||||
AND (
|
||||
LOWER(g.local_display_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(gp.display_name) LIKE '%' || ? || '%'
|
||||
@@ -2966,7 +2966,7 @@ getGroupChatItem db User {userId, userContactId} groupId itemId = ExceptT $ do
|
||||
i.forwarded_by_group_member_id, i.show_group_as_sender,
|
||||
-- GroupMember
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category,
|
||||
m.member_status, m.show_messages, m.member_restriction, m.is_chat_relay, m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id,
|
||||
m.member_status, m.show_messages, m.member_restriction, m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id,
|
||||
p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.chat_peer_type, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts,
|
||||
@@ -2974,20 +2974,18 @@ getGroupChatItem db User {userId, userContactId} groupId itemId = ExceptT $ do
|
||||
ri.chat_item_id, i.quoted_shared_msg_id, i.quoted_sent_at, i.quoted_content, i.quoted_sent,
|
||||
-- quoted GroupMember
|
||||
rm.group_member_id, rm.group_id, rm.index_in_group, rm.member_id, rm.peer_chat_min_version, rm.peer_chat_max_version, rm.member_role, rm.member_category,
|
||||
rm.member_status, rm.show_messages, rm.member_restriction, rm.is_chat_relay, rm.invited_by, rm.invited_by_group_member_id, rm.local_display_name, rm.contact_id, rm.contact_profile_id, rp.contact_profile_id,
|
||||
rm.member_status, rm.show_messages, rm.member_restriction, rm.invited_by, rm.invited_by_group_member_id, rm.local_display_name, rm.contact_id, rm.contact_profile_id, rp.contact_profile_id,
|
||||
rp.display_name, rp.full_name, rp.short_descr, rp.image, rp.contact_link, rp.chat_peer_type, rp.local_alias, rp.preferences,
|
||||
rm.created_at, rm.updated_at,
|
||||
rm.support_chat_ts, rm.support_chat_items_unread, rm.support_chat_items_member_attention, rm.support_chat_items_mentions, rm.support_chat_last_msg_from_member_ts,
|
||||
-- deleted by GroupMember
|
||||
dbm.group_member_id, dbm.group_id, dbm.index_in_group, dbm.member_id, dbm.peer_chat_min_version, dbm.peer_chat_max_version, dbm.member_role, dbm.member_category,
|
||||
dbm.member_status, dbm.show_messages, dbm.member_restriction, dbm.is_chat_relay, dbm.invited_by, dbm.invited_by_group_member_id, dbm.local_display_name, dbm.contact_id, dbm.contact_profile_id, dbp.contact_profile_id,
|
||||
dbm.member_status, dbm.show_messages, dbm.member_restriction, dbm.invited_by, dbm.invited_by_group_member_id, dbm.local_display_name, dbm.contact_id, dbm.contact_profile_id, dbp.contact_profile_id,
|
||||
dbp.display_name, dbp.full_name, dbp.short_descr, dbp.image, dbp.contact_link, dbp.chat_peer_type, dbp.local_alias, dbp.preferences,
|
||||
dbm.created_at, dbm.updated_at,
|
||||
dbm.support_chat_ts, dbm.support_chat_items_unread, dbm.support_chat_items_member_attention, dbm.support_chat_items_mentions, dbm.support_chat_last_msg_from_member_ts
|
||||
FROM chat_items i
|
||||
LEFT JOIN files f ON f.chat_item_id = i.chat_item_id
|
||||
LEFT JOIN group_members gsm ON gsm.group_member_id = i.group_scope_group_member_id
|
||||
LEFT JOIN contact_profiles gsp ON gsp.contact_profile_id = COALESCE(gsm.member_profile_id, gsm.contact_profile_id)
|
||||
LEFT JOIN group_members m ON m.group_member_id = i.group_member_id
|
||||
LEFT JOIN contact_profiles p ON p.contact_profile_id = COALESCE(m.member_profile_id, m.contact_profile_id)
|
||||
LEFT JOIN chat_items ri ON ri.shared_msg_id = i.quoted_shared_msg_id AND ri.group_id = i.group_id
|
||||
|
||||
@@ -12,35 +12,81 @@ m20260109_chat_relays =
|
||||
[r|
|
||||
CREATE TABLE chat_relays(
|
||||
chat_relay_id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
|
||||
address TEXT NOT NULL,
|
||||
address BYTEA NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
domains TEXT NOT NULL,
|
||||
preset SMALLINT NOT NULL DEFAULT 0,
|
||||
tested SMALLINT,
|
||||
enabled SMALLINT NOT NULL DEFAULT 1,
|
||||
user_id BIGINT NOT NULL REFERENCES users ON DELETE CASCADE,
|
||||
deleted SMALLINT NOT NULL DEFAULT 0,
|
||||
created_at TEXT NOT NULL DEFAULT (now()),
|
||||
updated_at TEXT NOT NULL DEFAULT (now()),
|
||||
UNIQUE(user_id, address),
|
||||
UNIQUE(user_id, name)
|
||||
updated_at TEXT NOT NULL DEFAULT (now())
|
||||
);
|
||||
|
||||
CREATE INDEX idx_chat_relays_user_id ON chat_relays(user_id);
|
||||
CREATE UNIQUE INDEX idx_chat_relays_user_id_address ON chat_relays(user_id, address);
|
||||
CREATE UNIQUE INDEX idx_chat_relays_user_id_name ON chat_relays(user_id, name);
|
||||
|
||||
ALTER TABLE users ADD COLUMN is_user_chat_relay SMALLINT NOT NULL DEFAULT 0;
|
||||
|
||||
ALTER TABLE group_members ADD COLUMN is_chat_relay SMALLINT NOT NULL DEFAULT 0;
|
||||
ALTER TABLE groups
|
||||
ADD COLUMN use_relays SMALLINT NOT NULL DEFAULT 0,
|
||||
ADD COLUMN creating_in_progress SMALLINT NOT NULL DEFAULT 0,
|
||||
ADD COLUMN relay_own_status TEXT,
|
||||
ADD COLUMN relay_request_inv_id BYTEA,
|
||||
ADD COLUMN relay_request_group_link BYTEA,
|
||||
ADD COLUMN relay_request_peer_chat_min_version INTEGER,
|
||||
ADD COLUMN relay_request_peer_chat_max_version INTEGER,
|
||||
ADD COLUMN relay_request_failed SMALLINT DEFAULT 0,
|
||||
ADD COLUMN relay_request_err_reason TEXT;
|
||||
|
||||
ALTER TABLE group_profiles ADD COLUMN group_link BYTEA;
|
||||
|
||||
CREATE TABLE group_relays(
|
||||
group_relay_id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
|
||||
group_id BIGINT NOT NULL REFERENCES groups ON DELETE CASCADE,
|
||||
group_member_id BIGINT NOT NULL REFERENCES group_members ON DELETE CASCADE,
|
||||
chat_relay_id BIGINT NOT NULL REFERENCES chat_relays ON DELETE CASCADE,
|
||||
relay_status TEXT NOT NULL,
|
||||
relay_link BYTEA,
|
||||
created_at TEXT NOT NULL DEFAULT (now()),
|
||||
updated_at TEXT NOT NULL DEFAULT (now())
|
||||
);
|
||||
CREATE INDEX idx_group_relays_group_id ON group_relays(group_id);
|
||||
CREATE UNIQUE INDEX idx_group_relays_group_member_id ON group_relays(group_member_id);
|
||||
CREATE INDEX idx_group_relays_chat_relay_id ON group_relays(chat_relay_id);
|
||||
|
||||
ALTER TABLE group_members ADD COLUMN relay_link BYTEA;
|
||||
|]
|
||||
|
||||
down_m20260109_chat_relays :: Text
|
||||
down_m20260109_chat_relays =
|
||||
T.pack
|
||||
[r|
|
||||
ALTER TABLE group_members DROP COLUMN is_chat_relay;
|
||||
|
||||
ALTER TABLE users DROP COLUMN is_user_chat_relay;
|
||||
|
||||
DROP INDEX idx_chat_relays_user_id;
|
||||
ALTER TABLE groups
|
||||
DROP COLUMN use_relays,
|
||||
DROP COLUMN creating_in_progress,
|
||||
DROP COLUMN relay_own_status,
|
||||
DROP COLUMN relay_request_inv_id,
|
||||
DROP COLUMN relay_request_group_link,
|
||||
DROP COLUMN relay_request_peer_chat_min_version,
|
||||
DROP COLUMN relay_request_peer_chat_max_version,
|
||||
DROP COLUMN relay_request_failed,
|
||||
DROP COLUMN relay_request_err_reason;
|
||||
|
||||
ALTER TABLE group_profiles DROP COLUMN group_link;
|
||||
|
||||
DROP INDEX idx_group_relays_group_id;
|
||||
DROP INDEX idx_group_relays_group_member_id;
|
||||
DROP INDEX idx_group_relays_chat_relay_id;
|
||||
DROP TABLE group_relays;
|
||||
|
||||
DROP INDEX idx_chat_relays_user_id;
|
||||
DROP INDEX idx_chat_relays_user_id_address;
|
||||
DROP INDEX idx_chat_relays_user_id_name;
|
||||
DROP TABLE chat_relays;
|
||||
|
||||
ALTER TABLE group_members DROP COLUMN relay_link;
|
||||
|]
|
||||
@@ -360,13 +360,14 @@ ALTER TABLE test_chat_schema.chat_items ALTER COLUMN chat_item_id ADD GENERATED
|
||||
|
||||
CREATE TABLE test_chat_schema.chat_relays (
|
||||
chat_relay_id bigint NOT NULL,
|
||||
address text NOT NULL,
|
||||
address bytea NOT NULL,
|
||||
name text NOT NULL,
|
||||
domains text NOT NULL,
|
||||
preset smallint DEFAULT 0 NOT NULL,
|
||||
tested smallint,
|
||||
enabled smallint DEFAULT 1 NOT NULL,
|
||||
user_id bigint NOT NULL,
|
||||
deleted smallint DEFAULT 0 NOT NULL,
|
||||
created_at text DEFAULT now() NOT NULL,
|
||||
updated_at text DEFAULT now() NOT NULL
|
||||
);
|
||||
@@ -809,7 +810,7 @@ CREATE TABLE test_chat_schema.group_members (
|
||||
member_welcome_shared_msg_id bytea,
|
||||
index_in_group bigint DEFAULT 0 NOT NULL,
|
||||
member_relations_vector bytea,
|
||||
is_chat_relay smallint DEFAULT 0 NOT NULL
|
||||
relay_link bytea
|
||||
);
|
||||
|
||||
|
||||
@@ -837,7 +838,8 @@ CREATE TABLE test_chat_schema.group_profiles (
|
||||
preferences text,
|
||||
description text,
|
||||
member_admission text,
|
||||
short_descr text
|
||||
short_descr text,
|
||||
group_link bytea
|
||||
);
|
||||
|
||||
|
||||
@@ -853,6 +855,30 @@ ALTER TABLE test_chat_schema.group_profiles ALTER COLUMN group_profile_id ADD GE
|
||||
|
||||
|
||||
|
||||
CREATE TABLE test_chat_schema.group_relays (
|
||||
group_relay_id bigint NOT NULL,
|
||||
group_id bigint NOT NULL,
|
||||
group_member_id bigint NOT NULL,
|
||||
chat_relay_id bigint NOT NULL,
|
||||
relay_status text NOT NULL,
|
||||
relay_link bytea,
|
||||
created_at text DEFAULT now() NOT NULL,
|
||||
updated_at text DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
|
||||
|
||||
ALTER TABLE test_chat_schema.group_relays ALTER COLUMN group_relay_id ADD GENERATED ALWAYS AS IDENTITY (
|
||||
SEQUENCE NAME test_chat_schema.group_relays_group_relay_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1
|
||||
);
|
||||
|
||||
|
||||
|
||||
CREATE TABLE test_chat_schema.group_snd_item_statuses (
|
||||
group_snd_item_status_id bigint NOT NULL,
|
||||
chat_item_id bigint NOT NULL,
|
||||
@@ -909,7 +935,16 @@ CREATE TABLE test_chat_schema.groups (
|
||||
conn_link_prepared_connection smallint DEFAULT 0 NOT NULL,
|
||||
via_group_link_uri bytea,
|
||||
summary_current_members_count bigint DEFAULT 0 NOT NULL,
|
||||
member_index bigint DEFAULT 0 NOT NULL
|
||||
member_index bigint DEFAULT 0 NOT NULL,
|
||||
use_relays smallint DEFAULT 0 NOT NULL,
|
||||
creating_in_progress smallint DEFAULT 0 NOT NULL,
|
||||
relay_own_status text,
|
||||
relay_request_inv_id bytea,
|
||||
relay_request_group_link bytea,
|
||||
relay_request_peer_chat_min_version integer,
|
||||
relay_request_peer_chat_max_version integer,
|
||||
relay_request_failed smallint DEFAULT 0,
|
||||
relay_request_err_reason text
|
||||
);
|
||||
|
||||
|
||||
@@ -1466,16 +1501,6 @@ ALTER TABLE ONLY test_chat_schema.chat_relays
|
||||
|
||||
|
||||
|
||||
ALTER TABLE ONLY test_chat_schema.chat_relays
|
||||
ADD CONSTRAINT chat_relays_user_id_address_key UNIQUE (user_id, address);
|
||||
|
||||
|
||||
|
||||
ALTER TABLE ONLY test_chat_schema.chat_relays
|
||||
ADD CONSTRAINT chat_relays_user_id_name_key UNIQUE (user_id, name);
|
||||
|
||||
|
||||
|
||||
ALTER TABLE ONLY test_chat_schema.chat_tags
|
||||
ADD CONSTRAINT chat_tags_pkey PRIMARY KEY (chat_tag_id);
|
||||
|
||||
@@ -1591,6 +1616,11 @@ ALTER TABLE ONLY test_chat_schema.group_profiles
|
||||
|
||||
|
||||
|
||||
ALTER TABLE ONLY test_chat_schema.group_relays
|
||||
ADD CONSTRAINT group_relays_pkey PRIMARY KEY (group_relay_id);
|
||||
|
||||
|
||||
|
||||
ALTER TABLE ONLY test_chat_schema.group_snd_item_statuses
|
||||
ADD CONSTRAINT group_snd_item_statuses_pkey PRIMARY KEY (group_snd_item_status_id);
|
||||
|
||||
@@ -1968,6 +1998,14 @@ CREATE INDEX idx_chat_relays_user_id ON test_chat_schema.chat_relays USING btree
|
||||
|
||||
|
||||
|
||||
CREATE UNIQUE INDEX idx_chat_relays_user_id_address ON test_chat_schema.chat_relays USING btree (user_id, address);
|
||||
|
||||
|
||||
|
||||
CREATE UNIQUE INDEX idx_chat_relays_user_id_name ON test_chat_schema.chat_relays USING btree (user_id, name);
|
||||
|
||||
|
||||
|
||||
CREATE INDEX idx_chat_tags_chats_chat_tag_id ON test_chat_schema.chat_tags_chats USING btree (chat_tag_id);
|
||||
|
||||
|
||||
@@ -2240,6 +2278,18 @@ CREATE INDEX idx_group_profiles_user_id ON test_chat_schema.group_profiles USING
|
||||
|
||||
|
||||
|
||||
CREATE INDEX idx_group_relays_chat_relay_id ON test_chat_schema.group_relays USING btree (chat_relay_id);
|
||||
|
||||
|
||||
|
||||
CREATE INDEX idx_group_relays_group_id ON test_chat_schema.group_relays USING btree (group_id);
|
||||
|
||||
|
||||
|
||||
CREATE UNIQUE INDEX idx_group_relays_group_member_id ON test_chat_schema.group_relays USING btree (group_member_id);
|
||||
|
||||
|
||||
|
||||
CREATE INDEX idx_group_snd_item_statuses_chat_item_id ON test_chat_schema.group_snd_item_statuses USING btree (chat_item_id);
|
||||
|
||||
|
||||
@@ -2919,6 +2969,21 @@ ALTER TABLE ONLY test_chat_schema.group_profiles
|
||||
|
||||
|
||||
|
||||
ALTER TABLE ONLY test_chat_schema.group_relays
|
||||
ADD CONSTRAINT group_relays_chat_relay_id_fkey FOREIGN KEY (chat_relay_id) REFERENCES test_chat_schema.chat_relays(chat_relay_id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
|
||||
ALTER TABLE ONLY test_chat_schema.group_relays
|
||||
ADD CONSTRAINT group_relays_group_id_fkey FOREIGN KEY (group_id) REFERENCES test_chat_schema.groups(group_id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
|
||||
ALTER TABLE ONLY test_chat_schema.group_relays
|
||||
ADD CONSTRAINT group_relays_group_member_id_fkey FOREIGN KEY (group_member_id) REFERENCES test_chat_schema.group_members(group_member_id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
|
||||
ALTER TABLE ONLY test_chat_schema.group_snd_item_statuses
|
||||
ADD CONSTRAINT group_snd_item_statuses_chat_item_id_fkey FOREIGN KEY (chat_item_id) REFERENCES test_chat_schema.chat_items(chat_item_id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ module Simplex.Chat.Store.Profiles
|
||||
getUsers,
|
||||
setActiveUser,
|
||||
getUser,
|
||||
getRelayUser,
|
||||
getUserIdByName,
|
||||
getUserByAConnId,
|
||||
getUserByASndFileId,
|
||||
@@ -58,6 +59,7 @@ module Simplex.Chat.Store.Profiles
|
||||
updateUserAddressSettings,
|
||||
getProtocolServers,
|
||||
getChatRelays,
|
||||
getChatRelayById,
|
||||
insertProtocolServer,
|
||||
getUpdateServerOperators,
|
||||
getServerOperators,
|
||||
@@ -216,6 +218,11 @@ getUser db userId =
|
||||
ExceptT . firstRow toUser (SEUserNotFound userId) $
|
||||
DB.query db (userQuery <> " WHERE u.user_id = ?") (Only userId)
|
||||
|
||||
getRelayUser :: DB.Connection -> ExceptT StoreError IO User
|
||||
getRelayUser db =
|
||||
ExceptT . firstRow toUser SERelayUserNotFound $
|
||||
DB.query_ db (userQuery <> " WHERE u.is_user_chat_relay = 1")
|
||||
|
||||
getUserIdByName :: DB.Connection -> UserName -> ExceptT StoreError IO Int64
|
||||
getUserIdByName db uName =
|
||||
ExceptT . firstRow fromOnly (SEUserNotFoundByName uName) $
|
||||
@@ -621,13 +628,25 @@ getChatRelays db User {userId} =
|
||||
[sql|
|
||||
SELECT chat_relay_id, address, name, domains, preset, tested, enabled
|
||||
FROM chat_relays
|
||||
WHERE user_id = ?
|
||||
WHERE user_id = ? AND deleted = 0
|
||||
|]
|
||||
(Only userId)
|
||||
where
|
||||
toChatRelay :: (DBEntityId, ShortLinkContact, Text, Text, BoolInt, Maybe BoolInt, BoolInt) -> UserChatRelay
|
||||
toChatRelay (chatRelayId, address, name, domains, BI preset, tested, BI enabled) =
|
||||
UserChatRelay {chatRelayId, address, name, domains = T.splitOn "," domains, preset, tested = unBI <$> tested, enabled, deleted = False}
|
||||
|
||||
toChatRelay :: (DBEntityId, ShortLinkContact, Text, Text, BoolInt, Maybe BoolInt, BoolInt) -> UserChatRelay
|
||||
toChatRelay (chatRelayId, address, name, domains, BI preset, tested, BI enabled) =
|
||||
UserChatRelay {chatRelayId, address, name, domains = T.splitOn "," domains, preset, tested = unBI <$> tested, enabled, deleted = False}
|
||||
|
||||
getChatRelayById :: DB.Connection -> User -> Int64 -> ExceptT StoreError IO UserChatRelay
|
||||
getChatRelayById db User {userId} relayId =
|
||||
ExceptT . firstRow toChatRelay (SEUserChatRelayNotFound relayId) $
|
||||
DB.query
|
||||
db
|
||||
[sql|
|
||||
SELECT chat_relay_id, address, name, domains, preset, tested, enabled
|
||||
FROM chat_relays
|
||||
WHERE user_id = ? AND chat_relay_id = ? AND deleted = 0
|
||||
|]
|
||||
(userId, relayId)
|
||||
|
||||
insertChatRelay :: DB.Connection -> User -> UTCTime -> NewUserChatRelay -> IO UserChatRelay
|
||||
insertChatRelay db User {userId} ts relay@UserChatRelay {address, name, domains, preset, tested, enabled} = do
|
||||
@@ -642,7 +661,7 @@ insertChatRelay db User {userId} ts relay@UserChatRelay {address, name, domains,
|
||||
RETURNING chat_relay_id
|
||||
|]
|
||||
(address, name, T.intercalate "," domains, BI preset, BI <$> tested, BI enabled, userId, ts, ts)
|
||||
pure relay {chatRelayId = DBEntityId crId}
|
||||
pure (relay :: NewUserChatRelay) {chatRelayId = DBEntityId crId}
|
||||
|
||||
updateChatRelay :: DB.Connection -> UTCTime -> UserChatRelay -> IO ()
|
||||
updateChatRelay db ts UserChatRelay {chatRelayId, address, name, domains, preset, tested, enabled} =
|
||||
@@ -907,7 +926,13 @@ setUserServers' db user@User {userId} ts UpdatedUserOperatorServers {operator, s
|
||||
| deleted -> pure Nothing
|
||||
| otherwise -> Just <$> insertChatRelay db user ts relay
|
||||
DBEntityId relayId
|
||||
| deleted -> Nothing <$ DB.execute db "DELETE FROM chat_relays WHERE user_id = ? AND chat_relay_id = ? AND preset = ?" (userId, relayId, BI False)
|
||||
| deleted -> do
|
||||
-- If relay is referenced in group_relays, mark it as deleted instead of deleting
|
||||
referenced <- fromOnly . head <$> DB.query db "SELECT EXISTS (SELECT 1 FROM group_relays WHERE chat_relay_id = ?)" (Only relayId)
|
||||
if referenced
|
||||
then DB.execute db "UPDATE chat_relays SET deleted = 1, updated_at = ? WHERE chat_relay_id = ?" (ts, relayId)
|
||||
else DB.execute db "DELETE FROM chat_relays WHERE user_id = ? AND chat_relay_id = ? AND preset = ?" (userId, relayId, BI False)
|
||||
pure Nothing
|
||||
| otherwise -> Just relay <$ updateChatRelay db ts relay
|
||||
|
||||
createCall :: DB.Connection -> User -> Call -> UTCTime -> IO ()
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DuplicateRecordFields #-}
|
||||
{-# LANGUAGE LambdaCase #-}
|
||||
{-# LANGUAGE NamedFieldPuns #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
|
||||
module Simplex.Chat.Store.RelayRequests
|
||||
( hasPendingRelayRequests,
|
||||
getNextPendingRelayRequest,
|
||||
setRelayRequestErr,
|
||||
)
|
||||
where
|
||||
|
||||
import Data.Maybe (fromMaybe)
|
||||
import Data.Text (Text)
|
||||
import Data.Time.Clock (getCurrentTime)
|
||||
import Simplex.Chat.Store.Shared
|
||||
import Simplex.Chat.Types
|
||||
import Simplex.Messaging.Agent.Protocol (InvitationId)
|
||||
import Simplex.Messaging.Agent.Store.AgentStore (getWorkItem, maybeFirstRow)
|
||||
import qualified Simplex.Messaging.Agent.Store.DB as DB
|
||||
import Simplex.Messaging.Util (firstRow')
|
||||
import Simplex.Messaging.Version
|
||||
#if defined(dbPostgres)
|
||||
import Database.PostgreSQL.Simple (Only (..))
|
||||
import Database.PostgreSQL.Simple.SqlQQ (sql)
|
||||
#else
|
||||
import Database.SQLite.Simple (Only (..))
|
||||
import Database.SQLite.Simple.QQ (sql)
|
||||
#endif
|
||||
|
||||
hasPendingRelayRequests :: DB.Connection -> IO Bool
|
||||
hasPendingRelayRequests db =
|
||||
fromOnly . head
|
||||
<$> DB.query
|
||||
db
|
||||
[sql|
|
||||
SELECT EXISTS (
|
||||
SELECT 1
|
||||
FROM groups
|
||||
WHERE relay_own_status = ?
|
||||
AND relay_request_failed = 0
|
||||
AND relay_request_err_reason IS NULL
|
||||
LIMIT 1
|
||||
)
|
||||
|]
|
||||
(Only RSInvited)
|
||||
|
||||
getNextPendingRelayRequest :: DB.Connection -> IO (Either StoreError (Maybe (GroupId, RelayRequestData)))
|
||||
getNextPendingRelayRequest db =
|
||||
getWorkItem "relay request" getNextRequestGroupId getRelayRequestData (markRelayRequestFailed db)
|
||||
where
|
||||
getNextRequestGroupId :: IO (Maybe GroupId)
|
||||
getNextRequestGroupId =
|
||||
maybeFirstRow fromOnly $
|
||||
DB.query
|
||||
db
|
||||
[sql|
|
||||
SELECT group_id
|
||||
FROM groups
|
||||
WHERE relay_own_status = ?
|
||||
AND relay_request_failed = 0
|
||||
AND relay_request_err_reason IS NULL
|
||||
ORDER BY group_id ASC
|
||||
LIMIT 1
|
||||
|]
|
||||
(Only RSInvited)
|
||||
getRelayRequestData :: GroupId -> IO (Either StoreError (GroupId, RelayRequestData))
|
||||
getRelayRequestData groupId =
|
||||
firstRow' toRelayRequestData (SEGroupNotFound groupId) $
|
||||
DB.query
|
||||
db
|
||||
[sql|
|
||||
SELECT
|
||||
relay_request_inv_id, relay_request_group_link,
|
||||
relay_request_peer_chat_min_version, relay_request_peer_chat_max_version
|
||||
FROM groups
|
||||
WHERE group_id = ?
|
||||
|]
|
||||
(Only groupId)
|
||||
where
|
||||
toRelayRequestData :: (Maybe InvitationId, Maybe ShortLinkContact, Maybe VersionChat, Maybe VersionChat) -> Either StoreError (GroupId, RelayRequestData)
|
||||
toRelayRequestData = \case
|
||||
(Just relayInvId, Just reqGroupLink, Just minV, Just maxV) ->
|
||||
Right (groupId, RelayRequestData {relayInvId, reqGroupLink, reqChatVRange = fromMaybe (versionToRange maxV) $ safeVersionRange minV maxV})
|
||||
_ -> Left $ SEInternalError "missing relay request data"
|
||||
|
||||
markRelayRequestFailed :: DB.Connection -> GroupId -> IO ()
|
||||
markRelayRequestFailed db groupId = do
|
||||
currentTs <- getCurrentTime
|
||||
DB.execute
|
||||
db
|
||||
"UPDATE groups SET relay_request_failed = 1, updated_at = ? WHERE group_id = ?"
|
||||
(currentTs, groupId)
|
||||
|
||||
setRelayRequestErr :: DB.Connection -> GroupId -> Text -> IO ()
|
||||
setRelayRequestErr db groupId errReason = do
|
||||
currentTs <- getCurrentTime
|
||||
DB.execute
|
||||
db
|
||||
"UPDATE groups SET relay_request_err_reason = ?, updated_at = ? WHERE group_id = ?"
|
||||
(errReason, currentTs, groupId)
|
||||
@@ -5,39 +5,102 @@ module Simplex.Chat.Store.SQLite.Migrations.M20260109_chat_relays where
|
||||
import Database.SQLite.Simple (Query)
|
||||
import Database.SQLite.Simple.QQ (sql)
|
||||
|
||||
-- TODO [relays] TBC schema improvement - relay_link is duplicate on group_relays and group_members for owner
|
||||
-- - chat_relays - user's list of chat relays to choose from (similar to protocol_servers)
|
||||
-- - users.is_user_chat_relay - indicates that the user can serve as a chat relay
|
||||
-- (TBC usage, e.g. agree to invitations to be relay)
|
||||
-- - group_relays - group owner's list of relays for a group
|
||||
-- - group_relays.relay_link - links for all relays of a group are included in GroupShortLinkData
|
||||
-- - group_relays.relay_status - group owner's status for each relay (RelayStatus)
|
||||
-- - group_relays.chat_relay_id - associates group_relays record with a chat_relays record,
|
||||
-- chat_relays.deleted is to keep associated record if user removes chat relay from configuration,
|
||||
-- but has group relays using it
|
||||
-- - group_members.relay_link - relay link, saved on member record for user joining group
|
||||
-- - groups.relay_own_status - indicates for a relay client that it is chat relay for the group (RelayStatus)
|
||||
-- - groups.relay_request_* - relay request "work item" fields
|
||||
m20260109_chat_relays :: Query
|
||||
m20260109_chat_relays =
|
||||
[sql|
|
||||
CREATE TABLE chat_relays(
|
||||
chat_relay_id INTEGER PRIMARY KEY,
|
||||
address TEXT NOT NULL,
|
||||
address BLOB NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
domains TEXT NOT NULL,
|
||||
preset INTEGER NOT NULL DEFAULT 0,
|
||||
tested INTEGER,
|
||||
enabled INTEGER NOT NULL DEFAULT 1,
|
||||
user_id INTEGER NOT NULL REFERENCES users ON DELETE CASCADE,
|
||||
deleted INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TEXT NOT NULL DEFAULT(datetime('now')),
|
||||
updated_at TEXT NOT NULL DEFAULT(datetime('now')),
|
||||
UNIQUE(user_id, address),
|
||||
UNIQUE(user_id, name)
|
||||
);
|
||||
|
||||
updated_at TEXT NOT NULL DEFAULT(datetime('now'))
|
||||
) STRICT;
|
||||
CREATE INDEX idx_chat_relays_user_id ON chat_relays(user_id);
|
||||
CREATE UNIQUE INDEX idx_chat_relays_user_id_address ON chat_relays(user_id, address);
|
||||
CREATE UNIQUE INDEX idx_chat_relays_user_id_name ON chat_relays(user_id, name);
|
||||
|
||||
ALTER TABLE users ADD COLUMN is_user_chat_relay INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
ALTER TABLE group_members ADD COLUMN is_chat_relay INTEGER NOT NULL DEFAULT 0;
|
||||
ALTER TABLE groups ADD COLUMN use_relays INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
ALTER TABLE groups ADD COLUMN creating_in_progress INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
ALTER TABLE groups ADD COLUMN relay_own_status TEXT;
|
||||
|
||||
ALTER TABLE groups ADD COLUMN relay_request_inv_id BLOB;
|
||||
ALTER TABLE groups ADD COLUMN relay_request_group_link BLOB;
|
||||
ALTER TABLE groups ADD COLUMN relay_request_peer_chat_min_version INTEGER;
|
||||
ALTER TABLE groups ADD COLUMN relay_request_peer_chat_max_version INTEGER;
|
||||
ALTER TABLE groups ADD COLUMN relay_request_failed INTEGER DEFAULT 0;
|
||||
ALTER TABLE groups ADD COLUMN relay_request_err_reason TEXT;
|
||||
|
||||
ALTER TABLE group_profiles ADD COLUMN group_link BLOB;
|
||||
|
||||
CREATE TABLE group_relays(
|
||||
group_relay_id INTEGER PRIMARY KEY,
|
||||
group_id INTEGER NOT NULL REFERENCES groups ON DELETE CASCADE,
|
||||
group_member_id INTEGER NOT NULL REFERENCES group_members ON DELETE CASCADE,
|
||||
chat_relay_id INTEGER NOT NULL REFERENCES chat_relays ON DELETE CASCADE,
|
||||
relay_status TEXT NOT NULL,
|
||||
relay_link BLOB,
|
||||
created_at TEXT NOT NULL DEFAULT(datetime('now')),
|
||||
updated_at TEXT NOT NULL DEFAULT(datetime('now'))
|
||||
) STRICT;
|
||||
CREATE INDEX idx_group_relays_group_id ON group_relays(group_id);
|
||||
CREATE UNIQUE INDEX idx_group_relays_group_member_id ON group_relays(group_member_id);
|
||||
CREATE INDEX idx_group_relays_chat_relay_id ON group_relays(chat_relay_id);
|
||||
|
||||
ALTER TABLE group_members ADD COLUMN relay_link BLOB;
|
||||
|]
|
||||
|
||||
down_m20260109_chat_relays :: Query
|
||||
down_m20260109_chat_relays =
|
||||
[sql|
|
||||
ALTER TABLE group_members DROP COLUMN is_chat_relay;
|
||||
|
||||
ALTER TABLE users DROP COLUMN is_user_chat_relay;
|
||||
|
||||
DROP INDEX idx_chat_relays_user_id;
|
||||
ALTER TABLE groups DROP COLUMN use_relays;
|
||||
|
||||
ALTER TABLE groups DROP COLUMN creating_in_progress;
|
||||
|
||||
ALTER TABLE groups DROP COLUMN relay_own_status;
|
||||
|
||||
ALTER TABLE groups DROP COLUMN relay_request_inv_id;
|
||||
ALTER TABLE groups DROP COLUMN relay_request_group_link;
|
||||
ALTER TABLE groups DROP COLUMN relay_request_peer_chat_min_version;
|
||||
ALTER TABLE groups DROP COLUMN relay_request_peer_chat_max_version;
|
||||
ALTER TABLE groups DROP COLUMN relay_request_failed;
|
||||
ALTER TABLE groups DROP COLUMN relay_request_err_reason;
|
||||
|
||||
ALTER TABLE group_profiles DROP COLUMN group_link;
|
||||
|
||||
DROP INDEX idx_group_relays_group_id;
|
||||
DROP INDEX idx_group_relays_group_member_id;
|
||||
DROP INDEX idx_group_relays_chat_relay_id;
|
||||
DROP TABLE group_relays;
|
||||
|
||||
DROP INDEX idx_chat_relays_user_id;
|
||||
DROP INDEX idx_chat_relays_user_id_address;
|
||||
DROP INDEX idx_chat_relays_user_id_name;
|
||||
DROP TABLE chat_relays;
|
||||
|
||||
ALTER TABLE group_members DROP COLUMN relay_link;
|
||||
|]
|
||||
@@ -30,6 +30,7 @@ Query:
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
|
||||
Plan:
|
||||
SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?)
|
||||
SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_single_sender_group_member_id (single_sender_group_member_id=?)
|
||||
SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?)
|
||||
SEARCH delivery_tasks USING COVERING INDEX idx_delivery_tasks_sender_group_member_id (sender_group_member_id=?)
|
||||
@@ -82,6 +83,7 @@ Query:
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
|
||||
Plan:
|
||||
SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?)
|
||||
SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_single_sender_group_member_id (single_sender_group_member_id=?)
|
||||
SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?)
|
||||
SEARCH delivery_tasks USING COVERING INDEX idx_delivery_tasks_sender_group_member_id (sender_group_member_id=?)
|
||||
@@ -140,21 +142,22 @@ SEARCH c USING INDEX idx_connections_contact_id (contact_id=?) LEFT-JOIN
|
||||
Query:
|
||||
SELECT
|
||||
-- GroupInfo
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, gp.short_descr, g.local_alias, gp.description, gp.image,
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, gp.short_descr, g.local_alias, gp.description, gp.image, gp.group_link,
|
||||
g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, gp.member_admission,
|
||||
g.created_at, g.updated_at, g.chat_ts, g.user_member_profile_sent_at,
|
||||
g.conn_full_link_to_connect, g.conn_short_link_to_connect, g.conn_link_prepared_connection, g.conn_link_started_connection, g.welcome_shared_msg_id, g.request_shared_msg_id,
|
||||
g.business_chat, g.business_member_id, g.customer_member_id,
|
||||
g.use_relays, g.relay_own_status,
|
||||
g.ui_themes, g.summary_current_members_count, g.custom_data, g.chat_item_ttl, g.members_require_attention, g.via_group_link_uri,
|
||||
-- GroupInfo {membership}
|
||||
mu.group_member_id, mu.group_id, mu.index_in_group, mu.member_id, mu.peer_chat_min_version, mu.peer_chat_max_version, mu.member_role, mu.member_category,
|
||||
mu.member_status, mu.show_messages, mu.member_restriction, mu.is_chat_relay, mu.invited_by, mu.invited_by_group_member_id, mu.local_display_name, mu.contact_id, mu.contact_profile_id, pu.contact_profile_id,
|
||||
mu.member_status, mu.show_messages, mu.member_restriction, mu.invited_by, mu.invited_by_group_member_id, mu.local_display_name, mu.contact_id, mu.contact_profile_id, pu.contact_profile_id,
|
||||
-- GroupInfo {membership = GroupMember {memberProfile}}
|
||||
pu.display_name, pu.full_name, pu.short_descr, pu.image, pu.contact_link, pu.chat_peer_type, pu.local_alias, pu.preferences,
|
||||
mu.created_at, mu.updated_at,
|
||||
mu.support_chat_ts, mu.support_chat_items_unread, mu.support_chat_items_member_attention, mu.support_chat_items_mentions, mu.support_chat_last_msg_from_member_ts,
|
||||
-- from GroupMember
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction, m.is_chat_relay,
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.chat_peer_type, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts
|
||||
@@ -175,6 +178,21 @@ SEARCH gp USING INTEGER PRIMARY KEY (rowid=?)
|
||||
SEARCH mu USING INDEX idx_group_members_contact_id (contact_id=?)
|
||||
SEARCH pu USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
SELECT delivery_task_id
|
||||
FROM delivery_tasks
|
||||
WHERE group_id = ?
|
||||
AND worker_scope = ?
|
||||
AND job_scope_spec_tag IS NOT DISTINCT FROM ?
|
||||
AND job_scope_include_pending IS NOT DISTINCT FROM ?
|
||||
AND job_scope_support_gm_id IS NOT DISTINCT FROM ?
|
||||
AND failed = 0
|
||||
AND task_status = ?
|
||||
ORDER BY delivery_task_id ASC
|
||||
|
||||
Plan:
|
||||
SEARCH delivery_tasks USING COVERING INDEX idx_delivery_tasks_next_for_job_scope (group_id=? AND worker_scope=? AND job_scope_spec_tag=? AND job_scope_include_pending=? AND job_scope_support_gm_id=? AND failed=? AND task_status=?)
|
||||
|
||||
Query:
|
||||
SELECT delivery_task_id
|
||||
FROM delivery_tasks
|
||||
@@ -265,6 +283,7 @@ Query:
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
|
||||
Plan:
|
||||
SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?)
|
||||
SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_single_sender_group_member_id (single_sender_group_member_id=?)
|
||||
SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?)
|
||||
SEARCH delivery_tasks USING COVERING INDEX idx_delivery_tasks_sender_group_member_id (sender_group_member_id=?)
|
||||
@@ -299,6 +318,7 @@ Query:
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
|
||||
Plan:
|
||||
SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?)
|
||||
SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_single_sender_group_member_id (single_sender_group_member_id=?)
|
||||
SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?)
|
||||
SEARCH delivery_tasks USING COVERING INDEX idx_delivery_tasks_sender_group_member_id (sender_group_member_id=?)
|
||||
@@ -333,6 +353,7 @@ Query:
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
|
||||
Plan:
|
||||
SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?)
|
||||
SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_single_sender_group_member_id (single_sender_group_member_id=?)
|
||||
SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?)
|
||||
SEARCH delivery_tasks USING COVERING INDEX idx_delivery_tasks_sender_group_member_id (sender_group_member_id=?)
|
||||
@@ -490,6 +511,75 @@ Query:
|
||||
Plan:
|
||||
SEARCH users USING COVERING INDEX sqlite_autoindex_users_1 (contact_id=?)
|
||||
|
||||
Query:
|
||||
INSERT INTO group_members
|
||||
( group_id, index_in_group, member_id, member_role, member_category, member_status,
|
||||
user_id, local_display_name, contact_id, contact_profile_id, created_at, updated_at)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
|
||||
Plan:
|
||||
SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?)
|
||||
SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_single_sender_group_member_id (single_sender_group_member_id=?)
|
||||
SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?)
|
||||
SEARCH delivery_tasks USING COVERING INDEX idx_delivery_tasks_sender_group_member_id (sender_group_member_id=?)
|
||||
SEARCH delivery_tasks USING COVERING INDEX idx_delivery_tasks_job_scope_support_gm_id (job_scope_support_gm_id=?)
|
||||
SEARCH received_probes USING COVERING INDEX idx_received_probes_group_member_id (group_member_id=?)
|
||||
SEARCH sent_probe_hashes USING COVERING INDEX idx_sent_probe_hashes_group_member_id (group_member_id=?)
|
||||
SEARCH sent_probes USING COVERING INDEX idx_sent_probes_group_member_id (group_member_id=?)
|
||||
SEARCH group_snd_item_statuses USING COVERING INDEX idx_group_snd_item_statuses_group_member_id (group_member_id=?)
|
||||
SEARCH chat_item_moderations USING COVERING INDEX idx_chat_item_moderations_moderator_member_id (moderator_member_id=?)
|
||||
SEARCH chat_item_reactions USING COVERING INDEX idx_chat_item_reactions_group_member_id (group_member_id=?)
|
||||
SEARCH chat_items USING COVERING INDEX idx_chat_items_group_scope_group_member_id (group_scope_group_member_id=?)
|
||||
SEARCH chat_items USING COVERING INDEX idx_chat_items_forwarded_by_group_member_id (forwarded_by_group_member_id=?)
|
||||
SEARCH chat_items USING COVERING INDEX idx_chat_items_item_deleted_by_group_member_id (item_deleted_by_group_member_id=?)
|
||||
SEARCH chat_items USING COVERING INDEX idx_chat_items_group_member_id (group_member_id=?)
|
||||
SEARCH pending_group_messages USING COVERING INDEX idx_pending_group_messages_group_member_id (group_member_id=?)
|
||||
SEARCH messages USING COVERING INDEX idx_messages_forwarded_by_group_member_id (forwarded_by_group_member_id=?)
|
||||
SEARCH messages USING COVERING INDEX idx_messages_author_group_member_id (author_group_member_id=?)
|
||||
SEARCH connections USING COVERING INDEX idx_connections_group_member_id (group_member_id=?)
|
||||
SEARCH rcv_files USING COVERING INDEX idx_rcv_files_group_member_id (group_member_id=?)
|
||||
SEARCH snd_files USING COVERING INDEX idx_snd_files_group_member_id (group_member_id=?)
|
||||
SEARCH group_member_intros USING COVERING INDEX idx_group_member_intros_to_group_member_id (to_group_member_id=?)
|
||||
SEARCH group_member_intros USING COVERING INDEX idx_group_member_intros_re_group_member_id (re_group_member_id=?)
|
||||
SEARCH group_members USING COVERING INDEX idx_group_members_invited_by_group_member_id (invited_by_group_member_id=?)
|
||||
SEARCH contacts USING COVERING INDEX idx_contacts_grp_direct_inv_from_group_member_id (grp_direct_inv_from_group_member_id=?)
|
||||
SEARCH contacts USING COVERING INDEX idx_contacts_contact_group_member_id (contact_group_member_id=?)
|
||||
|
||||
Query:
|
||||
INSERT INTO group_members
|
||||
( group_id, index_in_group, member_id, member_role, member_category, member_status, invited_by,
|
||||
user_id, local_display_name, contact_profile_id, created_at, updated_at, relay_link
|
||||
)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
|
||||
Plan:
|
||||
SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?)
|
||||
SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_single_sender_group_member_id (single_sender_group_member_id=?)
|
||||
SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?)
|
||||
SEARCH delivery_tasks USING COVERING INDEX idx_delivery_tasks_sender_group_member_id (sender_group_member_id=?)
|
||||
SEARCH delivery_tasks USING COVERING INDEX idx_delivery_tasks_job_scope_support_gm_id (job_scope_support_gm_id=?)
|
||||
SEARCH received_probes USING COVERING INDEX idx_received_probes_group_member_id (group_member_id=?)
|
||||
SEARCH sent_probe_hashes USING COVERING INDEX idx_sent_probe_hashes_group_member_id (group_member_id=?)
|
||||
SEARCH sent_probes USING COVERING INDEX idx_sent_probes_group_member_id (group_member_id=?)
|
||||
SEARCH group_snd_item_statuses USING COVERING INDEX idx_group_snd_item_statuses_group_member_id (group_member_id=?)
|
||||
SEARCH chat_item_moderations USING COVERING INDEX idx_chat_item_moderations_moderator_member_id (moderator_member_id=?)
|
||||
SEARCH chat_item_reactions USING COVERING INDEX idx_chat_item_reactions_group_member_id (group_member_id=?)
|
||||
SEARCH chat_items USING COVERING INDEX idx_chat_items_group_scope_group_member_id (group_scope_group_member_id=?)
|
||||
SEARCH chat_items USING COVERING INDEX idx_chat_items_forwarded_by_group_member_id (forwarded_by_group_member_id=?)
|
||||
SEARCH chat_items USING COVERING INDEX idx_chat_items_item_deleted_by_group_member_id (item_deleted_by_group_member_id=?)
|
||||
SEARCH chat_items USING COVERING INDEX idx_chat_items_group_member_id (group_member_id=?)
|
||||
SEARCH pending_group_messages USING COVERING INDEX idx_pending_group_messages_group_member_id (group_member_id=?)
|
||||
SEARCH messages USING COVERING INDEX idx_messages_forwarded_by_group_member_id (forwarded_by_group_member_id=?)
|
||||
SEARCH messages USING COVERING INDEX idx_messages_author_group_member_id (author_group_member_id=?)
|
||||
SEARCH connections USING COVERING INDEX idx_connections_group_member_id (group_member_id=?)
|
||||
SEARCH rcv_files USING COVERING INDEX idx_rcv_files_group_member_id (group_member_id=?)
|
||||
SEARCH snd_files USING COVERING INDEX idx_snd_files_group_member_id (group_member_id=?)
|
||||
SEARCH group_member_intros USING COVERING INDEX idx_group_member_intros_to_group_member_id (to_group_member_id=?)
|
||||
SEARCH group_member_intros USING COVERING INDEX idx_group_member_intros_re_group_member_id (re_group_member_id=?)
|
||||
SEARCH group_members USING COVERING INDEX idx_group_members_invited_by_group_member_id (invited_by_group_member_id=?)
|
||||
SEARCH contacts USING COVERING INDEX idx_contacts_grp_direct_inv_from_group_member_id (grp_direct_inv_from_group_member_id=?)
|
||||
SEARCH contacts USING COVERING INDEX idx_contacts_contact_group_member_id (contact_group_member_id=?)
|
||||
|
||||
Query:
|
||||
INSERT INTO group_members
|
||||
( group_id, index_in_group, member_id, member_role, member_category, member_status, member_relations_vector, invited_by,
|
||||
@@ -497,6 +587,7 @@ Query:
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
|
||||
Plan:
|
||||
SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?)
|
||||
SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_single_sender_group_member_id (single_sender_group_member_id=?)
|
||||
SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?)
|
||||
SEARCH delivery_tasks USING COVERING INDEX idx_delivery_tasks_sender_group_member_id (sender_group_member_id=?)
|
||||
@@ -531,6 +622,7 @@ Query:
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
|
||||
Plan:
|
||||
SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?)
|
||||
SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_single_sender_group_member_id (single_sender_group_member_id=?)
|
||||
SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?)
|
||||
SEARCH delivery_tasks USING COVERING INDEX idx_delivery_tasks_sender_group_member_id (sender_group_member_id=?)
|
||||
@@ -590,6 +682,16 @@ Query:
|
||||
Plan:
|
||||
SEARCH delivery_jobs USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
SELECT
|
||||
relay_request_inv_id, relay_request_group_link,
|
||||
relay_request_peer_chat_min_version, relay_request_peer_chat_max_version
|
||||
FROM groups
|
||||
WHERE group_id = ?
|
||||
|
||||
Plan:
|
||||
SEARCH groups USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
SELECT COUNT(1)
|
||||
FROM (
|
||||
@@ -864,7 +966,7 @@ Plan:
|
||||
SEARCH delivery_tasks USING COVERING INDEX idx_delivery_tasks_next (group_id=? AND worker_scope=? AND failed=? AND task_status=?)
|
||||
|
||||
Query:
|
||||
SELECT gp.display_name, gp.full_name, gp.short_descr, gp.description, gp.image, gp.preferences, gp.member_admission
|
||||
SELECT gp.display_name, gp.full_name, gp.short_descr, gp.description, gp.image, gp.group_link, gp.preferences, gp.member_admission
|
||||
FROM group_profiles gp
|
||||
JOIN groups g ON gp.group_profile_id = g.group_profile_id
|
||||
WHERE g.group_id = ?
|
||||
@@ -873,6 +975,18 @@ Plan:
|
||||
SEARCH g USING INTEGER PRIMARY KEY (rowid=?)
|
||||
SEARCH gp USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
SELECT group_id
|
||||
FROM groups
|
||||
WHERE relay_own_status = ?
|
||||
AND relay_request_failed = 0
|
||||
AND relay_request_err_reason IS NULL
|
||||
ORDER BY group_id ASC
|
||||
LIMIT 1
|
||||
|
||||
Plan:
|
||||
SCAN groups
|
||||
|
||||
Query:
|
||||
SELECT i.chat_item_id
|
||||
FROM chat_items i
|
||||
@@ -892,7 +1006,7 @@ Query:
|
||||
SELECT i.chat_item_id,
|
||||
-- GroupMember
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category,
|
||||
m.member_status, m.show_messages, m.member_restriction, m.is_chat_relay, m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id,
|
||||
m.member_status, m.show_messages, m.member_restriction, m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id,
|
||||
p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.chat_peer_type, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts
|
||||
@@ -1016,16 +1130,52 @@ Query:
|
||||
RETURNING chat_relay_id
|
||||
|
||||
Plan:
|
||||
SEARCH group_relays USING COVERING INDEX idx_group_relays_chat_relay_id (chat_relay_id=?)
|
||||
|
||||
Query:
|
||||
INSERT INTO group_members
|
||||
( group_id, index_in_group, member_id, member_role, member_category, member_status, invited_by, invited_by_group_member_id,
|
||||
user_id, local_display_name, contact_profile_id, created_at, updated_at)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
|
||||
Plan:
|
||||
SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?)
|
||||
SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_single_sender_group_member_id (single_sender_group_member_id=?)
|
||||
SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?)
|
||||
SEARCH delivery_tasks USING COVERING INDEX idx_delivery_tasks_sender_group_member_id (sender_group_member_id=?)
|
||||
SEARCH delivery_tasks USING COVERING INDEX idx_delivery_tasks_job_scope_support_gm_id (job_scope_support_gm_id=?)
|
||||
SEARCH received_probes USING COVERING INDEX idx_received_probes_group_member_id (group_member_id=?)
|
||||
SEARCH sent_probe_hashes USING COVERING INDEX idx_sent_probe_hashes_group_member_id (group_member_id=?)
|
||||
SEARCH sent_probes USING COVERING INDEX idx_sent_probes_group_member_id (group_member_id=?)
|
||||
SEARCH group_snd_item_statuses USING COVERING INDEX idx_group_snd_item_statuses_group_member_id (group_member_id=?)
|
||||
SEARCH chat_item_moderations USING COVERING INDEX idx_chat_item_moderations_moderator_member_id (moderator_member_id=?)
|
||||
SEARCH chat_item_reactions USING COVERING INDEX idx_chat_item_reactions_group_member_id (group_member_id=?)
|
||||
SEARCH chat_items USING COVERING INDEX idx_chat_items_group_scope_group_member_id (group_scope_group_member_id=?)
|
||||
SEARCH chat_items USING COVERING INDEX idx_chat_items_forwarded_by_group_member_id (forwarded_by_group_member_id=?)
|
||||
SEARCH chat_items USING COVERING INDEX idx_chat_items_item_deleted_by_group_member_id (item_deleted_by_group_member_id=?)
|
||||
SEARCH chat_items USING COVERING INDEX idx_chat_items_group_member_id (group_member_id=?)
|
||||
SEARCH pending_group_messages USING COVERING INDEX idx_pending_group_messages_group_member_id (group_member_id=?)
|
||||
SEARCH messages USING COVERING INDEX idx_messages_forwarded_by_group_member_id (forwarded_by_group_member_id=?)
|
||||
SEARCH messages USING COVERING INDEX idx_messages_author_group_member_id (author_group_member_id=?)
|
||||
SEARCH connections USING COVERING INDEX idx_connections_group_member_id (group_member_id=?)
|
||||
SEARCH rcv_files USING COVERING INDEX idx_rcv_files_group_member_id (group_member_id=?)
|
||||
SEARCH snd_files USING COVERING INDEX idx_snd_files_group_member_id (group_member_id=?)
|
||||
SEARCH group_member_intros USING COVERING INDEX idx_group_member_intros_to_group_member_id (to_group_member_id=?)
|
||||
SEARCH group_member_intros USING COVERING INDEX idx_group_member_intros_re_group_member_id (re_group_member_id=?)
|
||||
SEARCH group_members USING COVERING INDEX idx_group_members_invited_by_group_member_id (invited_by_group_member_id=?)
|
||||
SEARCH contacts USING COVERING INDEX idx_contacts_grp_direct_inv_from_group_member_id (grp_direct_inv_from_group_member_id=?)
|
||||
SEARCH contacts USING COVERING INDEX idx_contacts_contact_group_member_id (contact_group_member_id=?)
|
||||
|
||||
Query:
|
||||
INSERT INTO group_members
|
||||
(group_id, index_in_group, member_id, member_role, member_category, member_status, member_relations_vector,
|
||||
member_restriction, is_chat_relay, invited_by, invited_by_group_member_id,
|
||||
member_restriction, invited_by, invited_by_group_member_id,
|
||||
user_id, local_display_name, contact_id, contact_profile_id, created_at, updated_at,
|
||||
peer_chat_min_version, peer_chat_max_version)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
|
||||
Plan:
|
||||
SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?)
|
||||
SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_single_sender_group_member_id (single_sender_group_member_id=?)
|
||||
SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?)
|
||||
SEARCH delivery_tasks USING COVERING INDEX idx_delivery_tasks_sender_group_member_id (sender_group_member_id=?)
|
||||
@@ -1056,16 +1206,16 @@ Query:
|
||||
INSERT INTO groups
|
||||
(group_profile_id, local_display_name, user_id, enable_ntfs,
|
||||
created_at, updated_at, chat_ts, user_member_profile_sent_at, conn_full_link_to_connect, conn_short_link_to_connect, welcome_shared_msg_id,
|
||||
business_chat, business_member_id, customer_member_id)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
business_chat, business_member_id, customer_member_id, use_relays, relay_own_status)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
|
||||
Plan:
|
||||
|
||||
Query:
|
||||
INSERT INTO groups
|
||||
(local_display_name, user_id, group_profile_id, enable_ntfs,
|
||||
(use_relays, creating_in_progress, local_display_name, user_id, group_profile_id, enable_ntfs,
|
||||
created_at, updated_at, chat_ts, user_member_profile_sent_at)
|
||||
VALUES (?,?,?,?,?,?,?,?)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?)
|
||||
|
||||
Plan:
|
||||
|
||||
@@ -1121,7 +1271,7 @@ Query:
|
||||
i.forwarded_by_group_member_id, i.show_group_as_sender,
|
||||
-- GroupMember
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category,
|
||||
m.member_status, m.show_messages, m.member_restriction, m.is_chat_relay, m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id,
|
||||
m.member_status, m.show_messages, m.member_restriction, m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id,
|
||||
p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.chat_peer_type, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts,
|
||||
@@ -1129,20 +1279,18 @@ Query:
|
||||
ri.chat_item_id, i.quoted_shared_msg_id, i.quoted_sent_at, i.quoted_content, i.quoted_sent,
|
||||
-- quoted GroupMember
|
||||
rm.group_member_id, rm.group_id, rm.index_in_group, rm.member_id, rm.peer_chat_min_version, rm.peer_chat_max_version, rm.member_role, rm.member_category,
|
||||
rm.member_status, rm.show_messages, rm.member_restriction, rm.is_chat_relay, rm.invited_by, rm.invited_by_group_member_id, rm.local_display_name, rm.contact_id, rm.contact_profile_id, rp.contact_profile_id,
|
||||
rm.member_status, rm.show_messages, rm.member_restriction, rm.invited_by, rm.invited_by_group_member_id, rm.local_display_name, rm.contact_id, rm.contact_profile_id, rp.contact_profile_id,
|
||||
rp.display_name, rp.full_name, rp.short_descr, rp.image, rp.contact_link, rp.chat_peer_type, rp.local_alias, rp.preferences,
|
||||
rm.created_at, rm.updated_at,
|
||||
rm.support_chat_ts, rm.support_chat_items_unread, rm.support_chat_items_member_attention, rm.support_chat_items_mentions, rm.support_chat_last_msg_from_member_ts,
|
||||
-- deleted by GroupMember
|
||||
dbm.group_member_id, dbm.group_id, dbm.index_in_group, dbm.member_id, dbm.peer_chat_min_version, dbm.peer_chat_max_version, dbm.member_role, dbm.member_category,
|
||||
dbm.member_status, dbm.show_messages, dbm.member_restriction, dbm.is_chat_relay, dbm.invited_by, dbm.invited_by_group_member_id, dbm.local_display_name, dbm.contact_id, dbm.contact_profile_id, dbp.contact_profile_id,
|
||||
dbm.member_status, dbm.show_messages, dbm.member_restriction, dbm.invited_by, dbm.invited_by_group_member_id, dbm.local_display_name, dbm.contact_id, dbm.contact_profile_id, dbp.contact_profile_id,
|
||||
dbp.display_name, dbp.full_name, dbp.short_descr, dbp.image, dbp.contact_link, dbp.chat_peer_type, dbp.local_alias, dbp.preferences,
|
||||
dbm.created_at, dbm.updated_at,
|
||||
dbm.support_chat_ts, dbm.support_chat_items_unread, dbm.support_chat_items_member_attention, dbm.support_chat_items_mentions, dbm.support_chat_last_msg_from_member_ts
|
||||
FROM chat_items i
|
||||
LEFT JOIN files f ON f.chat_item_id = i.chat_item_id
|
||||
LEFT JOIN group_members gsm ON gsm.group_member_id = i.group_scope_group_member_id
|
||||
LEFT JOIN contact_profiles gsp ON gsp.contact_profile_id = COALESCE(gsm.member_profile_id, gsm.contact_profile_id)
|
||||
LEFT JOIN group_members m ON m.group_member_id = i.group_member_id
|
||||
LEFT JOIN contact_profiles p ON p.contact_profile_id = COALESCE(m.member_profile_id, m.contact_profile_id)
|
||||
LEFT JOIN chat_items ri ON ri.shared_msg_id = i.quoted_shared_msg_id AND ri.group_id = i.group_id
|
||||
@@ -1155,7 +1303,6 @@ Query:
|
||||
Plan:
|
||||
SEARCH i USING INTEGER PRIMARY KEY (rowid=?)
|
||||
SEARCH f USING INDEX idx_files_chat_item_id (chat_item_id=?) LEFT-JOIN
|
||||
SEARCH gsm USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN
|
||||
SEARCH m USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN
|
||||
SEARCH p USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN
|
||||
SEARCH ri USING INDEX idx_chat_items_group_id_shared_msg_id (group_id=? AND shared_msg_id=?) LEFT-JOIN
|
||||
@@ -1568,7 +1715,7 @@ SEARCH group_members USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
UPDATE group_profiles
|
||||
SET display_name = ?, full_name = ?, short_descr = ?, description = ?, image = ?, preferences = ?, member_admission = ?, updated_at = ?
|
||||
SET display_name = ?, full_name = ?, short_descr = ?, description = ?, image = ?, group_link = ?, preferences = ?, member_admission = ?, updated_at = ?
|
||||
WHERE group_profile_id IN (
|
||||
SELECT group_profile_id
|
||||
FROM groups
|
||||
@@ -1580,6 +1727,26 @@ SEARCH group_profiles USING INTEGER PRIMARY KEY (rowid=?)
|
||||
LIST SUBQUERY 1
|
||||
SEARCH groups USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
UPDATE groups
|
||||
SET relay_request_inv_id = ?,
|
||||
relay_request_group_link = ?,
|
||||
relay_request_peer_chat_min_version = ?,
|
||||
relay_request_peer_chat_max_version = ?
|
||||
WHERE group_id = ?
|
||||
|
||||
Plan:
|
||||
SEARCH groups USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
INSERT INTO connections (
|
||||
user_id, agent_conn_id, conn_level, conn_status, conn_type,
|
||||
group_member_id, conn_chat_version, to_subscribe, pq_support, pq_encryption,
|
||||
created_at, updated_at
|
||||
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
|
||||
Plan:
|
||||
|
||||
Query:
|
||||
INSERT INTO connections (
|
||||
user_id, agent_conn_id, conn_level, conn_status, conn_type, contact_id, custom_user_profile_id,
|
||||
@@ -1613,6 +1780,7 @@ Query:
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
|
||||
Plan:
|
||||
SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?)
|
||||
SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_single_sender_group_member_id (single_sender_group_member_id=?)
|
||||
SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?)
|
||||
SEARCH delivery_tasks USING COVERING INDEX idx_delivery_tasks_sender_group_member_id (sender_group_member_id=?)
|
||||
@@ -1639,6 +1807,13 @@ SEARCH group_members USING COVERING INDEX idx_group_members_invited_by_group_mem
|
||||
SEARCH contacts USING COVERING INDEX idx_contacts_grp_direct_inv_from_group_member_id (grp_direct_inv_from_group_member_id=?)
|
||||
SEARCH contacts USING COVERING INDEX idx_contacts_contact_group_member_id (contact_group_member_id=?)
|
||||
|
||||
Query:
|
||||
INSERT INTO group_relays
|
||||
(group_id, group_member_id, chat_relay_id, relay_status, created_at, updated_at)
|
||||
VALUES (?,?,?,?,?,?)
|
||||
|
||||
Plan:
|
||||
|
||||
Query:
|
||||
INSERT INTO msg_deliveries
|
||||
(message_id, connection_id, agent_msg_id, agent_msg_meta, chat_ts, created_at, updated_at, delivery_status)
|
||||
@@ -2237,7 +2412,7 @@ Query:
|
||||
) ReportCount ON ReportCount.group_id = g.group_id
|
||||
|
||||
JOIN group_profiles gp ON gp.group_profile_id = g.group_profile_id
|
||||
WHERE g.user_id = ?
|
||||
WHERE g.user_id = ? AND g.creating_in_progress = 0
|
||||
AND (
|
||||
LOWER(g.local_display_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(gp.display_name) LIKE '%' || ? || '%'
|
||||
@@ -2289,7 +2464,7 @@ Query:
|
||||
GROUP BY group_id
|
||||
) ReportCount ON ReportCount.group_id = g.group_id
|
||||
|
||||
WHERE g.user_id = ?
|
||||
WHERE g.user_id = ? AND g.creating_in_progress = 0
|
||||
AND (g.favorite = 1
|
||||
OR g.unread_chat = 1 OR ChatStats.UnreadCount > 0)
|
||||
ORDER BY g.chat_ts DESC LIMIT ?
|
||||
@@ -2335,7 +2510,7 @@ Query:
|
||||
GROUP BY group_id
|
||||
) ReportCount ON ReportCount.group_id = g.group_id
|
||||
|
||||
WHERE g.user_id = ?
|
||||
WHERE g.user_id = ? AND g.creating_in_progress = 0
|
||||
AND (g.unread_chat = 1 OR ChatStats.UnreadCount > 0)
|
||||
AND g.chat_ts < ? ORDER BY g.chat_ts DESC LIMIT ?
|
||||
Plan:
|
||||
@@ -2380,7 +2555,7 @@ Query:
|
||||
GROUP BY group_id
|
||||
) ReportCount ON ReportCount.group_id = g.group_id
|
||||
|
||||
WHERE g.user_id = ?
|
||||
WHERE g.user_id = ? AND g.creating_in_progress = 0
|
||||
AND (g.unread_chat = 1 OR ChatStats.UnreadCount > 0)
|
||||
AND g.chat_ts > ? ORDER BY g.chat_ts ASC LIMIT ?
|
||||
Plan:
|
||||
@@ -2425,7 +2600,7 @@ Query:
|
||||
GROUP BY group_id
|
||||
) ReportCount ON ReportCount.group_id = g.group_id
|
||||
|
||||
WHERE g.user_id = ?
|
||||
WHERE g.user_id = ? AND g.creating_in_progress = 0
|
||||
AND (g.unread_chat = 1 OR ChatStats.UnreadCount > 0)
|
||||
ORDER BY g.chat_ts DESC LIMIT ?
|
||||
Plan:
|
||||
@@ -2470,7 +2645,7 @@ Query:
|
||||
GROUP BY group_id
|
||||
) ReportCount ON ReportCount.group_id = g.group_id
|
||||
|
||||
WHERE g.user_id = ?
|
||||
WHERE g.user_id = ? AND g.creating_in_progress = 0
|
||||
AND g.favorite = 1
|
||||
AND g.chat_ts < ? ORDER BY g.chat_ts DESC LIMIT ?
|
||||
Plan:
|
||||
@@ -2515,7 +2690,7 @@ Query:
|
||||
GROUP BY group_id
|
||||
) ReportCount ON ReportCount.group_id = g.group_id
|
||||
|
||||
WHERE g.user_id = ?
|
||||
WHERE g.user_id = ? AND g.creating_in_progress = 0
|
||||
AND g.favorite = 1
|
||||
AND g.chat_ts > ? ORDER BY g.chat_ts ASC LIMIT ?
|
||||
Plan:
|
||||
@@ -2560,7 +2735,7 @@ Query:
|
||||
GROUP BY group_id
|
||||
) ReportCount ON ReportCount.group_id = g.group_id
|
||||
|
||||
WHERE g.user_id = ?
|
||||
WHERE g.user_id = ? AND g.creating_in_progress = 0
|
||||
AND g.favorite = 1
|
||||
ORDER BY g.chat_ts DESC LIMIT ?
|
||||
Plan:
|
||||
@@ -2604,7 +2779,7 @@ Query:
|
||||
AND msg_content_tag = ? AND item_deleted = ? AND item_sent = 0
|
||||
GROUP BY group_id
|
||||
) ReportCount ON ReportCount.group_id = g.group_id
|
||||
WHERE g.user_id = ? AND g.chat_ts < ? ORDER BY g.chat_ts DESC LIMIT ?
|
||||
WHERE g.user_id = ? AND g.creating_in_progress = 0 AND g.chat_ts < ? ORDER BY g.chat_ts DESC LIMIT ?
|
||||
Plan:
|
||||
MATERIALIZE ChatStats
|
||||
SEARCH chat_items USING COVERING INDEX idx_chat_items_group_scope_stats_all (user_id=? AND group_id>?)
|
||||
@@ -2646,7 +2821,7 @@ Query:
|
||||
AND msg_content_tag = ? AND item_deleted = ? AND item_sent = 0
|
||||
GROUP BY group_id
|
||||
) ReportCount ON ReportCount.group_id = g.group_id
|
||||
WHERE g.user_id = ? AND g.chat_ts > ? ORDER BY g.chat_ts ASC LIMIT ?
|
||||
WHERE g.user_id = ? AND g.creating_in_progress = 0 AND g.chat_ts > ? ORDER BY g.chat_ts ASC LIMIT ?
|
||||
Plan:
|
||||
MATERIALIZE ChatStats
|
||||
SEARCH chat_items USING COVERING INDEX idx_chat_items_group_scope_stats_all (user_id=? AND group_id>?)
|
||||
@@ -2688,7 +2863,7 @@ Query:
|
||||
AND msg_content_tag = ? AND item_deleted = ? AND item_sent = 0
|
||||
GROUP BY group_id
|
||||
) ReportCount ON ReportCount.group_id = g.group_id
|
||||
WHERE g.user_id = ? ORDER BY g.chat_ts DESC LIMIT ?
|
||||
WHERE g.user_id = ? AND g.creating_in_progress = 0 ORDER BY g.chat_ts DESC LIMIT ?
|
||||
Plan:
|
||||
MATERIALIZE ChatStats
|
||||
SEARCH chat_items USING COVERING INDEX idx_chat_items_group_scope_stats_all (user_id=? AND group_id>?)
|
||||
@@ -3065,6 +3240,21 @@ Query:
|
||||
Plan:
|
||||
SEARCH chat_items USING COVERING INDEX idx_chat_items_notes (user_id=? AND note_folder_id=? AND item_status=?)
|
||||
|
||||
Query:
|
||||
SELECT EXISTS (
|
||||
SELECT 1
|
||||
FROM groups
|
||||
WHERE relay_own_status = ?
|
||||
AND relay_request_failed = 0
|
||||
AND relay_request_err_reason IS NULL
|
||||
LIMIT 1
|
||||
)
|
||||
|
||||
Plan:
|
||||
SCAN CONSTANT ROW
|
||||
SCALAR SUBQUERY 1
|
||||
SCAN groups
|
||||
|
||||
Query:
|
||||
SELECT agent_conn_id
|
||||
FROM connections
|
||||
@@ -3230,7 +3420,15 @@ SEARCH chat_item_versions USING INDEX idx_chat_item_versions_chat_item_id (chat_
|
||||
Query:
|
||||
SELECT chat_relay_id, address, name, domains, preset, tested, enabled
|
||||
FROM chat_relays
|
||||
WHERE user_id = ?
|
||||
WHERE user_id = ? AND chat_relay_id = ? AND deleted = 0
|
||||
|
||||
Plan:
|
||||
SEARCH chat_relays USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
SELECT chat_relay_id, address, name, domains, preset, tested, enabled
|
||||
FROM chat_relays
|
||||
WHERE user_id = ? AND deleted = 0
|
||||
|
||||
Plan:
|
||||
SEARCH chat_relays USING INDEX idx_chat_relays_user_id (user_id=?)
|
||||
@@ -3364,6 +3562,30 @@ Query:
|
||||
Plan:
|
||||
SEARCH files USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
SELECT group_member_id
|
||||
FROM group_members
|
||||
WHERE group_id = ?
|
||||
AND contact_id IS DISTINCT FROM ?
|
||||
AND group_member_id IS DISTINCT FROM ?
|
||||
AND member_status IN (?,?,?,?,?,?)
|
||||
AND group_member_id > ? ORDER BY group_member_id ASC LIMIT ?
|
||||
Plan:
|
||||
SEARCH group_members USING INDEX idx_group_members_group_id_index_in_group (group_id=?)
|
||||
USE TEMP B-TREE FOR ORDER BY
|
||||
|
||||
Query:
|
||||
SELECT group_member_id
|
||||
FROM group_members
|
||||
WHERE group_id = ?
|
||||
AND contact_id IS DISTINCT FROM ?
|
||||
AND group_member_id IS DISTINCT FROM ?
|
||||
AND member_status IN (?,?,?,?,?,?)
|
||||
ORDER BY group_member_id ASC LIMIT ?
|
||||
Plan:
|
||||
SEARCH group_members USING INDEX idx_group_members_group_id_index_in_group (group_id=?)
|
||||
USE TEMP B-TREE FOR ORDER BY
|
||||
|
||||
Query:
|
||||
SELECT group_member_id, group_snd_item_status, via_proxy
|
||||
FROM group_snd_item_statuses
|
||||
@@ -4664,6 +4886,14 @@ Query:
|
||||
Plan:
|
||||
SEARCH group_members USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
UPDATE group_members
|
||||
SET relay_link = ?, updated_at = ?
|
||||
WHERE group_member_id = ?
|
||||
|
||||
Plan:
|
||||
SEARCH group_members USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
UPDATE group_members
|
||||
SET show_messages = ?, updated_at = ?
|
||||
@@ -4699,6 +4929,14 @@ SEARCH group_profiles USING INTEGER PRIMARY KEY (rowid=?)
|
||||
LIST SUBQUERY 1
|
||||
SEARCH groups USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
UPDATE group_relays
|
||||
SET relay_link = ?, relay_status = ?, updated_at = ?
|
||||
WHERE group_relay_id = ?
|
||||
|
||||
Plan:
|
||||
SEARCH group_relays USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
UPDATE group_snd_item_statuses
|
||||
SET group_snd_item_status = ?, updated_at = ?
|
||||
@@ -4858,15 +5096,16 @@ SEARCH pending_group_messages USING COVERING INDEX idx_pending_group_messages_me
|
||||
Query:
|
||||
SELECT
|
||||
-- GroupInfo
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, gp.short_descr, g.local_alias, gp.description, gp.image,
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, gp.short_descr, g.local_alias, gp.description, gp.image, gp.group_link,
|
||||
g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, gp.member_admission,
|
||||
g.created_at, g.updated_at, g.chat_ts, g.user_member_profile_sent_at,
|
||||
g.conn_full_link_to_connect, g.conn_short_link_to_connect, g.conn_link_prepared_connection, g.conn_link_started_connection, g.welcome_shared_msg_id, g.request_shared_msg_id,
|
||||
g.business_chat, g.business_member_id, g.customer_member_id,
|
||||
g.use_relays, g.relay_own_status,
|
||||
g.ui_themes, g.summary_current_members_count, g.custom_data, g.chat_item_ttl, g.members_require_attention, g.via_group_link_uri,
|
||||
-- GroupMember - membership
|
||||
mu.group_member_id, mu.group_id, mu.index_in_group, mu.member_id, mu.peer_chat_min_version, mu.peer_chat_max_version, mu.member_role, mu.member_category,
|
||||
mu.member_status, mu.show_messages, mu.member_restriction, mu.is_chat_relay, mu.invited_by, mu.invited_by_group_member_id, mu.local_display_name, mu.contact_id, mu.contact_profile_id, pu.contact_profile_id,
|
||||
mu.member_status, mu.show_messages, mu.member_restriction, mu.invited_by, mu.invited_by_group_member_id, mu.local_display_name, mu.contact_id, mu.contact_profile_id, pu.contact_profile_id,
|
||||
pu.display_name, pu.full_name, pu.short_descr, pu.image, pu.contact_link, pu.chat_peer_type, pu.local_alias, pu.preferences,
|
||||
mu.created_at, mu.updated_at,
|
||||
mu.support_chat_ts, mu.support_chat_items_unread, mu.support_chat_items_member_attention, mu.support_chat_items_mentions, mu.support_chat_last_msg_from_member_ts
|
||||
@@ -4892,15 +5131,16 @@ SEARCH pu USING INTEGER PRIMARY KEY (rowid=?)
|
||||
Query:
|
||||
SELECT
|
||||
-- GroupInfo
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, gp.short_descr, g.local_alias, gp.description, gp.image,
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, gp.short_descr, g.local_alias, gp.description, gp.image, gp.group_link,
|
||||
g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, gp.member_admission,
|
||||
g.created_at, g.updated_at, g.chat_ts, g.user_member_profile_sent_at,
|
||||
g.conn_full_link_to_connect, g.conn_short_link_to_connect, g.conn_link_prepared_connection, g.conn_link_started_connection, g.welcome_shared_msg_id, g.request_shared_msg_id,
|
||||
g.business_chat, g.business_member_id, g.customer_member_id,
|
||||
g.use_relays, g.relay_own_status,
|
||||
g.ui_themes, g.summary_current_members_count, g.custom_data, g.chat_item_ttl, g.members_require_attention, g.via_group_link_uri,
|
||||
-- GroupMember - membership
|
||||
mu.group_member_id, mu.group_id, mu.index_in_group, mu.member_id, mu.peer_chat_min_version, mu.peer_chat_max_version, mu.member_role, mu.member_category,
|
||||
mu.member_status, mu.show_messages, mu.member_restriction, mu.is_chat_relay, mu.invited_by, mu.invited_by_group_member_id, mu.local_display_name, mu.contact_id, mu.contact_profile_id, pu.contact_profile_id,
|
||||
mu.member_status, mu.show_messages, mu.member_restriction, mu.invited_by, mu.invited_by_group_member_id, mu.local_display_name, mu.contact_id, mu.contact_profile_id, pu.contact_profile_id,
|
||||
pu.display_name, pu.full_name, pu.short_descr, pu.image, pu.contact_link, pu.chat_peer_type, pu.local_alias, pu.preferences,
|
||||
mu.created_at, mu.updated_at,
|
||||
mu.support_chat_ts, mu.support_chat_items_unread, mu.support_chat_items_member_attention, mu.support_chat_items_mentions, mu.support_chat_last_msg_from_member_ts
|
||||
@@ -4919,15 +5159,16 @@ SEARCH pu USING INTEGER PRIMARY KEY (rowid=?)
|
||||
Query:
|
||||
SELECT
|
||||
-- GroupInfo
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, gp.short_descr, g.local_alias, gp.description, gp.image,
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, gp.short_descr, g.local_alias, gp.description, gp.image, gp.group_link,
|
||||
g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, gp.member_admission,
|
||||
g.created_at, g.updated_at, g.chat_ts, g.user_member_profile_sent_at,
|
||||
g.conn_full_link_to_connect, g.conn_short_link_to_connect, g.conn_link_prepared_connection, g.conn_link_started_connection, g.welcome_shared_msg_id, g.request_shared_msg_id,
|
||||
g.business_chat, g.business_member_id, g.customer_member_id,
|
||||
g.use_relays, g.relay_own_status,
|
||||
g.ui_themes, g.summary_current_members_count, g.custom_data, g.chat_item_ttl, g.members_require_attention, g.via_group_link_uri,
|
||||
-- GroupMember - membership
|
||||
mu.group_member_id, mu.group_id, mu.index_in_group, mu.member_id, mu.peer_chat_min_version, mu.peer_chat_max_version, mu.member_role, mu.member_category,
|
||||
mu.member_status, mu.show_messages, mu.member_restriction, mu.is_chat_relay, mu.invited_by, mu.invited_by_group_member_id, mu.local_display_name, mu.contact_id, mu.contact_profile_id, pu.contact_profile_id,
|
||||
mu.member_status, mu.show_messages, mu.member_restriction, mu.invited_by, mu.invited_by_group_member_id, mu.local_display_name, mu.contact_id, mu.contact_profile_id, pu.contact_profile_id,
|
||||
pu.display_name, pu.full_name, pu.short_descr, pu.image, pu.contact_link, pu.chat_peer_type, pu.local_alias, pu.preferences,
|
||||
mu.created_at, mu.updated_at,
|
||||
mu.support_chat_ts, mu.support_chat_items_unread, mu.support_chat_items_member_attention, mu.support_chat_items_mentions, mu.support_chat_last_msg_from_member_ts
|
||||
@@ -4975,7 +5216,7 @@ SEARCH p USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
SELECT
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction, m.is_chat_relay,
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.chat_peer_type, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts,
|
||||
@@ -5002,7 +5243,7 @@ SEARCH c USING INDEX idx_connections_group_member_id (group_member_id=?) LEFT-JO
|
||||
|
||||
Query:
|
||||
SELECT
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction, m.is_chat_relay,
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.chat_peer_type, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts,
|
||||
@@ -5021,7 +5262,7 @@ SEARCH c USING INDEX idx_connections_group_member_id (group_member_id=?) LEFT-JO
|
||||
|
||||
Query:
|
||||
SELECT
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction, m.is_chat_relay,
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.chat_peer_type, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts,
|
||||
@@ -5040,7 +5281,7 @@ SEARCH c USING INDEX idx_connections_group_member_id (group_member_id=?) LEFT-JO
|
||||
|
||||
Query:
|
||||
SELECT
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction, m.is_chat_relay,
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.chat_peer_type, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts,
|
||||
@@ -5059,7 +5300,7 @@ SEARCH c USING INDEX idx_connections_group_member_id (group_member_id=?) LEFT-JO
|
||||
|
||||
Query:
|
||||
SELECT
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction, m.is_chat_relay,
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.chat_peer_type, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts,
|
||||
@@ -5078,7 +5319,7 @@ SEARCH c USING INDEX idx_connections_group_member_id (group_member_id=?) LEFT-JO
|
||||
|
||||
Query:
|
||||
SELECT
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction, m.is_chat_relay,
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.chat_peer_type, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts,
|
||||
@@ -5097,7 +5338,26 @@ SEARCH c USING INDEX idx_connections_group_member_id (group_member_id=?) LEFT-JO
|
||||
|
||||
Query:
|
||||
SELECT
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction, m.is_chat_relay,
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.chat_peer_type, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts,
|
||||
c.connection_id, c.agent_conn_id, c.conn_level, c.via_contact, c.via_user_contact_link, c.via_group_link, c.group_link_id, c.xcontact_id, c.custom_user_profile_id,
|
||||
c.conn_status, c.conn_type, c.contact_conn_initiated, c.local_alias, c.contact_id, c.group_member_id, c.user_contact_link_id,
|
||||
c.created_at, c.security_code, c.security_code_verified_at, c.pq_support, c.pq_encryption, c.pq_snd_enabled, c.pq_rcv_enabled, c.auth_err_counter, c.quota_err_counter,
|
||||
c.conn_chat_version, c.peer_chat_min_version, c.peer_chat_max_version
|
||||
FROM group_members m
|
||||
JOIN contact_profiles p ON p.contact_profile_id = COALESCE(m.member_profile_id, m.contact_profile_id)
|
||||
LEFT JOIN connections c ON c.group_member_id = m.group_member_id
|
||||
WHERE m.group_id = ? AND m.relay_link = ?
|
||||
Plan:
|
||||
SEARCH m USING INDEX idx_group_members_group_id_index_in_group (group_id=?)
|
||||
SEARCH p USING INTEGER PRIMARY KEY (rowid=?)
|
||||
SEARCH c USING INDEX idx_connections_group_member_id (group_member_id=?) LEFT-JOIN
|
||||
|
||||
Query:
|
||||
SELECT
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.chat_peer_type, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts,
|
||||
@@ -5116,7 +5376,7 @@ SEARCH c USING INDEX idx_connections_group_member_id (group_member_id=?) LEFT-JO
|
||||
|
||||
Query:
|
||||
SELECT
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction, m.is_chat_relay,
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.chat_peer_type, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts,
|
||||
@@ -5135,7 +5395,7 @@ SEARCH c USING INDEX idx_connections_group_member_id (group_member_id=?) LEFT-JO
|
||||
|
||||
Query:
|
||||
SELECT
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction, m.is_chat_relay,
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.chat_peer_type, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts,
|
||||
@@ -5152,6 +5412,25 @@ SEARCH m USING INDEX idx_group_members_group_id (user_id=? AND group_id=?)
|
||||
SEARCH p USING INTEGER PRIMARY KEY (rowid=?)
|
||||
SEARCH c USING INDEX idx_connections_group_member_id (group_member_id=?) LEFT-JOIN
|
||||
|
||||
Query:
|
||||
SELECT
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.chat_peer_type, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts,
|
||||
c.connection_id, c.agent_conn_id, c.conn_level, c.via_contact, c.via_user_contact_link, c.via_group_link, c.group_link_id, c.xcontact_id, c.custom_user_profile_id,
|
||||
c.conn_status, c.conn_type, c.contact_conn_initiated, c.local_alias, c.contact_id, c.group_member_id, c.user_contact_link_id,
|
||||
c.created_at, c.security_code, c.security_code_verified_at, c.pq_support, c.pq_encryption, c.pq_snd_enabled, c.pq_rcv_enabled, c.auth_err_counter, c.quota_err_counter,
|
||||
c.conn_chat_version, c.peer_chat_min_version, c.peer_chat_max_version
|
||||
FROM group_members m
|
||||
JOIN contact_profiles p ON p.contact_profile_id = COALESCE(m.member_profile_id, m.contact_profile_id)
|
||||
LEFT JOIN connections c ON c.group_member_id = m.group_member_id
|
||||
WHERE m.user_id = ? AND m.group_id = ? AND m.contact_id IS DISTINCT FROM ? AND m.member_role = ?
|
||||
Plan:
|
||||
SEARCH m USING INDEX idx_group_members_group_id (user_id=? AND group_id=?)
|
||||
SEARCH p USING INTEGER PRIMARY KEY (rowid=?)
|
||||
SEARCH c USING INDEX idx_connections_group_member_id (group_member_id=?) LEFT-JOIN
|
||||
|
||||
Query:
|
||||
SELECT f.file_id, f.ci_file_status, f.file_path
|
||||
FROM chat_items i
|
||||
@@ -5206,6 +5485,27 @@ Plan:
|
||||
SEARCH i USING COVERING INDEX idx_chat_items_notes_created_at (user_id=? AND note_folder_id=?)
|
||||
SEARCH f USING INDEX idx_files_chat_item_id (chat_item_id=?)
|
||||
|
||||
Query:
|
||||
SELECT group_relay_id, group_member_id, chat_relay_id, relay_status, relay_link
|
||||
FROM group_relays
|
||||
WHERE group_id = ?
|
||||
Plan:
|
||||
SEARCH group_relays USING INDEX idx_group_relays_group_id (group_id=?)
|
||||
|
||||
Query:
|
||||
SELECT group_relay_id, group_member_id, chat_relay_id, relay_status, relay_link
|
||||
FROM group_relays
|
||||
WHERE group_member_id = ?
|
||||
Plan:
|
||||
SEARCH group_relays USING INDEX idx_group_relays_group_member_id (group_member_id=?)
|
||||
|
||||
Query:
|
||||
SELECT group_relay_id, group_member_id, chat_relay_id, relay_status, relay_link
|
||||
FROM group_relays
|
||||
WHERE group_relay_id = ?
|
||||
Plan:
|
||||
SEARCH group_relays USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
SELECT m.group_member_id, m.member_id, m.member_role, p.display_name, p.local_alias
|
||||
FROM group_members m
|
||||
@@ -5379,6 +5679,18 @@ SEARCH u USING INTEGER PRIMARY KEY (rowid=?)
|
||||
SEARCH uct USING INTEGER PRIMARY KEY (rowid=?)
|
||||
SEARCH ucp USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
SELECT u.user_id, u.agent_user_id, u.contact_id, ucp.contact_profile_id, u.active_user, u.active_order, u.local_display_name, ucp.full_name, ucp.short_descr, ucp.image, ucp.contact_link, ucp.chat_peer_type, ucp.preferences,
|
||||
u.show_ntfs, u.send_rcpts_contacts, u.send_rcpts_small_groups, u.auto_accept_member_contacts, u.view_pwd_hash, u.view_pwd_salt, u.user_member_profile_updated_at, u.ui_themes, u.is_user_chat_relay
|
||||
FROM users u
|
||||
JOIN contacts uct ON uct.contact_id = u.contact_id
|
||||
JOIN contact_profiles ucp ON ucp.contact_profile_id = uct.contact_profile_id
|
||||
WHERE u.is_user_chat_relay = 1
|
||||
Plan:
|
||||
SCAN u
|
||||
SEARCH uct USING INTEGER PRIMARY KEY (rowid=?)
|
||||
SEARCH ucp USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
SELECT u.user_id, u.agent_user_id, u.contact_id, ucp.contact_profile_id, u.active_user, u.active_order, u.local_display_name, ucp.full_name, ucp.short_descr, ucp.image, ucp.contact_link, ucp.chat_peer_type, ucp.preferences,
|
||||
u.show_ntfs, u.send_rcpts_contacts, u.send_rcpts_small_groups, u.auto_accept_member_contacts, u.view_pwd_hash, u.view_pwd_salt, u.user_member_profile_updated_at, u.ui_themes, u.is_user_chat_relay
|
||||
@@ -5651,6 +5963,7 @@ SEARCH groups USING COVERING INDEX idx_groups_chat_item_id (chat_item_id=?)
|
||||
Query: DELETE FROM chat_relays WHERE user_id = ? AND chat_relay_id = ? AND preset = ?
|
||||
Plan:
|
||||
SEARCH chat_relays USING INTEGER PRIMARY KEY (rowid=?)
|
||||
SEARCH group_relays USING COVERING INDEX idx_group_relays_chat_relay_id (chat_relay_id=?)
|
||||
|
||||
Query: DELETE FROM commands WHERE user_id = ? AND command_id = ?
|
||||
Plan:
|
||||
@@ -5746,6 +6059,7 @@ SEARCH files USING COVERING INDEX idx_files_redirect_file_id (redirect_file_id=?
|
||||
Query: DELETE FROM group_members WHERE user_id = ? AND group_id = ?
|
||||
Plan:
|
||||
SEARCH group_members USING COVERING INDEX idx_group_members_group_id (user_id=? AND group_id=?)
|
||||
SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?)
|
||||
SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_single_sender_group_member_id (single_sender_group_member_id=?)
|
||||
SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?)
|
||||
SEARCH delivery_tasks USING COVERING INDEX idx_delivery_tasks_sender_group_member_id (sender_group_member_id=?)
|
||||
@@ -5775,6 +6089,7 @@ SEARCH contacts USING COVERING INDEX idx_contacts_contact_group_member_id (conta
|
||||
Query: DELETE FROM group_members WHERE user_id = ? AND group_member_id = ?
|
||||
Plan:
|
||||
SEARCH group_members USING INTEGER PRIMARY KEY (rowid=?)
|
||||
SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?)
|
||||
SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_single_sender_group_member_id (single_sender_group_member_id=?)
|
||||
SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?)
|
||||
SEARCH delivery_tasks USING COVERING INDEX idx_delivery_tasks_sender_group_member_id (sender_group_member_id=?)
|
||||
@@ -5804,6 +6119,7 @@ SEARCH contacts USING COVERING INDEX idx_contacts_contact_group_member_id (conta
|
||||
Query: DELETE FROM groups WHERE user_id = ? AND group_id = ?
|
||||
Plan:
|
||||
SEARCH groups USING INTEGER PRIMARY KEY (rowid=?)
|
||||
SEARCH group_relays USING COVERING INDEX idx_group_relays_group_id (group_id=?)
|
||||
SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_group_id (group_id=?)
|
||||
SEARCH delivery_tasks USING COVERING INDEX idx_delivery_tasks_group_id (group_id=?)
|
||||
SEARCH chat_item_mentions USING COVERING INDEX idx_chat_item_mentions_group_id (group_id=?)
|
||||
@@ -6091,6 +6407,18 @@ SCAN CONSTANT ROW
|
||||
SCALAR SUBQUERY 1
|
||||
SEARCH chat_items USING COVERING INDEX idx_chat_items_contacts_created_at (user_id=? AND contact_id=?)
|
||||
|
||||
Query: SELECT EXISTS (SELECT 1 FROM group_members WHERE group_id = ? AND member_id = ?)
|
||||
Plan:
|
||||
SCAN CONSTANT ROW
|
||||
SCALAR SUBQUERY 1
|
||||
SEARCH group_members USING COVERING INDEX sqlite_autoindex_group_members_1 (group_id=? AND member_id=?)
|
||||
|
||||
Query: SELECT EXISTS (SELECT 1 FROM group_relays WHERE chat_relay_id = ?)
|
||||
Plan:
|
||||
SCAN CONSTANT ROW
|
||||
SCALAR SUBQUERY 1
|
||||
SEARCH group_relays USING COVERING INDEX idx_group_relays_chat_relay_id (chat_relay_id=?)
|
||||
|
||||
Query: SELECT accepted_at FROM operator_usage_conditions WHERE server_operator_id = ? AND conditions_commit = ?
|
||||
Plan:
|
||||
SEARCH operator_usage_conditions USING INDEX idx_operator_usage_conditions_conditions_commit (conditions_commit=? AND server_operator_id=?)
|
||||
@@ -6223,6 +6551,10 @@ Query: SELECT group_id FROM groups WHERE user_id = ? AND chat_item_ttl > 0 OR ch
|
||||
Plan:
|
||||
SCAN groups
|
||||
|
||||
Query: SELECT group_id FROM groups WHERE user_id = ? AND creating_in_progress = 1 AND created_at <= ?
|
||||
Plan:
|
||||
SEARCH groups USING INDEX idx_groups_chat_ts (user_id=?)
|
||||
|
||||
Query: SELECT group_id FROM groups WHERE user_id = ? AND local_display_name = ?
|
||||
Plan:
|
||||
SEARCH groups USING COVERING INDEX sqlite_autoindex_groups_1 (user_id=? AND local_display_name=?)
|
||||
@@ -6283,6 +6615,14 @@ Query: SELECT quota_err_counter FROM connections WHERE user_id = ? AND connectio
|
||||
Plan:
|
||||
SEARCH connections USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query: SELECT relay_own_status FROM groups WHERE group_id = ?
|
||||
Plan:
|
||||
SEARCH groups USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query: SELECT relay_status FROM group_relays WHERE group_relay_id = ?
|
||||
Plan:
|
||||
SEARCH group_relays USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query: SELECT sent_inv_queue_info FROM group_members WHERE group_member_id = ? AND user_id = ?
|
||||
Plan:
|
||||
SEARCH group_members USING INTEGER PRIMARY KEY (rowid=?)
|
||||
@@ -6435,6 +6775,10 @@ Query: UPDATE contacts SET xcontact_id = ? WHERE contact_id = ?
|
||||
Plan:
|
||||
SEARCH contacts USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query: UPDATE delivery_jobs SET cursor_group_member_id = ?, updated_at = ? WHERE delivery_job_id = ?
|
||||
Plan:
|
||||
SEARCH delivery_jobs USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query: UPDATE delivery_jobs SET job_status = ?, job_err_reason = ?, updated_at = ? WHERE delivery_job_id = ?
|
||||
Plan:
|
||||
SEARCH delivery_jobs USING INTEGER PRIMARY KEY (rowid=?)
|
||||
@@ -6519,6 +6863,10 @@ Query: UPDATE group_members SET xgrplinkmem_received = ?, updated_at = ? WHERE g
|
||||
Plan:
|
||||
SEARCH group_members USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query: UPDATE group_relays SET relay_status = ?, updated_at = ? WHERE group_relay_id = ?
|
||||
Plan:
|
||||
SEARCH group_relays USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query: UPDATE groups SET business_member_id = ?, customer_member_id = ? WHERE group_id = ?
|
||||
Plan:
|
||||
SEARCH groups USING INTEGER PRIMARY KEY (rowid=?)
|
||||
@@ -6539,6 +6887,10 @@ Query: UPDATE groups SET conn_link_started_connection = ?, updated_at = ? WHERE
|
||||
Plan:
|
||||
SEARCH groups USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query: UPDATE groups SET creating_in_progress = 0, updated_at = ? WHERE group_id = ?
|
||||
Plan:
|
||||
SEARCH groups USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query: UPDATE groups SET enable_ntfs = ?, send_rcpts = ?, favorite = ? WHERE user_id = ? AND group_id = ?
|
||||
Plan:
|
||||
SEARCH groups USING INTEGER PRIMARY KEY (rowid=?)
|
||||
@@ -6555,6 +6907,10 @@ Query: UPDATE groups SET members_require_attention=1 WHERE group_id=?
|
||||
Plan:
|
||||
SEARCH groups USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query: UPDATE groups SET relay_own_status = ?, updated_at = ? WHERE group_id = ?
|
||||
Plan:
|
||||
SEARCH groups USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query: UPDATE groups SET request_shared_msg_id = ? WHERE group_id = ?
|
||||
Plan:
|
||||
SEARCH groups USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
@@ -122,7 +122,8 @@ CREATE TABLE group_profiles(
|
||||
preferences TEXT,
|
||||
description TEXT NULL,
|
||||
member_admission TEXT,
|
||||
short_descr TEXT
|
||||
short_descr TEXT,
|
||||
group_link BLOB
|
||||
) STRICT;
|
||||
CREATE TABLE groups(
|
||||
group_id INTEGER PRIMARY KEY, -- local group ID
|
||||
@@ -157,7 +158,16 @@ CREATE TABLE groups(
|
||||
conn_link_prepared_connection INTEGER NOT NULL DEFAULT 0,
|
||||
via_group_link_uri BLOB,
|
||||
summary_current_members_count INTEGER NOT NULL DEFAULT 0,
|
||||
member_index INTEGER NOT NULL DEFAULT 0, -- received
|
||||
member_index INTEGER NOT NULL DEFAULT 0,
|
||||
use_relays INTEGER NOT NULL DEFAULT 0,
|
||||
creating_in_progress INTEGER NOT NULL DEFAULT 0,
|
||||
relay_own_status TEXT,
|
||||
relay_request_inv_id BLOB,
|
||||
relay_request_group_link BLOB,
|
||||
relay_request_peer_chat_min_version INTEGER,
|
||||
relay_request_peer_chat_max_version INTEGER,
|
||||
relay_request_failed INTEGER DEFAULT 0,
|
||||
relay_request_err_reason TEXT, -- received
|
||||
FOREIGN KEY(user_id, local_display_name)
|
||||
REFERENCES display_names(user_id, local_display_name)
|
||||
ON DELETE CASCADE
|
||||
@@ -199,7 +209,7 @@ CREATE TABLE group_members(
|
||||
member_welcome_shared_msg_id BLOB,
|
||||
index_in_group INTEGER NOT NULL DEFAULT 0,
|
||||
member_relations_vector BLOB,
|
||||
is_chat_relay INTEGER NOT NULL DEFAULT 0,
|
||||
relay_link BLOB,
|
||||
FOREIGN KEY(user_id, local_display_name)
|
||||
REFERENCES display_names(user_id, local_display_name)
|
||||
ON DELETE CASCADE
|
||||
@@ -727,18 +737,27 @@ CREATE TABLE connections_sync(
|
||||
) STRICT;
|
||||
CREATE TABLE chat_relays(
|
||||
chat_relay_id INTEGER PRIMARY KEY,
|
||||
address TEXT NOT NULL,
|
||||
address BLOB NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
domains TEXT NOT NULL,
|
||||
preset INTEGER NOT NULL DEFAULT 0,
|
||||
tested INTEGER,
|
||||
enabled INTEGER NOT NULL DEFAULT 1,
|
||||
user_id INTEGER NOT NULL REFERENCES users ON DELETE CASCADE,
|
||||
deleted INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TEXT NOT NULL DEFAULT(datetime('now')),
|
||||
updated_at TEXT NOT NULL DEFAULT(datetime('now')),
|
||||
UNIQUE(user_id, address),
|
||||
UNIQUE(user_id, name)
|
||||
);
|
||||
updated_at TEXT NOT NULL DEFAULT(datetime('now'))
|
||||
) STRICT;
|
||||
CREATE TABLE group_relays(
|
||||
group_relay_id INTEGER PRIMARY KEY,
|
||||
group_id INTEGER NOT NULL REFERENCES groups ON DELETE CASCADE,
|
||||
group_member_id INTEGER NOT NULL REFERENCES group_members ON DELETE CASCADE,
|
||||
chat_relay_id INTEGER NOT NULL REFERENCES chat_relays ON DELETE CASCADE,
|
||||
relay_status TEXT NOT NULL,
|
||||
relay_link BLOB,
|
||||
created_at TEXT NOT NULL DEFAULT(datetime('now')),
|
||||
updated_at TEXT NOT NULL DEFAULT(datetime('now'))
|
||||
) STRICT;
|
||||
CREATE INDEX contact_profiles_index ON contact_profiles(
|
||||
display_name,
|
||||
full_name
|
||||
@@ -1216,6 +1235,16 @@ CREATE INDEX idx_chat_items_note_folder_msg_content_tag_created_at ON chat_items
|
||||
created_at
|
||||
);
|
||||
CREATE INDEX idx_chat_relays_user_id ON chat_relays(user_id);
|
||||
CREATE UNIQUE INDEX idx_chat_relays_user_id_address ON chat_relays(
|
||||
user_id,
|
||||
address
|
||||
);
|
||||
CREATE UNIQUE INDEX idx_chat_relays_user_id_name ON chat_relays(user_id, name);
|
||||
CREATE INDEX idx_group_relays_group_id ON group_relays(group_id);
|
||||
CREATE UNIQUE INDEX idx_group_relays_group_member_id ON group_relays(
|
||||
group_member_id
|
||||
);
|
||||
CREATE INDEX idx_group_relays_chat_relay_id ON group_relays(chat_relay_id);
|
||||
CREATE TRIGGER on_group_members_insert_update_summary
|
||||
AFTER INSERT ON group_members
|
||||
FOR EACH ROW
|
||||
|
||||
@@ -75,6 +75,7 @@ data ChatLockEntity
|
||||
data StoreError
|
||||
= SEDuplicateName
|
||||
| SEUserNotFound {userId :: UserId}
|
||||
| SERelayUserNotFound
|
||||
| SEUserNotFoundByName {contactName :: ContactName}
|
||||
| SEUserNotFoundByContactId {contactId :: ContactId}
|
||||
| SEUserNotFoundByGroupId {groupId :: GroupId}
|
||||
@@ -102,6 +103,7 @@ data StoreError
|
||||
| SEInvalidMemberRelationUpdate
|
||||
| SEGroupWithoutUser
|
||||
| SEDuplicateGroupMember
|
||||
| SEDuplicateMemberId
|
||||
| SEGroupAlreadyJoined
|
||||
| SEGroupInvitationNotFound
|
||||
| SENoteFolderAlreadyExists {noteFolderId :: NoteFolderId}
|
||||
@@ -150,6 +152,9 @@ data StoreError
|
||||
| SEProhibitedDeleteUser {userId :: UserId, contactId :: ContactId}
|
||||
| SEOperatorNotFound {serverOperatorId :: Int64}
|
||||
| SEUsageConditionsNotFound
|
||||
| SEUserChatRelayNotFound {chatRelayId :: Int64}
|
||||
| SEGroupRelayNotFound {groupRelayId :: Int64}
|
||||
| SEGroupRelayNotFoundByMemberId {groupMemberId :: GroupMemberId}
|
||||
| SEInvalidQuote
|
||||
| SEInvalidMention
|
||||
| SEInvalidDeliveryTask {taskId :: Int64}
|
||||
@@ -657,22 +662,22 @@ type PreparedGroupRow = (Maybe ConnReqContact, Maybe ShortLinkContact, BoolInt,
|
||||
|
||||
type BusinessChatInfoRow = (Maybe BusinessChatType, Maybe MemberId, Maybe MemberId)
|
||||
|
||||
type GroupInfoRow = (Int64, GroupName, GroupName, Text, Maybe Text, Text, Maybe Text, Maybe ImageData) :. (Maybe MsgFilter, Maybe BoolInt, BoolInt, Maybe GroupPreferences, Maybe GroupMemberAdmission) :. (UTCTime, UTCTime, Maybe UTCTime, Maybe UTCTime) :. PreparedGroupRow :. BusinessChatInfoRow :. (Maybe UIThemeEntityOverrides, Int64, Maybe CustomData, Maybe Int64, Int, Maybe ConnReqContact) :. GroupMemberRow
|
||||
type GroupInfoRow = (Int64, GroupName, GroupName, Text, Maybe Text, Text, Maybe Text, Maybe ImageData, Maybe ShortLinkContact) :. (Maybe MsgFilter, Maybe BoolInt, BoolInt, Maybe GroupPreferences, Maybe GroupMemberAdmission) :. (UTCTime, UTCTime, Maybe UTCTime, Maybe UTCTime) :. PreparedGroupRow :. BusinessChatInfoRow :. (BoolInt, Maybe RelayStatus, Maybe UIThemeEntityOverrides, Int64, Maybe CustomData, Maybe Int64, Int, Maybe ConnReqContact) :. GroupMemberRow
|
||||
|
||||
type GroupMemberRow = (GroupMemberId, GroupId, Int64, MemberId, VersionChat, VersionChat, GroupMemberRole, GroupMemberCategory, GroupMemberStatus, BoolInt, Maybe MemberRestrictionStatus, BoolInt) :. (Maybe Int64, Maybe GroupMemberId, ContactName, Maybe ContactId, ProfileId) :. ProfileRow :. (UTCTime, UTCTime) :. (Maybe UTCTime, Int64, Int64, Int64, Maybe UTCTime)
|
||||
type GroupMemberRow = (GroupMemberId, GroupId, Int64, MemberId, VersionChat, VersionChat, GroupMemberRole, GroupMemberCategory, GroupMemberStatus, BoolInt, Maybe MemberRestrictionStatus) :. (Maybe Int64, Maybe GroupMemberId, ContactName, Maybe ContactId, ProfileId) :. ProfileRow :. (UTCTime, UTCTime) :. (Maybe UTCTime, Int64, Int64, Int64, Maybe UTCTime)
|
||||
|
||||
type ProfileRow = (ProfileId, ContactName, Text, Maybe Text, Maybe ImageData, Maybe ConnLinkContact, Maybe ChatPeerType, LocalAlias, Maybe Preferences)
|
||||
|
||||
toGroupInfo :: VersionRangeChat -> Int64 -> [ChatTagId] -> GroupInfoRow -> GroupInfo
|
||||
toGroupInfo vr userContactId chatTags ((groupId, localDisplayName, displayName, fullName, shortDescr, localAlias, description, image) :. (enableNtfs_, sendRcpts, BI favorite, groupPreferences, memberAdmission) :. (createdAt, updatedAt, chatTs, userMemberProfileSentAt) :. preparedGroupRow :. businessRow :. (uiThemes, currentMembers, customData, chatItemTTL, membersRequireAttention, viaGroupLinkUri) :. userMemberRow) =
|
||||
toGroupInfo vr userContactId chatTags ((groupId, localDisplayName, displayName, fullName, shortDescr, localAlias, description, image, groupLink) :. (enableNtfs_, sendRcpts, BI favorite, groupPreferences, memberAdmission) :. (createdAt, updatedAt, chatTs, userMemberProfileSentAt) :. preparedGroupRow :. businessRow :. (BI useRelays, relayOwnStatus, uiThemes, currentMembers, customData, chatItemTTL, membersRequireAttention, viaGroupLinkUri) :. userMemberRow) =
|
||||
let membership = (toGroupMember userContactId userMemberRow) {memberChatVRange = vr}
|
||||
chatSettings = ChatSettings {enableNtfs = fromMaybe MFAll enableNtfs_, sendRcpts = unBI <$> sendRcpts, favorite}
|
||||
fullGroupPreferences = mergeGroupPreferences groupPreferences
|
||||
groupProfile = GroupProfile {displayName, fullName, shortDescr, description, image, groupPreferences, memberAdmission}
|
||||
groupProfile = GroupProfile {displayName, fullName, shortDescr, description, image, groupPreferences, memberAdmission, groupLink}
|
||||
businessChat = toBusinessChatInfo businessRow
|
||||
preparedGroup = toPreparedGroup preparedGroupRow
|
||||
groupSummary = GroupSummary {currentMembers}
|
||||
in GroupInfo {groupId, useRelays = BoolDef False, localDisplayName, groupProfile, localAlias, businessChat, fullGroupPreferences, membership, chatSettings, createdAt, updatedAt, chatTs, userMemberProfileSentAt, preparedGroup, chatTags, chatItemTTL, uiThemes, groupSummary, customData, membersRequireAttention, viaGroupLinkUri}
|
||||
in GroupInfo {groupId, useRelays = BoolDef useRelays, relayOwnStatus, localDisplayName, groupProfile, localAlias, businessChat, fullGroupPreferences, membership, chatSettings, createdAt, updatedAt, chatTs, userMemberProfileSentAt, preparedGroup, chatTags, chatItemTTL, uiThemes, groupSummary, customData, membersRequireAttention, viaGroupLinkUri}
|
||||
|
||||
toPreparedGroup :: PreparedGroupRow -> Maybe PreparedGroup
|
||||
toPreparedGroup = \case
|
||||
@@ -681,14 +686,13 @@ toPreparedGroup = \case
|
||||
_ -> Nothing
|
||||
|
||||
toGroupMember :: Int64 -> GroupMemberRow -> GroupMember
|
||||
toGroupMember userContactId ((groupMemberId, groupId, indexInGroup, memberId, minVer, maxVer, memberRole, memberCategory, memberStatus, BI showMessages, memberRestriction_, BI isCRelay) :. (invitedById, invitedByGroupMemberId, localDisplayName, memberContactId, memberContactProfileId) :. profileRow :. (createdAt, updatedAt) :. (supportChatTs_, supportChatUnread, supportChatMemberAttention, supportChatMentions, supportChatLastMsgFromMemberTs)) =
|
||||
toGroupMember userContactId ((groupMemberId, groupId, indexInGroup, memberId, minVer, maxVer, memberRole, memberCategory, memberStatus, BI showMessages, memberRestriction_) :. (invitedById, invitedByGroupMemberId, localDisplayName, memberContactId, memberContactProfileId) :. profileRow :. (createdAt, updatedAt) :. (supportChatTs_, supportChatUnread, supportChatMemberAttention, supportChatMentions, supportChatLastMsgFromMemberTs)) =
|
||||
let memberProfile = rowToLocalProfile profileRow
|
||||
memberSettings = GroupMemberSettings {showMessages}
|
||||
blockedByAdmin = maybe False mrsBlocked memberRestriction_
|
||||
invitedBy = toInvitedBy userContactId invitedById
|
||||
activeConn = Nothing
|
||||
memberChatVRange = fromMaybe (versionToRange maxVer) $ safeVersionRange minVer maxVer
|
||||
isChatRelay = BoolDef isCRelay
|
||||
supportChat = case supportChatTs_ of
|
||||
Just chatTs ->
|
||||
Just
|
||||
@@ -706,7 +710,7 @@ groupMemberQuery :: Query
|
||||
groupMemberQuery =
|
||||
[sql|
|
||||
SELECT
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction, m.is_chat_relay,
|
||||
m.group_member_id, m.group_id, m.index_in_group, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.chat_peer_type, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts,
|
||||
@@ -739,15 +743,16 @@ groupInfoQueryFields =
|
||||
[sql|
|
||||
SELECT
|
||||
-- GroupInfo
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, gp.short_descr, g.local_alias, gp.description, gp.image,
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, gp.short_descr, g.local_alias, gp.description, gp.image, gp.group_link,
|
||||
g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, gp.member_admission,
|
||||
g.created_at, g.updated_at, g.chat_ts, g.user_member_profile_sent_at,
|
||||
g.conn_full_link_to_connect, g.conn_short_link_to_connect, g.conn_link_prepared_connection, g.conn_link_started_connection, g.welcome_shared_msg_id, g.request_shared_msg_id,
|
||||
g.business_chat, g.business_member_id, g.customer_member_id,
|
||||
g.use_relays, g.relay_own_status,
|
||||
g.ui_themes, g.summary_current_members_count, g.custom_data, g.chat_item_ttl, g.members_require_attention, g.via_group_link_uri,
|
||||
-- GroupMember - membership
|
||||
mu.group_member_id, mu.group_id, mu.index_in_group, mu.member_id, mu.peer_chat_min_version, mu.peer_chat_max_version, mu.member_role, mu.member_category,
|
||||
mu.member_status, mu.show_messages, mu.member_restriction, mu.is_chat_relay, mu.invited_by, mu.invited_by_group_member_id, mu.local_display_name, mu.contact_id, mu.contact_profile_id, pu.contact_profile_id,
|
||||
mu.member_status, mu.show_messages, mu.member_restriction, mu.invited_by, mu.invited_by_group_member_id, mu.local_display_name, mu.contact_id, mu.contact_profile_id, pu.contact_profile_id,
|
||||
pu.display_name, pu.full_name, pu.short_descr, pu.image, pu.contact_link, pu.chat_peer_type, pu.local_alias, pu.preferences,
|
||||
mu.created_at, mu.updated_at,
|
||||
mu.support_chat_ts, mu.support_chat_items_unread, mu.support_chat_items_member_attention, mu.support_chat_items_mentions, mu.support_chat_last_msg_from_member_ts
|
||||
@@ -835,6 +840,37 @@ addGroupChatTags db g@GroupInfo {groupId} = do
|
||||
chatTags <- getGroupChatTags db groupId
|
||||
pure (g :: GroupInfo) {chatTags}
|
||||
|
||||
getGroupInfo :: DB.Connection -> VersionRangeChat -> User -> Int64 -> ExceptT StoreError IO GroupInfo
|
||||
getGroupInfo db vr User {userId, userContactId} groupId = ExceptT $ do
|
||||
chatTags <- getGroupChatTags db groupId
|
||||
firstRow (toGroupInfo vr userContactId chatTags) (SEGroupNotFound groupId) $
|
||||
DB.query
|
||||
db
|
||||
(groupInfoQuery <> " WHERE g.group_id = ? AND g.user_id = ? AND mu.contact_id = ?")
|
||||
(groupId, userId, userContactId)
|
||||
|
||||
-- Set group link info and optionally incognito profile before connecting to relays.
|
||||
-- This is called once before connecting to relays, unlike createConnReqConnection -> setPreparedGroupLinkInfo_,
|
||||
-- which is used in single-connection flows.
|
||||
setPreparedGroupLinkInfo :: DB.Connection -> VersionRangeChat -> User -> GroupInfo -> ConnReqContact -> ConnReqUriHash -> Maybe Profile -> ExceptT StoreError IO GroupInfo
|
||||
setPreparedGroupLinkInfo db vr user@User {userId} gInfo@GroupInfo {groupId} cReq cReqHash incognitoProfile = do
|
||||
currentTs <- liftIO getCurrentTime
|
||||
customUserProfileId <- liftIO $ mapM (createIncognitoProfile_ db userId currentTs) incognitoProfile
|
||||
liftIO $ setPreparedGroupLinkInfo_ db gInfo cReq cReqHash customUserProfileId currentTs
|
||||
getGroupInfo db vr user groupId
|
||||
|
||||
setPreparedGroupLinkInfo_ :: DB.Connection -> GroupInfo -> ConnReqContact -> ConnReqUriHash -> Maybe Int64 -> UTCTime -> IO ()
|
||||
setPreparedGroupLinkInfo_ db GroupInfo {groupId, membership} cReq cReqHash customUserProfileId currentTs = do
|
||||
DB.execute
|
||||
db
|
||||
"UPDATE groups SET via_group_link_uri = ?, via_group_link_uri_hash = ?, conn_link_prepared_connection = ?, updated_at = ? WHERE group_id = ?"
|
||||
(cReq, cReqHash, BI True, currentTs, groupId)
|
||||
when (isJust customUserProfileId) $
|
||||
DB.execute
|
||||
db
|
||||
"UPDATE group_members SET member_profile_id = ?, updated_at = ? WHERE group_member_id = ?"
|
||||
(customUserProfileId, currentTs, groupMemberId' membership)
|
||||
|
||||
setViaGroupLinkUri :: DB.Connection -> GroupId -> Int64 -> IO ()
|
||||
setViaGroupLinkUri db groupId connId = do
|
||||
r <-
|
||||
|
||||
Reference in new issue
Block a user