Places available renamed to seats left

This commit is contained in:
2022-04-30 00:44:46 +02:00
parent 316723a9ac
commit 6c43cb0352
12 changed files with 61 additions and 44 deletions

View File

@@ -41,7 +41,7 @@ object CommandParser {
try {
when (command) {
"create" -> handleCreate(user, room, args)
"join" -> Usecase.joinTravel(room, user)
"join" -> Usecase.joinTravel(room, user, args)
"leave" -> Usecase.leaveTravel(room, user)
"cancel" -> Usecase.cancelTravel(room, user)
}
@@ -70,7 +70,7 @@ object CommandParser {
from = args[0],
to = args[1],
time = unixTime,
places = args[4].toIntOrNull() ?: 0,
seats = args[4].toIntOrNull() ?: 0,
description = args.subList(5, args.size).joinToString(" ")
)

View File

@@ -6,13 +6,13 @@ import org.jetbrains.exposed.dao.IntEntityClass
import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.dao.id.IntIdTable
object TravelsTable: IntIdTable() {
object TravelsTable : IntIdTable() {
val roomId = varchar("room_id", 255)
val driver = varchar("driver", 255)
val from = varchar("from", 255)
val to = varchar("to", 255)
val time = long("time")
val places = integer("places")
val seats = integer("seats")
val description = varchar("description", 1023)
}
@@ -24,15 +24,16 @@ class TravelEntity(id: EntityID<Int>) : IntEntity(id) {
this.from = travel.options.from
this.to = travel.options.to
this.time = travel.options.time
this.places = travel.options.places
this.seats = travel.options.seats
this.description = travel.options.description
}
}
var roomId by TravelsTable.roomId
var driver by TravelsTable.driver
var from by TravelsTable.from
var to by TravelsTable.to
var time by TravelsTable.time
var places by TravelsTable.places
var seats by TravelsTable.seats
var description by TravelsTable.description
}

View File

@@ -1,12 +1,12 @@
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_MESSAGE_EVENT_TYPE
import eu.fosil.okupamicoche.matrix.event.message.TravelJoinMessageEventContent
import eu.fosil.okupamicoche.matrix.event.message.TravelMessageEventContent
import eu.fosil.okupamicoche.matrix.event.state.MEMBERSHIP_STATE_EVENT_TYPE
import eu.fosil.okupamicoche.matrix.event.state.MembershipStateEventContent
import eu.fosil.okupamicoche.matrix.event.state.TRAVEL_STATE_EVENT_TYPE
import eu.fosil.okupamicoche.matrix.event.state.TravelMembershipStateEventContent
import eu.fosil.okupamicoche.matrix.event.state.TravelStateEventContent
import net.folivo.trixnity.core.model.events.MessageEventContent
import net.folivo.trixnity.core.model.events.StateEventContent
@@ -16,10 +16,10 @@ import net.folivo.trixnity.core.serialization.events.EventContentSerializerMappi
object TravelEventContentSerializerMappings : BaseEventContentSerializerMappings() {
override val message: Set<EventContentSerializerMapping<out MessageEventContent>> = setOf(
EventContentSerializerMapping.of<TravelMessageEventContent>(TRAVEL_MESSAGE_EVENT_TYPE),
EventContentSerializerMapping.of<JoinMessageEventContent>(JOIN_MESSAGE_EVENT_TYPE)
EventContentSerializerMapping.of<TravelJoinMessageEventContent>(JOIN_MESSAGE_EVENT_TYPE)
)
override val state: Set<EventContentSerializerMapping<out StateEventContent>> = setOf(
EventContentSerializerMapping.of<TravelStateEventContent>(TRAVEL_STATE_EVENT_TYPE),
EventContentSerializerMapping.of<MembershipStateEventContent>(MEMBERSHIP_STATE_EVENT_TYPE)
EventContentSerializerMapping.of<TravelMembershipStateEventContent>(MEMBERSHIP_STATE_EVENT_TYPE)
)
}

View File

@@ -10,7 +10,7 @@ import net.folivo.trixnity.core.model.events.RelatesTo
const val JOIN_MESSAGE_EVENT_TYPE = "eu.fosil.travel.join"
@Serializable
data class JoinMessageEventContent(
data class TravelJoinMessageEventContent(
@SerialName("room")
val room: String,
@SerialName("user")

View File

@@ -21,8 +21,8 @@ data class TravelMessageEventContent(
val to: String,
@SerialName("time")
val time: Long,
@SerialName("places")
val places: Int,
@SerialName("seats")
val seats: Int,
@SerialName("description")
val description: String,
@SerialName("duplicateNum")
@@ -38,7 +38,7 @@ data class TravelMessageEventContent(
travel.options.from,
travel.options.to,
travel.options.time,
travel.options.places,
travel.options.seats,
travel.options.description,
travel.duplicateNum,
travel.canceled

View File

@@ -9,14 +9,17 @@ import net.folivo.trixnity.core.model.events.m.room.Membership
const val MEMBERSHIP_STATE_EVENT_TYPE = "eu.fosil.travel.member"
@Serializable
data class MembershipStateEventContent(
data class TravelMembershipStateEventContent(
@SerialName("user")
val user: String,
@SerialName("membership")
val membership: String
val membership: String,
@SerialName("seats")
val seats: Int
) : StateEventContent {
constructor(userId: UserId, membership: Membership) : this(
constructor(userId: UserId, membership: Membership, seats: Int = 1) : this(
userId.full,
membership.value
membership.value,
seats
)
}

View File

@@ -18,8 +18,8 @@ data class TravelStateEventContent(
val to: String,
@SerialName("time")
val time: Long,
@SerialName("places")
val places: Int,
@SerialName("seats")
val seats: Int,
@SerialName("description")
val description: String,
@SerialName("duplicateNum")
@@ -37,7 +37,7 @@ data class TravelStateEventContent(
travelOptions.from,
travelOptions.to,
travelOptions.time,
travelOptions.places,
travelOptions.seats,
travelOptions.description,
duplicateNum,
canceled

View File

@@ -19,7 +19,7 @@ class TravelOptions(
var from: String,
var to: String,
var time: Long,
var places: Int,
var seats: Int,
var description: String
) {
fun getRoomAliasPrefix(): String {
@@ -41,8 +41,8 @@ class TravelOptions(
fun getRoomName(duplicateNum: Int?, travelers: List<UserId>? = null): String {
val attemptSuffix = if ((duplicateNum ?: 0) > 0) " ($duplicateNum)" else ""
val availablePlaces = places - (travelers?.size ?: 0)
val availableSeats = seats - (travelers?.size ?: 0)
return getRoomNamePrefix() + " | $availablePlaces places available" + attemptSuffix
return getRoomNamePrefix() + " | $availableSeats seats available" + attemptSuffix
}
}

View File

@@ -1,7 +1,7 @@
package eu.fosil.okupamicoche.model
import eu.fosil.okupamicoche.matrix.MatrixApiClient
import eu.fosil.okupamicoche.matrix.event.state.MembershipStateEventContent
import eu.fosil.okupamicoche.matrix.event.state.TravelMembershipStateEventContent
import eu.fosil.okupamicoche.matrix.event.state.TravelStateEventContent
import net.folivo.trixnity.clientserverapi.client.getStateEvent
import net.folivo.trixnity.core.model.RoomId
@@ -30,7 +30,7 @@ object TravelRepository {
from = travelCreatedstateEvent.from,
to = travelCreatedstateEvent.to,
time = travelCreatedstateEvent.time,
places = travelCreatedstateEvent.places,
seats = travelCreatedstateEvent.seats,
description = travelCreatedstateEvent.description
),
travelers = getTravelers(roomId) ?: listOf(),
@@ -44,25 +44,27 @@ object TravelRepository {
).getOrNull()?.driver == userId.full
suspend fun getTravelMembership(roomId: RoomId, userId: UserId) =
MatrixApiClient.client.rooms.getStateEvent<MembershipStateEventContent>(
MatrixApiClient.client.rooms.getStateEvent<TravelMembershipStateEventContent>(
roomId,
userId.full.substring(1) // Synapse throws 403 if stateKey starts with '@'
).getOrNull()?.membership
suspend fun getTravelers(roomId: RoomId) = MatrixApiClient.client.rooms.getState(roomId).getOrNull()?.filter {
val content = it.content
(content is MembershipStateEventContent) && (content.membership == Membership.JOIN.value)
(content is TravelMembershipStateEventContent) && (content.membership == Membership.JOIN.value)
}?.map { UserId("@${it.stateKey}") }
suspend fun getAvailablePlaces(roomId: RoomId): Int? {
// Get travel total places (not counting driver)
suspend fun getSeatsLeft(roomId: RoomId): Int? {
// Get travel total seats (not counting driver)
val roomState = MatrixApiClient.client.rooms.getStateEvent<TravelStateEventContent>(roomId).getOrNull()
?: return null
// TODO sum seats per traveler
// Get travelers count
val travelersCount = getTravelers(roomId)?.size ?: 0
return roomState.places - travelersCount
return roomState.seats - travelersCount
}
}

View File

@@ -94,10 +94,10 @@ private suspend fun sendCreateMessageEvents(
// Send text message to main room
val displayName = TravelRepository.getDisplayName(travel.driver)
val body = "$displayName created a new travel! ${travel.options.from}-${travel.options.to}" +
" on $date $time with ${travel.options.places} free places."
" on $date $time with ${travel.options.seats} free seats."
val formattedBody =
"\uD83D\uDE97 $displayName created a new travel!<br><br>${travel.options.from}-${travel.options.to}" +
" on $date $time with ${travel.options.places} free places."
" on $date $time with ${travel.options.seats} free seats."
MatrixApiClient.client.rooms.sendMessageEvent(
mainRoomId,
RoomMessageEventContent.TextMessageEventContent(

View File

@@ -1,7 +1,7 @@
package eu.fosil.okupamicoche.usecase.travel
import eu.fosil.okupamicoche.matrix.MatrixApiClient
import eu.fosil.okupamicoche.matrix.event.state.MembershipStateEventContent
import eu.fosil.okupamicoche.matrix.event.state.TravelMembershipStateEventContent
import eu.fosil.okupamicoche.model.TravelRepository
import eu.fosil.okupamicoche.usecase.Usecase
import net.folivo.trixnity.core.model.RoomId
@@ -11,11 +11,15 @@ import net.folivo.trixnity.core.model.events.m.room.RoomMessageEventContent
suspend fun Usecase.joinTravel(
roomId: RoomId,
userId: UserId
userId: UserId,
args: List<String>
) {
val isTravel = TravelRepository.isTravel(roomId)
val isDriver = TravelRepository.isDriver(roomId, userId)
val membershipState = TravelRepository.getTravelMembership(roomId, userId)
val seatsLeft = TravelRepository.getSeatsLeft(roomId) ?: 0
// Seats asked by traveler, 1 if no specified
val seats = args.firstOrNull()?.toIntOrNull() ?: 1
if (!isTravel) {
MatrixApiClient.sendErrorTextMessage(roomId, "There is no travel.")
@@ -23,8 +27,12 @@ suspend fun Usecase.joinTravel(
MatrixApiClient.sendErrorTextMessage(roomId, "You are the driver, you don't need to join.")
} else if (membershipState == Membership.JOIN.value) {
MatrixApiClient.sendErrorTextMessage(roomId, "You are already joined.")
} else if (seatsLeft == 0) {
MatrixApiClient.sendErrorTextMessage(roomId, "Travel is full, no seats left.")
} else if (seatsLeft < seats) {
MatrixApiClient.sendErrorTextMessage(roomId, "Not enough seats left, only $seatsLeft available.")
} else {
sendJoinedMessageEvents(roomId, userId)
sendJoinedMessageEvents(roomId, userId, seats)
val roomNameInfo = Usecase.getRoomNameInfoFromRoomId(roomId)
MatrixApiClient.setRoomName(roomId, roomNameInfo?.name)
}
@@ -32,19 +40,22 @@ suspend fun Usecase.joinTravel(
private suspend fun sendJoinedMessageEvents(
roomId: RoomId,
userId: UserId
userId: UserId,
seats: Int
) {
// Send membership change state event to travel room
MatrixApiClient.client.rooms.sendStateEvent(
roomId,
MembershipStateEventContent(userId, Membership.JOIN),
TravelMembershipStateEventContent(userId, Membership.JOIN, seats),
stateKey = userId.full.substring(1) // Synapse throws 403 if stateKey starts with '@'
).getOrThrow()
// Send text message to travel room
val displayName = TravelRepository.getDisplayName(userId)
val availablePlaces = TravelRepository.getAvailablePlaces(roomId)
val messageBody = "$displayName joined the travel! Places available: $availablePlaces"
val seatsLeft = TravelRepository.getSeatsLeft(roomId)
val messageBody = "$displayName joined the travel!" +
(if (seats == 1) null else " They are using $seats seats.") +
" Seats left: $seatsLeft"
MatrixApiClient.client.rooms.sendMessageEvent(
roomId,
RoomMessageEventContent.TextMessageEventContent(messageBody)

View File

@@ -1,7 +1,7 @@
package eu.fosil.okupamicoche.usecase.travel
import eu.fosil.okupamicoche.matrix.MatrixApiClient
import eu.fosil.okupamicoche.matrix.event.state.MembershipStateEventContent
import eu.fosil.okupamicoche.matrix.event.state.TravelMembershipStateEventContent
import eu.fosil.okupamicoche.model.TravelRepository
import eu.fosil.okupamicoche.usecase.Usecase
import net.folivo.trixnity.core.model.RoomId
@@ -43,14 +43,14 @@ private suspend fun sendLeftMessageEvents(
// Send membership change state event to travel room
MatrixApiClient.client.rooms.sendStateEvent(
roomId,
MembershipStateEventContent(userId, Membership.LEAVE),
TravelMembershipStateEventContent(userId, Membership.LEAVE),
stateKey = userId.full.substring(1) // Synapse throws 403 if stateKey starts with '@'
).getOrThrow()
// Send text message to travel room
val displayName = TravelRepository.getDisplayName(userId)
val availablePlaces = TravelRepository.getAvailablePlaces(roomId)
val messageBody = "$displayName left the travel. Places available: $availablePlaces"
val availableSeats = TravelRepository.getSeatsLeft(roomId)
val messageBody = "$displayName left the travel. Seats available: $availableSeats"
MatrixApiClient.client.rooms.sendMessageEvent(
roomId,
RoomMessageEventContent.TextMessageEventContent(messageBody)