core: show/keep message as moderated for moderator (#1916)

This commit is contained in:
JRoberts 2023-02-08 22:29:36 +04:00 committed by GitHub
parent 9e347484eb
commit bd3325a889
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 40 additions and 28 deletions

View File

@ -557,19 +557,19 @@ processChatCommand = \case
(CIDMBroadcast, SMDSnd, Just itemSharedMId) -> do (CIDMBroadcast, SMDSnd, Just itemSharedMId) -> do
assertUserGroupRole gInfo GRObserver -- can still delete messages sent earlier assertUserGroupRole gInfo GRObserver -- can still delete messages sent earlier
SndMessage {msgId} <- sendGroupMessage user gInfo ms $ XMsgDel itemSharedMId Nothing SndMessage {msgId} <- sendGroupMessage user gInfo ms $ XMsgDel itemSharedMId Nothing
delGroupChatItem user gInfo ci msgId delGroupChatItem user gInfo ci msgId Nothing
(CIDMBroadcast, _, _) -> throwChatError CEInvalidChatItemDelete (CIDMBroadcast, _, _) -> throwChatError CEInvalidChatItemDelete
CTContactRequest -> pure $ chatCmdError (Just user) "not supported" CTContactRequest -> pure $ chatCmdError (Just user) "not supported"
CTContactConnection -> pure $ chatCmdError (Just user) "not supported" CTContactConnection -> pure $ chatCmdError (Just user) "not supported"
APIDeleteMemberChatItem gId mId itemId -> withUser $ \user -> withChatLock "deleteChatItem" $ do APIDeleteMemberChatItem gId mId itemId -> withUser $ \user -> withChatLock "deleteChatItem" $ do
Group gInfo ms <- withStore $ \db -> getGroup db user gId Group gInfo@GroupInfo {membership} ms <- withStore $ \db -> getGroup db user gId
ci@(CChatItem _ ChatItem {chatDir, meta = CIMeta {itemSharedMsgId}}) <- withStore $ \db -> getGroupChatItem db user gId itemId ci@(CChatItem _ ChatItem {chatDir, meta = CIMeta {itemSharedMsgId}}) <- withStore $ \db -> getGroupChatItem db user gId itemId
case (chatDir, itemSharedMsgId) of case (chatDir, itemSharedMsgId) of
(CIGroupRcv GroupMember {groupMemberId, memberRole, memberId}, Just itemSharedMId) -> do (CIGroupRcv GroupMember {groupMemberId, memberRole, memberId}, Just itemSharedMId) -> do
when (groupMemberId /= mId) $ throwChatError CEInvalidChatItemDelete when (groupMemberId /= mId) $ throwChatError CEInvalidChatItemDelete
assertUserGroupRole gInfo $ max GRAdmin memberRole assertUserGroupRole gInfo $ max GRAdmin memberRole
SndMessage {msgId} <- sendGroupMessage user gInfo ms $ XMsgDel itemSharedMId $ Just memberId SndMessage {msgId} <- sendGroupMessage user gInfo ms $ XMsgDel itemSharedMId $ Just memberId
delGroupChatItem user gInfo ci msgId delGroupChatItem user gInfo ci msgId (Just membership)
(_, _) -> throwChatError CEInvalidChatItemDelete (_, _) -> throwChatError CEInvalidChatItemDelete
APIChatRead (ChatRef cType chatId) fromToIds -> withUser $ \_ -> case cType of APIChatRead (ChatRef cType chatId) fromToIds -> withUser $ \_ -> case cType of
CTDirect -> do CTDirect -> do
@ -1482,12 +1482,12 @@ processChatCommand = \case
when (memberStatus membership == GSMemInvited) $ throwChatError (CEGroupNotJoined g) when (memberStatus membership == GSMemInvited) $ throwChatError (CEGroupNotJoined g)
when (memberRemoved membership) $ throwChatError CEGroupMemberUserRemoved when (memberRemoved membership) $ throwChatError CEGroupMemberUserRemoved
unless (memberActive membership) $ throwChatError CEGroupMemberNotActive unless (memberActive membership) $ throwChatError CEGroupMemberNotActive
delGroupChatItem :: User -> GroupInfo -> CChatItem 'CTGroup -> MessageId -> m ChatResponse delGroupChatItem :: User -> GroupInfo -> CChatItem 'CTGroup -> MessageId -> Maybe GroupMember -> m ChatResponse
delGroupChatItem user gInfo@GroupInfo {localDisplayName = gName} ci msgId = do delGroupChatItem user gInfo@GroupInfo {localDisplayName = gName} ci msgId byGroupMember = do
setActive $ ActiveG gName setActive $ ActiveG gName
if groupFeatureAllowed SGFFullDelete gInfo if groupFeatureAllowed SGFFullDelete gInfo
then deleteGroupCI user gInfo ci True False Nothing then deleteGroupCI user gInfo ci True False byGroupMember
else markGroupCIDeleted user gInfo ci msgId True Nothing else markGroupCIDeleted user gInfo ci msgId True byGroupMember
updateGroupProfileByName :: GroupName -> (GroupProfile -> GroupProfile) -> m ChatResponse updateGroupProfileByName :: GroupName -> (GroupProfile -> GroupProfile) -> m ChatResponse
updateGroupProfileByName gName update = withUser $ \user -> do updateGroupProfileByName gName update = withUser $ \user -> do
g@(Group GroupInfo {groupProfile = p} _) <- withStore $ \db -> g@(Group GroupInfo {groupProfile = p} _) <- withStore $ \db ->

View File

@ -90,6 +90,11 @@ chatInfoToRef = \case
ContactRequest UserContactRequest {contactRequestId} -> ChatRef CTContactRequest contactRequestId ContactRequest UserContactRequest {contactRequestId} -> ChatRef CTContactRequest contactRequestId
ContactConnection PendingContactConnection {pccConnId} -> ChatRef CTContactConnection pccConnId ContactConnection PendingContactConnection {pccConnId} -> ChatRef CTContactConnection pccConnId
chatInfoMembership :: ChatInfo c -> Maybe GroupMember
chatInfoMembership = \case
GroupChat GroupInfo {membership} -> Just membership
_ -> Nothing
data JSONChatInfo data JSONChatInfo
= JCInfoDirect {contact :: Contact} = JCInfoDirect {contact :: Contact}
| JCInfoGroup {groupInfo :: GroupInfo} | JCInfoGroup {groupInfo :: GroupInfo}

View File

@ -244,19 +244,19 @@ responseToView user_ ChatConfig {logLevel, testView} liveItems ts = \case
testViewChats chats = [sShow $ map toChatView chats] testViewChats chats = [sShow $ map toChatView chats]
where where
toChatView :: AChat -> (Text, Text, Maybe ConnStatus) toChatView :: AChat -> (Text, Text, Maybe ConnStatus)
toChatView (AChat _ (Chat (DirectChat Contact {localDisplayName, activeConn}) items _)) = ("@" <> localDisplayName, toCIPreview items, Just $ connStatus activeConn) toChatView (AChat _ (Chat (DirectChat Contact {localDisplayName, activeConn}) items _)) = ("@" <> localDisplayName, toCIPreview items Nothing, Just $ connStatus activeConn)
toChatView (AChat _ (Chat (GroupChat GroupInfo {localDisplayName}) items _)) = ("#" <> localDisplayName, toCIPreview items, Nothing) toChatView (AChat _ (Chat (GroupChat GroupInfo {membership, localDisplayName}) items _)) = ("#" <> localDisplayName, toCIPreview items (Just membership), Nothing)
toChatView (AChat _ (Chat (ContactRequest UserContactRequest {localDisplayName}) items _)) = ("<@" <> localDisplayName, toCIPreview items, Nothing) toChatView (AChat _ (Chat (ContactRequest UserContactRequest {localDisplayName}) items _)) = ("<@" <> localDisplayName, toCIPreview items Nothing, Nothing)
toChatView (AChat _ (Chat (ContactConnection PendingContactConnection {pccConnId, pccConnStatus}) items _)) = (":" <> T.pack (show pccConnId), toCIPreview items, Just pccConnStatus) toChatView (AChat _ (Chat (ContactConnection PendingContactConnection {pccConnId, pccConnStatus}) items _)) = (":" <> T.pack (show pccConnId), toCIPreview items Nothing, Just pccConnStatus)
toCIPreview :: [CChatItem c] -> Text toCIPreview :: [CChatItem c] -> Maybe GroupMember -> Text
toCIPreview (ci : _) = testViewItem ci toCIPreview (ci : _) membership_ = testViewItem ci membership_
toCIPreview _ = "" toCIPreview _ _ = ""
testViewChat :: AChat -> [StyledString] testViewChat :: AChat -> [StyledString]
testViewChat (AChat _ Chat {chatItems}) = [sShow $ map toChatView chatItems] testViewChat (AChat _ Chat {chatInfo, chatItems}) = [sShow $ map toChatView chatItems]
where where
toChatView :: CChatItem c -> ((Int, Text), Maybe (Int, Text), Maybe String) toChatView :: CChatItem c -> ((Int, Text), Maybe (Int, Text), Maybe String)
toChatView ci@(CChatItem dir ChatItem {quotedItem, file}) = toChatView ci@(CChatItem dir ChatItem {quotedItem, file}) =
((msgDirectionInt $ toMsgDirection dir, testViewItem ci), qItem, fPath) ((msgDirectionInt $ toMsgDirection dir, testViewItem ci (chatInfoMembership chatInfo)), qItem, fPath)
where where
qItem = case quotedItem of qItem = case quotedItem of
Nothing -> Nothing Nothing -> Nothing
@ -265,8 +265,10 @@ responseToView user_ ChatConfig {logLevel, testView} liveItems ts = \case
fPath = case file of fPath = case file of
Just CIFile {filePath = Just fp} -> Just fp Just CIFile {filePath = Just fp} -> Just fp
_ -> Nothing _ -> Nothing
testViewItem :: CChatItem c -> Text testViewItem :: CChatItem c -> Maybe GroupMember -> Text
testViewItem (CChatItem _ ci@ChatItem {meta = CIMeta {itemText}}) = itemText <> maybe "" (\t -> " [" <> t <> "]") (chatItemDeletedText ci) testViewItem (CChatItem _ ci@ChatItem {meta = CIMeta {itemText}}) membership_ =
let deleted_ = maybe "" (\t -> " [" <> t <> "]") (chatItemDeletedText ci membership_)
in itemText <> deleted_
viewErrorsSummary :: [a] -> StyledString -> [StyledString] viewErrorsSummary :: [a] -> StyledString -> [StyledString]
viewErrorsSummary summary s = [ttyError (T.pack . show $ length summary) <> s <> " (run with -c option to show each error)" | not (null summary)] viewErrorsSummary summary s = [ttyError (T.pack . show $ length summary) <> s <> " (run with -c option to show each error)" | not (null summary)]
contactList :: [ContactRef] -> String contactList :: [ContactRef] -> String
@ -276,14 +278,17 @@ responseToView user_ ChatConfig {logLevel, testView} liveItems ts = \case
| muted chat chatItem = [] | muted chat chatItem = []
| otherwise = s | otherwise = s
chatItemDeletedText :: ChatItem c d -> Maybe Text chatItemDeletedText :: ChatItem c d -> Maybe GroupMember -> Maybe Text
chatItemDeletedText ci = deletedStateToText <$> chatItemDeletedState ci chatItemDeletedText ci membership_ = deletedStateToText <$> chatItemDeletedState ci
where where
deletedStateToText = \CIDeletedState {markedDeleted, deletedByMember} -> deletedStateToText = \CIDeletedState {markedDeleted, deletedByMember} ->
if markedDeleted if markedDeleted
then "marked deleted" <> byMember deletedByMember then "marked deleted" <> byMember deletedByMember
else "deleted" <> byMember deletedByMember else "deleted" <> byMember deletedByMember
byMember m_ = maybe "" (\GroupMember {localDisplayName = m} -> " by " <> m) m_ byMember m_ = case (m_, membership_) of
(Just GroupMember {groupMemberId = mId, localDisplayName = n}, Just GroupMember {groupMemberId = membershipId}) ->
" by " <> if mId == membershipId then "you" else n
_ -> ""
viewUsersList :: [UserInfo] -> [StyledString] viewUsersList :: [UserInfo] -> [StyledString]
viewUsersList = map userInfo . sortOn ldn viewUsersList = map userInfo . sortOn ldn
@ -325,7 +330,7 @@ viewChats ts = concatMap chatPreview . reverse
_ -> [] _ -> []
viewChatItem :: forall c d. MsgDirectionI d => ChatInfo c -> ChatItem c d -> Bool -> CurrentTime -> [StyledString] viewChatItem :: forall c d. MsgDirectionI d => ChatInfo c -> ChatItem c d -> Bool -> CurrentTime -> [StyledString]
viewChatItem chat ci@ChatItem {chatDir, meta = meta@CIMeta {itemDeleted}, content, quotedItem, file} doShow ts = viewChatItem chat ci@ChatItem {chatDir, meta = meta, content, quotedItem, file} doShow ts =
withItemDeleted <$> case chat of withItemDeleted <$> case chat of
DirectChat c -> case chatDir of DirectChat c -> case chatDir of
CIDirectSnd -> case content of CIDirectSnd -> case content of
@ -361,7 +366,9 @@ viewChatItem chat ci@ChatItem {chatDir, meta = meta@CIMeta {itemDeleted}, conten
quote = maybe [] (groupQuote g) quotedItem quote = maybe [] (groupQuote g) quotedItem
_ -> [] _ -> []
where where
withItemDeleted item = if isJust itemDeleted then item <> styled (colored Red) (T.unpack $ maybe "" (\t -> " [" <> t <> "]") (chatItemDeletedText ci)) else item withItemDeleted item = case chatItemDeletedText ci (chatInfoMembership chat) of
Nothing -> item
Just t -> item <> styled (colored Red) (" [" <> t <> "]")
withSndFile = withFile viewSentFileInvitation withSndFile = withFile viewSentFileInvitation
withRcvFile = withFile viewReceivedFileInvitation withRcvFile = withFile viewReceivedFileInvitation
withFile view dir l = maybe l (\f -> l <> view dir f ts meta) file withFile view dir l = maybe l (\f -> l <> view dir f ts meta) file
@ -434,7 +441,7 @@ viewItemDelete chat ChatItem {chatDir, meta, content = deletedContent} toItem by
deletedText_ :: Maybe Text deletedText_ :: Maybe Text
deletedText_ = case toItem of deletedText_ = case toItem of
Nothing -> Just "deleted" Nothing -> Just "deleted"
Just (AChatItem _ _ _ ci) -> chatItemDeletedText ci Just (AChatItem _ _ _ ci) -> chatItemDeletedText ci $ chatInfoMembership chat
prohibited = [styled (colored Red) ("[unexpected message deletion, please report to developers]" :: String)] prohibited = [styled (colored Red) ("[unexpected message deletion, please report to developers]" :: String)]
directQuote :: forall d'. MsgDirectionI d' => CIDirection 'CTDirect d' -> CIQuote 'CTDirect -> [StyledString] directQuote :: forall d'. MsgDirectionI d' => CIDirection 'CTDirect d' -> CIQuote 'CTDirect -> [StyledString]

View File

@ -1220,12 +1220,12 @@ testGroupMemberMessageDelete =
(alice <# "#team cath> hi") (alice <# "#team cath> hi")
(bob <# "#team cath> hi") (bob <# "#team cath> hi")
bob ##> "\\\\ #team @cath hi" bob ##> "\\\\ #team @cath hi"
bob <## "message marked deleted" bob <## "message marked deleted by you"
concurrently_ concurrently_
(alice <# "#team cath> [marked deleted by bob] hi") (alice <# "#team cath> [marked deleted by bob] hi")
(cath <# "#team cath> [marked deleted by bob] hi") (cath <# "#team cath> [marked deleted by bob] hi")
alice #$> ("/_get chat #1 count=1", chat, [(0, "hi [marked deleted by bob]")]) alice #$> ("/_get chat #1 count=1", chat, [(0, "hi [marked deleted by bob]")])
bob #$> ("/_get chat #1 count=1", chat, [(0, "hi [marked deleted]")]) bob #$> ("/_get chat #1 count=1", chat, [(0, "hi [marked deleted by you]")])
cath #$> ("/_get chat #1 count=1", chat, [(1, "hi [marked deleted by bob]")]) cath #$> ("/_get chat #1 count=1", chat, [(1, "hi [marked deleted by bob]")])
testGroupMemberMessageFullDelete :: HasCallStack => FilePath -> IO () testGroupMemberMessageFullDelete :: HasCallStack => FilePath -> IO ()
@ -1258,12 +1258,12 @@ testGroupMemberMessageFullDelete =
(alice <# "#team cath> hi") (alice <# "#team cath> hi")
(bob <# "#team cath> hi") (bob <# "#team cath> hi")
bob ##> "\\\\ #team @cath hi" bob ##> "\\\\ #team @cath hi"
bob <## "message deleted" bob <## "message deleted by you"
concurrently_ concurrently_
(alice <# "#team cath> [deleted by bob] hi") (alice <# "#team cath> [deleted by bob] hi")
(cath <# "#team cath> [deleted by bob] hi") (cath <# "#team cath> [deleted by bob] hi")
alice #$> ("/_get chat #1 count=1", chat, [(0, "moderated [deleted by bob]")]) alice #$> ("/_get chat #1 count=1", chat, [(0, "moderated [deleted by bob]")])
bob #$> ("/_get chat #1 count=1", chat, [(0, "Full deletion: on")]) -- fully deleted for bob bob #$> ("/_get chat #1 count=1", chat, [(0, "moderated [deleted by you]")])
cath #$> ("/_get chat #1 count=1", chat, [(1, "moderated [deleted by bob]")]) cath #$> ("/_get chat #1 count=1", chat, [(1, "moderated [deleted by bob]")])
testGroupAsync :: HasCallStack => FilePath -> IO () testGroupAsync :: HasCallStack => FilePath -> IO ()