Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Ask user about messaging in Degraded conversation (WPB-1771) #2220

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,11 @@ interface ConversationRepository {
*/
suspend fun updateProtocolLocally(conversationId: ConversationId, protocol: Conversation.Protocol): Either<CoreFailure, Boolean>

suspend fun observeDegradedConversationNotified(conversationId: QualifiedID): Flow<Boolean>
suspend fun setDegradedConversationNotifiedFlag(
conversationId: QualifiedID,
value: Boolean
): Either<CoreFailure, Unit>
}

@Suppress("LongParameterList", "TooManyFunctions", "LargeClass")
Expand Down Expand Up @@ -1056,6 +1061,19 @@ internal class ConversationDataSource internal constructor(
}
}

override suspend fun setDegradedConversationNotifiedFlag(
conversationId: QualifiedID,
value: Boolean
): Either<CoreFailure, Unit> =
wrapStorageRequest {
conversationDAO.updateDegradedConversationNotifiedFlag(conversationId.toDao(), value)
}

override suspend fun observeDegradedConversationNotified(conversationId: QualifiedID): Flow<Boolean> =
conversationDAO.observeDegradedConversationNotified(conversationId.toDao())
.wrapStorageRequest()
.mapToRightOr(true)

companion object {
const val DEFAULT_MEMBER_ROLE = "wire_member"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,4 +307,9 @@ class ConversationScope internal constructor(
val clearUsersTypingEvents: ClearUsersTypingEventsUseCase
get() = ClearUsersTypingEventsUseCaseImpl(typingIndicatorIncomingRepository)

val setUserInformedAboutVerificationBeforeMessagingUseCase: SetUserInformedAboutVerificationUseCase
get() = SetUserInformedAboutVerificationUseCaseImpl(conversationRepository)
val observeInformAboutVerificationBeforeMessagingFlagUseCase: ObserveDegradedConversationNotifiedUseCase
get() = ObserveDegradedConversationNotifiedUseCaseImpl(conversationRepository)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Wire
* Copyright (C) 2023 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.feature.conversation

import com.wire.kalium.logic.data.conversation.ConversationRepository
import com.wire.kalium.logic.data.id.ConversationId
import kotlinx.coroutines.flow.Flow

/**
* UseCase for observing if User was notified about verification degrading of conversation
*/
interface ObserveDegradedConversationNotifiedUseCase {
/**
* @return [Flow] of [Boolean], false means conversation's verification degraded and user needs to be notified
* true in other cases.
*/
suspend operator fun invoke(conversationId: ConversationId): Flow<Boolean>
}

class ObserveDegradedConversationNotifiedUseCaseImpl internal constructor(
private val conversationRepository: ConversationRepository
) : ObserveDegradedConversationNotifiedUseCase {

override suspend fun invoke(conversationId: ConversationId): Flow<Boolean> =
conversationRepository.observeDegradedConversationNotified(conversationId)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Wire
* Copyright (C) 2023 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.feature.conversation

import com.wire.kalium.logic.data.conversation.ConversationRepository
import com.wire.kalium.logic.data.id.ConversationId

/**
* UseCase for setting DegradedConversationNotified flag to true,
* means user was notified about verification changes and no need to do it again.
*/
interface SetUserInformedAboutVerificationUseCase {
suspend operator fun invoke(conversationId: ConversationId)
}

class SetUserInformedAboutVerificationUseCaseImpl internal constructor(
private val conversationRepository: ConversationRepository
) : SetUserInformedAboutVerificationUseCase {

override suspend fun invoke(conversationId: ConversationId) {
conversationRepository.setDegradedConversationNotifiedFlag(conversationId, true)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ CREATE TABLE Conversation (
archived_date_time INTEGER AS Instant,
-- mls_verification_status
verification_status TEXT AS ConversationEntity.VerificationStatus NOT NULL DEFAULT "NOT_VERIFIED",
proteus_verification_status TEXT AS ConversationEntity.VerificationStatus NOT NULL DEFAULT "NOT_VERIFIED"
proteus_verification_status TEXT AS ConversationEntity.VerificationStatus NOT NULL DEFAULT "NOT_VERIFIED",
degraded_conversation_notified INTEGER AS Boolean NOT NULL DEFAULT 1
);

-- Optimise comparisons and sorting by dates:
Expand Down Expand Up @@ -141,6 +142,11 @@ UPDATE Conversation
SET mls_degraded_notified = ?
WHERE qualified_id = :qualified_id;

updateDegradedConversationNotifiedFlag:
UPDATE Conversation
SET degraded_conversation_notified = ?
WHERE qualified_id = :qualified_id;

CREATE VIEW IF NOT EXISTS ConversationDetails AS
SELECT
Conversation.qualified_id AS qualifiedId,
Expand Down Expand Up @@ -401,6 +407,10 @@ UPDATE Conversation
SET verification_status = :status
WHERE qualified_id = :conversationId;

selectDegradedConversationNotified:
SELECT degraded_conversation_notified FROM Conversation
WHERE qualified_id = :conversationId;

clearContent {
DELETE FROM Asset WHERE key IN (SELECT asset_id FROM MessageAssetContent WHERE conversation_id = :conversationId);
DELETE FROM Message WHERE conversation_id = :conversationId;
Expand Down Expand Up @@ -430,4 +440,8 @@ BEGIN
"SENT",
"VISIBLE"
);

UPDATE Conversation
SET degraded_conversation_notified = (new.proteus_verification_status != "DEGRADED")
WHERE qualified_id = new.qualified_id;
END;
33 changes: 33 additions & 0 deletions persistence/src/commonMain/db_user/migrations/65.sqm
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import kotlin.Boolean;

ALTER TABLE Conversation
ADD COLUMN degraded_conversation_notified INTEGER AS Boolean NOT NULL DEFAULT 1;

DROP TRIGGER IF EXISTS addMessageAfterProteusVerificationStatusChange;

CREATE TRIGGER addMessageAfterProteusVerificationStatusChange
AFTER UPDATE ON Conversation
WHEN new.proteus_verification_status != old.proteus_verification_status
AND (new.proteus_verification_status = "VERIFIED" OR old.proteus_verification_status = "VERIFIED")
BEGIN
INSERT OR IGNORE INTO Message(id, content_type, conversation_id, creation_date, sender_user_id, sender_client_id, status, visibility)
VALUES(
(SELECT lower(hex(randomblob(4)) || '-' || lower(hex(randomblob(2))) || '-4' ||
substr(lower(hex(randomblob(2))),2) || '-a' || substr(lower(hex(randomblob(2))),2)
|| '-' || lower(hex(randomblob(6))))),
(CASE (new.proteus_verification_status)
WHEN "VERIFIED" THEN "CONVERSATION_VERIFIED_PROTEUS"
ELSE "CONVERSATION_DEGRADED_PROTEUS" END
),
new.qualified_id,
(SELECT CAST((julianday('now') - 2440587.5) * 86400 * 1000 AS INTEGER)),
(SELECT SelfUser.id FROM SelfUser LIMIT 1),
(SELECT Client.id FROM Client WHERE Client.user_id = (SELECT SelfUser.id FROM SelfUser LIMIT 1) LIMIT 1),
"SENT",
"VISIBLE"
);

UPDATE Conversation
SET degraded_conversation_notified = (new.proteus_verification_status != "DEGRADED")
WHERE qualified_id = new.qualified_id;
END;
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,6 @@ interface ConversationDAO {
suspend fun updateMlsVerificationStatus(verificationStatus: ConversationEntity.VerificationStatus, conversationId: QualifiedIDEntity)
suspend fun getConversationByGroupID(groupID: String): ConversationViewEntity
suspend fun observeUnreadArchivedConversationsCount(): Flow<Long>
suspend fun observeDegradedConversationNotified(conversationId: QualifiedIDEntity): Flow<Boolean>
suspend fun updateDegradedConversationNotifiedFlag(conversationId: QualifiedIDEntity, updateFlag: Boolean)
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import com.wire.kalium.persistence.dao.QualifiedIDEntity
import com.wire.kalium.persistence.dao.UserIDEntity
import com.wire.kalium.persistence.util.mapToList
import com.wire.kalium.persistence.util.mapToOne
import com.wire.kalium.persistence.util.mapToOneOrDefault
import com.wire.kalium.persistence.util.mapToOneOrNull
import com.wire.kalium.util.DateTimeUtil
import com.wire.kalium.util.DateTimeUtil.toIsoDateTimeString
Expand Down Expand Up @@ -373,6 +374,17 @@ internal class ConversationDAOImpl internal constructor(
conversationQueries.selectConversationIdsWithoutMetadata().executeAsList()
}

override suspend fun updateDegradedConversationNotifiedFlag(conversationId: QualifiedIDEntity, updateFlag: Boolean) =
withContext(coroutineContext) {
conversationQueries.updateDegradedConversationNotifiedFlag(updateFlag, conversationId)
}

override suspend fun observeDegradedConversationNotified(conversationId: QualifiedIDEntity): Flow<Boolean> =
conversationQueries.selectDegradedConversationNotified(conversationId)
.asFlow()
.mapToOneOrDefault(true)
.flowOn(coroutineContext)

override suspend fun clearContent(conversationId: QualifiedIDEntity) = withContext(coroutineContext) {
conversationQueries.clearContent(conversationId)
}
Expand Down
Loading