Skip to content

Commit

Permalink
Add/Remove local alias (#2428)
Browse files Browse the repository at this point in the history
  • Loading branch information
bmarty committed Nov 23, 2020
1 parent 5b027be commit 4c469e0
Show file tree
Hide file tree
Showing 19 changed files with 262 additions and 94 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,9 @@ interface AliasService {
* Get list of local alias of the room
*/
suspend fun getRoomAliases(): List<String>

/**
* Add local alias to the room
*/
suspend fun addAlias(aliasLocalPart: String)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* 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.api.session.room.alias

sealed class RoomAliasError : Throwable() {
object AliasEmpty : RoomAliasError()
object AliasNotAvailable : RoomAliasError()
object AliasInvalid : RoomAliasError()
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,10 @@ package org.matrix.android.sdk.api.session.room.failure

import org.matrix.android.sdk.api.failure.Failure
import org.matrix.android.sdk.api.failure.MatrixError
import org.matrix.android.sdk.api.session.room.alias.RoomAliasError

sealed class CreateRoomFailure : Failure.FeatureFailure() {
object CreatedWithTimeout : CreateRoomFailure()
data class CreatedWithFederationFailure(val matrixError: MatrixError) : CreateRoomFailure()
sealed class RoomAliasError : CreateRoomFailure() {
object AliasEmpty : RoomAliasError()
object AliasNotAvailable : RoomAliasError()
object AliasInvalid : RoomAliasError()
}
data class AliasError(val aliasError: RoomAliasError) : CreateRoomFailure()
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,6 @@ interface StateService {
*/
fun updateName(name: String, callback: MatrixCallback<Unit>): Cancelable

/**
* Add new alias to the room.
*/
fun addRoomAlias(roomAlias: String, callback: MatrixCallback<Unit>): Cancelable

/**
* Update the canonical alias of the room
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ internal interface DirectoryAPI {
* Add alias to the room.
* @param roomAlias the room alias.
*/
// TODO Remove (https://github.com/matrix-org/matrix-doc/blob/rav/proposal/alt_canonical_aliases/proposals/2432-revised-alias-publishing.md)
@PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "directory/room/{roomAlias}")
fun addRoomAlias(@Path("roomAlias") roomAlias: String,
@Body body: AddRoomAliasBody): Call<Unit>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,33 @@
package org.matrix.android.sdk.internal.session.room.alias

import org.greenrobot.eventbus.EventBus
import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.network.executeRequest
import org.matrix.android.sdk.internal.session.directory.DirectoryAPI
import org.matrix.android.sdk.internal.session.room.alias.RoomAliasAvailabilityChecker.Companion.toFullAlias
import org.matrix.android.sdk.internal.task.Task
import javax.inject.Inject

internal interface AddRoomAliasTask : Task<AddRoomAliasTask.Params, Unit> {
data class Params(
val roomId: String,
val roomAlias: String
val aliasLocalPart: String
)
}

internal class DefaultAddRoomAliasTask @Inject constructor(
@UserId private val userId: String,
private val directoryAPI: DirectoryAPI,
private val aliasAvailabilityChecker: RoomAliasAvailabilityChecker,
private val eventBus: EventBus
) : AddRoomAliasTask {

override suspend fun execute(params: AddRoomAliasTask.Params) {
aliasAvailabilityChecker.check(params.aliasLocalPart)

executeRequest<Unit>(eventBus) {
apiCall = directoryAPI.addRoomAlias(
roomAlias = params.roomAlias,
roomAlias = params.aliasLocalPart.toFullAlias(userId),
body = AddRoomAliasBody(
roomId = params.roomId
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import org.matrix.android.sdk.api.session.room.alias.AliasService

internal class DefaultAliasService @AssistedInject constructor(
@Assisted private val roomId: String,
private val getRoomLocalAliasesTask: GetRoomLocalAliasesTask
private val getRoomLocalAliasesTask: GetRoomLocalAliasesTask,
private val addRoomAliasTask: AddRoomAliasTask
) : AliasService {

@AssistedInject.Factory
Expand All @@ -33,4 +34,8 @@ internal class DefaultAliasService @AssistedInject constructor(
override suspend fun getRoomAliases(): List<String> {
return getRoomLocalAliasesTask.execute(GetRoomLocalAliasesTask.Params(roomId))
}

override suspend fun addAlias(aliasLocalPart: String) {
addRoomAliasTask.execute(AddRoomAliasTask.Params(roomId, aliasLocalPart))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* 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.alias

import org.greenrobot.eventbus.EventBus
import org.matrix.android.sdk.api.failure.Failure
import org.matrix.android.sdk.api.session.room.alias.RoomAliasError
import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.network.executeRequest
import org.matrix.android.sdk.internal.session.directory.DirectoryAPI
import javax.inject.Inject

internal class RoomAliasAvailabilityChecker @Inject constructor(
@UserId private val userId: String,
private val directoryAPI: DirectoryAPI,
private val eventBus: EventBus
) {
@Throws(RoomAliasError::class)
suspend fun check(aliasLocalPart: String?) {
if (aliasLocalPart.isNullOrEmpty()) {
throw RoomAliasError.AliasEmpty
}
// Check alias availability
val fullAlias = aliasLocalPart.toFullAlias(userId)
try {
executeRequest<RoomAliasDescription>(eventBus) {
apiCall = directoryAPI.getRoomIdByAlias(fullAlias)
}
} catch (throwable: Throwable) {
if (throwable is Failure.ServerError && throwable.httpCode == 404) {
// This is a 404, so the alias is available: nominal case
null
} else {
// Other error, propagate it
throw throwable
}
}
?.let {
// Alias already exists: error case
throw RoomAliasError.AliasNotAvailable
}
}

companion object {
internal fun String.toFullAlias(userId: String) = "#" + this + ":" + userId.substringAfter(":")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import kotlinx.coroutines.TimeoutCancellationException
import org.greenrobot.eventbus.EventBus
import org.matrix.android.sdk.api.failure.Failure
import org.matrix.android.sdk.api.failure.MatrixError
import org.matrix.android.sdk.api.session.room.alias.RoomAliasError
import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset
Expand All @@ -31,11 +32,9 @@ import org.matrix.android.sdk.internal.database.model.RoomEntityFields
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
import org.matrix.android.sdk.internal.database.query.where
import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.network.executeRequest
import org.matrix.android.sdk.internal.session.directory.DirectoryAPI
import org.matrix.android.sdk.internal.session.room.RoomAPI
import org.matrix.android.sdk.internal.session.room.alias.RoomAliasDescription
import org.matrix.android.sdk.internal.session.room.alias.RoomAliasAvailabilityChecker
import org.matrix.android.sdk.internal.session.room.read.SetReadMarkersTask
import org.matrix.android.sdk.internal.session.user.accountdata.DirectChatsHelper
import org.matrix.android.sdk.internal.session.user.accountdata.UpdateUserAccountDataTask
Expand All @@ -48,9 +47,8 @@ internal interface CreateRoomTask : Task<CreateRoomParams, String>

internal class DefaultCreateRoomTask @Inject constructor(
private val roomAPI: RoomAPI,
private val directoryAPI: DirectoryAPI,
@UserId private val userId: String,
@SessionDatabase private val monarchy: Monarchy,
private val aliasAvailabilityChecker: RoomAliasAvailabilityChecker,
private val directChatsHelper: DirectChatsHelper,
private val updateUserAccountDataTask: UpdateUserAccountDataTask,
private val readMarkersTask: SetReadMarkersTask,
Expand All @@ -67,28 +65,11 @@ internal class DefaultCreateRoomTask @Inject constructor(
} else null

if (params.preset == CreateRoomPreset.PRESET_PUBLIC_CHAT) {
if (params.roomAliasName.isNullOrEmpty()) {
throw CreateRoomFailure.RoomAliasError.AliasEmpty
}
// Check alias availability
val fullAlias = "#" + params.roomAliasName + ":" + userId.substringAfter(":")
try {
executeRequest<RoomAliasDescription>(eventBus) {
apiCall = directoryAPI.getRoomIdByAlias(fullAlias)
}
} catch (throwable: Throwable) {
if (throwable is Failure.ServerError && throwable.httpCode == 404) {
// This is a 404, so the alias is available: nominal case
null
} else {
// Other error, propagate it
throw throwable
}
aliasAvailabilityChecker.check(params.roomAliasName)
} catch (aliasError: RoomAliasError) {
throw CreateRoomFailure.AliasError(aliasError)
}
?.let {
// Alias already exists: error case
throw CreateRoomFailure.RoomAliasError.AliasNotAvailable
}
}

val createRoomBody = createRoomBodyBuilder.build(params)
Expand All @@ -106,7 +87,7 @@ internal class DefaultCreateRoomTask @Inject constructor(
} else if (throwable.httpCode == 400
&& throwable.error.code == MatrixError.M_UNKNOWN
&& throwable.error.message == "Invalid characters in room alias") {
throw CreateRoomFailure.RoomAliasError.AliasInvalid
throw CreateRoomFailure.AliasError(RoomAliasError.AliasInvalid)
}
}
throw throwable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,14 +104,6 @@ internal class DefaultStateService @AssistedInject constructor(@Assisted private
)
}

override fun addRoomAlias(roomAlias: String, callback: MatrixCallback<Unit>): Cancelable {
return addRoomAliasTask
.configureWith(AddRoomAliasTask.Params(roomId, roomAlias)) {
this.callback = callback
}
.executeBy(taskExecutor)
}

override fun updateCanonicalAlias(alias: String, callback: MatrixCallback<Unit>): Cancelable {
return sendStateEvent(
eventType = EventType.STATE_ROOM_CANONICAL_ALIAS,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,20 @@ import com.airbnb.epoxy.TypedEpoxyController
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Loading
import im.vector.app.R
import im.vector.app.core.error.ErrorFormatter
import im.vector.app.core.resources.StringProvider
import im.vector.app.features.discovery.settingsSectionTitleItem
import im.vector.app.features.form.formAdvancedToggleItem
import im.vector.app.features.form.formEditTextItem
import im.vector.app.features.form.formEditableAvatarItem
import im.vector.app.features.form.formSubmitButtonItem
import im.vector.app.features.form.formSwitchItem
import org.matrix.android.sdk.api.session.room.alias.RoomAliasError
import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
import javax.inject.Inject

class CreateRoomController @Inject constructor(private val stringProvider: StringProvider,
private val errorFormatter: ErrorFormatter
class CreateRoomController @Inject constructor(
private val stringProvider: StringProvider,
private val roomAliasErrorFormatter: RoomAliasErrorFormatter
) : TypedEpoxyController<CreateRoomViewState>() {

var listener: Listener? = null
Expand Down Expand Up @@ -103,15 +104,7 @@ class CreateRoomController @Inject constructor(private val stringProvider: Strin
enabled(enableFormElement)
value(viewState.roomType.aliasLocalPart)
homeServer(":" + viewState.homeServerName)
errorMessage(
when ((viewState.asyncCreateRoomRequest as? Fail)?.error) {
is CreateRoomFailure.RoomAliasError.AliasEmpty -> R.string.create_room_alias_empty
is CreateRoomFailure.RoomAliasError.AliasNotAvailable -> R.string.create_room_alias_already_in_use
is CreateRoomFailure.RoomAliasError.AliasInvalid -> R.string.create_room_alias_invalid
else -> null
}
?.let { stringProvider.getString(it) }
)
errorMessage(roomAliasErrorFormatter.format((((viewState.asyncCreateRoomRequest as? Fail)?.error) as? CreateRoomFailure.AliasError)?.aliasError))
onTextChange { value ->
listener?.setAliasLocalPart(value)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class CreateRoomFragment @Inject constructor(

override fun showFailure(throwable: Throwable) {
// Note: RoomAliasError are displayed directly in the form
if (throwable !is CreateRoomFailure.RoomAliasError) {
if (throwable !is CreateRoomFailure.AliasError) {
super.showFailure(throwable)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* 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 im.vector.app.features.roomdirectory.createroom

import im.vector.app.R
import im.vector.app.core.resources.StringProvider
import org.matrix.android.sdk.api.session.room.alias.RoomAliasError
import javax.inject.Inject

class RoomAliasErrorFormatter @Inject constructor(
private val stringProvider: StringProvider
) {
fun format(roomAliasError: RoomAliasError?): String? {
return when (roomAliasError) {
is RoomAliasError.AliasEmpty -> R.string.create_room_alias_empty
is RoomAliasError.AliasNotAvailable -> R.string.create_room_alias_already_in_use
is RoomAliasError.AliasInvalid -> R.string.create_room_alias_invalid
else -> null
}
?.let { stringProvider.getString(it) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ sealed class RoomAliasAction : VectorViewModelAction {
object UnSetCanonicalAlias : RoomAliasAction()

// Local
data class AddLocalAlias(val aliasLocalPart: String) : RoomAliasAction()
data class RemoveLocalAlias(val alias: String) : RoomAliasAction()
data class SetNewLocalAliasLocalPart(val aliasLocalPart: String) : RoomAliasAction()
object AddLocalAlias : RoomAliasAction()
}
Loading

0 comments on commit 4c469e0

Please sign in to comment.