diff --git a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift index 7111524118..7814d962eb 100644 --- a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift +++ b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift @@ -380,8 +380,8 @@ struct ComposeView: View { Divider() } // preference checks should match checks in forwarding list - let simplexLinkProhibited = hasSimplexLink && !chat.groupFeatureEnabled(.simplexLinks) - let fileProhibited = composeState.attachmentPreview && !chat.groupFeatureEnabled(.files) + let simplexLinkProhibited = im.secondaryIMFilter == nil && hasSimplexLink && !chat.groupFeatureEnabled(.simplexLinks) + let fileProhibited = im.secondaryIMFilter == nil && composeState.attachmentPreview && !chat.groupFeatureEnabled(.files) let voiceProhibited = composeState.voicePreview && !chat.chatInfo.featureEnabled(.voice) if simplexLinkProhibited { msgNotAllowedView("SimpleX links not allowed", icon: "link") @@ -411,7 +411,8 @@ struct ComposeView: View { .padding(.bottom, 16) .padding(.leading, 12) .tint(theme.colors.primary) - if case let .group(g, _) = chat.chatInfo, + if im.secondaryIMFilter == nil, + case let .group(g, _) = chat.chatInfo, !g.fullGroupPreferences.files.on(for: g.membership) { b.disabled(true).onTapGesture { AlertManager.shared.showAlertMsg( diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ComposeView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ComposeView.kt index f377540a95..d3bc7bb824 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ComposeView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ComposeView.kt @@ -1039,8 +1039,8 @@ fun ComposeView( if (ctx is ComposeContextItem.ReportedItem) { ReportReasonView(ctx.reason) } - val simplexLinkProhibited = hasSimplexLink.value && !chat.groupFeatureEnabled(GroupFeature.SimplexLinks) - val fileProhibited = composeState.value.attachmentPreview && !chat.groupFeatureEnabled(GroupFeature.Files) + val simplexLinkProhibited = chatsCtx.secondaryContextFilter == null && hasSimplexLink.value && !chat.groupFeatureEnabled(GroupFeature.SimplexLinks) + val fileProhibited = chatsCtx.secondaryContextFilter == null && composeState.value.attachmentPreview && !chat.groupFeatureEnabled(GroupFeature.Files) val voiceProhibited = composeState.value.preview is ComposePreview.VoicePreview && !chat.chatInfo.featureEnabled(ChatFeature.Voice) if (composeState.value.preview !is ComposePreview.VoicePreview || composeState.value.editing) { if (simplexLinkProhibited) { @@ -1069,7 +1069,10 @@ fun ComposeView( Surface(color = MaterialTheme.colors.background, contentColor = MaterialTheme.colors.onBackground) { Divider() Row(Modifier.padding(end = 8.dp), verticalAlignment = Alignment.Bottom) { - val isGroupAndProhibitedFiles = chat.chatInfo is ChatInfo.Group && !chat.chatInfo.groupInfo.fullGroupPreferences.files.on(chat.chatInfo.groupInfo.membership) + val isGroupAndProhibitedFiles = + chatsCtx.secondaryContextFilter == null + && chat.chatInfo is ChatInfo.Group + && !chat.chatInfo.groupInfo.fullGroupPreferences.files.on(chat.chatInfo.groupInfo.membership) val attachmentClicked = if (isGroupAndProhibitedFiles) { { AlertManager.shared.showAlertMsg( diff --git a/src/Simplex/Chat/Library/Commands.hs b/src/Simplex/Chat/Library/Commands.hs index 7e0ff3b4c7..9c1b31efb3 100644 --- a/src/Simplex/Chat/Library/Commands.hs +++ b/src/Simplex/Chat/Library/Commands.hs @@ -3386,7 +3386,7 @@ processChatCommand' vr = \case findProhibited :: [ComposedMessageReq] -> Maybe GroupFeature findProhibited = foldr' - (\(ComposedMessage {fileSource, msgContent = mc}, _, (_, ft), _) acc -> prohibitedGroupContent gInfo membership mc ft fileSource True <|> acc) + (\(ComposedMessage {fileSource, msgContent = mc}, _, (_, ft), _) acc -> prohibitedGroupContent gInfo membership chatScopeInfo mc ft fileSource True <|> acc) Nothing processComposedMessages :: CM ChatResponse processComposedMessages = do diff --git a/src/Simplex/Chat/Library/Internal.hs b/src/Simplex/Chat/Library/Internal.hs index 6200fb2435..d3a0e6e59f 100644 --- a/src/Simplex/Chat/Library/Internal.hs +++ b/src/Simplex/Chat/Library/Internal.hs @@ -323,12 +323,12 @@ quoteContent mc qmc ciFile_ qFileName = maybe qText (T.pack . getFileName) ciFile_ qTextOrFile = if T.null qText then qFileName else qText -prohibitedGroupContent :: GroupInfo -> GroupMember -> MsgContent -> Maybe MarkdownList -> Maybe f -> Bool -> Maybe GroupFeature -prohibitedGroupContent gInfo@GroupInfo {membership = GroupMember {memberRole = userRole}} m mc ft file_ sent +prohibitedGroupContent :: GroupInfo -> GroupMember -> Maybe GroupChatScopeInfo -> MsgContent -> Maybe MarkdownList -> Maybe f -> Bool -> Maybe GroupFeature +prohibitedGroupContent gInfo@GroupInfo {membership = GroupMember {memberRole = userRole}} m scopeInfo mc ft file_ sent | isVoice mc && not (groupFeatureMemberAllowed SGFVoice m gInfo) = Just GFVoice - | not (isVoice mc) && isJust file_ && not (groupFeatureMemberAllowed SGFFiles m gInfo) = Just GFFiles - | isReport mc && (badReportUser || not (groupFeatureAllowed SGFReports gInfo)) = Just GFReports - | prohibitedSimplexLinks gInfo m ft = Just GFSimplexLinks + | isNothing scopeInfo && not (isVoice mc) && isJust file_ && not (groupFeatureMemberAllowed SGFFiles m gInfo) = Just GFFiles + | isNothing scopeInfo && isReport mc && (badReportUser || not (groupFeatureAllowed SGFReports gInfo)) = Just GFReports + | isNothing scopeInfo && prohibitedSimplexLinks gInfo m ft = Just GFSimplexLinks | otherwise = Nothing where -- admins cannot send reports, non-admins cannot receive reports diff --git a/src/Simplex/Chat/Library/Subscriber.hs b/src/Simplex/Chat/Library/Subscriber.hs index e554ed4424..80e287f414 100644 --- a/src/Simplex/Chat/Library/Subscriber.hs +++ b/src/Simplex/Chat/Library/Subscriber.hs @@ -1648,62 +1648,60 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = e -> throwError e newGroupContentMessage :: GroupInfo -> GroupMember -> MsgContainer -> RcvMessage -> UTCTime -> Bool -> CM () - newGroupContentMessage gInfo m@GroupMember {memberId, memberRole} mc msg@RcvMessage {sharedMsgId_} brokerTs forwarded - | blockedByAdmin m = createBlockedByAdmin - | otherwise = case prohibitedGroupContent gInfo m content ft_ fInv_ False of - Just f -> rejected f - Nothing -> - withStore' (\db -> getCIModeration db vr user gInfo memberId sharedMsgId_) >>= \case - Just ciModeration -> do - applyModeration ciModeration - withStore' $ \db -> deleteCIModeration db gInfo memberId sharedMsgId_ - Nothing -> createContentItem + newGroupContentMessage gInfo m@GroupMember {memberId, memberRole} mc msg@RcvMessage {sharedMsgId_} brokerTs forwarded = do + (gInfo', m', scopeInfo) <- mkGetMessageChatScope vr user gInfo m msgScope_ + if blockedByAdmin m' + then createBlockedByAdmin gInfo' m' scopeInfo + else + case prohibitedGroupContent gInfo' m' scopeInfo content ft_ fInv_ False of + Just f -> rejected gInfo' m' scopeInfo f + Nothing -> + withStore' (\db -> getCIModeration db vr user gInfo' memberId sharedMsgId_) >>= \case + Just ciModeration -> do + applyModeration gInfo' m' scopeInfo ciModeration + withStore' $ \db -> deleteCIModeration db gInfo' memberId sharedMsgId_ + Nothing -> createContentItem gInfo' m' scopeInfo where - rejected f = newChatItem (ciContentNoParse $ CIRcvGroupFeatureRejected f) Nothing Nothing False - timed' = if forwarded then rcvCITimed_ (Just Nothing) itemTTL else rcvGroupCITimed gInfo itemTTL + rejected gInfo' m' scopeInfo f = newChatItem gInfo' m' scopeInfo (ciContentNoParse $ CIRcvGroupFeatureRejected f) Nothing Nothing False + timed' gInfo' = if forwarded then rcvCITimed_ (Just Nothing) itemTTL else rcvGroupCITimed gInfo' itemTTL live' = fromMaybe False live_ ExtMsgContent content mentions fInv_ itemTTL live_ msgScope_ = mcExtMsgContent mc ts@(_, ft_) = msgContentTexts content - saveRcvCI gInfo' scopeInfo m' = saveRcvChatItem' user (CDGroupRcv gInfo' scopeInfo m') msg sharedMsgId_ brokerTs - createBlockedByAdmin - | groupFeatureAllowed SGFFullDelete gInfo = do - (gInfo', m', scopeInfo) <- mkGetMessageChatScope vr user gInfo m msgScope_ + saveRcvCI gInfo' m' scopeInfo = saveRcvChatItem' user (CDGroupRcv gInfo' scopeInfo m') msg sharedMsgId_ brokerTs + createBlockedByAdmin gInfo' m' scopeInfo + | groupFeatureAllowed SGFFullDelete gInfo' = do -- ignores member role when blocked by admin - (ci, cInfo) <- saveRcvCI gInfo' scopeInfo m' (ciContentNoParse CIRcvBlocked) Nothing timed' False M.empty + (ci, cInfo) <- saveRcvCI gInfo' m' scopeInfo (ciContentNoParse CIRcvBlocked) Nothing (timed' gInfo') False M.empty ci' <- withStore' $ \db -> updateGroupCIBlockedByAdmin db user gInfo' ci brokerTs groupMsgToView cInfo ci' | otherwise = do - file_ <- processFileInv - (ci, cInfo) <- createNonLive file_ - ci' <- withStore' $ \db -> markGroupCIBlockedByAdmin db user gInfo ci + file_ <- processFileInv m' + (ci, cInfo) <- createNonLive gInfo' m' scopeInfo file_ + ci' <- withStore' $ \db -> markGroupCIBlockedByAdmin db user gInfo' ci groupMsgToView cInfo ci' - applyModeration CIModeration {moderatorMember = moderator@GroupMember {memberRole = moderatorRole}, moderatedAt} + applyModeration gInfo' m' scopeInfo CIModeration {moderatorMember = moderator@GroupMember {memberRole = moderatorRole}, moderatedAt} | moderatorRole < GRModerator || moderatorRole < memberRole = - createContentItem - | groupFeatureMemberAllowed SGFFullDelete moderator gInfo = do - (gInfo', m', scopeInfo) <- mkGetMessageChatScope vr user gInfo m msgScope_ - (ci, cInfo) <- saveRcvCI gInfo' scopeInfo m' (ciContentNoParse CIRcvModerated) Nothing timed' False M.empty + createContentItem gInfo' m' scopeInfo + | groupFeatureMemberAllowed SGFFullDelete moderator gInfo' = do + (ci, cInfo) <- saveRcvCI gInfo' m' scopeInfo (ciContentNoParse CIRcvModerated) Nothing (timed' gInfo') False M.empty ci' <- withStore' $ \db -> updateGroupChatItemModerated db user gInfo' ci moderator moderatedAt groupMsgToView cInfo ci' | otherwise = do - (gInfo', _m', scopeInfo) <- mkGetMessageChatScope vr user gInfo m msgScope_ - file_ <- processFileInv - (ci, _cInfo) <- createNonLive file_ + file_ <- processFileInv m' + (ci, _cInfo) <- createNonLive gInfo' m' scopeInfo file_ deletions <- markGroupCIsDeleted user gInfo' scopeInfo [CChatItem SMDRcv ci] (Just moderator) moderatedAt toView $ CEvtChatItemsDeleted user deletions False False - createNonLive file_ = do - (gInfo', m', scopeInfo) <- mkGetMessageChatScope vr user gInfo m msgScope_ - saveRcvCI gInfo' scopeInfo m' (CIRcvMsgContent content, ts) (snd <$> file_) timed' False mentions - createContentItem = do - file_ <- processFileInv - newChatItem (CIRcvMsgContent content, ts) (snd <$> file_) timed' live' - when (showMessages $ memberSettings m) $ autoAcceptFile file_ - processFileInv = - processFileInvitation fInv_ content $ \db -> createRcvGroupFileTransfer db userId m - newChatItem ciContent ciFile_ timed_ live = do - let mentions' = if showMessages (memberSettings m) then mentions else [] - (gInfo', m', scopeInfo) <- mkGetMessageChatScope vr user gInfo m msgScope_ - (ci, cInfo) <- saveRcvCI gInfo' scopeInfo m' ciContent ciFile_ timed_ live mentions' + createNonLive gInfo' m' scopeInfo file_ = do + saveRcvCI gInfo' m' scopeInfo (CIRcvMsgContent content, ts) (snd <$> file_) (timed' gInfo') False mentions + createContentItem gInfo' m' scopeInfo = do + file_ <- processFileInv m' + newChatItem gInfo' m' scopeInfo (CIRcvMsgContent content, ts) (snd <$> file_) (timed' gInfo') live' + when (showMessages $ memberSettings m') $ autoAcceptFile file_ + processFileInv m' = + processFileInvitation fInv_ content $ \db -> createRcvGroupFileTransfer db userId m' + newChatItem gInfo' m' scopeInfo ciContent ciFile_ timed_ live = do + let mentions' = if showMessages (memberSettings m') then mentions else [] + (ci, cInfo) <- saveRcvCI gInfo' m' scopeInfo ciContent ciFile_ timed_ live mentions' ci' <- blockedMember m' ci $ withStore' $ \db -> markGroupChatItemBlocked db user gInfo' ci reactions <- maybe (pure []) (\sharedMsgId -> withStore' $ \db -> getGroupCIReactions db gInfo' memberId sharedMsgId) sharedMsgId_ groupMsgToView cInfo ci' {reactions}