core: check user record when deleting contact and display name (#3826)
* filter out on merge
* checl contact, ldn
* fix
* corrections
* fix
* refactor
* diff
* refactor2
* remove contact id from error
* Revert "remove contact id from error"
This reverts commit f58af3dcac
.
* remove Maybe from error
---------
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
This commit is contained in:
parent
c544a636f6
commit
f7d7f5461f
@ -947,7 +947,7 @@ processChatCommand' vr = \case
|
||||
-- functions below are called in separate transactions to prevent crashes on android
|
||||
-- (possibly, race condition on integrity check?)
|
||||
withStore' $ \db -> deleteContactConnectionsAndFiles db userId ct
|
||||
withStore' $ \db -> deleteContact db user ct
|
||||
withStore $ \db -> deleteContact db user ct
|
||||
pure $ CRContactDeleted user ct
|
||||
CTContactConnection -> withChatLock "deleteChat contactConnection" . procCmd $ do
|
||||
conn@PendingContactConnection {pccAgentConnId = AgentConnId acId} <- withStore $ \db -> getPendingContactConnection db userId chatId
|
||||
@ -988,7 +988,7 @@ processChatCommand' vr = \case
|
||||
Just _ -> pure []
|
||||
Nothing -> do
|
||||
conns <- withStore' $ \db -> getContactConnections db userId ct
|
||||
withStore' (\db -> setContactDeleted db user ct)
|
||||
withStore (\db -> setContactDeleted db user ct)
|
||||
`catchChatError` (toView . CRChatError (Just user))
|
||||
pure $ map aConnId conns
|
||||
CTLocal -> pure $ chatCmdError (Just user) "not supported"
|
||||
@ -3056,7 +3056,7 @@ cleanupManager = do
|
||||
cleanupDeletedContacts user = do
|
||||
contacts <- withStore' (`getDeletedContacts` user)
|
||||
forM_ contacts $ \ct ->
|
||||
withStore' (\db -> deleteContactWithoutGroups db user ct)
|
||||
withStore (\db -> deleteContactWithoutGroups db user ct)
|
||||
`catchChatError` (toView . CRChatError (Just user))
|
||||
cleanupMessages = do
|
||||
ts <- liftIO getCurrentTime
|
||||
@ -4836,7 +4836,7 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage =
|
||||
else do
|
||||
contactConns <- withStore' $ \db -> getContactConnections db userId c
|
||||
deleteAgentConnectionsAsync user $ map aConnId contactConns
|
||||
withStore' $ \db -> deleteContact db user c
|
||||
withStore $ \db -> deleteContact db user c
|
||||
where
|
||||
brokerTs = metaBrokerTs msgMeta
|
||||
|
||||
|
@ -229,37 +229,45 @@ deleteContactConnectionsAndFiles db userId Contact {contactId} = do
|
||||
(userId, contactId)
|
||||
DB.execute db "DELETE FROM files WHERE user_id = ? AND contact_id = ?" (userId, contactId)
|
||||
|
||||
deleteContact :: DB.Connection -> User -> Contact -> IO ()
|
||||
deleteContact db user@User {userId} Contact {contactId, localDisplayName, activeConn} = do
|
||||
DB.execute db "DELETE FROM chat_items WHERE user_id = ? AND contact_id = ?" (userId, contactId)
|
||||
ctMember :: (Maybe ContactId) <- maybeFirstRow fromOnly $ DB.query db "SELECT contact_id FROM group_members WHERE user_id = ? AND contact_id = ? LIMIT 1" (userId, contactId)
|
||||
if isNothing ctMember
|
||||
then do
|
||||
deleteContactProfile_ db userId contactId
|
||||
DB.execute db "DELETE FROM display_names WHERE user_id = ? AND local_display_name = ?" (userId, localDisplayName)
|
||||
else do
|
||||
currentTs <- getCurrentTime
|
||||
DB.execute db "UPDATE group_members SET contact_id = NULL, updated_at = ? WHERE user_id = ? AND contact_id = ?" (currentTs, userId, contactId)
|
||||
DB.execute db "DELETE FROM contacts WHERE user_id = ? AND contact_id = ?" (userId, contactId)
|
||||
forM_ activeConn $ \Connection {customUserProfileId} ->
|
||||
forM_ customUserProfileId $ \profileId ->
|
||||
deleteUnusedIncognitoProfileById_ db user profileId
|
||||
deleteContact :: DB.Connection -> User -> Contact -> ExceptT StoreError IO ()
|
||||
deleteContact db user@User {userId} ct@Contact {contactId, localDisplayName, activeConn} = do
|
||||
assertNotUser db user ct
|
||||
liftIO $ do
|
||||
DB.execute db "DELETE FROM chat_items WHERE user_id = ? AND contact_id = ?" (userId, contactId)
|
||||
ctMember :: (Maybe ContactId) <- maybeFirstRow fromOnly $ DB.query db "SELECT contact_id FROM group_members WHERE user_id = ? AND contact_id = ? LIMIT 1" (userId, contactId)
|
||||
if isNothing ctMember
|
||||
then do
|
||||
deleteContactProfile_ db userId contactId
|
||||
-- user's local display name already checked in assertNotUser
|
||||
DB.execute db "DELETE FROM display_names WHERE user_id = ? AND local_display_name = ?" (userId, localDisplayName)
|
||||
else do
|
||||
currentTs <- getCurrentTime
|
||||
DB.execute db "UPDATE group_members SET contact_id = NULL, updated_at = ? WHERE user_id = ? AND contact_id = ?" (currentTs, userId, contactId)
|
||||
DB.execute db "DELETE FROM contacts WHERE user_id = ? AND contact_id = ?" (userId, contactId)
|
||||
forM_ activeConn $ \Connection {customUserProfileId} ->
|
||||
forM_ customUserProfileId $ \profileId ->
|
||||
deleteUnusedIncognitoProfileById_ db user profileId
|
||||
|
||||
-- should only be used if contact is not member of any groups
|
||||
deleteContactWithoutGroups :: DB.Connection -> User -> Contact -> IO ()
|
||||
deleteContactWithoutGroups db user@User {userId} Contact {contactId, localDisplayName, activeConn} = do
|
||||
DB.execute db "DELETE FROM chat_items WHERE user_id = ? AND contact_id = ?" (userId, contactId)
|
||||
deleteContactProfile_ db userId contactId
|
||||
DB.execute db "DELETE FROM display_names WHERE user_id = ? AND local_display_name = ?" (userId, localDisplayName)
|
||||
DB.execute db "DELETE FROM contacts WHERE user_id = ? AND contact_id = ?" (userId, contactId)
|
||||
forM_ activeConn $ \Connection {customUserProfileId} ->
|
||||
forM_ customUserProfileId $ \profileId ->
|
||||
deleteUnusedIncognitoProfileById_ db user profileId
|
||||
deleteContactWithoutGroups :: DB.Connection -> User -> Contact -> ExceptT StoreError IO ()
|
||||
deleteContactWithoutGroups db user@User {userId} ct@Contact {contactId, localDisplayName, activeConn} = do
|
||||
assertNotUser db user ct
|
||||
liftIO $ do
|
||||
DB.execute db "DELETE FROM chat_items WHERE user_id = ? AND contact_id = ?" (userId, contactId)
|
||||
deleteContactProfile_ db userId contactId
|
||||
-- user's local display name already checked in assertNotUser
|
||||
DB.execute db "DELETE FROM display_names WHERE user_id = ? AND local_display_name = ?" (userId, localDisplayName)
|
||||
DB.execute db "DELETE FROM contacts WHERE user_id = ? AND contact_id = ?" (userId, contactId)
|
||||
forM_ activeConn $ \Connection {customUserProfileId} ->
|
||||
forM_ customUserProfileId $ \profileId ->
|
||||
deleteUnusedIncognitoProfileById_ db user profileId
|
||||
|
||||
setContactDeleted :: DB.Connection -> User -> Contact -> IO ()
|
||||
setContactDeleted db User {userId} Contact {contactId} = do
|
||||
currentTs <- getCurrentTime
|
||||
DB.execute db "UPDATE contacts SET deleted = 1, updated_at = ? WHERE user_id = ? AND contact_id = ?" (currentTs, userId, contactId)
|
||||
setContactDeleted :: DB.Connection -> User -> Contact -> ExceptT StoreError IO ()
|
||||
setContactDeleted db user@User {userId} ct@Contact {contactId} = do
|
||||
assertNotUser db user ct
|
||||
liftIO $ do
|
||||
currentTs <- getCurrentTime
|
||||
DB.execute db "UPDATE contacts SET deleted = 1, updated_at = ? WHERE user_id = ? AND contact_id = ?" (currentTs, userId, contactId)
|
||||
|
||||
getDeletedContacts :: DB.Connection -> User -> IO [Contact]
|
||||
getDeletedContacts db user@User {userId} = do
|
||||
@ -320,7 +328,7 @@ updateContactProfile db user@User {userId} c p'
|
||||
ExceptT . withLocalDisplayName db userId newName $ \ldn -> do
|
||||
currentTs <- getCurrentTime
|
||||
updateContactProfile_' db userId profileId p' currentTs
|
||||
updateContactLDN_ db userId contactId localDisplayName ldn currentTs
|
||||
updateContactLDN_ db user contactId localDisplayName ldn currentTs
|
||||
pure $ Right c {localDisplayName = ldn, profile, mergedPreferences}
|
||||
where
|
||||
Contact {contactId, localDisplayName, profile = LocalProfile {profileId, displayName, localAlias}, userPreferences} = c
|
||||
@ -491,8 +499,8 @@ updateMemberContactProfile_' db userId profileId Profile {displayName, fullName,
|
||||
|]
|
||||
(displayName, fullName, image, updatedAt, userId, profileId)
|
||||
|
||||
updateContactLDN_ :: DB.Connection -> UserId -> Int64 -> ContactName -> ContactName -> UTCTime -> IO ()
|
||||
updateContactLDN_ db userId contactId displayName newName updatedAt = do
|
||||
updateContactLDN_ :: DB.Connection -> User -> Int64 -> ContactName -> ContactName -> UTCTime -> IO ()
|
||||
updateContactLDN_ db user@User {userId} contactId displayName newName updatedAt = do
|
||||
DB.execute
|
||||
db
|
||||
"UPDATE contacts SET local_display_name = ?, updated_at = ? WHERE user_id = ? AND contact_id = ?"
|
||||
@ -501,7 +509,7 @@ updateContactLDN_ db userId contactId displayName newName updatedAt = do
|
||||
db
|
||||
"UPDATE group_members SET local_display_name = ?, updated_at = ? WHERE user_id = ? AND contact_id = ?"
|
||||
(newName, updatedAt, userId, contactId)
|
||||
DB.execute db "DELETE FROM display_names WHERE local_display_name = ? AND user_id = ?" (displayName, userId)
|
||||
safeDeleteLDN db user displayName
|
||||
|
||||
getContactByName :: DB.Connection -> User -> ContactName -> ExceptT StoreError IO Contact
|
||||
getContactByName db user localDisplayName = do
|
||||
@ -614,7 +622,7 @@ createOrUpdateContactRequest db user@User {userId} userContactLinkId invId (Vers
|
||||
WHERE user_id = ? AND contact_request_id = ?
|
||||
|]
|
||||
(invId, minV, maxV, ldn, currentTs, userId, cReqId)
|
||||
DB.execute db "DELETE FROM display_names WHERE local_display_name = ? AND user_id = ?" (oldLdn, userId)
|
||||
safeDeleteLDN db user oldLdn
|
||||
where
|
||||
updateProfile currentTs =
|
||||
DB.execute
|
||||
@ -684,8 +692,9 @@ deleteContactRequest db User {userId} contactRequestId = do
|
||||
SELECT local_display_name FROM contact_requests
|
||||
WHERE user_id = ? AND contact_request_id = ?
|
||||
)
|
||||
AND local_display_name NOT IN (SELECT local_display_name FROM users WHERE user_id = ?)
|
||||
|]
|
||||
(userId, userId, contactRequestId)
|
||||
(userId, userId, contactRequestId, userId)
|
||||
DB.execute db "DELETE FROM contact_requests WHERE user_id = ? AND contact_request_id = ?" (userId, contactRequestId)
|
||||
|
||||
createAcceptedContact :: DB.Connection -> User -> ConnId -> VersionRange -> ContactName -> ProfileId -> Profile -> Int64 -> Maybe XContactId -> Maybe IncognitoProfile -> SubscriptionMode -> Bool -> IO Contact
|
||||
|
@ -225,8 +225,9 @@ deleteGroupLink db User {userId} GroupInfo {groupId} = do
|
||||
JOIN user_contact_links uc USING (user_contact_link_id)
|
||||
WHERE uc.user_id = ? AND uc.group_id = ?
|
||||
)
|
||||
AND local_display_name NOT IN (SELECT local_display_name FROM users WHERE user_id = ?)
|
||||
|]
|
||||
(userId, userId, groupId)
|
||||
(userId, userId, groupId, userId)
|
||||
DB.execute
|
||||
db
|
||||
[sql|
|
||||
@ -586,7 +587,7 @@ deleteGroup :: DB.Connection -> User -> GroupInfo -> IO ()
|
||||
deleteGroup db user@User {userId} g@GroupInfo {groupId, localDisplayName} = do
|
||||
deleteGroupProfile_ db userId groupId
|
||||
DB.execute db "DELETE FROM groups WHERE user_id = ? AND group_id = ?" (userId, groupId)
|
||||
DB.execute db "DELETE FROM display_names WHERE user_id = ? AND local_display_name = ?" (userId, localDisplayName)
|
||||
safeDeleteLDN db user localDisplayName
|
||||
forM_ (incognitoMembershipProfile g) $ deleteUnusedIncognitoProfileById_ db user . localProfileId
|
||||
|
||||
deleteGroupProfile_ :: DB.Connection -> UserId -> GroupId -> IO ()
|
||||
@ -1044,14 +1045,14 @@ deleteGroupMember db user@User {userId} m@GroupMember {groupMemberId, groupId, m
|
||||
when (memberIncognito m) $ deleteUnusedIncognitoProfileById_ db user $ localProfileId memberProfile
|
||||
|
||||
cleanupMemberProfileAndName_ :: DB.Connection -> User -> GroupMember -> IO ()
|
||||
cleanupMemberProfileAndName_ db User {userId} GroupMember {groupMemberId, memberContactId, memberContactProfileId, localDisplayName} =
|
||||
cleanupMemberProfileAndName_ db user@User {userId} GroupMember {groupMemberId, memberContactId, memberContactProfileId, localDisplayName} =
|
||||
-- check record has no memberContactId (contact_id) - it means contact has been deleted and doesn't use profile & ldn
|
||||
when (isNothing memberContactId) $ do
|
||||
-- check other group member records don't use profile & ldn
|
||||
sameProfileMember :: (Maybe GroupMemberId) <- maybeFirstRow fromOnly $ DB.query db "SELECT group_member_id FROM group_members WHERE user_id = ? AND contact_profile_id = ? AND group_member_id != ? LIMIT 1" (userId, memberContactProfileId, groupMemberId)
|
||||
when (isNothing sameProfileMember) $ do
|
||||
DB.execute db "DELETE FROM contact_profiles WHERE user_id = ? AND contact_profile_id = ?" (userId, memberContactProfileId)
|
||||
DB.execute db "DELETE FROM display_names WHERE user_id = ? AND local_display_name = ?" (userId, localDisplayName)
|
||||
safeDeleteLDN db user localDisplayName
|
||||
|
||||
deleteGroupMemberConnection :: DB.Connection -> User -> GroupMember -> IO ()
|
||||
deleteGroupMemberConnection db User {userId} GroupMember {groupMemberId} =
|
||||
@ -1330,7 +1331,7 @@ getViaGroupContact db user@User {userId} GroupMember {groupMemberId} = do
|
||||
maybe (pure Nothing) (fmap eitherToMaybe . runExceptT . getContact db user) contactId_
|
||||
|
||||
updateGroupProfile :: DB.Connection -> User -> GroupInfo -> GroupProfile -> ExceptT StoreError IO GroupInfo
|
||||
updateGroupProfile db User {userId} g@GroupInfo {groupId, localDisplayName, groupProfile = GroupProfile {displayName}} p'@GroupProfile {displayName = newName, fullName, description, image, groupPreferences}
|
||||
updateGroupProfile db user@User {userId} g@GroupInfo {groupId, localDisplayName, groupProfile = GroupProfile {displayName}} p'@GroupProfile {displayName = newName, fullName, description, image, groupPreferences}
|
||||
| displayName == newName = liftIO $ do
|
||||
currentTs <- getCurrentTime
|
||||
updateGroupProfile_ currentTs
|
||||
@ -1361,7 +1362,7 @@ updateGroupProfile db User {userId} g@GroupInfo {groupId, localDisplayName, grou
|
||||
db
|
||||
"UPDATE groups SET local_display_name = ?, updated_at = ? WHERE user_id = ? AND group_id = ?"
|
||||
(ldn, currentTs, userId, groupId)
|
||||
DB.execute db "DELETE FROM display_names WHERE local_display_name = ? AND user_id = ?" (localDisplayName, userId)
|
||||
safeDeleteLDN db user localDisplayName
|
||||
|
||||
getGroupInfo :: DB.Connection -> VersionRange -> User -> Int64 -> ExceptT StoreError IO GroupInfo
|
||||
getGroupInfo db vr User {userId, userContactId} groupId =
|
||||
@ -1464,7 +1465,7 @@ getMatchingContacts db user@User {userId} Contact {contactId, profile = LocalPro
|
||||
FROM contacts ct
|
||||
JOIN contact_profiles p ON ct.contact_profile_id = p.contact_profile_id
|
||||
WHERE ct.user_id = ? AND ct.contact_id != ?
|
||||
AND ct.contact_status = ? AND ct.deleted = 0
|
||||
AND ct.contact_status = ? AND ct.deleted = 0 AND ct.is_user = 0
|
||||
AND p.display_name = ? AND p.full_name = ?
|
||||
|]
|
||||
|
||||
@ -1502,7 +1503,7 @@ getMatchingMemberContacts db user@User {userId} GroupMember {memberProfile = Loc
|
||||
FROM contacts ct
|
||||
JOIN contact_profiles p ON ct.contact_profile_id = p.contact_profile_id
|
||||
WHERE ct.user_id = ?
|
||||
AND ct.contact_status = ? AND ct.deleted = 0
|
||||
AND ct.contact_status = ? AND ct.deleted = 0 AND ct.is_user = 0
|
||||
AND p.display_name = ? AND p.full_name = ?
|
||||
|]
|
||||
|
||||
@ -1615,6 +1616,8 @@ mergeContactRecords db user@User {userId} to@Contact {localDisplayName = keepLDN
|
||||
let (toCt, fromCt) = toFromContacts to from
|
||||
Contact {contactId = toContactId, localDisplayName = toLDN} = toCt
|
||||
Contact {contactId = fromContactId, localDisplayName = fromLDN} = fromCt
|
||||
assertNotUser db user toCt
|
||||
assertNotUser db user fromCt
|
||||
liftIO $ do
|
||||
currentTs <- getCurrentTime
|
||||
-- next query fixes incorrect unused contacts deletion
|
||||
@ -2018,7 +2021,7 @@ createMemberContactConn_
|
||||
pure Connection {connId, agentConnId = AgentConnId acId, peerChatVRange, connType = ConnContact, contactConnInitiated = False, entityId = Just contactId, viaContact = Nothing, viaUserContactLink = Nothing, viaGroupLink = False, groupLinkId = Nothing, customUserProfileId, connLevel, connStatus = ConnJoined, localAlias = "", createdAt = currentTs, connectionCode = Nothing, authErrCounter = 0}
|
||||
|
||||
updateMemberProfile :: DB.Connection -> User -> GroupMember -> Profile -> ExceptT StoreError IO GroupMember
|
||||
updateMemberProfile db User {userId} m p'
|
||||
updateMemberProfile db user@User {userId} m p'
|
||||
| displayName == newName = do
|
||||
liftIO $ updateMemberContactProfileReset_ db userId profileId p'
|
||||
pure m {memberProfile = profile}
|
||||
@ -2030,7 +2033,7 @@ updateMemberProfile db User {userId} m p'
|
||||
db
|
||||
"UPDATE group_members SET local_display_name = ?, updated_at = ? WHERE user_id = ? AND group_member_id = ?"
|
||||
(ldn, currentTs, userId, groupMemberId)
|
||||
DB.execute db "DELETE FROM display_names WHERE local_display_name = ? AND user_id = ?" (localDisplayName, userId)
|
||||
safeDeleteLDN db user localDisplayName
|
||||
pure $ Right m {localDisplayName = ldn, memberProfile = profile}
|
||||
where
|
||||
GroupMember {groupMemberId, localDisplayName, memberProfile = LocalProfile {profileId, displayName, localAlias}} = m
|
||||
@ -2038,7 +2041,7 @@ updateMemberProfile db User {userId} m p'
|
||||
profile = toLocalProfile profileId p' localAlias
|
||||
|
||||
updateContactMemberProfile :: DB.Connection -> User -> GroupMember -> Contact -> Profile -> ExceptT StoreError IO (GroupMember, Contact)
|
||||
updateContactMemberProfile db User {userId} m ct@Contact {contactId} p'
|
||||
updateContactMemberProfile db user@User {userId} m ct@Contact {contactId} p'
|
||||
| displayName == newName = do
|
||||
liftIO $ updateMemberContactProfile_ db userId profileId p'
|
||||
pure (m {memberProfile = profile}, ct {profile} :: Contact)
|
||||
@ -2046,7 +2049,7 @@ updateContactMemberProfile db User {userId} m ct@Contact {contactId} p'
|
||||
ExceptT . withLocalDisplayName db userId newName $ \ldn -> do
|
||||
currentTs <- getCurrentTime
|
||||
updateMemberContactProfile_' db userId profileId p' currentTs
|
||||
updateContactLDN_ db userId contactId localDisplayName ldn currentTs
|
||||
updateContactLDN_ db user contactId localDisplayName ldn currentTs
|
||||
pure $ Right (m {localDisplayName = ldn, memberProfile = profile}, ct {localDisplayName = ldn, profile} :: Contact)
|
||||
where
|
||||
GroupMember {localDisplayName, memberProfile = LocalProfile {profileId, displayName, localAlias}} = m
|
||||
|
@ -267,7 +267,7 @@ updateUserProfile db user p'
|
||||
"INSERT INTO display_names (local_display_name, ldn_base, user_id, created_at, updated_at) VALUES (?,?,?,?,?)"
|
||||
(newName, newName, userId, currentTs, currentTs)
|
||||
updateContactProfile_' db userId profileId p' currentTs
|
||||
updateContactLDN_ db userId userContactId localDisplayName newName currentTs
|
||||
updateContactLDN_ db user userContactId localDisplayName newName currentTs
|
||||
pure user {localDisplayName = newName, profile, fullPreferences, userMemberProfileUpdatedAt = userMemberProfileUpdatedAt'}
|
||||
where
|
||||
updateUserMemberProfileUpdatedAt_ currentTs
|
||||
@ -388,6 +388,7 @@ deleteUserAddress db user@User {userId} = do
|
||||
JOIN user_contact_links uc USING (user_contact_link_id)
|
||||
WHERE uc.user_id = :user_id AND uc.local_display_name = '' AND uc.group_id IS NULL
|
||||
)
|
||||
AND local_display_name NOT IN (SELECT local_display_name FROM users WHERE user_id = :user_id)
|
||||
|]
|
||||
[":user_id" := userId]
|
||||
DB.executeNamed
|
||||
|
@ -110,6 +110,7 @@ data StoreError
|
||||
| SERemoteHostDuplicateCA
|
||||
| SERemoteCtrlNotFound {remoteCtrlId :: RemoteCtrlId}
|
||||
| SERemoteCtrlDuplicateCA
|
||||
| SEProhibitedDeleteUser {userId :: UserId, contactId :: ContactId}
|
||||
deriving (Show, Exception)
|
||||
|
||||
$(J.deriveJSON (sumTypeJSON $ dropPrefix "SE") ''StoreError)
|
||||
@ -401,3 +402,33 @@ createWithRandomBytes' size gVar create = tryCreate 3
|
||||
|
||||
encodedRandomBytes :: TVar ChaChaDRG -> Int -> IO ByteString
|
||||
encodedRandomBytes gVar n = atomically $ B64.encode <$> C.randomBytes n gVar
|
||||
|
||||
assertNotUser :: DB.Connection -> User -> Contact -> ExceptT StoreError IO ()
|
||||
assertNotUser db User {userId} Contact {contactId, localDisplayName} = do
|
||||
r :: (Maybe Int64) <-
|
||||
-- This query checks that the foreign keys in the users table
|
||||
-- are not referencing the contact about to be deleted.
|
||||
-- With the current schema it would cause cascade delete of user,
|
||||
-- with mofified schema (in v5.6.0-beta.0) it would cause foreign key violation error.
|
||||
liftIO . maybeFirstRow fromOnly $
|
||||
DB.query
|
||||
db
|
||||
[sql|
|
||||
SELECT 1 FROM users
|
||||
WHERE (user_id = ? AND local_display_name = ?)
|
||||
OR contact_id = ?
|
||||
LIMIT 1
|
||||
|]
|
||||
(userId, localDisplayName, contactId)
|
||||
when (isJust r) $ throwError $ SEProhibitedDeleteUser userId contactId
|
||||
|
||||
safeDeleteLDN :: DB.Connection -> User -> ContactName -> IO ()
|
||||
safeDeleteLDN db User {userId} localDisplayName = do
|
||||
DB.execute
|
||||
db
|
||||
[sql|
|
||||
DELETE FROM display_names
|
||||
WHERE user_id = ? AND local_display_name = ?
|
||||
AND local_display_name NOT IN (SELECT local_display_name FROM users WHERE user_id = ?)
|
||||
|]
|
||||
(userId, localDisplayName, userId)
|
||||
|
Loading…
Reference in New Issue
Block a user