Skip to content
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 @@ -188,6 +188,26 @@ class TransferManager internal constructor(
transferController.getTransfersCountFlow().catchTransfersDbExceptions(crashReport).onEmpty { emit(0L) },
) { countInRoom, countInRealm -> countInRoom > 0 || countInRealm > 0L }.distinctUntilChanged()

/**
* Emits 'true' if there is at least one sent transfer for the current account, among all organizations of this account.
*
* Unlike [hasAnyTransferFlow], transfers belonging to another account and received transfers are ignored here.
*/
fun hasAccountTransferFlow(): Flow<Boolean> = userDependentFlow(
flowForAuthUser = { userId, _ ->
transferDao.accountTransfersCountFlow(userId, direction = TransferDirection.SENT).map { it > 0 }
},
flowForGuestUser = {
combine(
transferDao.accountTransfersCountFlow(userId = GuestUser.id, direction = TransferDirection.SENT),
transferController.getTransfersCountFlow(TransferDirection.SENT)
.catchTransfersDbExceptions(crashReport)
.onEmpty { emit(0L) },
) { countInRoom, countInRealm -> countInRoom > 0 || countInRealm > 0L }
},
merge = { hasAuthTransfer, hasGuestTransfer -> hasAuthTransfer || hasGuestTransfer },
).distinctUntilChanged().catchTransfersDbExceptions(crashReport)

@OptIn(ExperimentalCoroutinesApi::class)
fun getTransferFlow(transferUUID: String): Flow<TransferUi?> = userDependentFlow(
flowForAuthUser = { userId, _ ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ import kotlin.time.ExperimentalTime
@Dao
interface TransferDao {

@Query("SELECT * FROM TransferDB WHERE userOwnerId=:userId AND transferStatus!=:uploadStatus ORDER BY createdAt DESC")
@Query("SELECT * FROM TransferDB WHERE userOwnerId=:userId AND transferStatus!=:excludedUploadStatus ORDER BY createdAt DESC")
fun transfersFlow(
userId: Long,
uploadStatus: TransferStatus = TransferStatus.PENDING_UPLOAD,
excludedUploadStatus: TransferStatus = TransferStatus.PENDING_UPLOAD,
): Flow<List<TransferDB>>

@get:Query("SELECT * FROM TransferDB ORDER BY createdAt DESC")
Expand All @@ -51,31 +51,41 @@ interface TransferDao {
@OptIn(ExperimentalTime::class)
@Query(
"""SELECT * FROM TransferDB
WHERE userOwnerId=:userId AND transferStatus!=:uploadStatus AND transferDirection=:direction AND expiresAt >= :currentTime
WHERE userOwnerId=:userId AND transferStatus!=:excludedUploadStatus AND transferDirection=:direction AND expiresAt >= :currentTime
AND (organizationAccountId=:organizationAccountId OR (:organizationAccountId IS NULL AND organizationAccountId IS NULL))"""
)
fun validTransfersFlow(
userId: Long,
organizationAccountId: Long?,
direction: TransferDirection,
uploadStatus: TransferStatus = TransferStatus.PENDING_UPLOAD,
excludedUploadStatus: TransferStatus = TransferStatus.PENDING_UPLOAD,
currentTime: Long = Clock.System.now().epochSeconds,
): Flow<List<TransferDB>>

@OptIn(ExperimentalTime::class)
@Query(
"""SELECT * FROM TransferDB
WHERE userOwnerId=:userId AND transferStatus!=:uploadStatus AND transferDirection=:direction AND expiresAt < :currentTime
WHERE userOwnerId=:userId AND transferStatus!=:excludedUploadStatus AND transferDirection=:direction AND expiresAt < :currentTime
AND (organizationAccountId=:organizationAccountId OR (:organizationAccountId IS NULL AND organizationAccountId IS NULL))"""
)
fun expiredTransfersFlow(
userId: Long,
organizationAccountId: Long?,
direction: TransferDirection,
uploadStatus: TransferStatus = TransferStatus.PENDING_UPLOAD,
excludedUploadStatus: TransferStatus = TransferStatus.PENDING_UPLOAD,
currentTime: Long = Clock.System.now().epochSeconds,
): Flow<List<TransferDB>>

@Query(
"""SELECT count(*) FROM TransferDB
WHERE userOwnerId=:userId AND transferStatus!=:excludedUploadStatus AND transferDirection=:direction"""
)
fun accountTransfersCountFlow(
userId: Long,
direction: TransferDirection,
excludedUploadStatus: TransferStatus = TransferStatus.PENDING_UPLOAD,
): Flow<Int>
Comment thread
aymericmariaux marked this conversation as resolved.

@Query("SELECT * FROM TransferDB WHERE userOwnerId=:userId AND id=:transferId LIMIT 1")
fun transferFlow(userId: Long, transferId: String): Flow<TransferDB?>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ class TransfersTest : RobolectricTestsBase() {

private lateinit var appDatabase: AppDatabase
private val userId = 0L
private val otherUserId = 1L
private val orgA = 10L
private val orgB = 20L
private val transferDao get() = appDatabase.getTransferDao()

@BeforeTest
Expand Down Expand Up @@ -124,6 +127,99 @@ class TransfersTest : RobolectricTestsBase() {
assertEquals(2, count, "The transfers count must be 2")
}

@Test
fun accountTransfersCountFlow_countsTransfersOfAllOrganizationsOfTheAccount() = runTest {
insertTransfer("noOrg", userOwnerId = userId, direction = TransferDirection.SENT)
insertTransfer("orgA1", userOwnerId = userId, direction = TransferDirection.SENT, organizationAccountId = orgA)
insertTransfer("orgA2", userOwnerId = userId, direction = TransferDirection.SENT, organizationAccountId = orgA)
insertTransfer("orgB1", userOwnerId = userId, direction = TransferDirection.SENT, organizationAccountId = orgB)

val count = transferDao.accountTransfersCountFlow(userId, TransferDirection.SENT).first()

assertEquals(4, count, "All the transfers of the account must be counted, whatever their organization")
}

@Test
fun accountTransfersCountFlow_ignoresTransfersOfOtherAccounts() = runTest {
insertTransfer("mine", userOwnerId = userId, direction = TransferDirection.SENT, organizationAccountId = orgA)
insertTransfer("theirs1", userOwnerId = otherUserId, direction = TransferDirection.SENT, organizationAccountId = orgA)
insertTransfer("theirs2", userOwnerId = otherUserId, direction = TransferDirection.SENT)

assertEquals(
expected = 1,
actual = transferDao.accountTransfersCountFlow(userId, TransferDirection.SENT).first(),
message = "Only the transfers owned by the given user must be counted",
)
assertEquals(
expected = 2,
actual = transferDao.accountTransfersCountFlow(otherUserId, TransferDirection.SENT).first(),
message = "Each account must count its own transfers",
)
}

@Test
fun accountTransfersCountFlow_returnsZero_whenTheAccountHasNoTransfer() = runTest {
insertTransfer("theirs", userOwnerId = otherUserId, direction = TransferDirection.SENT, organizationAccountId = orgA)

val count = transferDao.accountTransfersCountFlow(userId, TransferDirection.SENT).first()

assertEquals(0, count, "An account without any transfer must be counted as 0")
}

@Test
fun accountTransfersCountFlow_filtersByDirection() = runTest {
insertTransfer("sent1", userOwnerId = userId, direction = TransferDirection.SENT)
insertTransfer("sent2", userOwnerId = userId, direction = TransferDirection.SENT, organizationAccountId = orgA)
insertTransfer("received1", userOwnerId = userId, direction = TransferDirection.RECEIVED)
insertTransfer("received2", userOwnerId = userId, direction = TransferDirection.RECEIVED, organizationAccountId = orgA)
insertTransfer("received3", userOwnerId = userId, direction = TransferDirection.RECEIVED, organizationAccountId = orgB)

assertEquals(
expected = 2,
actual = transferDao.accountTransfersCountFlow(userId, TransferDirection.SENT).first(),
message = "Received transfers must not be counted when asking for sent ones",
)
assertEquals(
expected = 3,
actual = transferDao.accountTransfersCountFlow(userId, TransferDirection.RECEIVED).first(),
message = "Sent transfers must not be counted when asking for received ones",
)
}

@Test
fun accountTransfersCountFlow_excludesPendingUploads() = runTest {
insertTransfer("ready", userOwnerId = userId, direction = TransferDirection.SENT)
insertTransfer(
id = "pendingNoOrg",
userOwnerId = userId,
direction = TransferDirection.SENT,
organizationAccountId = null,
transferStatus = TransferStatus.PENDING_UPLOAD
)
insertTransfer(
id = "pendingOrgA",
userOwnerId = userId,
direction = TransferDirection.SENT,
organizationAccountId = orgA,
transferStatus = TransferStatus.PENDING_UPLOAD
)

assertEquals(
expected = 1,
actual = transferDao.accountTransfersCountFlow(userId, TransferDirection.SENT).first(),
message = "Pending uploads must not be counted, whatever their organization",
)
assertEquals(
expected = 2,
actual = transferDao.accountTransfersCountFlow(
userId,
TransferDirection.SENT,
excludedUploadStatus = TransferStatus.READY
).first(),
message = "The excluded status must be the one given as parameter",
)
}

@Test
fun canGetTransferFlow() = runTest {
val transfer = DummyTransferForV2.transfer1
Expand Down Expand Up @@ -583,6 +679,24 @@ class TransfersTest : RobolectricTestsBase() {
}
}

private suspend fun insertTransfer(
id: String,
userOwnerId: Long,
direction: TransferDirection,
organizationAccountId: Long? = null,
transferStatus: TransferStatus = TransferStatus.READY,
) {
transferDao.upsertTransfer(
DummyTransferForV2.notExpired.copy(
id = id,
userOwnerId = userOwnerId,
transferDirection = direction,
organizationAccountId = organizationAccountId,
transferStatus = transferStatus,
)
)
}

private suspend fun insertTransfer(
transfer: TransferDB,
transferDirection: TransferDirection,
Expand Down
Loading