diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt index 218ce0a4d5..1475b67276 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt @@ -43,9 +43,11 @@ import org.matrix.android.sdk.internal.session.room.alias.DefaultGetRoomLocalAli import org.matrix.android.sdk.internal.session.room.alias.DeleteRoomAliasTask import org.matrix.android.sdk.internal.session.room.alias.GetRoomIdByAliasTask import org.matrix.android.sdk.internal.session.room.alias.GetRoomLocalAliasesTask +import org.matrix.android.sdk.internal.session.room.create.CreateLocalRoomStateEventsTask import org.matrix.android.sdk.internal.session.room.create.CreateLocalRoomTask import org.matrix.android.sdk.internal.session.room.create.CreateRoomFromLocalRoomTask import org.matrix.android.sdk.internal.session.room.create.CreateRoomTask +import org.matrix.android.sdk.internal.session.room.create.DefaultCreateLocalRoomStateEventsTask import org.matrix.android.sdk.internal.session.room.create.DefaultCreateLocalRoomTask import org.matrix.android.sdk.internal.session.room.create.DefaultCreateRoomFromLocalRoomTask import org.matrix.android.sdk.internal.session.room.create.DefaultCreateRoomTask @@ -215,6 +217,9 @@ internal abstract class RoomModule { @Binds abstract fun bindCreateLocalRoomTask(task: DefaultCreateLocalRoomTask): CreateLocalRoomTask + @Binds + abstract fun bindCreateLocalRoomStateEventsTask(task: DefaultCreateLocalRoomStateEventsTask): CreateLocalRoomStateEventsTask + @Binds abstract fun bindCreateRoomFromLocalRoomTask(task: DefaultCreateRoomFromLocalRoomTask): CreateRoomFromLocalRoomTask diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateLocalRoomStateEventsTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateLocalRoomStateEventsTask.kt new file mode 100644 index 0000000000..45980514dd --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateLocalRoomStateEventsTask.kt @@ -0,0 +1,296 @@ +/* + * Copyright 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.room.create + +import org.matrix.android.sdk.api.MatrixPatterns.getServerName +import org.matrix.android.sdk.api.extensions.orFalse +import org.matrix.android.sdk.api.extensions.tryOrNull +import org.matrix.android.sdk.api.session.events.model.Content +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.LocalEcho +import org.matrix.android.sdk.api.session.events.model.toContent +import org.matrix.android.sdk.api.session.room.model.GuestAccess +import org.matrix.android.sdk.api.session.room.model.Membership +import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent +import org.matrix.android.sdk.api.session.room.model.RoomCanonicalAliasContent +import org.matrix.android.sdk.api.session.room.model.RoomGuestAccessContent +import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility +import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibilityContent +import org.matrix.android.sdk.api.session.room.model.RoomJoinRules +import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent +import org.matrix.android.sdk.api.session.room.model.RoomMemberContent +import org.matrix.android.sdk.api.session.room.model.RoomNameContent +import org.matrix.android.sdk.api.session.room.model.RoomThirdPartyInviteContent +import org.matrix.android.sdk.api.session.room.model.RoomTopicContent +import org.matrix.android.sdk.api.session.room.model.banOrDefault +import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams +import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset +import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent +import org.matrix.android.sdk.api.session.room.model.eventsDefaultOrDefault +import org.matrix.android.sdk.api.session.room.model.inviteOrDefault +import org.matrix.android.sdk.api.session.room.model.kickOrDefault +import org.matrix.android.sdk.api.session.room.model.localecho.LocalRoomThirdPartyInviteContent +import org.matrix.android.sdk.api.session.room.model.redactOrDefault +import org.matrix.android.sdk.api.session.room.model.stateDefaultOrDefault +import org.matrix.android.sdk.api.session.room.model.usersDefaultOrDefault +import org.matrix.android.sdk.api.session.user.UserService +import org.matrix.android.sdk.internal.session.room.create.CreateLocalRoomStateEventsTask.Params +import org.matrix.android.sdk.internal.session.room.membership.threepid.toThreePid +import org.matrix.android.sdk.internal.task.Task +import org.matrix.android.sdk.internal.util.time.Clock +import javax.inject.Inject + +internal interface CreateLocalRoomStateEventsTask : Task> { + data class Params( + val roomCreatorUserId: String, + val createRoomBody: CreateRoomBody + ) +} + +internal class DefaultCreateLocalRoomStateEventsTask @Inject constructor( + private val userService: UserService, + private val clock: Clock, +) : CreateLocalRoomStateEventsTask { + + private lateinit var createRoomBody: CreateRoomBody + private lateinit var roomCreatorUserId: String + + override suspend fun execute(params: Params): List { + createRoomBody = params.createRoomBody + roomCreatorUserId = params.roomCreatorUserId + + return buildList { + createRoomCreateEvent() + createRoomMemberEvents(listOf(roomCreatorUserId)) + createRoomPowerLevelsEvent() + createRoomAliasEvent() + createRoomPresetEvents() + createRoomInitialStateEvents() + createRoomNameAndTopicStateEvents() + createRoomMemberEvents(createRoomBody.invitedUserIds.orEmpty()) + createRoomThreePidEvents() + createRoomDefaultEvents() + } + } + + /** + * Generate the create state event related to this room. + */ + private fun MutableList.createRoomCreateEvent() = apply { + val roomCreateEvent = createLocalEvent( + type = EventType.STATE_ROOM_CREATE, + content = RoomCreateContent( + creator = roomCreatorUserId, + roomVersion = createRoomBody.roomVersion, + type = (createRoomBody.creationContent as? Map<*, *>)?.get(CreateRoomParams.CREATION_CONTENT_KEY_ROOM_TYPE) as? String + + ).toContent(), + stateKey = "" + ) + add(roomCreateEvent) + } + + /** + * Generate the create state event related to the power levels using the given overridden values or the default values according to the specification. + * Ref: https://spec.matrix.org/latest/client-server-api/#mroompower_levels + */ + private fun MutableList.createRoomPowerLevelsEvent() = apply { + val powerLevelsContent = createLocalEvent( + type = EventType.STATE_ROOM_POWER_LEVELS, + content = (createRoomBody.powerLevelContentOverride ?: PowerLevelsContent()).let { + it.copy( + ban = it.banOrDefault(), + eventsDefault = it.eventsDefaultOrDefault(), + invite = it.inviteOrDefault(), + kick = it.kickOrDefault(), + redact = it.redactOrDefault(), + stateDefault = it.stateDefaultOrDefault(), + usersDefault = it.usersDefaultOrDefault(), + ) + }.toContent(), + stateKey = "" + ) + add(powerLevelsContent) + } + + /** + * Generate the local room member state events related to the given user ids, if any. + */ + private suspend fun MutableList.createRoomMemberEvents(userIds: List) = apply { + val memberEvents = userIds + .mapNotNull { tryOrNull { userService.resolveUser(it) } } + .map { user -> + createLocalEvent( + type = EventType.STATE_ROOM_MEMBER, + content = RoomMemberContent( + isDirect = createRoomBody.isDirect.takeUnless { user.userId == roomCreatorUserId }.orFalse(), + membership = if (user.userId == roomCreatorUserId) Membership.JOIN else Membership.INVITE, + displayName = user.displayName, + avatarUrl = user.avatarUrl + ).toContent(), + stateKey = user.userId + ) + } + addAll(memberEvents) + } + + /** + * Generate the local state events related to the given third party invites, if any. + */ + private fun MutableList.createRoomThreePidEvents() = apply { + val threePidEvents = createRoomBody.invite3pids.orEmpty().map { body -> + val localThirdPartyInviteEvent = createLocalEvent( + type = EventType.LOCAL_STATE_ROOM_THIRD_PARTY_INVITE, + content = LocalRoomThirdPartyInviteContent( + isDirect = createRoomBody.isDirect.orFalse(), + membership = Membership.INVITE, + displayName = body.address, + thirdPartyInvite = body.toThreePid() + ).toContent(), + stateKey = "" + ) + val thirdPartyInviteEvent = createLocalEvent( + type = EventType.STATE_ROOM_THIRD_PARTY_INVITE, + content = RoomThirdPartyInviteContent(body.address, null, null, null).toContent(), + stateKey = "" + ) + listOf(localThirdPartyInviteEvent, thirdPartyInviteEvent) + }.flatten() + addAll(threePidEvents) + } + + /** + * Generate the local state event related to the given alias, if any. + */ + fun MutableList.createRoomAliasEvent() = apply { + if (createRoomBody.roomAliasName != null) { + val canonicalAliasContent = createLocalEvent( + type = EventType.STATE_ROOM_CANONICAL_ALIAS, + content = RoomCanonicalAliasContent( + canonicalAlias = "${createRoomBody.roomAliasName}:${roomCreatorUserId.getServerName()}" + ).toContent(), + stateKey = "" + ) + add(canonicalAliasContent) + } + } + + /** + * Generate the local state events related to the given [CreateRoomPreset]. + * Ref: https://spec.matrix.org/latest/client-server-api/#post_matrixclientv3createroom + */ + private fun MutableList.createRoomPresetEvents() = apply { + val preset = createRoomBody.preset ?: return@apply + + var joinRules: RoomJoinRules? = null + var historyVisibility: RoomHistoryVisibility? = null + var guestAccess: GuestAccess? = null + when (preset) { + CreateRoomPreset.PRESET_PRIVATE_CHAT, + CreateRoomPreset.PRESET_TRUSTED_PRIVATE_CHAT -> { + joinRules = RoomJoinRules.INVITE + historyVisibility = RoomHistoryVisibility.SHARED + guestAccess = GuestAccess.CanJoin + } + CreateRoomPreset.PRESET_PUBLIC_CHAT -> { + joinRules = RoomJoinRules.PUBLIC + historyVisibility = RoomHistoryVisibility.SHARED + guestAccess = GuestAccess.Forbidden + } + } + + add(createLocalEvent(EventType.STATE_ROOM_JOIN_RULES, RoomJoinRulesContent(joinRules.value).toContent(), "")) + add(createLocalEvent(EventType.STATE_ROOM_HISTORY_VISIBILITY, RoomHistoryVisibilityContent(historyVisibility.value).toContent(), "")) + add(createLocalEvent(EventType.STATE_ROOM_GUEST_ACCESS, RoomGuestAccessContent(guestAccess.value).toContent(), "")) + } + + /** + * Generate the local state events related to the given initial states, if any. + * The given initial state events override the potential existing ones of the same type. + */ + private fun MutableList.createRoomInitialStateEvents() = apply { + val initialStates = createRoomBody.initialStates ?: return@apply + + val initialStateEvents = initialStates.map { createLocalEvent(it.type, it.content, it.stateKey) } + // Erase existing events of the same type + removeAll { event -> event.type in initialStateEvents.map { it.type } } + // Add the initial state events to the list + addAll(initialStateEvents) + } + + /** + * Generate the local events related to the given room name and topic, if any. + */ + private fun MutableList.createRoomNameAndTopicStateEvents() = apply { + if (createRoomBody.name != null) { + add(createLocalEvent(EventType.STATE_ROOM_NAME, RoomNameContent(createRoomBody.name).toContent(), "")) + } + if (createRoomBody.topic != null) { + add(createLocalEvent(EventType.STATE_ROOM_TOPIC, RoomTopicContent(createRoomBody.topic).toContent(), "")) + } + } + + /** + * Generate the local events which have not been set and are in that case provided by the server with default values. + * Default events: + * - m.room.history_visibility (https://spec.matrix.org/latest/client-server-api/#server-behaviour-5) + * - m.room.guest_access (https://spec.matrix.org/latest/client-server-api/#mroomguest_access) + */ + private fun MutableList.createRoomDefaultEvents() = apply { + // HistoryVisibility + if (none { it.type == EventType.STATE_ROOM_HISTORY_VISIBILITY }) { + add( + createLocalEvent( + type = EventType.STATE_ROOM_HISTORY_VISIBILITY, + content = RoomHistoryVisibilityContent(RoomHistoryVisibility.SHARED.value).toContent(), + stateKey = "" + ) + ) + } + // GuestAccess + if (none { it.type == EventType.STATE_ROOM_GUEST_ACCESS }) { + add( + createLocalEvent( + type = EventType.STATE_ROOM_GUEST_ACCESS, + content = RoomGuestAccessContent(GuestAccess.Forbidden.value).toContent(), + stateKey = "" + ) + ) + } + } + + /** + * Generate a local event from the given parameters. + * + * @param type the event type, see [EventType] + * @param content the content of the Event + * @param stateKey the stateKey, if any + * + * @return a local event + */ + private fun createLocalEvent(type: String?, content: Content?, stateKey: String?): Event { + return Event( + type = type, + senderId = roomCreatorUserId, + stateKey = stateKey, + content = content, + originServerTs = clock.epochMillis(), + eventId = LocalEcho.createLocalEchoId() + ) + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateLocalRoomTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateLocalRoomTask.kt index 160d9bfb24..5b45fbf6ae 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateLocalRoomTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateLocalRoomTask.kt @@ -21,43 +21,14 @@ import io.realm.Realm import io.realm.RealmConfiguration import io.realm.kotlin.createObject import kotlinx.coroutines.TimeoutCancellationException -import org.matrix.android.sdk.api.MatrixPatterns.getServerName -import org.matrix.android.sdk.api.extensions.orFalse -import org.matrix.android.sdk.api.extensions.tryOrNull -import org.matrix.android.sdk.api.session.events.model.Content -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.LocalEcho -import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure -import org.matrix.android.sdk.api.session.room.model.GuestAccess import org.matrix.android.sdk.api.session.room.model.Membership -import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent -import org.matrix.android.sdk.api.session.room.model.RoomCanonicalAliasContent -import org.matrix.android.sdk.api.session.room.model.RoomGuestAccessContent -import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility -import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibilityContent -import org.matrix.android.sdk.api.session.room.model.RoomJoinRules -import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent import org.matrix.android.sdk.api.session.room.model.RoomMemberContent -import org.matrix.android.sdk.api.session.room.model.RoomNameContent -import org.matrix.android.sdk.api.session.room.model.RoomThirdPartyInviteContent -import org.matrix.android.sdk.api.session.room.model.RoomTopicContent -import org.matrix.android.sdk.api.session.room.model.banOrDefault import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams -import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset -import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent -import org.matrix.android.sdk.api.session.room.model.eventsDefaultOrDefault -import org.matrix.android.sdk.api.session.room.model.inviteOrDefault -import org.matrix.android.sdk.api.session.room.model.kickOrDefault -import org.matrix.android.sdk.api.session.room.model.localecho.LocalRoomThirdPartyInviteContent import org.matrix.android.sdk.api.session.room.model.localecho.RoomLocalEcho -import org.matrix.android.sdk.api.session.room.model.redactOrDefault -import org.matrix.android.sdk.api.session.room.model.stateDefaultOrDefault -import org.matrix.android.sdk.api.session.room.model.usersDefaultOrDefault import org.matrix.android.sdk.api.session.room.send.SendState import org.matrix.android.sdk.api.session.sync.model.RoomSyncSummary -import org.matrix.android.sdk.api.session.user.UserService import org.matrix.android.sdk.internal.crypto.DefaultCryptoService import org.matrix.android.sdk.internal.database.awaitNotEmptyResult import org.matrix.android.sdk.internal.database.helper.addTimelineEvent @@ -78,7 +49,6 @@ import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.session.events.getFixedRoomMemberContent import org.matrix.android.sdk.internal.session.room.membership.RoomMemberEventHandler -import org.matrix.android.sdk.internal.session.room.membership.threepid.toThreePid import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryUpdater import org.matrix.android.sdk.internal.session.room.timeline.PaginationDirection import org.matrix.android.sdk.internal.task.Task @@ -96,9 +66,9 @@ internal class DefaultCreateLocalRoomTask @Inject constructor( private val roomSummaryUpdater: RoomSummaryUpdater, @SessionDatabase private val realmConfiguration: RealmConfiguration, private val createRoomBodyBuilder: CreateRoomBodyBuilder, - private val userService: UserService, private val cryptoService: DefaultCryptoService, private val clock: Clock, + private val createLocalRoomStateEventsTask: CreateLocalRoomStateEventsTask, ) : CreateLocalRoomTask { override suspend fun execute(params: CreateRoomParams): String { @@ -186,7 +156,7 @@ internal class DefaultCreateLocalRoomTask @Inject constructor( isLastForward = true } - val eventList = createLocalRoomEvents(createRoomBody) + val eventList = createLocalRoomStateEventsTask.execute(CreateLocalRoomStateEventsTask.Params(myUserId, createRoomBody)) val roomMemberContentsByUser = HashMap() for (event in eventList) { @@ -226,232 +196,4 @@ internal class DefaultCreateLocalRoomTask @Inject constructor( return chunkEntity } - - /** - * Build the list of state events related to the room creation body. - * The events list is ordered following the specification: https://spec.matrix.org/latest/client-server-api/#post_matrixclientv3createroom - * - * @param createRoomBody the room creation body - * - * @return the list of events - */ - private suspend fun createLocalRoomEvents(createRoomBody: CreateRoomBody): List { - return buildList { - createRoomCreateEvent(createRoomBody) - createRoomMemberEvents(listOf(myUserId)) - createRoomPowerLevelsEvent(createRoomBody) - createRoomAliasEvent(createRoomBody) - createRoomPresetEvents(createRoomBody) - createRoomInitialStateEvents(createRoomBody) - createRoomNameAndTopicStateEvents(createRoomBody) - createRoomMemberEvents(createRoomBody.invitedUserIds.orEmpty()) - createRoomThreePidEvents(createRoomBody) - createRoomDefaultEvents() - } - } - - /** - * Generate the create state event related to this room. - */ - private fun MutableList.createRoomCreateEvent(createRoomBody: CreateRoomBody) = apply { - val roomCreateEvent = createLocalEvent( - type = EventType.STATE_ROOM_CREATE, - content = RoomCreateContent( - creator = myUserId, - roomVersion = createRoomBody.roomVersion, - type = (createRoomBody.creationContent as? Map<*, *>)?.get(CreateRoomParams.CREATION_CONTENT_KEY_ROOM_TYPE) as? String - - ).toContent(), - stateKey = "" - ) - add(roomCreateEvent) - } - - /** - * Generate the create state event related to the power levels using the given overridden values or the default values according to the specification. - * Ref: https://spec.matrix.org/latest/client-server-api/#mroompower_levels - */ - private fun MutableList.createRoomPowerLevelsEvent(createRoomBody: CreateRoomBody) = apply { - val powerLevelsContent = createLocalEvent( - type = EventType.STATE_ROOM_POWER_LEVELS, - content = (createRoomBody.powerLevelContentOverride ?: PowerLevelsContent()).let { - it.copy( - ban = it.banOrDefault(), - eventsDefault = it.eventsDefaultOrDefault(), - invite = it.inviteOrDefault(), - kick = it.kickOrDefault(), - redact = it.redactOrDefault(), - stateDefault = it.stateDefaultOrDefault(), - usersDefault = it.usersDefaultOrDefault(), - ) - }.toContent(), - stateKey = "" - ) - add(powerLevelsContent) - } - - /** - * Generate the local room member state events related to the given user ids, if any. - */ - private suspend fun MutableList.createRoomMemberEvents(userIds: List, isDirect: Boolean? = null) = apply { - val memberEvents = userIds - .mapNotNull { tryOrNull { userService.resolveUser(it) } } - .map { user -> - createLocalEvent( - type = EventType.STATE_ROOM_MEMBER, - content = RoomMemberContent( - isDirect = isDirect.orFalse(), - membership = if (user.userId == myUserId) Membership.JOIN else Membership.INVITE, - displayName = user.displayName, - avatarUrl = user.avatarUrl - ).toContent(), - stateKey = user.userId - ) - } - addAll(memberEvents) - } - - /** - * Generate the local state events related to the given third party invites, if any. - */ - private fun MutableList.createRoomThreePidEvents(createRoomBody: CreateRoomBody) = apply { - val threePidEvents = createRoomBody.invite3pids.orEmpty().map { body -> - val localThirdPartyInviteEvent = createLocalEvent( - type = EventType.LOCAL_STATE_ROOM_THIRD_PARTY_INVITE, - content = LocalRoomThirdPartyInviteContent( - isDirect = createRoomBody.isDirect.orFalse(), - membership = Membership.INVITE, - displayName = body.address, - thirdPartyInvite = body.toThreePid() - ).toContent(), - stateKey = "" - ) - val thirdPartyInviteEvent = createLocalEvent( - type = EventType.STATE_ROOM_THIRD_PARTY_INVITE, - content = RoomThirdPartyInviteContent(body.address, null, null, null).toContent(), - stateKey = "" - ) - listOf(localThirdPartyInviteEvent, thirdPartyInviteEvent) - }.flatten() - addAll(threePidEvents) - } - - /** - * Generate the local state event related to the given alias, if any. - */ - fun MutableList.createRoomAliasEvent(createRoomBody: CreateRoomBody) = apply { - if (createRoomBody.roomAliasName != null) { - val canonicalAliasContent = createLocalEvent( - type = EventType.STATE_ROOM_CANONICAL_ALIAS, - content = RoomCanonicalAliasContent( - canonicalAlias = "${createRoomBody.roomAliasName}:${myUserId.getServerName()}" - ).toContent(), - stateKey = "" - ) - add(canonicalAliasContent) - } - } - - /** - * Generate the local state events related to the given [CreateRoomPreset]. - * Ref: https://spec.matrix.org/latest/client-server-api/#post_matrixclientv3createroom - */ - private fun MutableList.createRoomPresetEvents(createRoomBody: CreateRoomBody) = apply { - createRoomBody.preset ?: return@apply - - var joinRules: RoomJoinRules? = null - var historyVisibility: RoomHistoryVisibility? = null - var guestAccess: GuestAccess? = null - when (createRoomBody.preset) { - CreateRoomPreset.PRESET_PRIVATE_CHAT, - CreateRoomPreset.PRESET_TRUSTED_PRIVATE_CHAT -> { - joinRules = RoomJoinRules.INVITE - historyVisibility = RoomHistoryVisibility.SHARED - guestAccess = GuestAccess.CanJoin - } - CreateRoomPreset.PRESET_PUBLIC_CHAT -> { - joinRules = RoomJoinRules.PUBLIC - historyVisibility = RoomHistoryVisibility.SHARED - guestAccess = GuestAccess.Forbidden - } - } - - add(createLocalEvent(EventType.STATE_ROOM_JOIN_RULES, RoomJoinRulesContent(joinRules.value).toContent(), "")) - add(createLocalEvent(EventType.STATE_ROOM_HISTORY_VISIBILITY, RoomHistoryVisibilityContent(historyVisibility.value).toContent(), "")) - add(createLocalEvent(EventType.STATE_ROOM_GUEST_ACCESS, RoomGuestAccessContent(guestAccess.value).toContent(), "")) - } - - /** - * Generate the local state events related to the given initial states, if any. - * The given initial state events override the potential existing ones of the same type. - */ - private fun MutableList.createRoomInitialStateEvents(createRoomBody: CreateRoomBody) = apply { - createRoomBody.initialStates ?: return@apply - - val initialStateEvents = createRoomBody.initialStates.map { createLocalEvent(it.type, it.content, it.stateKey) } - // Erase existing events of the same type - removeAll { event -> event.type in initialStateEvents.map { it.type } } - // Add the initial state events to the list - addAll(initialStateEvents) - } - - /** - * Generate the local events related to the given room name and topic, if any. - */ - private fun MutableList.createRoomNameAndTopicStateEvents(createRoomBody: CreateRoomBody) = apply { - if (createRoomBody.name != null) { - add(createLocalEvent(EventType.STATE_ROOM_NAME, RoomNameContent(createRoomBody.name).toContent(), "")) - } - if (createRoomBody.topic != null) { - add(createLocalEvent(EventType.STATE_ROOM_TOPIC, RoomTopicContent(createRoomBody.topic).toContent(), "")) - } - } - - /** - * Generate the local events which have not been set and are in that case provided by the server with default values: - * - m.room.history_visibility (https://spec.matrix.org/latest/client-server-api/#server-behaviour-5) - * - m.room.guest_access (https://spec.matrix.org/latest/client-server-api/#mroomguest_access) - */ - private fun MutableList.createRoomDefaultEvents() = apply { - // HistoryVisibility - if (none { it.type == EventType.STATE_ROOM_HISTORY_VISIBILITY }) { - add( - createLocalEvent( - type = EventType.STATE_ROOM_HISTORY_VISIBILITY, - content = RoomHistoryVisibilityContent(RoomHistoryVisibility.SHARED.value).toContent(), - stateKey = "" - ) - ) - } - // GuestAccess - if (none { it.type == EventType.STATE_ROOM_GUEST_ACCESS }) { - add( - createLocalEvent( - type = EventType.STATE_ROOM_GUEST_ACCESS, - content = RoomGuestAccessContent(GuestAccess.Forbidden.value).toContent(), - stateKey = "" - ) - ) - } - } - - /** - * Generate a local event from the given parameters. - * - * @param type the event type, see [EventType] - * @param content the content of the Event - * @param stateKey the stateKey, if any - * - * @return a local event - */ - private fun createLocalEvent(type: String?, content: Content?, stateKey: String?): Event { - return Event( - type = type, - senderId = myUserId, - stateKey = stateKey, - content = content, - originServerTs = clock.epochMillis(), - eventId = LocalEcho.createLocalEchoId() - ) - } }