From ab1d652f1725d6c5d116c51de48b13e9e008094e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 7 Jul 2020 19:52:04 +0200 Subject: [PATCH] Invite by email (msisdn not working), command line (#548) --- .../session/room/members/MembershipService.kt | 7 ++ .../identity/DefaultIdentityService.kt | 14 +--- .../session/identity/EnsureIdentityToken.kt | 59 +++++++++++++++++ .../session/identity/IdentityModule.kt | 3 + .../android/internal/session/room/RoomAPI.kt | 9 +++ .../internal/session/room/RoomModule.kt | 5 ++ .../membership/DefaultMembershipService.kt | 12 ++++ .../membership/threepid/InviteThreePidTask.kt | 65 +++++++++++++++++++ .../membership/threepid/ThreePidInviteBody.kt | 41 ++++++++++++ .../riotx/core/extensions/BasicExtensions.kt | 15 +++++ .../riotx/features/command/CommandParser.kt | 30 ++++++--- .../riotx/features/command/ParsedCommand.kt | 3 + .../home/room/detail/RoomDetailFragment.kt | 2 +- .../home/room/detail/RoomDetailViewModel.kt | 10 +++ 14 files changed, 253 insertions(+), 22 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/EnsureIdentityToken.kt create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/threepid/InviteThreePidTask.kt create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/threepid/ThreePidInviteBody.kt diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/members/MembershipService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/members/MembershipService.kt index f011d317cd..bb74b5afa5 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/members/MembershipService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/members/MembershipService.kt @@ -18,6 +18,7 @@ package im.vector.matrix.android.api.session.room.members import androidx.lifecycle.LiveData import im.vector.matrix.android.api.MatrixCallback +import im.vector.matrix.android.api.session.identity.ThreePid import im.vector.matrix.android.api.session.room.model.RoomMemberSummary import im.vector.matrix.android.api.util.Cancelable @@ -63,6 +64,12 @@ interface MembershipService { reason: String? = null, callback: MatrixCallback): Cancelable + /** + * Invite a user with email or phone number in the room + */ + fun invite3pid(threePid: ThreePid, + callback: MatrixCallback): Cancelable + /** * Ban a user from the room */ diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/DefaultIdentityService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/DefaultIdentityService.kt index 3f10bf791c..13c97599f7 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/DefaultIdentityService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/DefaultIdentityService.kt @@ -62,6 +62,7 @@ import javax.net.ssl.HttpsURLConnection @SessionScope internal class DefaultIdentityService @Inject constructor( private val identityStore: IdentityStore, + private val ensureIdentityTokenTask: EnsureIdentityTokenTask, private val getOpenIdTokenTask: GetOpenIdTokenTask, private val identityBulkLookupTask: IdentityBulkLookupTask, private val identityRegisterTask: IdentityRegisterTask, @@ -278,7 +279,7 @@ internal class DefaultIdentityService @Inject constructor( } private suspend fun lookUpInternal(canRetry: Boolean, threePids: List): List { - ensureToken() + ensureIdentityTokenTask.execute(Unit) return try { identityBulkLookupTask.execute(IdentityBulkLookupTask.Params(threePids)) @@ -295,17 +296,6 @@ internal class DefaultIdentityService @Inject constructor( } } - private suspend fun ensureToken() { - val identityData = identityStore.getIdentityData() ?: throw IdentityServiceError.NoIdentityServerConfigured - val url = identityData.identityServerUrl ?: throw IdentityServiceError.NoIdentityServerConfigured - - if (identityData.token == null) { - // Try to get a token - val token = getNewIdentityServerToken(url) - identityStore.setToken(token) - } - } - private suspend fun getNewIdentityServerToken(url: String): String { val api = retrofitFactory.create(unauthenticatedOkHttpClient, url).create(IdentityAuthAPI::class.java) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/EnsureIdentityToken.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/EnsureIdentityToken.kt new file mode 100644 index 0000000000..e727cd69bc --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/EnsureIdentityToken.kt @@ -0,0 +1,59 @@ +/* + * 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.matrix.android.internal.session.identity + +import dagger.Lazy +import im.vector.matrix.android.api.session.identity.IdentityServiceError +import im.vector.matrix.android.internal.di.UnauthenticatedWithCertificate +import im.vector.matrix.android.internal.network.RetrofitFactory +import im.vector.matrix.android.internal.session.identity.data.IdentityStore +import im.vector.matrix.android.internal.session.openid.GetOpenIdTokenTask +import im.vector.matrix.android.internal.task.Task +import okhttp3.OkHttpClient +import javax.inject.Inject + +internal interface EnsureIdentityTokenTask : Task + +internal class DefaultEnsureIdentityTokenTask @Inject constructor( + private val identityStore: IdentityStore, + private val retrofitFactory: RetrofitFactory, + @UnauthenticatedWithCertificate + private val unauthenticatedOkHttpClient: Lazy, + private val getOpenIdTokenTask: GetOpenIdTokenTask, + private val identityRegisterTask: IdentityRegisterTask +) : EnsureIdentityTokenTask { + + override suspend fun execute(params: Unit) { + val identityData = identityStore.getIdentityData() ?: throw IdentityServiceError.NoIdentityServerConfigured + val url = identityData.identityServerUrl ?: throw IdentityServiceError.NoIdentityServerConfigured + + if (identityData.token == null) { + // Try to get a token + val token = getNewIdentityServerToken(url) + identityStore.setToken(token) + } + } + + private suspend fun getNewIdentityServerToken(url: String): String { + val api = retrofitFactory.create(unauthenticatedOkHttpClient, url).create(IdentityAuthAPI::class.java) + + val openIdToken = getOpenIdTokenTask.execute(Unit) + val token = identityRegisterTask.execute(IdentityRegisterTask.Params(api, openIdToken)) + + return token.token + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/IdentityModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/IdentityModule.kt index 9f902f79f1..79160b8c59 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/IdentityModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/identity/IdentityModule.kt @@ -78,6 +78,9 @@ internal abstract class IdentityModule { @Binds abstract fun bindIdentityStore(store: RealmIdentityStore): IdentityStore + @Binds + abstract fun bindEnsureIdentityTokenTask(task: DefaultEnsureIdentityTokenTask): EnsureIdentityTokenTask + @Binds abstract fun bindIdentityPingTask(task: DefaultIdentityPingTask): IdentityPingTask diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAPI.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAPI.kt index 59fc0efbc0..e00a94297a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAPI.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAPI.kt @@ -31,6 +31,7 @@ import im.vector.matrix.android.internal.session.room.alias.RoomAliasDescription import im.vector.matrix.android.internal.session.room.membership.RoomMembersResponse import im.vector.matrix.android.internal.session.room.membership.admin.UserIdAndReason import im.vector.matrix.android.internal.session.room.membership.joining.InviteBody +import im.vector.matrix.android.internal.session.room.membership.threepid.ThreePidInviteBody import im.vector.matrix.android.internal.session.room.relation.RelationsResponse import im.vector.matrix.android.internal.session.room.reporting.ReportContentBody import im.vector.matrix.android.internal.session.room.send.SendResponse @@ -170,6 +171,14 @@ internal interface RoomAPI { @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/invite") fun invite(@Path("roomId") roomId: String, @Body body: InviteBody): Call + /** + * Invite a user to a room, using a ThreePid + * Ref: https://matrix.org/docs/spec/client_server/r0.6.1#id101 + * @param roomId Required. The room identifier (not alias) to which to invite the user. + */ + @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/invite") + fun invite3pid(@Path("roomId") roomId: String, @Body body: ThreePidInviteBody): Call + /** * Send a generic state events * diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt index 7fa9c1526a..3eb5427b70 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt @@ -44,6 +44,8 @@ import im.vector.matrix.android.internal.session.room.membership.joining.InviteT import im.vector.matrix.android.internal.session.room.membership.joining.JoinRoomTask import im.vector.matrix.android.internal.session.room.membership.leaving.DefaultLeaveRoomTask import im.vector.matrix.android.internal.session.room.membership.leaving.LeaveRoomTask +import im.vector.matrix.android.internal.session.room.membership.threepid.DefaultInviteThreePidTask +import im.vector.matrix.android.internal.session.room.membership.threepid.InviteThreePidTask import im.vector.matrix.android.internal.session.room.read.DefaultMarkAllRoomsReadTask import im.vector.matrix.android.internal.session.room.read.DefaultSetReadMarkersTask import im.vector.matrix.android.internal.session.room.read.MarkAllRoomsReadTask @@ -139,6 +141,9 @@ internal abstract class RoomModule { @Binds abstract fun bindInviteTask(task: DefaultInviteTask): InviteTask + @Binds + abstract fun bindInviteThreePidTask(task: DefaultInviteThreePidTask): InviteThreePidTask + @Binds abstract fun bindJoinRoomTask(task: DefaultJoinRoomTask): JoinRoomTask diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/DefaultMembershipService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/DefaultMembershipService.kt index 8467e8b46c..f413f5c9c0 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/DefaultMembershipService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/DefaultMembershipService.kt @@ -21,6 +21,7 @@ import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.api.MatrixCallback +import im.vector.matrix.android.api.session.identity.ThreePid import im.vector.matrix.android.api.session.room.members.MembershipService import im.vector.matrix.android.api.session.room.members.RoomMemberQueryParams import im.vector.matrix.android.api.session.room.model.Membership @@ -36,6 +37,7 @@ import im.vector.matrix.android.internal.session.room.membership.admin.Membershi import im.vector.matrix.android.internal.session.room.membership.joining.InviteTask import im.vector.matrix.android.internal.session.room.membership.joining.JoinRoomTask import im.vector.matrix.android.internal.session.room.membership.leaving.LeaveRoomTask +import im.vector.matrix.android.internal.session.room.membership.threepid.InviteThreePidTask import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.configureWith import im.vector.matrix.android.internal.util.fetchCopied @@ -48,6 +50,7 @@ internal class DefaultMembershipService @AssistedInject constructor( private val taskExecutor: TaskExecutor, private val loadRoomMembersTask: LoadRoomMembersTask, private val inviteTask: InviteTask, + private val inviteThreePidTask: InviteThreePidTask, private val joinTask: JoinRoomTask, private val leaveRoomTask: LeaveRoomTask, private val membershipAdminTask: MembershipAdminTask, @@ -152,6 +155,15 @@ internal class DefaultMembershipService @AssistedInject constructor( .executeBy(taskExecutor) } + override fun invite3pid(threePid: ThreePid, callback: MatrixCallback): Cancelable { + val params = InviteThreePidTask.Params(roomId, threePid) + return inviteThreePidTask + .configureWith(params) { + this.callback = callback + } + .executeBy(taskExecutor) + } + override fun join(reason: String?, viaServers: List, callback: MatrixCallback): Cancelable { val params = JoinRoomTask.Params(roomId, reason, viaServers) return joinTask diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/threepid/InviteThreePidTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/threepid/InviteThreePidTask.kt new file mode 100644 index 0000000000..25fe7b4888 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/threepid/InviteThreePidTask.kt @@ -0,0 +1,65 @@ +/* + * Copyright 2019 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.matrix.android.internal.session.room.membership.threepid + +import im.vector.matrix.android.api.session.identity.IdentityServiceError +import im.vector.matrix.android.api.session.identity.ThreePid +import im.vector.matrix.android.api.session.identity.toMedium +import im.vector.matrix.android.internal.di.AuthenticatedIdentity +import im.vector.matrix.android.internal.network.executeRequest +import im.vector.matrix.android.internal.network.token.AccessTokenProvider +import im.vector.matrix.android.internal.session.identity.EnsureIdentityTokenTask +import im.vector.matrix.android.internal.session.identity.data.IdentityStore +import im.vector.matrix.android.internal.session.identity.data.getIdentityServerUrlWithoutProtocol +import im.vector.matrix.android.internal.session.room.RoomAPI +import im.vector.matrix.android.internal.task.Task +import org.greenrobot.eventbus.EventBus +import javax.inject.Inject + +internal interface InviteThreePidTask : Task { + data class Params( + val roomId: String, + val threePid: ThreePid + ) +} + +internal class DefaultInviteThreePidTask @Inject constructor( + private val roomAPI: RoomAPI, + private val eventBus: EventBus, + private val identityStore: IdentityStore, + private val ensureIdentityTokenTask: EnsureIdentityTokenTask, + @AuthenticatedIdentity + private val accessTokenProvider: AccessTokenProvider +) : InviteThreePidTask { + + override suspend fun execute(params: InviteThreePidTask.Params) { + ensureIdentityTokenTask.execute(Unit) + + val identityServerUrlWithoutProtocol = identityStore.getIdentityServerUrlWithoutProtocol() ?: throw IdentityServiceError.NoIdentityServerConfigured + val identityServerAccessToken = accessTokenProvider.getToken() ?: throw IdentityServiceError.NoIdentityServerConfigured + + return executeRequest(eventBus) { + val body = ThreePidInviteBody( + id_server = identityServerUrlWithoutProtocol, + id_access_token = identityServerAccessToken, + medium = params.threePid.toMedium(), + address = params.threePid.value + ) + apiCall = roomAPI.invite3pid(params.roomId, body) + } + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/threepid/ThreePidInviteBody.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/threepid/ThreePidInviteBody.kt new file mode 100644 index 0000000000..23dd6bad77 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/threepid/ThreePidInviteBody.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2019 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.matrix.android.internal.session.room.membership.threepid + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +internal data class ThreePidInviteBody( + /** + * Required. The hostname+port of the identity server which should be used for third party identifier lookups. + */ + @Json(name = "id_server") val id_server: String, + /** + * Required. An access token previously registered with the identity server. Servers can treat this as optional + * to distinguish between r0.5-compatible clients and this specification version. + */ + @Json(name = "id_access_token") val id_access_token: String, + /** + * Required. The kind of address being passed in the address field, for example email. + */ + @Json(name = "medium") val medium: String, + /** + * Required. The invitee's third party identifier. + */ + @Json(name = "address") val address: String +) diff --git a/vector/src/main/java/im/vector/riotx/core/extensions/BasicExtensions.kt b/vector/src/main/java/im/vector/riotx/core/extensions/BasicExtensions.kt index 5bd6852e8a..6afd4fb279 100644 --- a/vector/src/main/java/im/vector/riotx/core/extensions/BasicExtensions.kt +++ b/vector/src/main/java/im/vector/riotx/core/extensions/BasicExtensions.kt @@ -19,6 +19,8 @@ package im.vector.riotx.core.extensions import android.os.Bundle import android.util.Patterns import androidx.fragment.app.Fragment +import com.google.i18n.phonenumbers.NumberParseException +import com.google.i18n.phonenumbers.PhoneNumberUtil fun Boolean.toOnOff() = if (this) "ON" else "OFF" @@ -33,3 +35,16 @@ fun T.withArgs(block: Bundle.() -> Unit) = apply { arguments = Bu * Check if a CharSequence is an email */ fun CharSequence.isEmail() = Patterns.EMAIL_ADDRESS.matcher(this).matches() + +/** + * Check if a CharSequence is a phone number + * FIXME It does not work? + */ +fun CharSequence.isMsisdn(): Boolean { + return try { + PhoneNumberUtil.getInstance().parse(this, null) + true + } catch (e: NumberParseException) { + false + } +} diff --git a/vector/src/main/java/im/vector/riotx/features/command/CommandParser.kt b/vector/src/main/java/im/vector/riotx/features/command/CommandParser.kt index 7c32a34aff..2b38a1ac25 100644 --- a/vector/src/main/java/im/vector/riotx/features/command/CommandParser.kt +++ b/vector/src/main/java/im/vector/riotx/features/command/CommandParser.kt @@ -17,6 +17,9 @@ package im.vector.riotx.features.command import im.vector.matrix.android.api.MatrixPatterns +import im.vector.matrix.android.api.session.identity.ThreePid +import im.vector.riotx.core.extensions.isEmail +import im.vector.riotx.core.extensions.isMsisdn import timber.log.Timber object CommandParser { @@ -139,15 +142,24 @@ object CommandParser { if (messageParts.size >= 2) { val userId = messageParts[1] - if (MatrixPatterns.isUserId(userId)) { - ParsedCommand.Invite( - userId, - textMessage.substring(Command.INVITE.length + userId.length) - .trim() - .takeIf { it.isNotBlank() } - ) - } else { - ParsedCommand.ErrorSyntax(Command.INVITE) + when { + MatrixPatterns.isUserId(userId) -> { + ParsedCommand.Invite( + userId, + textMessage.substring(Command.INVITE.length + userId.length) + .trim() + .takeIf { it.isNotBlank() } + ) + } + userId.isEmail() -> { + ParsedCommand.Invite3Pid(ThreePid.Email(userId)) + } + userId.isMsisdn() -> { + ParsedCommand.Invite3Pid(ThreePid.Msisdn(userId)) + } + else -> { + ParsedCommand.ErrorSyntax(Command.INVITE) + } } } else { ParsedCommand.ErrorSyntax(Command.INVITE) diff --git a/vector/src/main/java/im/vector/riotx/features/command/ParsedCommand.kt b/vector/src/main/java/im/vector/riotx/features/command/ParsedCommand.kt index 44ad2265e1..041da3dcac 100644 --- a/vector/src/main/java/im/vector/riotx/features/command/ParsedCommand.kt +++ b/vector/src/main/java/im/vector/riotx/features/command/ParsedCommand.kt @@ -16,6 +16,8 @@ package im.vector.riotx.features.command +import im.vector.matrix.android.api.session.identity.ThreePid + /** * Represent a parsed command */ @@ -41,6 +43,7 @@ sealed class ParsedCommand { class UnbanUser(val userId: String, val reason: String?) : ParsedCommand() class SetUserPowerLevel(val userId: String, val powerLevel: Int?) : ParsedCommand() class Invite(val userId: String, val reason: String?) : ParsedCommand() + class Invite3Pid(val threePid: ThreePid) : ParsedCommand() class JoinRoom(val roomAlias: String, val reason: String?) : ParsedCommand() class PartRoom(val roomAlias: String, val reason: String?) : ParsedCommand() class ChangeTopic(val topic: String) : ParsedCommand() diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt index 62078c3053..3c65b6281f 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt @@ -960,7 +960,7 @@ class RoomDetailFragment @Inject constructor( updateComposerText("") } is RoomDetailViewEvents.SlashCommandResultError -> { - displayCommandError(sendMessageResult.throwable.localizedMessage ?: getString(R.string.unexpected_error)) + displayCommandError(errorFormatter.toHumanReadable(sendMessageResult.throwable)) } is RoomDetailViewEvents.SlashCommandNotImplemented -> { displayCommandError(getString(R.string.not_implemented)) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt index 982448d1c1..a396152f6b 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt @@ -457,6 +457,10 @@ class RoomDetailViewModel @AssistedInject constructor( handleInviteSlashCommand(slashCommandResult) popDraft() } + is ParsedCommand.Invite3Pid -> { + handleInvite3pidSlashCommand(slashCommandResult) + popDraft() + } is ParsedCommand.SetUserPowerLevel -> { handleSetUserPowerLevel(slashCommandResult) popDraft() @@ -678,6 +682,12 @@ class RoomDetailViewModel @AssistedInject constructor( } } + private fun handleInvite3pidSlashCommand(invite: ParsedCommand.Invite3Pid) { + launchSlashCommandFlow { + room.invite3pid(invite.threePid, it) + } + } + private fun handleSetUserPowerLevel(setUserPowerLevel: ParsedCommand.SetUserPowerLevel) { val currentPowerLevelsContent = room.getStateEvent(EventType.STATE_ROOM_POWER_LEVELS) ?.content