mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-04-27 19:26:12 +00:00
wip
This commit is contained in:
@@ -2344,6 +2344,7 @@ Known:
|
||||
|
||||
**Record type**:
|
||||
- groupRelayId: int64
|
||||
- userChatRelayId: int64
|
||||
- relayStatus: [RelayStatus](#relaystatus)
|
||||
- relayLink: string?
|
||||
|
||||
@@ -3588,6 +3589,14 @@ OperatorNotFound:
|
||||
UsageConditionsNotFound:
|
||||
- type: "usageConditionsNotFound"
|
||||
|
||||
UserChatRelayNotFound:
|
||||
- type: "userChatRelayNotFound"
|
||||
- chatRelayId: int64
|
||||
|
||||
GroupRelayNotFound:
|
||||
- type: "groupRelayNotFound"
|
||||
- groupRelayId: int64
|
||||
|
||||
InvalidQuote:
|
||||
- type: "invalidQuote"
|
||||
|
||||
|
||||
@@ -2594,6 +2594,7 @@ export interface GroupProfile {
|
||||
|
||||
export interface GroupRelay {
|
||||
groupRelayId: number // int64
|
||||
userChatRelayId: number // int64
|
||||
relayStatus: RelayStatus
|
||||
relayLink?: string
|
||||
}
|
||||
@@ -3812,6 +3813,8 @@ export type StoreError =
|
||||
| StoreError.ProhibitedDeleteUser
|
||||
| StoreError.OperatorNotFound
|
||||
| StoreError.UsageConditionsNotFound
|
||||
| StoreError.UserChatRelayNotFound
|
||||
| StoreError.GroupRelayNotFound
|
||||
| StoreError.InvalidQuote
|
||||
| StoreError.InvalidMention
|
||||
| StoreError.InvalidDeliveryTask
|
||||
@@ -3897,6 +3900,8 @@ export namespace StoreError {
|
||||
| "prohibitedDeleteUser"
|
||||
| "operatorNotFound"
|
||||
| "usageConditionsNotFound"
|
||||
| "userChatRelayNotFound"
|
||||
| "groupRelayNotFound"
|
||||
| "invalidQuote"
|
||||
| "invalidMention"
|
||||
| "invalidDeliveryTask"
|
||||
@@ -4274,6 +4279,16 @@ export namespace StoreError {
|
||||
type: "usageConditionsNotFound"
|
||||
}
|
||||
|
||||
export interface UserChatRelayNotFound extends Interface {
|
||||
type: "userChatRelayNotFound"
|
||||
chatRelayId: number // int64
|
||||
}
|
||||
|
||||
export interface GroupRelayNotFound extends Interface {
|
||||
type: "groupRelayNotFound"
|
||||
groupRelayId: number // int64
|
||||
}
|
||||
|
||||
export interface InvalidQuote extends Interface {
|
||||
type: "invalidQuote"
|
||||
}
|
||||
|
||||
@@ -2690,7 +2690,7 @@ processChatCommand vr nm = \case
|
||||
-- TODO - prepare group link (without creating on server)
|
||||
-- TODO - add link, owner key to group profile, sign
|
||||
-- TODO - create group link on server, use signed profile as data
|
||||
-- vvv
|
||||
-- vvv FROM HERE vvv
|
||||
(connId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a nm (aUserId user) True True SCMContact (Just userData) (Just crClientData) IKPQOff subMode
|
||||
ccLink' <- createdGroupLink <$> shortenCreatedLink ccLink
|
||||
sLnk <- case toShortLinkContact ccLink' of
|
||||
@@ -2700,7 +2700,7 @@ processChatCommand vr nm = \case
|
||||
userData' = encodeShortLinkData $ GroupShortLinkData groupProfile'
|
||||
-- same link with updated profile
|
||||
_sLnk' <- shortenShortLink' . toShortGroupLink =<< withAgent (\a -> setConnShortLink a nm connId SCMContact userData' (Just crClientData))
|
||||
-- ^^^
|
||||
-- ^^^ TO HERE ^^^
|
||||
gVar <- asks random
|
||||
(gLink, gInfo') <- withFastStore $ \db -> do
|
||||
gLink <- createGroupLink db gVar user gInfo connId ccLink' groupLinkId GRMember subMode
|
||||
@@ -2709,7 +2709,7 @@ processChatCommand vr nm = \case
|
||||
if autoChooseRelays
|
||||
then do
|
||||
relays <- chooseRelays user
|
||||
groupRelays <- addRelays user gInfo' relays
|
||||
groupRelays <- addRelays user gInfo' sLnk relays
|
||||
pure $ CRGroupRelaysAdded user gInfo' gLink groupRelays
|
||||
else
|
||||
pure $ CRGroupLinkCreated user gInfo' gLink
|
||||
@@ -2722,12 +2722,15 @@ processChatCommand vr nm = \case
|
||||
when (null selectedRelays) $ throwChatError $ CEException "failed to select relays: no enabled relays configured"
|
||||
pure selectedRelays
|
||||
APIAddRelays groupId relayIds -> withUser $ \user -> withGroupLock "addRelays" groupId $ do
|
||||
(gInfo, gLink) <- withFastStore $ \db -> do
|
||||
(gInfo, gLink@GroupLink {connLinkContact}) <- withFastStore $ \db -> do
|
||||
gInfo <- getGroupInfo db vr user groupId
|
||||
gLink <- getGroupLink db user gInfo
|
||||
pure (gInfo, gLink)
|
||||
sLnk <- case toShortLinkContact connLinkContact of
|
||||
Just sl -> pure sl
|
||||
Nothing -> throwChatError $ CEException "failed to add relays: no short link in group link"
|
||||
relays <- withFastStore $ \db -> mapM (getChatRelayById db user) (L.toList relayIds)
|
||||
groupRelays <- addRelays user gInfo relays
|
||||
groupRelays <- addRelays user gInfo sLnk relays
|
||||
pure $ CRGroupRelaysAdded user gInfo gLink groupRelays
|
||||
APIGroupLinkMemberRole groupId mRole' -> withUser $ \user -> withGroupLock "groupLinkMemberRole" groupId $ do
|
||||
gInfo <- withFastStore $ \db -> getGroupInfo db vr user groupId
|
||||
@@ -3571,13 +3574,45 @@ processChatCommand vr nm = \case
|
||||
toView $ CEvtNewChatItems user [AChatItem SCTDirect SMDSnd (DirectChat ct) ci]
|
||||
forM_ (timed_ >>= timedDeleteAt') $
|
||||
startProximateTimedItemThread user (ChatRef CTDirect contactId Nothing, chatItemId' ci)
|
||||
addRelays :: User -> GroupInfo -> [UserChatRelay] -> CM [GroupRelay]
|
||||
addRelays _user _gInfo _relays = do
|
||||
-- TODO [relays] owner: send contact requests to relays
|
||||
-- TODO - create relay member connections, relay records (group_relays), relay status: RSNew
|
||||
-- TODO - send requests to relays: INV message - XGrpRelayInv, relay status: RSInvited
|
||||
-- TODO - agent joinConnectionAsync for contact links (currently prohibited)
|
||||
pure []
|
||||
addRelays :: User -> GroupInfo -> ShortLinkContact -> [UserChatRelay] -> CM [GroupRelay]
|
||||
addRelays user gInfo@GroupInfo {membership} groupSLink relays =
|
||||
forM relays $ \relay -> addRelay relay
|
||||
where
|
||||
addRelay :: UserChatRelay -> CM GroupRelay
|
||||
addRelay relay@UserChatRelay {address} = do
|
||||
-- TODO [relays] owner: can update relay profile from data retrieved via getConnShortLink
|
||||
(cReq, _cData) <- withAgent $ \a -> getConnShortLink a nm (aUserId user) address
|
||||
lift (withAgent' $ \a -> connRequestPQSupport a PQSupportOff cReq) >>= \case
|
||||
Nothing -> throwChatError CEInvalidConnReq
|
||||
Just (agentV, _) -> do
|
||||
let chatV = agentToChatVersion agentV
|
||||
gVar <- asks random
|
||||
subMode <- chatReadVar subscriptionMode
|
||||
-- TODO [relays] owner: replace with async join (joinConnectionAsync currently prohibited for contact links)
|
||||
-- TODO - or make "add relays" api retriable, via prepared connection
|
||||
connId <- withAgent $ \a -> prepareConnectionToJoin a (aUserId user) True cReq PQSupportOff
|
||||
(relayMember, conn, groupRelay) <- withStore $ \db -> do
|
||||
groupRelay <- createGroupRelayRecord db gInfo relay
|
||||
relayMember <- createRelayMemberRecord db vr gVar user gInfo relay groupRelay
|
||||
conn <- createRelayConnection db vr user (groupMemberId' relayMember) connId ConnPrepared chatV subMode
|
||||
pure (relayMember, conn, groupRelay)
|
||||
let GroupMember {memberRole = userRole, memberId = userMemberId} = membership
|
||||
allowSimplexLinks = groupFeatureUserAllowed SGFSimplexLinks gInfo
|
||||
membershipProfile = redactedMemberProfile allowSimplexLinks $ fromLocalProfile $ memberProfile membership
|
||||
GroupMember {memberRole = relayRole, memberId = relayMemberId} = relayMember
|
||||
relayInv = GroupRelayInvitation {
|
||||
fromMember = MemberIdRole userMemberId userRole,
|
||||
fromMemberProfile = membershipProfile,
|
||||
invitedMember = MemberIdRole relayMemberId relayRole,
|
||||
groupLink = groupSLink
|
||||
}
|
||||
dm <- encodeConnInfo $ XGrpRelayInv relayInv
|
||||
(sqSecured, _serviceId) <- withAgent $ \a -> joinConnection a nm (aUserId user) (aConnId conn) True cReq dm PQSupportOff subMode
|
||||
let newConnStatus = if sqSecured then ConnSndReady else ConnJoined
|
||||
groupRelay' <- withFastStore' $ \db -> do
|
||||
void $ updateConnectionStatusFromTo db conn ConnPrepared newConnStatus
|
||||
updateRelayStatusFromTo db groupRelay RSNew RSInvited
|
||||
pure groupRelay'
|
||||
drgRandomBytes :: Int -> CM ByteString
|
||||
drgRandomBytes n = asks random >>= atomically . C.randomBytes n
|
||||
privateGetUser :: UserId -> CM User
|
||||
|
||||
@@ -1150,7 +1150,7 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage =
|
||||
case chatMsgEvent of
|
||||
XContact p xContactId_ welcomeMsgId_ requestMsg_ -> profileContactRequest invId chatVRange p xContactId_ welcomeMsgId_ requestMsg_ pqSupport
|
||||
XInfo p -> profileContactRequest invId chatVRange p Nothing Nothing Nothing pqSupport
|
||||
XGrpRelayInv groupLink -> relayContactRequest groupLink
|
||||
XGrpRelayInv groupRelayInv -> relayContactRequest groupRelayInv
|
||||
-- TODO show/log error, other events in contact request
|
||||
_ -> pure ()
|
||||
MERR _ err -> do
|
||||
@@ -1319,8 +1319,8 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage =
|
||||
| otherwise -> do
|
||||
mem <- acceptGroupJoinSendRejectAsync user uclId gInfo invId chatVRange p xContactId_ rjctReason
|
||||
toViewTE $ TERejectingGroupJoinRequestMember user gInfo mem rjctReason
|
||||
relayContactRequest :: ShortLinkContact -> CM ()
|
||||
relayContactRequest _groupLink = do
|
||||
relayContactRequest :: GroupRelayInvitation -> CM ()
|
||||
relayContactRequest _groupRelayInv = do
|
||||
-- TODO [relays] relay: process contact request to server group
|
||||
-- TODO - retrieve group link data, validate group profile, verify owner's signature
|
||||
-- TODO - create group record, relay status: RSInvited
|
||||
|
||||
@@ -328,7 +328,7 @@ data ChatMsgEvent (e :: MsgEncoding) where
|
||||
XGrpLinkReject :: GroupLinkRejection -> ChatMsgEvent 'Json
|
||||
XGrpLinkMem :: Profile -> ChatMsgEvent 'Json
|
||||
XGrpLinkAcpt :: GroupAcceptance -> GroupMemberRole -> MemberId -> ChatMsgEvent 'Json
|
||||
XGrpRelayInv :: ShortLinkContact -> ChatMsgEvent 'Json
|
||||
XGrpRelayInv :: GroupRelayInvitation -> ChatMsgEvent 'Json
|
||||
XGrpRelayAcpt :: ShortLinkContact -> ChatMsgEvent 'Json
|
||||
XGrpMemNew :: MemberInfo -> Maybe MsgScope -> ChatMsgEvent 'Json
|
||||
XGrpMemIntro :: MemberInfo -> Maybe MemberRestrictions -> ChatMsgEvent 'Json
|
||||
@@ -1100,7 +1100,7 @@ appJsonToCM AppMessageJson {v, msgId, event, params} = do
|
||||
XGrpLinkReject_ -> XGrpLinkReject <$> p "groupLinkRejection"
|
||||
XGrpLinkMem_ -> XGrpLinkMem <$> p "profile"
|
||||
XGrpLinkAcpt_ -> XGrpLinkAcpt <$> p "acceptance" <*> p "role" <*> p "memberId"
|
||||
XGrpRelayInv_ -> XGrpRelayInv <$> p "groupLink"
|
||||
XGrpRelayInv_ -> XGrpRelayInv <$> p "groupRelayInvitation"
|
||||
XGrpRelayAcpt_ -> XGrpRelayAcpt <$> p "relayLink"
|
||||
XGrpMemNew_ -> XGrpMemNew <$> p "memberInfo" <*> opt "scope"
|
||||
XGrpMemIntro_ -> XGrpMemIntro <$> p "memberInfo" <*> opt "memberRestrictions"
|
||||
@@ -1161,7 +1161,7 @@ chatToAppMessage chatMsg@ChatMessage {chatVRange, msgId, chatMsgEvent} = case en
|
||||
XGrpLinkReject groupLinkRjct -> o ["groupLinkRejection" .= groupLinkRjct]
|
||||
XGrpLinkMem profile -> o ["profile" .= profile]
|
||||
XGrpLinkAcpt acceptance role memberId -> o ["acceptance" .= acceptance, "role" .= role, "memberId" .= memberId]
|
||||
XGrpRelayInv groupLink -> o ["groupLink" .= groupLink]
|
||||
XGrpRelayInv groupRelayInv -> o ["groupRelayInvitation" .= groupRelayInv]
|
||||
XGrpRelayAcpt relayLink -> o ["relayLink" .= relayLink]
|
||||
XGrpMemNew memInfo scope -> o $ ("scope" .=? scope) ["memberInfo" .= memInfo]
|
||||
XGrpMemIntro memInfo memRestrictions -> o $ ("memberRestrictions" .=? memRestrictions) ["memberInfo" .= memInfo]
|
||||
|
||||
@@ -149,13 +149,13 @@ getConnectionEntity db vr user@User {userId, userContactId} agentConnId = do
|
||||
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,
|
||||
mu.is_chat_relay, NULL, NULL, NULL,
|
||||
mu.is_chat_relay, NULL, NULL, NULL, NULL,
|
||||
-- from GroupMember
|
||||
m.group_member_id, m.group_id, 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,
|
||||
m.is_chat_relay, r.group_relay_id, r.relay_status, r.relay_link
|
||||
m.is_chat_relay, r.group_relay_id, r.chat_relay_id, r.relay_status, r.relay_link
|
||||
FROM group_members m
|
||||
JOIN contact_profiles p ON p.contact_profile_id = COALESCE(m.member_profile_id, m.contact_profile_id)
|
||||
LEFT JOIN group_relays r ON r.group_relay_id = m.group_relay_id
|
||||
|
||||
@@ -74,6 +74,11 @@ module Simplex.Chat.Store.Groups
|
||||
getContactGroupPreferences,
|
||||
getGroupInvitation,
|
||||
createNewContactMember,
|
||||
createGroupRelayRecord,
|
||||
getGroupRelayById,
|
||||
createRelayMemberRecord,
|
||||
createRelayConnection,
|
||||
updateRelayStatusFromTo,
|
||||
createNewContactMemberAsync,
|
||||
createJoiningMember,
|
||||
getMemberJoinRequest,
|
||||
@@ -156,6 +161,7 @@ import Crypto.Random (ChaChaDRG)
|
||||
import Data.Bifunctor (second)
|
||||
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 +171,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
|
||||
@@ -190,11 +197,11 @@ import Database.SQLite.Simple (Only (..), Query, (:.) (..))
|
||||
import Database.SQLite.Simple.QQ (sql)
|
||||
#endif
|
||||
|
||||
type MaybeGroupMemberRow = (Maybe Int64, 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) :. (Maybe BoolInt, Maybe Int64, Maybe RelayStatus, Maybe ShortLinkContact)
|
||||
type MaybeGroupMemberRow = (Maybe Int64, 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) :. (Maybe BoolInt, Maybe Int64, Maybe Int64, Maybe RelayStatus, Maybe ShortLinkContact)
|
||||
|
||||
toMaybeGroupMember :: Int64 -> MaybeGroupMemberRow -> Maybe GroupMember
|
||||
toMaybeGroupMember userContactId ((Just groupMemberId, Just groupId, 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 isChatRelay, groupRelayId, relayStatus, relayLink)) =
|
||||
Just $ toGroupMember userContactId ((groupMemberId, groupId, 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) :. (isChatRelay, groupRelayId, relayStatus, relayLink))
|
||||
toMaybeGroupMember userContactId ((Just groupMemberId, Just groupId, 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 isChatRelay, groupRelayId, chatRelayId, relayStatus, relayLink)) =
|
||||
Just $ toGroupMember userContactId ((groupMemberId, groupId, 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) :. (isChatRelay, groupRelayId, chatRelayId, relayStatus, relayLink))
|
||||
toMaybeGroupMember _ _ = Nothing
|
||||
|
||||
createGroupLink :: DB.Connection -> TVar ChaChaDRG -> User -> GroupInfo -> ConnId -> CreatedLinkContact -> GroupLinkId -> GroupMemberRole -> SubscriptionMode -> ExceptT StoreError IO GroupLink
|
||||
@@ -1122,6 +1129,95 @@ createNewContactMember db gVar User {userId, userContactId} GroupInfo {groupId,
|
||||
:. (minV, maxV)
|
||||
)
|
||||
|
||||
createGroupRelayRecord :: DB.Connection -> GroupInfo -> UserChatRelay -> ExceptT StoreError IO GroupRelay
|
||||
createGroupRelayRecord db GroupInfo {groupId} UserChatRelay {chatRelayId} = do
|
||||
currentTs <- liftIO getCurrentTime
|
||||
liftIO $
|
||||
DB.execute
|
||||
db
|
||||
[sql|
|
||||
INSERT INTO group_relays
|
||||
(group_id, chat_relay_id, relay_status, created_at, updated_at)
|
||||
VALUES (?,?,?,?,?)
|
||||
|]
|
||||
(groupId, 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
|
||||
[sql|
|
||||
SELECT group_relay_id, chat_relay_id, chat_relay_id, relay_status, relay_link
|
||||
FROM group_relays
|
||||
WHERE group_relay_id = ?
|
||||
|]
|
||||
(Only relayId)
|
||||
where
|
||||
toGroupRelay :: (Int64, Int64, RelayStatus, Maybe ShortLinkContact) -> GroupRelay
|
||||
toGroupRelay (groupRelayId, userChatRelayId, relayStatus, relayLink) =
|
||||
GroupRelay {groupRelayId, userChatRelayId, relayStatus, relayLink}
|
||||
|
||||
-- TODO [relays] TBC role, category, relay profile
|
||||
-- TODO - GCInviteeMember -> GCRelayMember?
|
||||
-- TODO - GRMember -> GRRelay?
|
||||
-- TODO - create 1 profile per relay, link to chat_relays?
|
||||
createRelayMemberRecord :: DB.Connection -> VersionRangeChat -> TVar ChaChaDRG -> User -> GroupInfo -> UserChatRelay -> GroupRelay -> ExceptT StoreError IO GroupMember
|
||||
createRelayMemberRecord db vr gVar user@User {userId, userContactId} GroupInfo {groupId, membership} UserChatRelay {name} GroupRelay {groupRelayId} = do
|
||||
currentTs <- liftIO getCurrentTime
|
||||
let relayProfile = profileFromName name
|
||||
(localDisplayName, memProfileId) <- createNewMemberProfile_ db user relayProfile currentTs
|
||||
groupMemberId <- createWithRandomId gVar $ \memId -> do
|
||||
DB.execute
|
||||
db
|
||||
[sql|
|
||||
INSERT INTO group_members
|
||||
( group_id, 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,
|
||||
is_chat_relay, group_relay_id
|
||||
)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
|]
|
||||
( (groupId, MemberId memId, GRMember, GCInviteeMember, GSMemInvited, fromInvitedBy userContactId IBUser, groupMemberId' membership)
|
||||
:. (userId, localDisplayName, memProfileId, currentTs, currentTs)
|
||||
:. (BI True, groupRelayId)
|
||||
)
|
||||
insertedRowId db
|
||||
getGroupMemberById db vr user 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
|
||||
|
||||
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)
|
||||
|
||||
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 gVar $ \memId -> do
|
||||
|
||||
@@ -679,7 +679,7 @@ getChatItemQuote_ db User {userId, userContactId} chatDirection QuotedMsg {msgRe
|
||||
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,
|
||||
m.is_chat_relay, r.group_relay_id, r.relay_status, r.relay_link
|
||||
m.is_chat_relay, r.group_relay_id, r.chat_relay_id, r.relay_status, r.relay_link
|
||||
FROM group_members m
|
||||
JOIN contact_profiles p ON p.contact_profile_id = COALESCE(m.member_profile_id, m.contact_profile_id)
|
||||
LEFT JOIN group_relays r ON r.group_relay_id = m.group_relay_id
|
||||
@@ -3005,7 +3005,7 @@ getGroupChatItem db User {userId, userContactId} groupId itemId = ExceptT $ do
|
||||
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,
|
||||
m.is_chat_relay, r.group_relay_id, r.relay_status, r.relay_link,
|
||||
m.is_chat_relay, r.group_relay_id, r.chat_relay_id, r.relay_status, r.relay_link,
|
||||
-- quoted ChatItem
|
||||
ri.chat_item_id, i.quoted_shared_msg_id, i.quoted_sent_at, i.quoted_content, i.quoted_sent,
|
||||
-- quoted GroupMember
|
||||
@@ -3014,14 +3014,14 @@ getGroupChatItem db User {userId, userContactId} groupId itemId = ExceptT $ do
|
||||
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,
|
||||
rm.is_chat_relay, rr.group_relay_id, rr.relay_status, rr.relay_link,
|
||||
rm.is_chat_relay, rr.group_relay_id, rr.chat_relay_id, rr.relay_status, rr.relay_link,
|
||||
-- deleted by GroupMember
|
||||
dbm.group_member_id, dbm.group_id, 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.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,
|
||||
dbm.is_chat_relay, dbr.group_relay_id, dbr.relay_status, dbr.relay_link
|
||||
dbm.is_chat_relay, dbr.group_relay_id, dbr.chat_relay_id, dbr.relay_status, dbr.relay_link
|
||||
FROM chat_items i
|
||||
LEFT JOIN files f ON f.chat_item_id = i.chat_item_id
|
||||
LEFT JOIN group_members m ON m.group_member_id = i.group_member_id
|
||||
|
||||
@@ -53,7 +53,9 @@ CREATE TABLE group_relays(
|
||||
group_id INTEGER NOT NULL REFERENCES groups ON DELETE CASCADE,
|
||||
chat_relay_id INTEGER NOT NULL REFERENCES chat_relays ON DELETE CASCADE,
|
||||
relay_status TEXT NOT NULL,
|
||||
relay_link BLOB
|
||||
relay_link BLOB,
|
||||
created_at TEXT NOT NULL DEFAULT(datetime('now')),
|
||||
updated_at TEXT NOT NULL DEFAULT(datetime('now'))
|
||||
);
|
||||
CREATE INDEX idx_group_relays_group_id ON group_relays(group_id);
|
||||
CREATE INDEX idx_group_relays_chat_relay_id ON group_relays(chat_relay_id);
|
||||
|
||||
@@ -747,7 +747,9 @@ CREATE TABLE group_relays(
|
||||
group_id INTEGER NOT NULL REFERENCES groups ON DELETE CASCADE,
|
||||
chat_relay_id INTEGER NOT NULL REFERENCES chat_relays ON DELETE CASCADE,
|
||||
relay_status TEXT NOT NULL,
|
||||
relay_link BLOB
|
||||
relay_link BLOB,
|
||||
created_at TEXT NOT NULL DEFAULT(datetime('now')),
|
||||
updated_at TEXT NOT NULL DEFAULT(datetime('now'))
|
||||
);
|
||||
CREATE INDEX contact_profiles_index ON contact_profiles(
|
||||
display_name,
|
||||
|
||||
@@ -148,6 +148,7 @@ data StoreError
|
||||
| SEOperatorNotFound {serverOperatorId :: Int64}
|
||||
| SEUsageConditionsNotFound
|
||||
| SEUserChatRelayNotFound {chatRelayId :: Int64}
|
||||
| SEGroupRelayNotFound {groupRelayId :: Int64}
|
||||
| SEInvalidQuote
|
||||
| SEInvalidMention
|
||||
| SEInvalidDeliveryTask {taskId :: Int64}
|
||||
@@ -657,7 +658,7 @@ type BusinessChatInfoRow = (Maybe BusinessChatType, Maybe MemberId, Maybe Member
|
||||
|
||||
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 = (Int64, 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) :. (BoolInt, Maybe Int64, Maybe RelayStatus, Maybe ShortLinkContact)
|
||||
type GroupMemberRow = (Int64, 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) :. (BoolInt, Maybe Int64, Maybe Int64, Maybe RelayStatus, Maybe ShortLinkContact)
|
||||
|
||||
type ProfileRow = (ProfileId, ContactName, Text, Maybe Text, Maybe ImageData, Maybe ConnLinkContact, Maybe ChatPeerType, LocalAlias, Maybe Preferences)
|
||||
|
||||
@@ -679,7 +680,7 @@ toPreparedGroup = \case
|
||||
_ -> Nothing
|
||||
|
||||
toGroupMember :: Int64 -> GroupMemberRow -> GroupMember
|
||||
toGroupMember userContactId ((groupMemberId, groupId, memberId, minVer, maxVer, memberRole, memberCategory, memberStatus, BI showMessages, memberRestriction_) :. (invitedById, invitedByGroupMemberId, localDisplayName, memberContactId, memberContactProfileId) :. profileRow :. (createdAt, updatedAt) :. (supportChatTs_, supportChatUnread, supportChatMemberAttention, supportChatMentions, supportChatLastMsgFromMemberTs) :. (BI isCRelay, groupRelayId_, relayStatus_, relayLink)) =
|
||||
toGroupMember userContactId ((groupMemberId, groupId, memberId, minVer, maxVer, memberRole, memberCategory, memberStatus, BI showMessages, memberRestriction_) :. (invitedById, invitedByGroupMemberId, localDisplayName, memberContactId, memberContactProfileId) :. profileRow :. (createdAt, updatedAt) :. (supportChatTs_, supportChatUnread, supportChatMemberAttention, supportChatMentions, supportChatLastMsgFromMemberTs) :. (BI isCRelay, groupRelayId_, chatRelayId_, relayStatus_, relayLink)) =
|
||||
let memberProfile = rowToLocalProfile profileRow
|
||||
memberSettings = GroupMemberSettings {showMessages}
|
||||
blockedByAdmin = maybe False mrsBlocked memberRestriction_
|
||||
@@ -698,8 +699,8 @@ toGroupMember userContactId ((groupMemberId, groupId, memberId, minVer, maxVer,
|
||||
}
|
||||
_ -> Nothing
|
||||
isChatRelay = BoolDef isCRelay
|
||||
relayData = case (groupRelayId_, relayStatus_) of
|
||||
(Just groupRelayId, Just relayStatus) -> Just GroupRelay {groupRelayId, relayStatus, relayLink}
|
||||
relayData = case (groupRelayId_, chatRelayId_, relayStatus_) of
|
||||
(Just groupRelayId, Just userChatRelayId, Just relayStatus) -> Just GroupRelay {groupRelayId, userChatRelayId, relayStatus, relayLink}
|
||||
_ -> Nothing
|
||||
in GroupMember {..}
|
||||
|
||||
@@ -711,7 +712,7 @@ groupMemberQuery =
|
||||
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,
|
||||
m.is_chat_relay, r.group_relay_id, r.relay_status, r.relay_link,
|
||||
m.is_chat_relay, r.group_relay_id, r.chat_relay_id, r.relay_status, r.relay_link,
|
||||
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,
|
||||
@@ -737,7 +738,7 @@ toBusinessChatInfo _ = Nothing
|
||||
groupInfoQuery :: Query
|
||||
groupInfoQuery = groupInfoQueryFields <> " " <> groupInfoQueryFrom
|
||||
|
||||
-- membership "member" never references group_relays, therefore `NULL, NULL, NULL` which avoids extra join
|
||||
-- membership "member" never references group_relays, therefore `NULL, NULL, NULL, NULL` which avoids extra join
|
||||
groupInfoQueryFields :: Query
|
||||
groupInfoQueryFields =
|
||||
[sql|
|
||||
@@ -756,7 +757,7 @@ groupInfoQueryFields =
|
||||
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,
|
||||
mu.is_chat_relay, NULL, NULL, NULL
|
||||
mu.is_chat_relay, NULL, NULL, NULL, NULL
|
||||
|]
|
||||
|
||||
groupInfoQueryFrom :: Query
|
||||
|
||||
@@ -820,8 +820,9 @@ data GroupLinkRejection = GroupLinkRejection
|
||||
|
||||
data GroupRelayInvitation = GroupRelayInvitation
|
||||
{ fromMember :: MemberIdRole,
|
||||
fromMemberProfile :: Profile,
|
||||
invitedMember :: MemberIdRole,
|
||||
groupProfile :: GroupProfile
|
||||
groupLink :: ShortLinkContact
|
||||
}
|
||||
deriving (Eq, Show)
|
||||
|
||||
@@ -968,6 +969,7 @@ data GroupMember = GroupMember
|
||||
|
||||
data GroupRelay = GroupRelay
|
||||
{ groupRelayId :: Int64,
|
||||
userChatRelayId :: Int64, -- ID of configured UserChatRelay
|
||||
relayStatus :: RelayStatus,
|
||||
relayLink :: Maybe ShortLinkContact
|
||||
}
|
||||
@@ -2076,6 +2078,8 @@ $(JQ.deriveJSON defaultJSON ''GroupLinkInvitation)
|
||||
|
||||
$(JQ.deriveJSON defaultJSON ''GroupLinkRejection)
|
||||
|
||||
$(JQ.deriveJSON defaultJSON ''GroupRelayInvitation)
|
||||
|
||||
$(JQ.deriveJSON defaultJSON ''IntroInvitation)
|
||||
|
||||
$(JQ.deriveJSON defaultJSON ''MemberRestrictions)
|
||||
|
||||
Reference in New Issue
Block a user