From 9f8d59b7a96edb3b70fe5957a84bab84693777d4 Mon Sep 17 00:00:00 2001 From: Eneko Nieto Date: Mon, 21 Mar 2022 23:29:17 +0100 Subject: [PATCH] Powerlevels --- src/main/kotlin/eu/fosil/okupamicoche/Main.kt | 3 +- .../fosil/okupamicoche/cli/CommandParser.kt | 8 ++++ .../okupamicoche/matrix/createAppService.kt | 14 +++---- ...kt => TravelCreatedMessageEventContent.kt} | 6 ++- .../event/TravelCreatedStateEventContent.kt | 31 ++++++++++++++++ .../TravelEventContentSerializerMappings.kt | 8 ++-- .../okupamicoche/matrix/matrixApiClient.kt | 19 +++++++++- .../usecase/travel/createTravel.kt | 37 ++++++++++++++----- 8 files changed, 102 insertions(+), 24 deletions(-) rename src/main/kotlin/eu/fosil/okupamicoche/matrix/event/{TravelCreatedEventContent.kt => TravelCreatedMessageEventContent.kt} (89%) create mode 100644 src/main/kotlin/eu/fosil/okupamicoche/matrix/event/TravelCreatedStateEventContent.kt diff --git a/src/main/kotlin/eu/fosil/okupamicoche/Main.kt b/src/main/kotlin/eu/fosil/okupamicoche/Main.kt index b68e6ad..59ddc57 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/Main.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/Main.kt @@ -29,8 +29,7 @@ suspend fun main() { launch { val roomMainAlias = "#${config.mainRoom}:${config.homeserver.host}" - val roomAliasRes = - matrixApiClient.rooms.getRoomAlias(RoomAliasId(roomMainAlias)).getOrNull() + val roomAliasRes = matrixApiClient.rooms.getRoomAlias(RoomAliasId(roomMainAlias)).getOrNull() if (roomAliasRes == null) { logger.info("Creating $roomMainAlias public room") matrixApiClient.rooms.createRoom( diff --git a/src/main/kotlin/eu/fosil/okupamicoche/cli/CommandParser.kt b/src/main/kotlin/eu/fosil/okupamicoche/cli/CommandParser.kt index c30be55..04176f8 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/cli/CommandParser.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/cli/CommandParser.kt @@ -1,10 +1,12 @@ 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 mu.KotlinLogging import net.folivo.trixnity.core.model.RoomId import net.folivo.trixnity.core.model.UserId +import net.folivo.trixnity.core.model.events.m.room.RoomMessageEventContent import java.time.Instant import java.time.ZoneId import java.time.format.DateTimeFormatter @@ -34,12 +36,18 @@ object CommandParser { ) { logger.info("command=$command args=$args") try { + requireNotNull(matrixApiClient) + when (command) { "create" -> handleCreate(user, room, args) } } catch (e: Exception) { logger.error { "Exception captured: $e" } e.printStackTrace() + matrixApiClient?.rooms?.sendMessageEvent( + room, + RoomMessageEventContent.TextMessageEventContent("Error executing command: $e") + ) } } diff --git a/src/main/kotlin/eu/fosil/okupamicoche/matrix/createAppService.kt b/src/main/kotlin/eu/fosil/okupamicoche/matrix/createAppService.kt index 987c0fb..043e224 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.TravelCreatedEventContent +import eu.fosil.okupamicoche.matrix.event.TravelCreatedMessageEventContent import eu.fosil.okupamicoche.matrix.services.EventTnxService import eu.fosil.okupamicoche.matrix.services.RoomService import eu.fosil.okupamicoche.matrix.services.UserService @@ -29,7 +29,9 @@ fun createAppService(matrixClientServerApiClient: MatrixClientServerApiClient): } return DefaultAppserviceService( - EventTnxService(), UserService(matrixClientServerApiClient), RoomService(matrixClientServerApiClient) + EventTnxService(), + UserService(matrixClientServerApiClient), + RoomService(matrixClientServerApiClient) ).apply { subscribeAllEvents { logger.debug("All events: $it") @@ -39,9 +41,9 @@ fun createAppService(matrixClientServerApiClient: MatrixClientServerApiClient): logger.info("${it.content.creator} created room ${it.roomId}") } } - subscribe { event-> - logger.info("NEW TRAVEL CREATED EVENT!!") - logger.info("$event") + subscribe { event -> + logger.info("NEW TRAVEL CREATED EVENT!!") + logger.info("$event") } subscribe { event -> require(event is Event.MessageEvent) @@ -60,5 +62,3 @@ fun createAppService(matrixClientServerApiClient: MatrixClientServerApiClient): } } } - - diff --git a/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/TravelCreatedEventContent.kt b/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/TravelCreatedMessageEventContent.kt similarity index 89% rename from src/main/kotlin/eu/fosil/okupamicoche/matrix/event/TravelCreatedEventContent.kt rename to src/main/kotlin/eu/fosil/okupamicoche/matrix/event/TravelCreatedMessageEventContent.kt index 2ac1ba3..ea133c8 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/TravelCreatedEventContent.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/TravelCreatedMessageEventContent.kt @@ -6,8 +6,10 @@ 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_ID = "eu.fosil.travel.created" + @Serializable -data class TravelCreatedEventContent( +data class TravelCreatedMessageEventContent( @SerialName("room") val room: String, @SerialName("driver") @@ -34,4 +36,4 @@ data class TravelCreatedEventContent( travel.options.places, travel.options.description ) -} \ No newline at end of file +} diff --git a/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/TravelCreatedStateEventContent.kt b/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/TravelCreatedStateEventContent.kt new file mode 100644 index 0000000..4d168e3 --- /dev/null +++ b/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/TravelCreatedStateEventContent.kt @@ -0,0 +1,31 @@ +package eu.fosil.okupamicoche.matrix.event + +import eu.fosil.okupamicoche.model.TravelOptions +import kotlinx.serialization.SerialName +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_ID = "eu.fosil.travel.created" + +@Serializable +data class TravelCreatedStateEventContent( + @SerialName("driver") + val driver: String, + @SerialName("from") + val from: String, + @SerialName("to") + val to: String, + @SerialName("time") + val time: Long, + @SerialName("places") + val places: Int +) : StateEventContent { + constructor(travelOptions: TravelOptions, driver: UserId) : this( + driver.full, + travelOptions.from, + travelOptions.to, + travelOptions.time, + travelOptions.places + ) +} 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 5a5ef1f..3716a47 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/TravelEventContentSerializerMappings.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/matrix/event/TravelEventContentSerializerMappings.kt @@ -6,11 +6,13 @@ import net.folivo.trixnity.core.serialization.events.EventContentSerializerMappi object TravelEventContentSerializerMappings : EventContentSerializerMappings { override val message: Set> = setOf( - EventContentSerializerMapping.of("eu.fosil.travel.created") + EventContentSerializerMapping.of(TRAVEL_CREATED_MESSAGE_EVENT_ID) + ) + override val state: Set> = setOf( + EventContentSerializerMapping.of(TRAVEL_CREATED_STATE_EVENT_ID) ) - override val state: Set> = setOf() override val ephemeral: Set> = setOf() override val globalAccountData: Set> = setOf() override val roomAccountData: Set> = setOf() override val toDevice: Set> = setOf() -} \ No newline at end of file +} diff --git a/src/main/kotlin/eu/fosil/okupamicoche/matrix/matrixApiClient.kt b/src/main/kotlin/eu/fosil/okupamicoche/matrix/matrixApiClient.kt index cbb1973..c5834e9 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/matrix/matrixApiClient.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/matrix/matrixApiClient.kt @@ -3,7 +3,11 @@ package eu.fosil.okupamicoche.matrix import eu.fosil.okupamicoche.config.ConfigReader import eu.fosil.okupamicoche.matrix.event.TravelEventContentSerializerMappings import io.ktor.http.* +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import net.folivo.trixnity.clientserverapi.client.MatrixClientServerApiClient +import net.folivo.trixnity.core.model.UserId import net.folivo.trixnity.core.serialization.events.DefaultEventContentSerializerMappings val config = ConfigReader.load() @@ -13,4 +17,17 @@ val matrixApiClient = if (config == null) null else MatrixClientServerApiClient( "://${config.homeserver.host}:${config.homeserver.port}" ), eventContentSerializerMappings = DefaultEventContentSerializerMappings + TravelEventContentSerializerMappings -).apply { accessToken.value = config.tokens.appService } \ No newline at end of file +).apply { accessToken.value = config.tokens.appService } + +object MatrixApiClient { + var appServiceUserId: UserId? = null + + init { + requireNotNull(matrixApiClient) + + val ioScope = CoroutineScope(Dispatchers.IO) + ioScope.launch { + appServiceUserId = matrixApiClient.users.whoAmI().getOrThrow().userId + } + } +} 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 be016d6..5919592 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/usecase/travel/createTravel.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/usecase/travel/createTravel.kt @@ -2,8 +2,12 @@ package eu.fosil.okupamicoche.usecase.travel import eu.fosil.okupamicoche.config.ConfigReader 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.TravelCreatedEventContent +import eu.fosil.okupamicoche.matrix.event.TRAVEL_CREATED_STATE_EVENT_ID +import eu.fosil.okupamicoche.matrix.event.TravelCreatedMessageEventContent +import eu.fosil.okupamicoche.matrix.event.TravelCreatedStateEventContent import eu.fosil.okupamicoche.matrix.matrixApiClient import eu.fosil.okupamicoche.model.Travel import eu.fosil.okupamicoche.model.TravelOptions @@ -12,6 +16,8 @@ import net.folivo.trixnity.clientserverapi.model.rooms.Visibility import net.folivo.trixnity.core.model.RoomAliasId import net.folivo.trixnity.core.model.RoomId import net.folivo.trixnity.core.model.UserId +import net.folivo.trixnity.core.model.events.Event +import net.folivo.trixnity.core.model.events.m.room.PowerLevelsEventContent import net.folivo.trixnity.core.model.events.m.room.RoomMessageEventContent import org.jetbrains.exposed.sql.transactions.transaction import java.time.Instant @@ -30,8 +36,6 @@ suspend fun createTravel( driver: UserId, roomId: RoomId ) { - requireNotNull(matrixApiClient) - val newRoomId = createRoom(travelOptions, driver) val travel = Travel( newRoomId, @@ -39,7 +43,7 @@ suspend fun createTravel( travelOptions ) - sendCreateEvents(travel, roomId) + sendCreateMessageEvents(travel, roomId) transaction(db) { TravelEntity.new(travel) @@ -48,14 +52,29 @@ suspend fun createTravel( private suspend fun createRoom(travelOptions: TravelOptions, driver: UserId): RoomId { requireNotNull(matrixApiClient) + requireNotNull(config) val newRoomAliasAndName = getRoomAliasAndName(travelOptions) + val initialState = Event.InitialStateEvent( + TravelCreatedStateEventContent(travelOptions, driver), + "" + ) + val powerLevels = PowerLevelsEventContent( + events = mapOf(Pair(TRAVEL_CREATED_STATE_EVENT_ID, 100)), + users = mapOf( + Pair(MatrixApiClient.appServiceUserId!!, 100), + Pair(driver, 50) + ) + ) + return matrixApiClient.rooms.createRoom( visibility = Visibility.PUBLIC, roomAliasId = newRoomAliasAndName.aliasId, name = newRoomAliasAndName.name, topic = travelOptions.description, - invite = setOf(driver) + invite = setOf(driver), + initialState = listOf(initialState), + powerLevelContentOverride = powerLevels ).getOrThrow() } @@ -104,14 +123,14 @@ private fun getRoomName(travelOptions: TravelOptions, attempt: Int): String { val instant = Instant.ofEpochMilli(travelOptions.time) val date = DateTimeFormatter.ofPattern("yyyy/MM/dd").withZone(ZoneId.systemDefault()).format(instant) val time = DateTimeFormatter.ofPattern("H:mm").withZone(ZoneId.systemDefault()).format(instant) - val attemptSuffix = if (attempt > 0) " ($attempt)" else null + val attemptSuffix = if (attempt > 0) " ($attempt)" else "" return travelOptions.run { - "Viaje ${from}-${to} $date $time | $places places available" + attemptSuffix + "Travel ${from}-${to} $date $time | $places places available" + attemptSuffix } } -private suspend fun sendCreateEvents( +private suspend fun sendCreateMessageEvents( travel: Travel, roomId: RoomId ) { @@ -133,7 +152,7 @@ private suspend fun sendCreateEvents( // Send new travel event matrixApiClient.rooms.sendMessageEvent( roomId, - TravelCreatedEventContent(travel) + TravelCreatedMessageEventContent(travel) ) }