Skip to content

Commit

Permalink
Merge pull request #6319 from vector-im/feature/bma/stateEventQuery
Browse files Browse the repository at this point in the history
Enforce query on state event
  • Loading branch information
bmarty authored Jun 16, 2022
2 parents fe75157 + 3557121 commit 8238cd7
Show file tree
Hide file tree
Showing 34 changed files with 109 additions and 80 deletions.
1 change: 1 addition & 0 deletions changelog.d/6319.sdk
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Create `QueryStateEventValue` to do query on `stateKey` for State Event. Also remove the default parameter values for those type.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ package org.matrix.android.sdk.flow

import androidx.lifecycle.asFlow
import kotlinx.coroutines.flow.Flow
import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.query.QueryStateEventValue
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.room.Room
import org.matrix.android.sdk.api.session.room.getStateEvent
Expand Down Expand Up @@ -67,17 +67,17 @@ class FlowRoom(private val room: Room) {
}
}

fun liveStateEvent(eventType: String, stateKey: QueryStringValue): Flow<Optional<Event>> {
fun liveStateEvent(eventType: String, stateKey: QueryStateEventValue): Flow<Optional<Event>> {
return room.stateService().getStateEventLive(eventType, stateKey).asFlow()
.startWith(room.coroutineDispatchers.io) {
room.getStateEvent(eventType, stateKey).toOptional()
}
}

fun liveStateEvents(eventTypes: Set<String>): Flow<List<Event>> {
return room.stateService().getStateEventsLive(eventTypes).asFlow()
fun liveStateEvents(eventTypes: Set<String>, stateKey: QueryStateEventValue): Flow<List<Event>> {
return room.stateService().getStateEventsLive(eventTypes, stateKey).asFlow()
.startWith(room.coroutineDispatchers.io) {
room.stateService().getStateEvents(eventTypes)
room.stateService().getStateEvents(eventTypes, stateKey)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package org.matrix.android.sdk.flow
import androidx.lifecycle.asFlow
import androidx.paging.PagedList
import kotlinx.coroutines.flow.Flow
import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.query.QueryStateEventValue
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.accountdata.UserAccountDataEvent
import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
Expand Down Expand Up @@ -179,7 +179,7 @@ class FlowSession(private val session: Session) {

fun liveRoomWidgets(
roomId: String,
widgetId: QueryStringValue,
widgetId: QueryStateEventValue,
widgetTypes: Set<String>? = null,
excludedTypes: Set<String>? = null
): Flow<List<Widget>> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.junit.runners.MethodSorters
import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.getStateEvent
Expand Down Expand Up @@ -73,27 +74,37 @@ class SpaceCreationTest : InstrumentedTest {
// assertEquals(topic, syncedSpace.asRoom().roomSummary()?., "Room topic should be set")

assertNotNull("Space should be found by Id", syncedSpace)
val creationEvent = syncedSpace!!.asRoom().getStateEvent(EventType.STATE_ROOM_CREATE)
val createContent = creationEvent?.content.toModel<RoomCreateContent>()
val createContent = syncedSpace!!.asRoom()
.getStateEvent(EventType.STATE_ROOM_CREATE, QueryStringValue.IsEmpty)
?.content
?.toModel<RoomCreateContent>()
assertEquals("Room type should be space", RoomType.SPACE, createContent?.type)

var powerLevelsContent: PowerLevelsContent? = null
commonTestHelper.waitWithLatch { latch ->
commonTestHelper.retryPeriodicallyWithLatch(latch) {
val toModel = syncedSpace.asRoom().getStateEvent(EventType.STATE_ROOM_POWER_LEVELS)?.content.toModel<PowerLevelsContent>()
powerLevelsContent = toModel
toModel != null
powerLevelsContent = syncedSpace.asRoom()
.getStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.IsEmpty)
?.content
?.toModel<PowerLevelsContent>()
powerLevelsContent != null
}
}
assertEquals("Space-rooms should be created with a power level for events_default of 100", 100, powerLevelsContent?.eventsDefault)

val guestAccess = syncedSpace.asRoom().getStateEvent(EventType.STATE_ROOM_GUEST_ACCESS)?.content
?.toModel<RoomGuestAccessContent>()?.guestAccess
val guestAccess = syncedSpace.asRoom()
.getStateEvent(EventType.STATE_ROOM_GUEST_ACCESS, QueryStringValue.IsEmpty)
?.content
?.toModel<RoomGuestAccessContent>()
?.guestAccess

assertEquals("Public space room should be peekable by guest", GuestAccess.CanJoin, guestAccess)

val historyVisibility = syncedSpace.asRoom().getStateEvent(EventType.STATE_ROOM_HISTORY_VISIBILITY)?.content
?.toModel<RoomHistoryVisibilityContent>()?.historyVisibility
val historyVisibility = syncedSpace.asRoom()
.getStateEvent(EventType.STATE_ROOM_HISTORY_VISIBILITY, QueryStringValue.IsEmpty)
?.content
?.toModel<RoomHistoryVisibilityContent>()
?.historyVisibility

assertEquals("Public space room should be world readable", RoomHistoryVisibility.WORLD_READABLE, historyVisibility)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -569,8 +569,9 @@ class SpaceHierarchyTest : InstrumentedTest {
commonTestHelper.waitWithLatch {
val room = bobSession.getRoom(bobRoomId)!!
val currentPLContent = room
.getStateEvent(EventType.STATE_ROOM_POWER_LEVELS)
?.let { it.content.toModel<PowerLevelsContent>() }
.getStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.IsEmpty)
?.content
.toModel<PowerLevelsContent>()

val newPowerLevelsContent = currentPLContent
?.setUserPowerLevel(aliceSession.myUserId, Role.Admin.value)
Expand All @@ -583,7 +584,7 @@ class SpaceHierarchyTest : InstrumentedTest {
commonTestHelper.waitWithLatch { latch ->
commonTestHelper.retryPeriodicallyWithLatch(latch) {
val powerLevelsHelper = aliceSession.getRoom(bobRoomId)!!
.getStateEvent(EventType.STATE_ROOM_POWER_LEVELS)
.getStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.IsEmpty)
?.content
?.toModel<PowerLevelsContent>()
?.let { PowerLevelsHelper(it) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@

package org.matrix.android.sdk.api.query

/**
* Only a subset of [QueryStringValue] are applicable to query the `stateKey` of a state event.
*/
sealed interface QueryStateEventValue

/**
* Basic query language. All these cases are mutually exclusive.
*/
Expand All @@ -33,22 +38,22 @@ sealed interface QueryStringValue {
/**
* The tested field has to be not null.
*/
object IsNotNull : QueryStringValue
object IsNotNull : QueryStringValue, QueryStateEventValue

/**
* The tested field has to be empty.
*/
object IsEmpty : QueryStringValue
object IsEmpty : QueryStringValue, QueryStateEventValue

/**
* The tested field has to not empty.
* The tested field has to be not empty.
*/
object IsNotEmpty : QueryStringValue
object IsNotEmpty : QueryStringValue, QueryStateEventValue

/**
* Interface to check String content.
*/
sealed interface ContentQueryStringValue : QueryStringValue {
sealed interface ContentQueryStringValue : QueryStringValue, QueryStateEventValue {
val string: String
val case: Case
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,21 @@

package org.matrix.android.sdk.api.session.room

import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.query.QueryStateEventValue
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent

/**
* Get a TimelineEvent using the TimelineService of a Room.
* @param eventId The id of the event to retrieve
*/
fun Room.getTimelineEvent(eventId: String): TimelineEvent? =
timelineService().getTimelineEvent(eventId)

/**
* Get a StateEvent using the StateService of a Room.
* @param eventType The type of the event, see [org.matrix.android.sdk.api.session.events.model.EventType].
* @param stateKey the query which will be done on the stateKey.
*/
fun Room.getStateEvent(eventType: String, stateKey: QueryStringValue = QueryStringValue.NoCondition): Event? =
fun Room.getStateEvent(eventType: String, stateKey: QueryStateEventValue): Event? =
stateService().getStateEvent(eventType, stateKey)
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ package org.matrix.android.sdk.api.session.room.state

import android.net.Uri
import androidx.lifecycle.LiveData
import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.query.QueryStateEventValue
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.room.model.GuestAccess
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
Expand Down Expand Up @@ -93,28 +93,28 @@ interface StateService {
* @param eventType An eventType.
* @param stateKey the query which will be done on the stateKey
*/
fun getStateEvent(eventType: String, stateKey: QueryStringValue = QueryStringValue.NoCondition): Event?
fun getStateEvent(eventType: String, stateKey: QueryStateEventValue): Event?

/**
* Get a live state event of the room.
* @param eventType An eventType.
* @param stateKey the query which will be done on the stateKey
*/
fun getStateEventLive(eventType: String, stateKey: QueryStringValue = QueryStringValue.NoCondition): LiveData<Optional<Event>>
fun getStateEventLive(eventType: String, stateKey: QueryStateEventValue): LiveData<Optional<Event>>

/**
* Get state events of the room.
* @param eventTypes Set of eventType. If empty, all state events will be returned
* @param stateKey the query which will be done on the stateKey
*/
fun getStateEvents(eventTypes: Set<String>, stateKey: QueryStringValue = QueryStringValue.NoCondition): List<Event>
fun getStateEvents(eventTypes: Set<String>, stateKey: QueryStateEventValue): List<Event>

/**
* Get live state events of the room.
* @param eventTypes Set of eventType to observe. If empty, all state events will be observed
* @param stateKey the query which will be done on the stateKey
*/
fun getStateEventsLive(eventTypes: Set<String>, stateKey: QueryStringValue = QueryStringValue.NoCondition): LiveData<List<Event>>
fun getStateEventsLive(eventTypes: Set<String>, stateKey: QueryStateEventValue): LiveData<List<Event>>

suspend fun setJoinRulePublic()
suspend fun setJoinRuleInviteOnly()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent
* Return true if a room can be joined by anyone (RoomJoinRules.PUBLIC).
*/
fun StateService.isPublic(): Boolean {
return getStateEvent(EventType.STATE_ROOM_JOIN_RULES, QueryStringValue.NoCondition)
return getStateEvent(EventType.STATE_ROOM_JOIN_RULES, QueryStringValue.IsEmpty)
?.content
?.toModel<RoomJoinRulesContent>()
?.joinRules == RoomJoinRules.PUBLIC
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
package org.matrix.android.sdk.api.session.widgets

import androidx.lifecycle.LiveData
import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.query.QueryStateEventValue
import org.matrix.android.sdk.api.session.events.model.Content
import org.matrix.android.sdk.api.session.widgets.model.Widget

Expand Down Expand Up @@ -49,7 +49,7 @@ interface WidgetService {
*/
fun getRoomWidgets(
roomId: String,
widgetId: QueryStringValue = QueryStringValue.NoCondition,
widgetId: QueryStateEventValue,
widgetTypes: Set<String>? = null,
excludedTypes: Set<String>? = null
): List<Widget>
Expand All @@ -70,7 +70,7 @@ interface WidgetService {
*/
fun getRoomWidgetsLive(
roomId: String,
widgetId: QueryStringValue = QueryStringValue.NoCondition,
widgetId: QueryStateEventValue,
widgetTypes: Set<String>? = null,
excludedTypes: Set<String>? = null
): LiveData<List<Widget>>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ internal class ViaParameterFinder @Inject constructor(
}

fun userCanInvite(userId: String, roomId: String): Boolean {
val powerLevelsHelper = stateEventDataSource.getStateEvent(roomId, EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition)
val powerLevelsHelper = stateEventDataSource.getStateEvent(roomId, EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.IsEmpty)
?.content?.toModel<PowerLevelsContent>()
?.let { PowerLevelsHelper(it) }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package org.matrix.android.sdk.internal.session.pushers

import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.toModel
Expand Down Expand Up @@ -55,7 +56,7 @@ internal class DefaultConditionResolver @Inject constructor(
val roomId = event.roomId ?: return false
val room = roomGetter.getRoom(roomId) ?: return false

val powerLevelsContent = room.getStateEvent(EventType.STATE_ROOM_POWER_LEVELS)
val powerLevelsContent = room.getStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.IsEmpty)
?.content
?.toModel<PowerLevelsContent>()
?: PowerLevelsContent()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
}

private fun getPowerLevelsHelper(roomId: String): PowerLevelsHelper? {
return stateEventDataSource.getStateEvent(roomId, EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition)
return stateEventDataSource.getStateEvent(roomId, EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.IsEmpty)
?.content?.toModel<PowerLevelsContent>()
?.let { PowerLevelsHelper(it) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ internal class DefaultLeaveRoomTask @Inject constructor(
val roomCreateStateEvent = stateEventDataSource.getStateEvent(
roomId = roomId,
eventType = EventType.STATE_ROOM_CREATE,
stateKey = QueryStringValue.NoCondition
stateKey = QueryStringValue.IsEmpty,
)
// Server is not cleaning predecessor rooms, so we also try to left them
val predecessorRoomId = roomCreateStateEvent?.getClearContent()?.toModel<RoomCreateContent>()?.predecessor?.roomId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.query.QueryStateEventValue
import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.events.model.EventType
Expand Down Expand Up @@ -54,19 +55,19 @@ internal class DefaultStateService @AssistedInject constructor(
fun create(roomId: String): DefaultStateService
}

override fun getStateEvent(eventType: String, stateKey: QueryStringValue): Event? {
override fun getStateEvent(eventType: String, stateKey: QueryStateEventValue): Event? {
return stateEventDataSource.getStateEvent(roomId, eventType, stateKey)
}

override fun getStateEventLive(eventType: String, stateKey: QueryStringValue): LiveData<Optional<Event>> {
override fun getStateEventLive(eventType: String, stateKey: QueryStateEventValue): LiveData<Optional<Event>> {
return stateEventDataSource.getStateEventLive(roomId, eventType, stateKey)
}

override fun getStateEvents(eventTypes: Set<String>, stateKey: QueryStringValue): List<Event> {
override fun getStateEvents(eventTypes: Set<String>, stateKey: QueryStateEventValue): List<Event> {
return stateEventDataSource.getStateEvents(roomId, eventTypes, stateKey)
}

override fun getStateEventsLive(eventTypes: Set<String>, stateKey: QueryStringValue): LiveData<List<Event>> {
override fun getStateEventsLive(eventTypes: Set<String>, stateKey: QueryStateEventValue): LiveData<List<Event>> {
return stateEventDataSource.getStateEventsLive(roomId, eventTypes, stateKey)
}

Expand Down
Loading

0 comments on commit 8238cd7

Please sign in to comment.