diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/notification/LocalNotificationMessageMapper.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/notification/LocalNotificationMessageMapper.kt index 2a1e58a43ad..0acb8118f33 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/notification/LocalNotificationMessageMapper.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/notification/LocalNotificationMessageMapper.kt @@ -124,13 +124,17 @@ class LocalNotificationMessageMapperImpl : LocalNotificationMessageMapper { ): List = list.groupBy { it.conversationId } .map { (conversationId, messages) -> + val isReplyAllowed = messages.first().run { + degradedConversationNotified + && (legalHoldStatus != ConversationEntity.LegalHoldStatus.ENABLED || legalHoldStatusChangeNotified) + } LocalNotification.Conversation( // todo: needs some clean up! id = conversationId.toModel(), conversationName = messages.first().conversationName ?: "", messages = messages.take(messageSizePerConversation).mapNotNull { mapMessage(it) }, isOneToOneConversation = messages.first().conversationType == ConversationEntity.Type.ONE_ON_ONE, - isReplyAllowed = messages.first().degradedConversationNotified + isReplyAllowed = isReplyAllowed ) } } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/message/MessageRepositoryTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/message/MessageRepositoryTest.kt index 507cdb71bba..20daf4044a2 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/message/MessageRepositoryTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/message/MessageRepositoryTest.kt @@ -870,7 +870,9 @@ class MessageRepositoryTest { conversationName = null, mutedStatus = ConversationEntity.MutedStatus.ALL_ALLOWED, conversationType = ConversationEntity.Type.ONE_ON_ONE, - degradedConversationNotified = true + degradedConversationNotified = true, + legalHoldStatus = ConversationEntity.LegalHoldStatus.ENABLED, + legalHoldStatusChangeNotified = true ) } } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/notification/LocalNotificationMessageMapperTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/notification/LocalNotificationMessageMapperTest.kt new file mode 100644 index 00000000000..15d2727fd05 --- /dev/null +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/notification/LocalNotificationMessageMapperTest.kt @@ -0,0 +1,156 @@ +/* + * Wire + * Copyright (C) 2024 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.logic.data.notification + +import com.wire.kalium.logic.framework.TestConversation +import com.wire.kalium.logic.framework.TestUser +import com.wire.kalium.persistence.dao.conversation.ConversationEntity +import com.wire.kalium.persistence.dao.message.MessageEntity +import com.wire.kalium.persistence.dao.message.NotificationMessageEntity +import kotlinx.datetime.Instant +import kotlin.test.BeforeTest +import kotlin.test.Test +import kotlin.test.assertEquals + +class LocalNotificationMessageMapperTest { + private lateinit var notificationMapper: LocalNotificationMessageMapper + + @BeforeTest + fun setup() { + notificationMapper = LocalNotificationMessageMapperImpl() + } + + @Test + fun givenListOfNotificationMessageEntity_whenDegradedConversationNotNotified_thenReplayDisabled() { + val result = notificationMapper.fromEntitiesToLocalNotifications( + listOf( + NOTIFICATION_ENTITY.copy(degradedConversationNotified = false), + ), + 10 + ) { _ -> TEXT_MASSAGE_NOTIFICATION } + + assertEquals(false, result[0].isReplyAllowed) + } + + @Test + fun givenListOfNotificationMessageEntity_whenLegalHoldDisabled_thenReplayAllowed() { + val result = notificationMapper.fromEntitiesToLocalNotifications( + listOf( + NOTIFICATION_ENTITY.copy( + legalHoldStatus = ConversationEntity.LegalHoldStatus.DISABLED, + legalHoldStatusChangeNotified = false + ) + ), + 10 + ) { _ -> TEXT_MASSAGE_NOTIFICATION } + + assertEquals(true, result[0].isReplyAllowed) + } + + @Test + fun givenListOfNotificationMessageEntity_whenLegalHoldEnabled_thenReplayDisabled() { + val result = notificationMapper.fromEntitiesToLocalNotifications( + listOf( + NOTIFICATION_ENTITY.copy( + legalHoldStatus = ConversationEntity.LegalHoldStatus.ENABLED, + legalHoldStatusChangeNotified = false + ) + ), + 10 + ) { _ -> TEXT_MASSAGE_NOTIFICATION } + + assertEquals(false, result[0].isReplyAllowed) + } + + @Test + fun givenListOfNotificationMessageEntity_whenLegalHoldEnabledAndUserNotified_thenReplayAllowed() { + val result = notificationMapper.fromEntitiesToLocalNotifications( + listOf( + NOTIFICATION_ENTITY.copy( + legalHoldStatus = ConversationEntity.LegalHoldStatus.ENABLED, + legalHoldStatusChangeNotified = true + ) + ), + 10 + ) { _ -> TEXT_MASSAGE_NOTIFICATION } + + assertEquals(true, result[0].isReplyAllowed) + } + + @Test + fun givenListOfNotificationMessageEntity_whenMessagePerConvSmaller_thenOlderMessagesFilteredOut() { + val result = notificationMapper.fromEntitiesToLocalNotifications( + listOf( + NOTIFICATION_ENTITY.copy( + id = "0", + legalHoldStatus = ConversationEntity.LegalHoldStatus.ENABLED, + legalHoldStatusChangeNotified = true + ), + NOTIFICATION_ENTITY.copy( + id = "1", + legalHoldStatus = ConversationEntity.LegalHoldStatus.ENABLED, + legalHoldStatusChangeNotified = true + ), + NOTIFICATION_ENTITY.copy( + id = "2", + legalHoldStatus = ConversationEntity.LegalHoldStatus.ENABLED, + legalHoldStatusChangeNotified = true + ), + NOTIFICATION_ENTITY.copy( + id = "3", + legalHoldStatus = ConversationEntity.LegalHoldStatus.ENABLED, + legalHoldStatusChangeNotified = true + ) + ), + 2 + ) { _ -> TEXT_MASSAGE_NOTIFICATION } + + assertEquals(2, result[0].messages.size) + } + + companion object { + private val TEXT_MASSAGE_NOTIFICATION = LocalNotificationMessage.Text( + messageId = "messageId", + author = LocalNotificationMessageAuthor("authorName", null), + text = "text of message", + time = Instant.DISTANT_PAST, + isQuotingSelfUser = false + ) + + private val NOTIFICATION_ENTITY = NotificationMessageEntity( + id = "message_id", + contentType = MessageEntity.ContentType.TEXT, + isSelfDelete = false, + senderUserId = TestUser.ENTITY_ID, + senderImage = null, + date = Instant.DISTANT_PAST, + senderName = "Sender", + text = "Some text in message", + assetMimeType = null, + isQuotingSelf = false, + conversationId = TestConversation.ENTITY_ID, + conversationName = null, + mutedStatus = ConversationEntity.MutedStatus.ALL_ALLOWED, + conversationType = ConversationEntity.Type.ONE_ON_ONE, + degradedConversationNotified = true, + legalHoldStatus = ConversationEntity.LegalHoldStatus.ENABLED, + legalHoldStatusChangeNotified = true + ) + } + +} diff --git a/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Notification.sq b/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Notification.sq index 606504f004e..f07a90dc149 100644 --- a/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Notification.sq +++ b/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Notification.sq @@ -16,6 +16,8 @@ WITH NumberedMessages AS ( c.muted_status AS mutedStatus, c.type AS conversationType, c.degraded_conversation_notified AS degradedConversationNotified, + c.legal_hold_status AS legalHoldStatus, + lhs.legal_hold_status_change_notified AS legalHoldStatusChangeNotified, ROW_NUMBER() OVER (PARTITION BY m.conversation_id ORDER BY m.creation_date DESC) AS row_num FROM Message m @@ -23,6 +25,8 @@ WITH NumberedMessages AS ( User u ON m.sender_user_id = u.qualified_id JOIN Conversation c ON m.conversation_id = c.qualified_id + JOIN + ConversationLegalHoldStatusChangeNotified AS lhs ON m.conversation_id == lhs.conversation_id AND (m.creation_date > IFNULL(c.last_notified_date, 0)) LEFT JOIN MessageAssetContent ac ON m.id = ac.message_id AND m.conversation_id = ac.conversation_id LEFT JOIN @@ -50,7 +54,9 @@ SELECT assetMimeType, mutedStatus, conversationType, - degradedConversationNotified + degradedConversationNotified, + legalHoldStatus, + legalHoldStatusChangeNotified FROM NumberedMessages WHERE diff --git a/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/message/MessageEntity.kt b/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/message/MessageEntity.kt index 54baa34818e..5a89b8cc834 100644 --- a/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/message/MessageEntity.kt +++ b/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/message/MessageEntity.kt @@ -385,7 +385,9 @@ data class NotificationMessageEntity( val conversationName: String?, val mutedStatus: ConversationEntity.MutedStatus, val conversationType: ConversationEntity.Type, - val degradedConversationNotified: Boolean + val degradedConversationNotified: Boolean, + val legalHoldStatus: ConversationEntity.LegalHoldStatus, + val legalHoldStatusChangeNotified: Boolean ) sealed class MessagePreviewEntityContent { diff --git a/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/message/MessageMapper.kt b/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/message/MessageMapper.kt index fafe04ef86a..399ae11c358 100644 --- a/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/message/MessageMapper.kt +++ b/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/message/MessageMapper.kt @@ -302,7 +302,9 @@ object MessageMapper { assetMimeType: String?, mutedStatus: ConversationEntity.MutedStatus, conversationType: ConversationEntity.Type, - degradedConversationNotified: Boolean + degradedConversationNotified: Boolean, + legalHoldStatus: ConversationEntity.LegalHoldStatus, + legalHoldStatusChangeNotified: Boolean ): NotificationMessageEntity = NotificationMessageEntity( id = id, contentType = contentType, @@ -318,7 +320,9 @@ object MessageMapper { conversationType = conversationType, isQuotingSelf = isQuotingSelf == true, isSelfDelete = isSelfDelete, - degradedConversationNotified = degradedConversationNotified + degradedConversationNotified = degradedConversationNotified, + legalHoldStatus = legalHoldStatus, + legalHoldStatusChangeNotified = legalHoldStatusChangeNotified ) private fun createMessageEntity( diff --git a/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/dao/message/MessageNotificationsTest.kt b/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/dao/message/MessageNotificationsTest.kt index 8a42f26d8f1..3f72b21300a 100644 --- a/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/dao/message/MessageNotificationsTest.kt +++ b/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/dao/message/MessageNotificationsTest.kt @@ -357,6 +357,8 @@ class MessageNotificationsTest : BaseMessageTest() { override suspend fun insertInitialData() { super.insertInitialData() // Always insert original messages + conversationDAO.updateLegalHoldStatusChangeNotified(TEST_CONVERSATION_1.id, true) + conversationDAO.updateLegalHoldStatusChangeNotified(TEST_CONVERSATION_2.id, true) } private companion object {