feat(backup): add backup record reads to FirestoreConversationDataSource (getConversationsForBackup, getBackupRecords)
This commit is contained in:
parent
522823f739
commit
909d261b6c
|
|
@ -2,6 +2,7 @@ package app.closer.data.remote
|
|||
|
||||
import app.closer.crypto.CoupleEncryptionManager
|
||||
import app.closer.crypto.FieldEncryptor
|
||||
import app.closer.domain.model.BackupMessageRecord
|
||||
import app.closer.domain.model.Conversation
|
||||
import app.closer.domain.model.QuestionMessage
|
||||
import com.google.firebase.firestore.DocumentSnapshot
|
||||
|
|
@ -232,6 +233,58 @@ class FirestoreConversationDataSource @Inject constructor(
|
|||
return runCatching { aead.decrypt(cipher, coupleId.toByteArray(Charsets.UTF_8)) }.getOrNull()
|
||||
}
|
||||
|
||||
// ─── Backup reads (source of truth for the encrypted backup) ─────────────────────
|
||||
|
||||
/** All conversations for the couple as (id, type) — `main` + per-question threads. */
|
||||
suspend fun getConversationsForBackup(coupleId: String): List<Pair<String, String>> =
|
||||
runCatching {
|
||||
conversationsRef(coupleId).get().await().documents.map {
|
||||
it.id to (it.getString("type") ?: "main")
|
||||
}
|
||||
}.getOrDefault(emptyList())
|
||||
|
||||
/**
|
||||
* Backup records for one conversation with a resolved `createdAt` strictly after [afterCreatedAt]
|
||||
* (0 = from the beginning). Pending-write docs (null server timestamp) are skipped so the cursor
|
||||
* never straddles an unresolved message. Includes tombstones + reactions for fidelity.
|
||||
*/
|
||||
suspend fun getBackupRecords(
|
||||
coupleId: String,
|
||||
conversationId: String,
|
||||
conversationType: String,
|
||||
afterCreatedAt: Long
|
||||
): List<BackupMessageRecord> = runCatching {
|
||||
var query: Query = messagesRef(coupleId, conversationId).orderBy("createdAt", Query.Direction.ASCENDING)
|
||||
if (afterCreatedAt > 0L) {
|
||||
query = query.whereGreaterThan("createdAt", com.google.firebase.Timestamp(java.util.Date(afterCreatedAt)))
|
||||
}
|
||||
query.get().await().documents.mapNotNull { it.toBackupRecord(conversationId, conversationType) }
|
||||
}.getOrDefault(emptyList())
|
||||
|
||||
private fun DocumentSnapshot.toBackupRecord(
|
||||
conversationId: String,
|
||||
conversationType: String
|
||||
): BackupMessageRecord? {
|
||||
// Skip unresolved server timestamps — back them up once they settle.
|
||||
val createdAt = getTimestamp("createdAt")?.toDate()?.time ?: return null
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val reactions = (get("reactions") as? Map<String, String>).orEmpty()
|
||||
val type = getString("type") ?: "text"
|
||||
return BackupMessageRecord(
|
||||
messageId = id,
|
||||
conversationId = conversationId,
|
||||
conversationType = conversationType,
|
||||
authorUserId = getString("authorUserId") ?: "",
|
||||
type = type,
|
||||
encText = if (type == "text") getString("text") else null,
|
||||
mediaUrl = getString("mediaUrl"),
|
||||
durationMs = getLong("durationMs"),
|
||||
createdAt = createdAt,
|
||||
deleted = getBoolean("deleted") ?: false,
|
||||
reactions = reactions
|
||||
)
|
||||
}
|
||||
|
||||
// ─── Mappers / await helpers ────────────────────────────────────────────────────
|
||||
|
||||
private fun DocumentSnapshot.toConversation(
|
||||
|
|
|
|||
Loading…
Reference in New Issue