mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-2192 Tech | Object permissions (#1986)
This commit is contained in:
parent
c1b0263dfa
commit
210b7e70a3
5 changed files with 509 additions and 2 deletions
|
@ -86,6 +86,7 @@ object Relations {
|
|||
const val SPACE_LOCAL_STATUS = "spaceLocalStatus"
|
||||
|
||||
const val IDENTITY_PROFILE_LINK = "identityProfileLink"
|
||||
const val PROFILE_OWNER_IDENTITY = "profileOwnerIdentity"
|
||||
|
||||
const val PARTICIPANT_STATUS = "participantStatus"
|
||||
const val PARTICIPANT_PERMISSIONS = "participantPermissions"
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package com.anytypeio.anytype.core_models.permissions
|
||||
|
||||
sealed class EditBlocksPermission {
|
||||
data object Edit : EditBlocksPermission()
|
||||
data object ReadOnly: EditBlocksPermission()
|
||||
}
|
|
@ -0,0 +1,187 @@
|
|||
package com.anytypeio.anytype.core_models.permissions
|
||||
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.ObjectType
|
||||
import com.anytypeio.anytype.core_models.ObjectTypeIds
|
||||
import com.anytypeio.anytype.core_models.ObjectView
|
||||
import com.anytypeio.anytype.core_models.Relations
|
||||
import com.anytypeio.anytype.core_models.SupportedLayouts
|
||||
import com.anytypeio.anytype.core_models.getSingleValue
|
||||
import com.anytypeio.anytype.core_models.restrictions.ObjectRestriction
|
||||
|
||||
/**
|
||||
* Represents a set of user permissions for a given object.
|
||||
*
|
||||
* @property canArchive Indicates whether this object can be archived.
|
||||
* @property canDelete Indicates whether this object can be permanently deleted.
|
||||
* @property canChangeType Indicates whether the object's type can be changed.
|
||||
* @property canTemplateSetAsDefault Indicates whether this template object can be set as the default for a type.
|
||||
* @property canApplyTemplates Indicates whether templates can be applied to this object.
|
||||
* @property canMakeAsTemplate Indicates whether this object can be turned into a template.
|
||||
* @property canDuplicate Indicates whether this object can be duplicated.
|
||||
* @property canUndoRedo Indicates whether undo and redo operations are allowed for this object.
|
||||
* @property canFavorite Indicates whether this object can be marked as a favorite.
|
||||
* @property canLinkItself Indicates whether this object can be linked to itself (if applicable).
|
||||
* @property canLock Indicates whether this object can be locked.
|
||||
* @property canChangeIcon Indicates whether the object icon can be changed.
|
||||
* @property canChangeCover Indicates whether the object cover can be changed.
|
||||
* @property canChangeLayout Indicates whether the layout of the object can be changed.
|
||||
* @property canEditRelationValues Indicates whether relation values on this object can be edited.
|
||||
* @property canEditRelationsList Indicates whether the list of relations for this object can be edited.
|
||||
* @property canEditBlocks Indicates whether blocks in this object can be edited.
|
||||
* @property canEditDetails Indicates whether general details on this object can be edited.
|
||||
* @property editBlocks Specifies the permission level regarding block editing (e.g., read-only vs. editable).
|
||||
* @property canCreateObjectThisType Indicates whether object with this type can be created.
|
||||
*/
|
||||
data class ObjectPermissions(
|
||||
val canArchive: Boolean = false,
|
||||
val canDelete: Boolean = false,
|
||||
val canChangeType: Boolean = false,
|
||||
val canTemplateSetAsDefault: Boolean = false,
|
||||
val canApplyTemplates: Boolean = false,
|
||||
val canMakeAsTemplate: Boolean = false,
|
||||
val canDuplicate: Boolean = false,
|
||||
val canUndoRedo: Boolean = false,
|
||||
val canFavorite: Boolean = false,
|
||||
val canLinkItself: Boolean = false,
|
||||
val canLock: Boolean = false,
|
||||
val canChangeIcon: Boolean = false,
|
||||
val canChangeCover: Boolean = false,
|
||||
val canChangeLayout: Boolean = false,
|
||||
val canEditRelationValues: Boolean = false,
|
||||
val canEditRelationsList: Boolean = false,
|
||||
val canEditBlocks: Boolean = false,
|
||||
val canEditDetails: Boolean = false,
|
||||
val editBlocks: EditBlocksPermission,
|
||||
val canCreateObjectThisType: Boolean = false
|
||||
)
|
||||
|
||||
/**
|
||||
* Converts this [ObjectView] instance into an [ObjectPermissions] by inspecting
|
||||
* its current state (e.g., archived, locked) and the user's participant edit rights.
|
||||
*
|
||||
* @param participantCanEdit Flag indicating whether the participant can perform edits.
|
||||
* @return An [ObjectPermissions] instance that encapsulates the allowed actions.
|
||||
*/
|
||||
fun ObjectView.toObjectPermissions(
|
||||
participantCanEdit: Boolean
|
||||
): ObjectPermissions {
|
||||
val rootBlock = blocks.find { it.id == root }
|
||||
val isLocked = rootBlock?.fields?.isLocked == true
|
||||
val isArchived = details[root]?.getSingleValue<Boolean>(Relations.IS_ARCHIVED) == true
|
||||
|
||||
val objTypeId = details[root]?.getSingleValue<String>(Relations.TYPE)
|
||||
val typeUniqueKey = if (objTypeId != null) {
|
||||
details[objTypeId]?.getSingleValue<Id>(Relations.TYPE_UNIQUE_KEY)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
val isTemplateObject = (typeUniqueKey == ObjectTypeIds.TEMPLATE)
|
||||
|
||||
val currentLayout = when (val value = details[root]?.getOrDefault(Relations.LAYOUT, null)) {
|
||||
is Double -> ObjectType.Layout.entries.singleOrNull { layout ->
|
||||
layout.code == value.toInt()
|
||||
}
|
||||
|
||||
else -> null
|
||||
}
|
||||
|
||||
val canEditRelations = !isLocked && !isArchived && participantCanEdit
|
||||
val canEdit = canEditRelations && !SupportedLayouts.isFileLayout(currentLayout)
|
||||
val canApplyUneditableActions = !isArchived && participantCanEdit
|
||||
val isProfileOwnerIdentity =
|
||||
details[root]?.getSingleValue<String>(Relations.PROFILE_OWNER_IDENTITY)
|
||||
val canEditDetails = !objectRestrictions.contains(ObjectRestriction.DETAILS)
|
||||
|
||||
val editBlocksPermission = when {
|
||||
isLocked -> EditBlocksPermission.ReadOnly
|
||||
isArchived -> EditBlocksPermission.ReadOnly
|
||||
!participantCanEdit -> EditBlocksPermission.ReadOnly
|
||||
objectRestrictions.contains(ObjectRestriction.BLOCKS) -> EditBlocksPermission.ReadOnly
|
||||
|
||||
else -> EditBlocksPermission.Edit
|
||||
}
|
||||
|
||||
return ObjectPermissions(
|
||||
canArchive = participantCanEdit && !objectRestrictions.contains(ObjectRestriction.DELETE) && !isArchived,
|
||||
canDelete = participantCanEdit && !objectRestrictions.contains(ObjectRestriction.DELETE),
|
||||
canChangeType = canEdit &&
|
||||
!isTemplateObject &&
|
||||
!objectRestrictions.contains(ObjectRestriction.TYPE_CHANGE),
|
||||
canTemplateSetAsDefault = canEdit && isTemplateObject,
|
||||
canApplyTemplates = canEdit && !isTemplateObject,
|
||||
canMakeAsTemplate = templatesAllowedLayouts.contains(currentLayout) &&
|
||||
!isTemplateObject &&
|
||||
isProfileOwnerIdentity.isNullOrEmpty() &&
|
||||
!objectRestrictions.contains(ObjectRestriction.TEMPLATE) &&
|
||||
canApplyUneditableActions,
|
||||
canDuplicate = canApplyUneditableActions && !objectRestrictions.contains(ObjectRestriction.DUPLICATE),
|
||||
canUndoRedo = canEdit && undoRedoLayouts.contains(currentLayout),
|
||||
canFavorite = canApplyUneditableActions && !isTemplateObject,
|
||||
canLinkItself = canApplyUneditableActions && !isTemplateObject,
|
||||
canLock = lockLayouts.contains(currentLayout) &&
|
||||
canApplyUneditableActions &&
|
||||
!isTemplateObject,
|
||||
canChangeIcon = canEditDetails && layoutsWithIcon.contains(currentLayout) && canEdit,
|
||||
canChangeCover = canEditDetails && layoutsWithCover.contains(currentLayout) && canEdit,
|
||||
canChangeLayout = canEditDetails &&
|
||||
possibleToChangeLayoutLayouts.contains(currentLayout) &&
|
||||
canEdit,
|
||||
canEditRelationValues = canEditRelations && canEditDetails,
|
||||
canEditRelationsList = canEditRelations &&
|
||||
canEditDetails &&
|
||||
!objectRestrictions.contains(ObjectRestriction.RELATIONS),
|
||||
canEditBlocks = (editBlocksPermission == EditBlocksPermission.Edit),
|
||||
canEditDetails = canEditDetails && canEdit,
|
||||
editBlocks = editBlocksPermission,
|
||||
canCreateObjectThisType = !objectRestrictions.contains(ObjectRestriction.CREATE_OBJECT_OF_THIS_TYPE) && canApplyUneditableActions
|
||||
)
|
||||
}
|
||||
|
||||
private val templatesAllowedLayouts = listOf(
|
||||
ObjectType.Layout.BASIC,
|
||||
ObjectType.Layout.PROFILE,
|
||||
ObjectType.Layout.TODO
|
||||
)
|
||||
|
||||
private val undoRedoLayouts = listOf(
|
||||
ObjectType.Layout.BASIC,
|
||||
ObjectType.Layout.PROFILE,
|
||||
ObjectType.Layout.TODO,
|
||||
ObjectType.Layout.NOTE,
|
||||
ObjectType.Layout.BOOKMARK
|
||||
)
|
||||
|
||||
private val lockLayouts = listOf(
|
||||
ObjectType.Layout.BASIC,
|
||||
ObjectType.Layout.PROFILE,
|
||||
ObjectType.Layout.TODO,
|
||||
ObjectType.Layout.NOTE,
|
||||
ObjectType.Layout.BOOKMARK
|
||||
)
|
||||
|
||||
private val layoutsWithIcon = listOf(
|
||||
ObjectType.Layout.FILE,
|
||||
ObjectType.Layout.IMAGE,
|
||||
ObjectType.Layout.VIDEO,
|
||||
ObjectType.Layout.AUDIO,
|
||||
ObjectType.Layout.PDF,
|
||||
|
||||
ObjectType.Layout.SET,
|
||||
ObjectType.Layout.COLLECTION,
|
||||
|
||||
ObjectType.Layout.BASIC,
|
||||
ObjectType.Layout.PROFILE
|
||||
)
|
||||
|
||||
private val layoutsWithCover = layoutsWithIcon + listOf(
|
||||
ObjectType.Layout.TODO,
|
||||
ObjectType.Layout.BOOKMARK
|
||||
)
|
||||
|
||||
private val possibleToChangeLayoutLayouts = listOf(
|
||||
ObjectType.Layout.BASIC,
|
||||
ObjectType.Layout.PROFILE,
|
||||
ObjectType.Layout.TODO,
|
||||
ObjectType.Layout.NOTE
|
||||
)
|
|
@ -0,0 +1,312 @@
|
|||
package com.anytypeio.anytype.presentation.objects
|
||||
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.core_models.ObjectType
|
||||
import com.anytypeio.anytype.core_models.Relations
|
||||
import com.anytypeio.anytype.core_models.StubObjectView
|
||||
import com.anytypeio.anytype.core_models.StubSmartBlock
|
||||
import com.anytypeio.anytype.core_models.permissions.EditBlocksPermission
|
||||
import com.anytypeio.anytype.core_models.permissions.toObjectPermissions
|
||||
import com.anytypeio.anytype.core_models.restrictions.ObjectRestriction
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
|
||||
class ObjectPermissionsTest {
|
||||
|
||||
@Test
|
||||
fun `Unlocked, not archived, participant can edit, BASIC layout`() {
|
||||
// GIVEN: An ObjectView with:
|
||||
// - root block is unlocked
|
||||
// - BASIC layout
|
||||
// - no object restrictions
|
||||
// - participant can edit
|
||||
val rootBlockId = "root-block"
|
||||
val objectView = StubObjectView(
|
||||
blocks = listOf(
|
||||
StubSmartBlock(
|
||||
id = rootBlockId
|
||||
)
|
||||
),
|
||||
root = rootBlockId,
|
||||
details = mapOf(
|
||||
rootBlockId to mapOf(
|
||||
Relations.ID to rootBlockId,
|
||||
Relations.LAYOUT to ObjectType.Layout.BASIC.code.toDouble()
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// WHEN
|
||||
val permissions = objectView.toObjectPermissions(participantCanEdit = true)
|
||||
|
||||
// THEN
|
||||
assertTrue(permissions.canArchive)
|
||||
assertTrue(permissions.canDelete)
|
||||
assertTrue(permissions.canChangeType)
|
||||
assertTrue(permissions.canUndoRedo)
|
||||
assertTrue(permissions.canChangeLayout)
|
||||
assertTrue(permissions.canEditRelationValues)
|
||||
assertTrue(permissions.canEditRelationsList)
|
||||
assertTrue(permissions.canEditBlocks)
|
||||
assertTrue(permissions.canEditDetails)
|
||||
assertTrue(permissions.editBlocks is EditBlocksPermission.Edit)
|
||||
assertTrue(permissions.canDuplicate)
|
||||
assertTrue(permissions.canLinkItself)
|
||||
assertTrue(permissions.canLock)
|
||||
assertTrue(permissions.canChangeIcon)
|
||||
assertTrue(permissions.canChangeCover)
|
||||
assertTrue(permissions.canMakeAsTemplate)
|
||||
assertTrue(permissions.canApplyTemplates)
|
||||
assertTrue(permissions.canFavorite)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Unlocked, not archived, participant cannot edit`() {
|
||||
// GIVEN: An ObjectView with:
|
||||
// - root block is unlocked
|
||||
// - BASIC layout
|
||||
// - no object restrictions
|
||||
// - participant can edit
|
||||
val rootBlockId = "root-block"
|
||||
val objectView = StubObjectView(
|
||||
blocks = listOf(
|
||||
StubSmartBlock(
|
||||
id = rootBlockId
|
||||
)
|
||||
),
|
||||
root = rootBlockId,
|
||||
details = mapOf(
|
||||
rootBlockId to mapOf(
|
||||
Relations.ID to rootBlockId,
|
||||
Relations.LAYOUT to ObjectType.Layout.BASIC.code.toDouble()
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// WHEN
|
||||
val permissions = objectView.toObjectPermissions(participantCanEdit = false)
|
||||
|
||||
// THEN
|
||||
assertFalse(permissions.canArchive)
|
||||
assertFalse(permissions.canDelete)
|
||||
assertFalse(permissions.canChangeType)
|
||||
assertFalse(permissions.canUndoRedo)
|
||||
assertFalse(permissions.canChangeLayout)
|
||||
assertFalse(permissions.canEditRelationValues)
|
||||
assertFalse(permissions.canEditRelationsList)
|
||||
assertFalse(permissions.canEditBlocks)
|
||||
assertFalse(permissions.canEditDetails)
|
||||
assertTrue(permissions.editBlocks == EditBlocksPermission.ReadOnly)
|
||||
assertFalse(permissions.canDuplicate)
|
||||
assertFalse(permissions.canLinkItself)
|
||||
assertFalse(permissions.canLock)
|
||||
assertFalse(permissions.canChangeIcon)
|
||||
assertFalse(permissions.canChangeCover)
|
||||
assertFalse(permissions.canMakeAsTemplate)
|
||||
assertFalse(permissions.canApplyTemplates)
|
||||
assertFalse(permissions.canFavorite)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Locked, not archived, participant can edit, BASIC layout`() {
|
||||
// GIVEN: An ObjectView with:
|
||||
// - root block is locked
|
||||
// - BASIC layout
|
||||
// - participant can edit
|
||||
// - no additional object restrictions
|
||||
val rootBlockId = "root-block"
|
||||
val objectView = StubObjectView(
|
||||
blocks = listOf(
|
||||
StubSmartBlock(
|
||||
id = rootBlockId,
|
||||
fields = Block.Fields(
|
||||
mapOf(
|
||||
Block.Fields.IS_LOCKED_KEY to true
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
root = rootBlockId,
|
||||
details = mapOf(
|
||||
rootBlockId to mapOf(
|
||||
Relations.ID to rootBlockId,
|
||||
Relations.LAYOUT to ObjectType.Layout.BASIC.code.toDouble(),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// WHEN
|
||||
val permissions = objectView.toObjectPermissions(participantCanEdit = true)
|
||||
|
||||
// THEN
|
||||
// Because the block is locked, editing blocks is read-only, but other actions may be allowed.
|
||||
assertTrue(permissions.canArchive)
|
||||
assertTrue(permissions.canDelete)
|
||||
assertFalse(permissions.canEditBlocks)
|
||||
assertTrue(permissions.editBlocks == EditBlocksPermission.ReadOnly)
|
||||
assertFalse(permissions.canChangeType)
|
||||
assertFalse(permissions.canChangeIcon)
|
||||
assertFalse(permissions.canChangeCover)
|
||||
assertTrue(permissions.canFavorite)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Archived, participant can edit, BASIC layout`() {
|
||||
// GIVEN: An ObjectView with:
|
||||
// - root block is unlocked
|
||||
// - BASIC layout
|
||||
// - object is archived
|
||||
// - participant can edit
|
||||
val rootBlockId = "root-block"
|
||||
val objectView = StubObjectView(
|
||||
blocks = listOf(
|
||||
StubSmartBlock(id = rootBlockId)
|
||||
),
|
||||
root = rootBlockId,
|
||||
details = mapOf(
|
||||
rootBlockId to mapOf(
|
||||
Relations.ID to rootBlockId,
|
||||
Relations.LAYOUT to ObjectType.Layout.BASIC.code.toDouble(),
|
||||
Relations.IS_ARCHIVED to true
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// WHEN
|
||||
val permissions = objectView.toObjectPermissions(participantCanEdit = true)
|
||||
|
||||
// THEN
|
||||
// An archived object can often be deleted, but not re-archived or edited.
|
||||
assertFalse(permissions.canArchive, "Cannot archive an already archived object.")
|
||||
assertTrue(permissions.canDelete, "Archived object can typically be deleted if user can edit.")
|
||||
assertFalse(permissions.canEditBlocks, "Archived objects are read-only for blocks.")
|
||||
assertTrue(permissions.editBlocks == EditBlocksPermission.ReadOnly)
|
||||
assertFalse(permissions.canChangeLayout, "Changing layout is disallowed if object is archived.")
|
||||
assertFalse(permissions.canChangeIcon, "Changing icon is disallowed if object is archived.")
|
||||
assertFalse(permissions.canMakeAsTemplate, "Cannot make an archived object into a template.")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Archived, participant cannot edit, BASIC layout`() {
|
||||
// GIVEN: An ObjectView with:
|
||||
// - root block is unlocked
|
||||
// - BASIC layout
|
||||
// - object is archived
|
||||
// - participant cannot edit
|
||||
val rootBlockId = "root-block"
|
||||
val objectView = StubObjectView(
|
||||
blocks = listOf(
|
||||
StubSmartBlock(id = rootBlockId)
|
||||
),
|
||||
root = rootBlockId,
|
||||
details = mapOf(
|
||||
rootBlockId to mapOf(
|
||||
Relations.ID to rootBlockId,
|
||||
Relations.LAYOUT to ObjectType.Layout.BASIC.code.toDouble(),
|
||||
Relations.IS_ARCHIVED to true
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// WHEN
|
||||
val permissions = objectView.toObjectPermissions(participantCanEdit = false)
|
||||
|
||||
// THEN
|
||||
// Participant can't edit => effectively all edit actions are false.
|
||||
assertFalse(permissions.canArchive, "Already archived and user can't edit => no re-archiving.")
|
||||
assertFalse(permissions.canDelete, "Cannot delete if participant can't edit.")
|
||||
assertFalse(permissions.canEditBlocks, "Can't edit blocks if participant can't edit overall.")
|
||||
assertTrue(permissions.editBlocks == EditBlocksPermission.ReadOnly)
|
||||
assertFalse(permissions.canMakeAsTemplate, "Cannot make a template if you have no edit rights.")
|
||||
assertFalse(permissions.canChangeIcon, "No editing privileges => cannot change icon.")
|
||||
assertFalse(permissions.canChangeCover, "No editing privileges => cannot change cover.")
|
||||
assertFalse(permissions.canDuplicate, "No editing privileges => cannot duplicate.")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Unlocked, not archived, participant can edit, NOTE layout`() {
|
||||
// GIVEN: An ObjectView with:
|
||||
// - root block is unlocked
|
||||
// - NOTE layout
|
||||
// - participant can edit
|
||||
val rootBlockId = "root-block"
|
||||
val objectView = StubObjectView(
|
||||
blocks = listOf(
|
||||
StubSmartBlock(id = rootBlockId)
|
||||
),
|
||||
root = rootBlockId,
|
||||
details = mapOf(
|
||||
rootBlockId to mapOf(
|
||||
Relations.ID to rootBlockId,
|
||||
Relations.LAYOUT to ObjectType.Layout.NOTE.code.toDouble(),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// WHEN
|
||||
val permissions = objectView.toObjectPermissions(participantCanEdit = true)
|
||||
|
||||
// THEN
|
||||
// NOTE layout is part of undoRedoLayouts, so undo/redo is allowed if unlocked & not archived.
|
||||
assertTrue(permissions.canArchive, "Unlocked + participant can edit => can archive.")
|
||||
assertTrue(permissions.canDelete, "archived or not => can't delete.")
|
||||
assertTrue(permissions.canUndoRedo, "NOTE layout supports undo/redo.")
|
||||
assertTrue(permissions.canEditBlocks, "Not locked + not archived + can edit => can edit blocks.")
|
||||
assertTrue(permissions.canEditDetails, "No restrictions => can edit details.")
|
||||
assertTrue(permissions.canFavorite, "Favoriting is typically allowed if participant can edit.")
|
||||
// etc.
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Unlocked, not archived, participant can edit, BASIC layout, with DELETE & RELATIONS & BLOCKS restrictions`() {
|
||||
// GIVEN: An ObjectView with:
|
||||
// - root block is unlocked
|
||||
// - BASIC layout
|
||||
// - objectRestrictions contains DELETE, RELATIONS, and BLOCKS
|
||||
// - participant can edit
|
||||
val rootBlockId = "root-block"
|
||||
val objectView = StubObjectView(
|
||||
blocks = listOf(
|
||||
StubSmartBlock(
|
||||
id = rootBlockId
|
||||
)
|
||||
),
|
||||
root = rootBlockId,
|
||||
details = mapOf(
|
||||
rootBlockId to mapOf(
|
||||
Relations.ID to rootBlockId,
|
||||
Relations.LAYOUT to ObjectType.Layout.BASIC.code.toDouble(),
|
||||
Relations.IS_ARCHIVED to false
|
||||
)
|
||||
),
|
||||
objectRestrictions = listOf(
|
||||
ObjectRestriction.DELETE,
|
||||
ObjectRestriction.RELATIONS,
|
||||
ObjectRestriction.BLOCKS,
|
||||
ObjectRestriction.DETAILS
|
||||
)
|
||||
)
|
||||
|
||||
// WHEN
|
||||
val permissions = objectView.toObjectPermissions(participantCanEdit = true)
|
||||
|
||||
// THEN
|
||||
// Because of DELETE restriction => cannot archive or delete.
|
||||
assertFalse(permissions.canArchive, "DELETE restriction => cannot archive.")
|
||||
assertFalse(permissions.canDelete, "DELETE restriction => cannot delete.")
|
||||
// Because of BLOCKS restriction => cannot edit blocks.
|
||||
assertFalse(permissions.canEditBlocks, "BLOCKS restriction => cannot edit blocks.")
|
||||
assertTrue(permissions.editBlocks == EditBlocksPermission.ReadOnly)
|
||||
// Because of RELATIONS restriction => cannot edit relations.
|
||||
assertFalse(permissions.canEditRelationsList)
|
||||
// Because of DETAILS restriction => cannot edit relations values.
|
||||
assertFalse(permissions.canEditRelationValues)
|
||||
// However, participant can still do other changes if not restricted:
|
||||
assertTrue(permissions.canChangeType, "Still allowed to change type unless restricted specifically.")
|
||||
assertTrue(permissions.canUndoRedo, "BASIC layout => supports undo/redo if user can edit.")
|
||||
assertTrue(permissions.canFavorite, "Favoriting is not restricted by DELETE, BLOCKS, or RELATIONS.")
|
||||
}
|
||||
|
||||
}
|
|
@ -254,11 +254,12 @@ fun StubBookmark(
|
|||
|
||||
fun StubSmartBlock(
|
||||
id: Id = MockDataFactory.randomString(),
|
||||
children: List<Id> = emptyList()
|
||||
children: List<Id> = emptyList(),
|
||||
fields: Block.Fields = Block.Fields.empty(),
|
||||
): Block = Block(
|
||||
id = id,
|
||||
children = children,
|
||||
fields = Block.Fields.empty(),
|
||||
fields = fields,
|
||||
content = Block.Content.Smart
|
||||
)
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue