From 52781d28622a0cee52bfa2afaa833b5e498079c5 Mon Sep 17 00:00:00 2001 From: Eneko Nieto Date: Sun, 17 Apr 2022 20:53:59 +0200 Subject: [PATCH] WIP: joinTravel --- .../fosil/okupamicoche/cli/CommandParser.kt | 12 ++++- .../okupamicoche/matrix/createAppService.kt | 2 +- .../TravelEventContentSerializerMappings.kt | 14 +++++- .../event/message/JoinMessageEventContent.kt | 25 ++++++++++ .../TravelCreatedMessageEventContent.kt | 4 +- .../MembershipChangeStateEventContent.kt | 22 +++++++++ .../TravelCreatedStateEventContent.kt | 4 +- .../okupamicoche/matrix/matrixApiClient.kt | 3 ++ .../usecase/travel/createTravel.kt | 11 +++-- .../okupamicoche/usecase/travel/joinTravel.kt | 46 +++++++++++++++++++ 10 files changed, 129 insertions(+), 14 deletions(-) create mode 100644 src/main/kotlin/eu/fosil/okupamicoche/matrix/event/message/JoinMessageEventContent.kt rename src/main/kotlin/eu/fosil/okupamicoche/matrix/event/{ => message}/TravelCreatedMessageEventContent.kt (94%) create mode 100644 src/main/kotlin/eu/fosil/okupamicoche/matrix/event/state/MembershipChangeStateEventContent.kt rename src/main/kotlin/eu/fosil/okupamicoche/matrix/event/{ => state}/TravelCreatedStateEventContent.kt (93%) create mode 100644 src/main/kotlin/eu/fosil/okupamicoche/usecase/travel/joinTravel.kt diff --git a/src/main/kotlin/eu/fosil/okupamicoche/cli/CommandParser.kt b/src/main/kotlin/eu/fosil/okupamicoche/cli/CommandParser.kt index 04176f8..f3f500e 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/cli/CommandParser.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/cli/CommandParser.kt @@ -3,6 +3,7 @@ package eu.fosil.okupamicoche.cli import eu.fosil.okupamicoche.matrix.matrixApiClient import eu.fosil.okupamicoche.model.TravelOptions import eu.fosil.okupamicoche.usecase.travel.createTravel +import eu.fosil.okupamicoche.usecase.travel.joinTravel import mu.KotlinLogging import net.folivo.trixnity.core.model.RoomId import net.folivo.trixnity.core.model.UserId @@ -40,6 +41,7 @@ object CommandParser { when (command) { "create" -> handleCreate(user, room, args) + "join" -> handleJoin(user, room) } } catch (e: Exception) { logger.error { "Exception captured: $e" } @@ -56,7 +58,6 @@ object CommandParser { roomId: RoomId, args: List ) { - val date = args[2] val time = args[3] val formatter = DateTimeFormatter.ofPattern("yyyy/M/d H:mm").withZone(ZoneId.systemDefault()) @@ -67,12 +68,19 @@ object CommandParser { to = args[1], time = unixTime, places = args[4].toIntOrNull() ?: 0, - description = args[5] + description = args.subList(5, args.size).joinToString(" ") ) createTravel(travelOptions, userId, roomId) + } + + private suspend fun handleJoin( + userId: UserId, + roomId: RoomId + ) { + joinTravel(roomId, userId) } } diff --git a/src/main/kotlin/eu/fosil/okupamicoche/matrix/createAppService.kt b/src/main/kotlin/eu/fosil/okupamicoche/matrix/createAppService.kt index 8998fb9..734065e 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/matrix/createAppService.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/matrix/createAppService.kt @@ -2,7 +2,7 @@ package eu.fosil.okupamicoche.matrix import eu.fosil.okupamicoche.cli.CommandParser import eu.fosil.okupamicoche.db.TravelsTable -import eu.fosil.okupamicoche.matrix.event.TravelCreatedMessageEventContent +import eu.fosil.okupamicoche.matrix.event.message.TravelCreatedMessageEventContent import eu.fosil.okupamicoche.matrix.services.EventTnxService import eu.fosil.okupamicoche.matrix.services.RoomService import eu.fosil.okupamicoche.matrix.services.UserService diff --git a/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/TravelEventContentSerializerMappings.kt b/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/TravelEventContentSerializerMappings.kt index 2bb3d7b..eee6479 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/TravelEventContentSerializerMappings.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/TravelEventContentSerializerMappings.kt @@ -1,5 +1,13 @@ package eu.fosil.okupamicoche.matrix.event +import eu.fosil.okupamicoche.matrix.event.message.JOIN_MESSAGE_EVENT_TYPE +import eu.fosil.okupamicoche.matrix.event.message.JoinMessageEventContent +import eu.fosil.okupamicoche.matrix.event.message.TRAVEL_CREATED_MESSAGE_EVENT_TYPE +import eu.fosil.okupamicoche.matrix.event.message.TravelCreatedMessageEventContent +import eu.fosil.okupamicoche.matrix.event.state.MEMBERSHIP_CHANGE_STATE_EVENT_TYPE +import eu.fosil.okupamicoche.matrix.event.state.MembershipChangeStateEventContent +import eu.fosil.okupamicoche.matrix.event.state.TRAVEL_CREATED_STATE_EVENT_TYPE +import eu.fosil.okupamicoche.matrix.event.state.TravelCreatedStateEventContent import net.folivo.trixnity.core.model.events.MessageEventContent import net.folivo.trixnity.core.model.events.StateEventContent import net.folivo.trixnity.core.serialization.events.BaseEventContentSerializerMappings @@ -7,9 +15,11 @@ import net.folivo.trixnity.core.serialization.events.EventContentSerializerMappi object TravelEventContentSerializerMappings : BaseEventContentSerializerMappings() { override val message: Set> = setOf( - EventContentSerializerMapping.of(TRAVEL_CREATED_MESSAGE_EVENT_TYPE) + EventContentSerializerMapping.of(TRAVEL_CREATED_MESSAGE_EVENT_TYPE), + EventContentSerializerMapping.of(JOIN_MESSAGE_EVENT_TYPE) ) override val state: Set> = setOf( - EventContentSerializerMapping.of(TRAVEL_CREATED_STATE_EVENT_TYPE) + EventContentSerializerMapping.of(TRAVEL_CREATED_STATE_EVENT_TYPE), + EventContentSerializerMapping.of(MEMBERSHIP_CHANGE_STATE_EVENT_TYPE) ) } diff --git a/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/message/JoinMessageEventContent.kt b/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/message/JoinMessageEventContent.kt new file mode 100644 index 0000000..386adab --- /dev/null +++ b/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/message/JoinMessageEventContent.kt @@ -0,0 +1,25 @@ +package eu.fosil.okupamicoche.matrix.event.message + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import net.folivo.trixnity.core.model.RoomId +import net.folivo.trixnity.core.model.UserId +import net.folivo.trixnity.core.model.events.MessageEventContent +import net.folivo.trixnity.core.model.events.RelatesTo + +const val JOIN_MESSAGE_EVENT_TYPE = "eu.fosil.travel.join" + +@Serializable +data class JoinMessageEventContent( + @SerialName("room") + val room: String, + @SerialName("user") + val user: String, + @SerialName("m.relates_to") + override val relatesTo: RelatesTo.Reference? = null +) : MessageEventContent { + constructor(roomId: RoomId, userId: UserId) : this( + roomId.full, + userId.full + ) +} diff --git a/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/TravelCreatedMessageEventContent.kt b/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/message/TravelCreatedMessageEventContent.kt similarity index 94% rename from src/main/kotlin/eu/fosil/okupamicoche/matrix/event/TravelCreatedMessageEventContent.kt rename to src/main/kotlin/eu/fosil/okupamicoche/matrix/event/message/TravelCreatedMessageEventContent.kt index 6d4eadb..002c0df 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/TravelCreatedMessageEventContent.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/message/TravelCreatedMessageEventContent.kt @@ -1,4 +1,4 @@ -package eu.fosil.okupamicoche.matrix.event +package eu.fosil.okupamicoche.matrix.event.message import eu.fosil.okupamicoche.model.Travel import kotlinx.serialization.SerialName @@ -6,7 +6,7 @@ import kotlinx.serialization.Serializable import net.folivo.trixnity.core.model.events.MessageEventContent import net.folivo.trixnity.core.model.events.RelatesTo -const val TRAVEL_CREATED_MESSAGE_EVENT_TYPE = "eu.fosil.travel.created" +const val TRAVEL_CREATED_MESSAGE_EVENT_TYPE = "eu.fosil.travel.created.message" @Serializable data class TravelCreatedMessageEventContent( diff --git a/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/state/MembershipChangeStateEventContent.kt b/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/state/MembershipChangeStateEventContent.kt new file mode 100644 index 0000000..f135b1d --- /dev/null +++ b/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/state/MembershipChangeStateEventContent.kt @@ -0,0 +1,22 @@ +package eu.fosil.okupamicoche.matrix.event.state + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import net.folivo.trixnity.core.model.UserId +import net.folivo.trixnity.core.model.events.StateEventContent +import net.folivo.trixnity.core.model.events.m.room.Membership + +const val MEMBERSHIP_CHANGE_STATE_EVENT_TYPE = "eu.fosil.travel.member" + +@Serializable +data class MembershipChangeStateEventContent( + @SerialName("user") + val user: String, + @SerialName("membership") + val membership: String +) : StateEventContent { + constructor(userId: UserId, membership: Membership) : this( + userId.full, + membership.value + ) +} diff --git a/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/TravelCreatedStateEventContent.kt b/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/state/TravelCreatedStateEventContent.kt similarity index 93% rename from src/main/kotlin/eu/fosil/okupamicoche/matrix/event/TravelCreatedStateEventContent.kt rename to src/main/kotlin/eu/fosil/okupamicoche/matrix/event/state/TravelCreatedStateEventContent.kt index c8d3de3..74e45a5 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/TravelCreatedStateEventContent.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/state/TravelCreatedStateEventContent.kt @@ -1,4 +1,4 @@ -package eu.fosil.okupamicoche.matrix.event +package eu.fosil.okupamicoche.matrix.event.state import eu.fosil.okupamicoche.model.TravelOptions import kotlinx.serialization.SerialName @@ -6,7 +6,7 @@ import kotlinx.serialization.Serializable import net.folivo.trixnity.core.model.UserId import net.folivo.trixnity.core.model.events.StateEventContent -const val TRAVEL_CREATED_STATE_EVENT_TYPE = "eu.fosil.travel.created" +const val TRAVEL_CREATED_STATE_EVENT_TYPE = "eu.fosil.travel.created.state" @Serializable data class TravelCreatedStateEventContent( diff --git a/src/main/kotlin/eu/fosil/okupamicoche/matrix/matrixApiClient.kt b/src/main/kotlin/eu/fosil/okupamicoche/matrix/matrixApiClient.kt index 54a2aed..d1f0c5f 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/matrix/matrixApiClient.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/matrix/matrixApiClient.kt @@ -33,6 +33,9 @@ object MatrixApiClient { mainRoomId = createMainRoomIfNeeded() } + suspend fun getDisplayName(userId: UserId) = + matrixApiClient?.users?.getDisplayName(userId)?.getOrNull() ?: userId.localpart + private suspend fun createMainRoomIfNeeded(): RoomId? { requireNotNull(config) requireNotNull(matrixApiClient) diff --git a/src/main/kotlin/eu/fosil/okupamicoche/usecase/travel/createTravel.kt b/src/main/kotlin/eu/fosil/okupamicoche/usecase/travel/createTravel.kt index 9e1f934..dd3b3a4 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/usecase/travel/createTravel.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/usecase/travel/createTravel.kt @@ -5,9 +5,9 @@ import eu.fosil.okupamicoche.db.TravelEntity import eu.fosil.okupamicoche.matrix.MatrixApiClient import eu.fosil.okupamicoche.matrix.config import eu.fosil.okupamicoche.matrix.db -import eu.fosil.okupamicoche.matrix.event.TRAVEL_CREATED_STATE_EVENT_TYPE -import eu.fosil.okupamicoche.matrix.event.TravelCreatedMessageEventContent -import eu.fosil.okupamicoche.matrix.event.TravelCreatedStateEventContent +import eu.fosil.okupamicoche.matrix.event.message.TravelCreatedMessageEventContent +import eu.fosil.okupamicoche.matrix.event.state.TRAVEL_CREATED_STATE_EVENT_TYPE +import eu.fosil.okupamicoche.matrix.event.state.TravelCreatedStateEventContent import eu.fosil.okupamicoche.matrix.matrixApiClient import eu.fosil.okupamicoche.model.Travel import eu.fosil.okupamicoche.model.TravelOptions @@ -74,7 +74,8 @@ private suspend fun createRoom(travelOptions: TravelOptions, driver: UserId): Ro name = newRoomAliasAndName.name, topic = travelOptions.description, invite = setOf(driver), - initialState = listOf(initialState), +// TODO: uncomment when https://gitlab.com/benkuly/trixnity/-/issues/119 gets fixed +// initialState = listOf(initialState), powerLevelContentOverride = powerLevels ).getOrThrow() } @@ -143,7 +144,7 @@ private suspend fun sendCreateMessageEvents( val time = DateTimeFormatter.ofPattern("H:mm").withZone(ZoneId.systemDefault()).format(instant) // Send text message to main room - val displayName = matrixApiClient.users.getDisplayName(travel.driver).getOrNull() ?: travel.driver.full + val displayName = MatrixApiClient.getDisplayName(travel.driver) val messageBody = "$displayName created a new travel! ${travel.options.from}-${travel.options.to}" + " on $date $time with ${travel.options.places} free places." matrixApiClient.rooms.sendMessageEvent( diff --git a/src/main/kotlin/eu/fosil/okupamicoche/usecase/travel/joinTravel.kt b/src/main/kotlin/eu/fosil/okupamicoche/usecase/travel/joinTravel.kt new file mode 100644 index 0000000..1711391 --- /dev/null +++ b/src/main/kotlin/eu/fosil/okupamicoche/usecase/travel/joinTravel.kt @@ -0,0 +1,46 @@ +package eu.fosil.okupamicoche.usecase.travel + +import eu.fosil.okupamicoche.matrix.MatrixApiClient +import eu.fosil.okupamicoche.matrix.event.state.MembershipChangeStateEventContent +import eu.fosil.okupamicoche.matrix.matrixApiClient +import net.folivo.trixnity.core.model.RoomId +import net.folivo.trixnity.core.model.UserId +import net.folivo.trixnity.core.model.events.m.room.Membership +import net.folivo.trixnity.core.model.events.m.room.RoomMessageEventContent + +suspend fun joinTravel( + roomId: RoomId, + userId: UserId +) { + + sendJoinMessageEvents(roomId, userId) +} + +private suspend fun sendJoinMessageEvents( + roomId: RoomId, + userId: UserId +) { + requireNotNull(matrixApiClient) + + // Send text message to travel room + val displayName = MatrixApiClient.getDisplayName(userId) + val messageBody = "$displayName joined the travel!" + matrixApiClient.rooms.sendMessageEvent( + roomId, + RoomMessageEventContent.TextMessageEventContent(messageBody) + ) + + // Send membership change state event to travel room + matrixApiClient.rooms.sendStateEvent( + roomId, + MembershipChangeStateEventContent(userId, Membership.JOIN), + stateKey = userId.full.substring(1) // Synapse throws 403 if stateKey starts with '@' + ).getOrThrow() + + // THIS EVENT IS SENT BY CLIENT, NO APP SERVICE + // Send new travel message event to main room +// matrixApiClient.rooms.sendMessageEvent( +// roomId, +// JoinTravelMessageEventContent(roomId, userId) +// ) +}