mirror of
https://github.com/bitwarden/android.git
synced 2026-10-23 03:23:53 -05:00
fix: Grant creating user manage access and fix permission checks
- Add organizationUserId to SyncResponseJson and Organization domain model to identify the current user's org membership ID - Include creating user with manage access in collection create request, matching web client behavior - Add limitCollectionCreation/limitCollectionDeletion to org model - Fix FAB visibility: use canManageCollections computed property that checks role (Owner/Admin) in addition to permissions flags, matching web client logic: !limitCollectionCreation || isAdmin || permissions
This commit is contained in:
1 parent
d0809a7c07
commit
5dcaf6e4a8
8 files changed
+62
-5
No files matched your search
@@ -31,7 +31,21 @@ data class Organization(
|
||||
val limitItemDeletion: Boolean,
|
||||
val shouldUseEvents: Boolean,
|
||||
val maxCollections: Int?,
|
||||
val limitCollectionCreation: Boolean,
|
||||
val limitCollectionDeletion: Boolean,
|
||||
val organizationUserId: String?,
|
||||
val canCreateNewCollections: Boolean,
|
||||
val canEditAnyCollection: Boolean,
|
||||
val canDeleteAnyCollection: Boolean,
|
||||
)
|
||||
) {
|
||||
/**
|
||||
* Whether the user can create new collections in this organization, accounting for
|
||||
* the organization's role and limitCollectionCreation setting.
|
||||
* Matches web client logic: `!limitCollectionCreation || isAdmin || permissions.createNewCollections`
|
||||
*/
|
||||
val canManageCollections: Boolean
|
||||
get() = !limitCollectionCreation ||
|
||||
role == OrganizationType.ADMIN ||
|
||||
role == OrganizationType.OWNER ||
|
||||
canCreateNewCollections
|
||||
}
|
||||
+3
@@ -29,6 +29,9 @@ fun SyncResponseJson.Profile.Organization.toOrganization(): Organization? =
|
||||
limitItemDeletion = this.limitItemDeletion,
|
||||
shouldUseEvents = this.shouldUseEvents,
|
||||
maxCollections = this.maxCollections,
|
||||
organizationUserId = this.organizationUserId,
|
||||
limitCollectionCreation = this.limitCollectionCreation,
|
||||
limitCollectionDeletion = this.limitCollectionDeletion,
|
||||
canCreateNewCollections = this.permissions.canCreateNewCollections,
|
||||
canEditAnyCollection = this.permissions.canEditAnyCollection,
|
||||
canDeleteAnyCollection = this.permissions.canDeleteAnyCollection,
|
||||
|
||||
@@ -11,9 +11,11 @@ import com.x8bit.bitwarden.data.vault.repository.model.UpdateCollectionResult
|
||||
interface CollectionManager {
|
||||
/**
|
||||
* Attempt to create a collection in the given [organizationId].
|
||||
* The [organizationUserId] is used to grant the creating user manage access.
|
||||
*/
|
||||
suspend fun createCollection(
|
||||
organizationId: String,
|
||||
organizationUserId: String?,
|
||||
collectionView: CollectionView,
|
||||
): CreateCollectionResult
|
||||
|
||||
|
||||
+17
-1
@@ -2,6 +2,7 @@ package com.x8bit.bitwarden.data.vault.manager
|
||||
|
||||
import com.bitwarden.collections.CollectionView
|
||||
import com.bitwarden.core.data.util.flatMap
|
||||
import com.bitwarden.network.model.CollectionAccessSelectionJson
|
||||
import com.bitwarden.network.model.CollectionJsonRequest
|
||||
import com.bitwarden.network.model.UpdateCollectionResponseJson
|
||||
import com.bitwarden.network.service.CollectionService
|
||||
@@ -27,16 +28,31 @@ class CollectionManagerImpl(
|
||||
|
||||
override suspend fun createCollection(
|
||||
organizationId: String,
|
||||
organizationUserId: String?,
|
||||
collectionView: CollectionView,
|
||||
): CreateCollectionResult {
|
||||
val userId = activeUserId
|
||||
?: return CreateCollectionResult.Error(error = NoActiveUserException())
|
||||
// Grant the creating user manage access, matching web client behavior.
|
||||
val users = organizationUserId?.let {
|
||||
listOf(
|
||||
CollectionAccessSelectionJson(
|
||||
id = it,
|
||||
readOnly = false,
|
||||
hidePasswords = false,
|
||||
manage = true,
|
||||
),
|
||||
)
|
||||
}
|
||||
return vaultSdkSource
|
||||
.encryptCollection(userId = userId, collectionView = collectionView)
|
||||
.flatMap {
|
||||
collectionService.createCollection(
|
||||
organizationId = organizationId,
|
||||
body = CollectionJsonRequest(name = it.name),
|
||||
body = CollectionJsonRequest(
|
||||
name = it.name,
|
||||
users = users,
|
||||
),
|
||||
)
|
||||
}
|
||||
.onSuccess {
|
||||
|
||||
+4
-3
@@ -12,6 +12,7 @@ import com.bitwarden.ui.platform.resource.BitwardenString
|
||||
import com.bitwarden.ui.util.Text
|
||||
import com.bitwarden.ui.util.asText
|
||||
import com.bitwarden.ui.util.concat
|
||||
import com.bitwarden.network.model.OrganizationType
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.Organization
|
||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||
@@ -88,7 +89,7 @@ class CollectionsViewModel @Inject constructor(
|
||||
// For now, use the first org with create permission.
|
||||
// TODO: If multiple orgs, show org picker (pending G1 decision).
|
||||
val org = authRepository.organizations.firstOrNull {
|
||||
it.canCreateNewCollections
|
||||
it.canManageCollections
|
||||
}
|
||||
if (org != null) {
|
||||
sendEvent(CollectionsEvent.NavigateToAddCollectionScreen(org.id))
|
||||
@@ -128,7 +129,7 @@ class CollectionsViewModel @Inject constructor(
|
||||
collectionList = vaultDataState.data
|
||||
.toDisplayItems(organizations),
|
||||
showAddButton = organizations.any {
|
||||
org -> org.canCreateNewCollections
|
||||
org -> org.canManageCollections
|
||||
},
|
||||
),
|
||||
)
|
||||
@@ -165,7 +166,7 @@ class CollectionsViewModel @Inject constructor(
|
||||
collectionList = vaultDataState.data
|
||||
.toDisplayItems(organizations),
|
||||
showAddButton = organizations.any {
|
||||
org -> org.canCreateNewCollections
|
||||
org -> org.canManageCollections
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
+6
@@ -12,6 +12,7 @@ import com.bitwarden.ui.platform.manager.snackbar.SnackbarRelayManager
|
||||
import com.bitwarden.ui.platform.resource.BitwardenString
|
||||
import com.bitwarden.ui.util.Text
|
||||
import com.bitwarden.ui.util.asText
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.CreateCollectionResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.DeleteCollectionResult
|
||||
@@ -38,6 +39,7 @@ private const val SLASH_CHAR = "/"
|
||||
@Suppress("TooManyFunctions", "LargeClass")
|
||||
class CollectionAddEditViewModel @Inject constructor(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
private val authRepository: AuthRepository,
|
||||
private val vaultRepository: VaultRepository,
|
||||
private val relayManager: SnackbarRelayManager<SnackbarRelay>,
|
||||
) : BaseViewModel<CollectionAddEditState, CollectionAddEditEvent, CollectionAddEditAction>(
|
||||
@@ -168,8 +170,12 @@ class CollectionAddEditViewModel @Inject constructor(
|
||||
viewModelScope.launch {
|
||||
when (collectionAddEditType) {
|
||||
is CollectionAddEditType.AddItem -> {
|
||||
val org = authRepository.organizations.find {
|
||||
it.id == collectionAddEditType.organizationId
|
||||
}
|
||||
val result = vaultRepository.createCollection(
|
||||
organizationId = collectionAddEditType.organizationId,
|
||||
organizationUserId = org?.organizationUserId,
|
||||
collectionView = CollectionView(
|
||||
id = null,
|
||||
organizationId = collectionAddEditType.organizationId,
|
||||
|
||||
@@ -18,6 +18,9 @@ fun createMockOrganization(
|
||||
limitItemDeletion: Boolean = false,
|
||||
shouldUseEvents: Boolean = false,
|
||||
maxCollections: Int? = null,
|
||||
organizationUserId: String? = null,
|
||||
limitCollectionCreation: Boolean = false,
|
||||
limitCollectionDeletion: Boolean = false,
|
||||
canCreateNewCollections: Boolean = false,
|
||||
canEditAnyCollection: Boolean = false,
|
||||
canDeleteAnyCollection: Boolean = false,
|
||||
@@ -33,6 +36,9 @@ fun createMockOrganization(
|
||||
limitItemDeletion = limitItemDeletion,
|
||||
shouldUseEvents = shouldUseEvents,
|
||||
maxCollections = maxCollections,
|
||||
organizationUserId = organizationUserId,
|
||||
limitCollectionCreation = limitCollectionCreation,
|
||||
limitCollectionDeletion = limitCollectionDeletion,
|
||||
canCreateNewCollections = canCreateNewCollections,
|
||||
canEditAnyCollection = canEditAnyCollection,
|
||||
canDeleteAnyCollection = canDeleteAnyCollection,
|
||||
|
||||
@@ -337,6 +337,9 @@ data class SyncResponseJson(
|
||||
@SerialName("userId")
|
||||
val userId: String?,
|
||||
|
||||
@SerialName("organizationUserId")
|
||||
val organizationUserId: String?,
|
||||
|
||||
@SerialName("useEvents")
|
||||
val shouldUseEvents: Boolean,
|
||||
|
||||
@@ -368,6 +371,12 @@ data class SyncResponseJson(
|
||||
|
||||
@SerialName("limitItemDeletion")
|
||||
val limitItemDeletion: Boolean = false,
|
||||
|
||||
@SerialName("limitCollectionCreation")
|
||||
val limitCollectionCreation: Boolean = false,
|
||||
|
||||
@SerialName("limitCollectionDeletion")
|
||||
val limitCollectionDeletion: Boolean = false,
|
||||
)
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user