From 81ddb8c5fb02c5f8707273e5b97c6e39baa1ff09 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 9 Apr 2019 14:35:18 +0200 Subject: [PATCH] SlashCommand: handle user invitation --- .../matrix/android/api/session/room/Room.kt | 1 - .../room/members/RoomMembersService.kt | 5 +++ .../android/internal/session/room/RoomAPI.kt | 10 +++++ .../internal/session/room/RoomFactory.kt | 4 +- .../internal/session/room/RoomModule.kt | 8 +++- .../session/room/invite/InviteBody.kt | 25 ++++++++++++ .../session/room/invite/InviteTask.kt | 40 +++++++++++++++++++ .../room/members/DefaultRoomMembersService.kt | 10 +++++ .../home/room/detail/RoomDetailFragment.kt | 18 ++++++--- .../home/room/detail/RoomDetailViewModel.kt | 25 +++++++----- .../home/room/detail/SendMessageResult.kt | 2 + 11 files changed, 129 insertions(+), 19 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/invite/InviteBody.kt create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/invite/InviteTask.kt diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/Room.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/Room.kt index f119df9412..cdc971fd2d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/Room.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/Room.kt @@ -22,7 +22,6 @@ import im.vector.matrix.android.api.session.room.model.RoomSummary import im.vector.matrix.android.api.session.room.read.ReadService import im.vector.matrix.android.api.session.room.send.SendService import im.vector.matrix.android.api.session.room.timeline.TimelineService -import im.vector.matrix.android.api.util.Cancelable /** * This interface defines methods to interact within a room. diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/members/RoomMembersService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/members/RoomMembersService.kt index 33cbfa5a8d..930afd7abf 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/members/RoomMembersService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/members/RoomMembersService.kt @@ -19,6 +19,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.room.model.RoomMember import im.vector.matrix.android.api.util.Cancelable @@ -48,5 +49,9 @@ interface RoomMembersService { */ fun getRoomMemberIdsLive(): LiveData> + /** + * Invite a user in the room + */ + fun invite(userId: String, callback: MatrixCallback) } \ No newline at end of file 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 bc44300f4d..1b89662daa 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 @@ -21,6 +21,7 @@ import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams import im.vector.matrix.android.api.session.room.model.create.CreateRoomResponse import im.vector.matrix.android.internal.network.NetworkConstants +import im.vector.matrix.android.internal.session.room.invite.InviteBody import im.vector.matrix.android.internal.session.room.members.RoomMembersResponse import im.vector.matrix.android.internal.session.room.send.SendResponse import im.vector.matrix.android.internal.session.room.timeline.EventContextResponse @@ -120,5 +121,14 @@ internal interface RoomAPI { @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/read_markers") fun sendReadMarker(@Path("roomId") roomId: String, @Body markers: Map): Call + /** + * Invite a user to the given room. + * Ref: https://matrix.org/docs/spec/client_server/r0.4.0.html#post-matrix-client-r0-rooms-roomid-invite + * + * @param roomId the room id + * @param body a object that just contains a user id + */ + @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/invite") + fun invite(@Path("roomId") roomId: String, @Body body: InviteBody): Call } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomFactory.kt index 1d91121e45..720d3804a9 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomFactory.kt @@ -18,6 +18,7 @@ package im.vector.matrix.android.internal.session.room import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.api.session.room.Room +import im.vector.matrix.android.internal.session.room.invite.InviteTask import im.vector.matrix.android.internal.session.room.members.DefaultRoomMembersService import im.vector.matrix.android.internal.session.room.members.LoadRoomMembersTask import im.vector.matrix.android.internal.session.room.members.RoomMemberExtractor @@ -32,6 +33,7 @@ import im.vector.matrix.android.internal.session.room.timeline.TimelineEventFact import im.vector.matrix.android.internal.task.TaskExecutor internal class RoomFactory(private val loadRoomMembersTask: LoadRoomMembersTask, + private val inviteTask: InviteTask, private val monarchy: Monarchy, private val paginationTask: PaginationTask, private val contextOfEventTask: GetContextOfEventTask, @@ -44,7 +46,7 @@ internal class RoomFactory(private val loadRoomMembersTask: LoadRoomMembersTask, val timelineEventFactory = TimelineEventFactory(roomMemberExtractor) val timelineService = DefaultTimelineService(roomId, monarchy, taskExecutor, contextOfEventTask, timelineEventFactory, paginationTask) val sendService = DefaultSendService(roomId, eventFactory, monarchy) - val roomMembersService = DefaultRoomMembersService(roomId, monarchy, loadRoomMembersTask, taskExecutor) + val roomMembersService = DefaultRoomMembersService(roomId, monarchy, loadRoomMembersTask, inviteTask, taskExecutor) val readService = DefaultReadService(roomId, monarchy, setReadMarkersTask, taskExecutor) return DefaultRoom( 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 f75302ffdf..ccdfe9ad99 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 @@ -19,6 +19,8 @@ package im.vector.matrix.android.internal.session.room import im.vector.matrix.android.internal.session.DefaultSession import im.vector.matrix.android.internal.session.room.create.CreateRoomTask import im.vector.matrix.android.internal.session.room.create.DefaultCreateRoomTask +import im.vector.matrix.android.internal.session.room.invite.DefaultInviteTask +import im.vector.matrix.android.internal.session.room.invite.InviteTask import im.vector.matrix.android.internal.session.room.members.DefaultLoadRoomMembersTask import im.vector.matrix.android.internal.session.room.members.LoadRoomMembersTask import im.vector.matrix.android.internal.session.room.read.DefaultSetReadMarkersTask @@ -63,12 +65,16 @@ class RoomModule { } scope(DefaultSession.SCOPE) { - RoomFactory(get(), get(), get(), get(), get(), get(), get()) + RoomFactory(get(), get(), get(), get(), get(), get(), get(), get()) } scope(DefaultSession.SCOPE) { DefaultCreateRoomTask(get(), get()) as CreateRoomTask } + scope(DefaultSession.SCOPE) { + DefaultInviteTask(get()) as InviteTask + } + } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/invite/InviteBody.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/invite/InviteBody.kt new file mode 100644 index 0000000000..652f8d63fb --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/invite/InviteBody.kt @@ -0,0 +1,25 @@ +/* + * 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.invite + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class InviteBody( + @Json(name = "user_id") val userId: String +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/invite/InviteTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/invite/InviteTask.kt new file mode 100644 index 0000000000..1086c6b5d9 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/invite/InviteTask.kt @@ -0,0 +1,40 @@ +/* + * 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.invite + +import arrow.core.Try +import im.vector.matrix.android.internal.network.executeRequest +import im.vector.matrix.android.internal.session.room.RoomAPI +import im.vector.matrix.android.internal.task.Task + + +internal interface InviteTask : Task { + data class Params( + val roomId: String, + val userId: String + ) +} + +internal class DefaultInviteTask(private val roomAPI: RoomAPI) : InviteTask { + + override fun execute(params: InviteTask.Params): Try { + return executeRequest { + val body = InviteBody(params.userId) + apiCall = roomAPI.invite(params.roomId, body) + } + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/DefaultRoomMembersService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/DefaultRoomMembersService.kt index 3a1fba7c7c..a007a1eb63 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/DefaultRoomMembersService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/DefaultRoomMembersService.kt @@ -20,12 +20,14 @@ package im.vector.matrix.android.internal.session.room.members import androidx.lifecycle.LiveData import com.zhuinden.monarchy.Monarchy +import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.session.events.model.toModel import im.vector.matrix.android.api.session.room.members.RoomMembersService import im.vector.matrix.android.api.session.room.model.Membership import im.vector.matrix.android.api.session.room.model.RoomMember import im.vector.matrix.android.api.util.Cancelable import im.vector.matrix.android.internal.database.mapper.asDomain +import im.vector.matrix.android.internal.session.room.invite.InviteTask import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.configureWith import im.vector.matrix.android.internal.util.fetchCopied @@ -33,6 +35,7 @@ import im.vector.matrix.android.internal.util.fetchCopied internal class DefaultRoomMembersService(private val roomId: String, private val monarchy: Monarchy, private val loadRoomMembersTask: LoadRoomMembersTask, + private val inviteTask: InviteTask, private val taskExecutor: TaskExecutor ) : RoomMembersService { @@ -58,4 +61,11 @@ internal class DefaultRoomMembersService(private val roomId: String, } ) } + + override fun invite(userId: String, callback: MatrixCallback) { + val params = InviteTask.Params(roomId, userId) + inviteTask.configureWith(params) + .dispatchTo(callback) + .executeBy(taskExecutor) + } } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt index 13ab8eec53..a5b6738411 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt @@ -40,7 +40,6 @@ import im.vector.riotredesign.core.extensions.observeEvent import im.vector.riotredesign.core.glide.GlideApp import im.vector.riotredesign.core.platform.ToolbarConfigurable import im.vector.riotredesign.core.platform.VectorBaseFragment -import im.vector.riotredesign.core.utils.toast import im.vector.riotredesign.features.autocomplete.command.AutocompleteCommandPresenter import im.vector.riotredesign.features.autocomplete.command.CommandAutocompletePolicy import im.vector.riotredesign.features.autocomplete.user.AutocompleteUserPresenter @@ -240,23 +239,30 @@ class RoomDetailFragment : VectorBaseFragment(), TimelineEventController.Callbac private fun renderSendMessageResult(sendMessageResult: SendMessageResult) { when (sendMessageResult) { - is SendMessageResult.MessageSent, is SendMessageResult.SlashCommandHandled -> { + is SendMessageResult.MessageSent, + is SendMessageResult.SlashCommandHandled -> { // Clear composer composerEditText.text = null } is SendMessageResult.SlashCommandError -> { - displayError(getString(R.string.command_problem_with_parameters, sendMessageResult.command.command)) + displayCommandError(getString(R.string.command_problem_with_parameters, sendMessageResult.command.command)) } is SendMessageResult.SlashCommandUnknown -> { - displayError(getString(R.string.unrecognized_command, sendMessageResult.command)) + displayCommandError(getString(R.string.unrecognized_command, sendMessageResult.command)) + } + is SendMessageResult.SlashCommandResultOk -> { + // Ignore + } + is SendMessageResult.SlashCommandResultError -> { + displayCommandError(sendMessageResult.throwable.localizedMessage) } is SendMessageResult.SlashCommandNotImplemented -> { - activity!!.toast(R.string.not_implemented) + displayCommandError(getString(R.string.not_implemented)) } } } - private fun displayError(message: String) { + private fun displayCommandError(message: String) { AlertDialog.Builder(activity!!) .setTitle(R.string.command_error) .setMessage(message) diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewModel.kt index ee9a591ecc..cb56cb6bbf 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewModel.kt @@ -100,17 +100,8 @@ class RoomDetailViewModel(initialState: RoomDetailViewState, is ParsedCommand.ErrorUnknownSlashCommand -> { _sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandUnknown(slashCommandResult.slashCommand))) } - else -> { - handleValidSlashCommand(slashCommandResult) - } - } - } - - private fun handleValidSlashCommand(parsedCommand: ParsedCommand) { - when (parsedCommand) { is ParsedCommand.Invite -> { - //room.invite(parsedCommand.userId) - _sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandHandled)) + handleInviteSlashCommand(slashCommandResult) } else -> { _sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandNotImplemented)) @@ -118,6 +109,20 @@ class RoomDetailViewModel(initialState: RoomDetailViewState, } } + private fun handleInviteSlashCommand(invite: ParsedCommand.Invite) { + _sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandHandled)) + + room.invite(invite.userId, object : MatrixCallback { + override fun onSuccess(data: Unit) { + _sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandResultOk)) + } + + override fun onFailure(failure: Throwable) { + _sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandResultError(failure))) + } + }) + } + private fun handleEventDisplayed(action: RoomDetailActions.EventDisplayed) { displayedEventsObservable.accept(action) } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/SendMessageResult.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/SendMessageResult.kt index 8570e4fc22..189ad90d88 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/SendMessageResult.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/SendMessageResult.kt @@ -23,6 +23,8 @@ sealed class SendMessageResult { class SlashCommandError(val command: Command) : SendMessageResult() class SlashCommandUnknown(val command: String) : SendMessageResult() object SlashCommandHandled : SendMessageResult() + object SlashCommandResultOk : SendMessageResult() + class SlashCommandResultError(val throwable: Throwable) : SendMessageResult() // TODO Remove object SlashCommandNotImplemented : SendMessageResult() } \ No newline at end of file