Skip to content

Commit

Permalink
feat: Ask user about messaging in Degraded conversation (WPB-1771) (#…
Browse files Browse the repository at this point in the history
…2220)

* feat: Ask user about messaging in Degraded conversation

* Review fixes
  • Loading branch information
borichellow authored Nov 14, 2023
1 parent 785e56e commit b0c7e37
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 1 deletion.
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

0 comments on commit b0c7e37

Please sign in to comment.