Coverage Summary for Class: LeaveWorkspaceUseCase (com.georgeci.moneysurfer.domain.usecase)
| Class |
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
| LeaveWorkspaceUseCase |
100%
(2/2)
|
81.2%
(13/16)
|
95.7%
(22/23)
|
97.2%
(351/361)
|
| LeaveWorkspaceUseCase$Companion |
|
| LeaveWorkspaceUseCase$invoke$1 |
|
| Total |
100%
(2/2)
|
81.2%
(13/16)
|
95.7%
(22/23)
|
97.2%
(351/361)
|
package com.georgeci.moneysurfer.domain.usecase
import arrow.core.Either
import arrow.core.raise.either
import arrow.core.raise.ensure
import co.touchlab.kermit.Logger
import com.georgeci.moneysurfer.domain.auth.SessionPointers
import com.georgeci.moneysurfer.domain.logging.redactUid
import com.georgeci.moneysurfer.domain.model.WorkspaceMemberStatus
import com.georgeci.moneysurfer.domain.model.WorkspaceRole
import com.georgeci.moneysurfer.domain.primitives.WorkspaceId
import com.georgeci.moneysurfer.domain.repositories.WorkspaceMemberRepository
import kotlinx.coroutines.flow.first
import org.koin.core.annotation.Single
/**
* Current user voluntarily leaves a workspace: status → LEFT.
*
* Refuses if caller is the last OWNER ([InviteError.OwnerCannotLeave]) — `TransferOwnership`
* is post-v1 (md/members.md decision 5). Until that lands, the only way out for the lone
* owner is to delete/clear the workspace.
*/
@Single
class LeaveWorkspaceUseCase(
private val memberRepository: WorkspaceMemberRepository,
private val session: SessionPointers,
) {
private val log = Logger.withTag(TAG)
suspend operator fun invoke(workspaceId: WorkspaceId): Either<InviteError, Unit> = either {
val callerId = session.currentUserId.first()
?: raise(InviteError.NoCurrentUser)
val members = memberRepository.getByWorkspaceId(workspaceId).first()
val self = members.firstOrNull { it.userId == callerId }
?: raise(InviteError.InviteNotFound)
ensure(self.status == WorkspaceMemberStatus.ACTIVE) { InviteError.InviteNotPending }
if (self.role == WorkspaceRole.OWNER) {
val otherActiveOwners = members.count {
it.role == WorkspaceRole.OWNER &&
it.status == WorkspaceMemberStatus.ACTIVE &&
it.userId != callerId
}
ensure(otherActiveOwners >= 1) { InviteError.OwnerCannotLeave }
}
Either.catch { memberRepository.markLeft(callerId, workspaceId) }
.onLeft { log.e(it) { "[local] markLeft failed uid=${callerId.value.redactUid()}" } }
.mapLeft { InviteError.LocalWriteFailed(it) }
.bind()
log.i { "[done] uid=${callerId.value.redactUid()} wid=${workspaceId.value}" }
}
private companion object {
const val TAG = "LeaveWorkspace"
}
}