@ -21,6 +21,9 @@ dependencies {
|
|||||||
implementation("com.github.ajalt.mordant:mordant:3.0.2")
|
implementation("com.github.ajalt.mordant:mordant:3.0.2")
|
||||||
implementation("com.github.ajalt.mordant:mordant-coroutines:3.0.2")
|
implementation("com.github.ajalt.mordant:mordant-coroutines:3.0.2")
|
||||||
|
|
||||||
|
implementation("ch.qos.logback:logback-core:1.5.19")
|
||||||
|
implementation("ch.qos.logback:logback-classic:1.5.19")
|
||||||
|
|
||||||
implementation("org.mariadb.jdbc:mariadb-java-client:3.3.1")
|
implementation("org.mariadb.jdbc:mariadb-java-client:3.3.1")
|
||||||
implementation("org.jetbrains.exposed:exposed-core:1.0.0-rc-2")
|
implementation("org.jetbrains.exposed:exposed-core:1.0.0-rc-2")
|
||||||
implementation("org.jetbrains.exposed:exposed-jdbc:1.0.0-rc-2")
|
implementation("org.jetbrains.exposed:exposed-jdbc:1.0.0-rc-2")
|
||||||
|
|||||||
@ -8,10 +8,11 @@ import de.steamwar.commands.database.InfoCommand
|
|||||||
import de.steamwar.commands.database.ResetCommand
|
import de.steamwar.commands.database.ResetCommand
|
||||||
import de.steamwar.commands.user.UserCommand
|
import de.steamwar.commands.user.UserCommand
|
||||||
import de.steamwar.commands.user.UserInfoCommand
|
import de.steamwar.commands.user.UserInfoCommand
|
||||||
|
import de.steamwar.commands.user.UserSearchCommand
|
||||||
|
|
||||||
fun main(args: Array<String>) = SteamWar()
|
fun main(args: Array<String>) = SteamWar()
|
||||||
.subcommands(
|
.subcommands(
|
||||||
DatabaseCommand().subcommands(InfoCommand(), ResetCommand()),
|
DatabaseCommand().subcommands(InfoCommand(), ResetCommand()),
|
||||||
UserCommand().subcommands(UserInfoCommand())
|
UserCommand().subcommands(UserInfoCommand(), UserSearchCommand())
|
||||||
)
|
)
|
||||||
.main(args)
|
.main(args)
|
||||||
@ -1,26 +1,7 @@
|
|||||||
package de.steamwar.commands.user
|
package de.steamwar.commands.user
|
||||||
|
|
||||||
import com.github.ajalt.clikt.core.CliktCommand
|
import com.github.ajalt.clikt.core.CliktCommand
|
||||||
import com.github.ajalt.clikt.core.CliktError
|
|
||||||
import com.github.ajalt.clikt.core.findOrSetObject
|
|
||||||
import com.github.ajalt.clikt.parameters.arguments.argument
|
|
||||||
import de.steamwar.db.schema.SteamwarUser
|
|
||||||
import de.steamwar.db.schema.SteamwarUserTable
|
|
||||||
import org.jetbrains.exposed.v1.core.eq
|
|
||||||
import org.jetbrains.exposed.v1.core.or
|
|
||||||
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
|
|
||||||
|
|
||||||
class UserCommand: CliktCommand("user") {
|
class UserCommand: CliktCommand("user") {
|
||||||
val userId by argument()
|
override fun run() = Unit
|
||||||
val user by findOrSetObject("user") {
|
|
||||||
transaction {
|
|
||||||
SteamwarUser.find { (SteamwarUserTable.id eq userId.toIntOrNull()) or (SteamwarUserTable.username eq userId) }
|
|
||||||
.firstOrNull()
|
|
||||||
?.let { return@transaction it } ?: throw CliktError("User not found!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun run() {
|
|
||||||
user.id
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -1,28 +1,38 @@
|
|||||||
package de.steamwar.commands.user
|
package de.steamwar.commands.user
|
||||||
|
|
||||||
import com.github.ajalt.clikt.core.CliktCommand
|
import com.github.ajalt.clikt.core.CliktCommand
|
||||||
import com.github.ajalt.clikt.core.requireObject
|
import com.github.ajalt.clikt.core.CliktError
|
||||||
|
import com.github.ajalt.clikt.core.findOrSetObject
|
||||||
|
import com.github.ajalt.clikt.parameters.arguments.argument
|
||||||
|
import com.github.ajalt.clikt.parameters.arguments.help
|
||||||
import com.github.ajalt.mordant.table.table
|
import com.github.ajalt.mordant.table.table
|
||||||
|
import de.steamwar.db.findUser
|
||||||
import de.steamwar.db.schema.Session
|
import de.steamwar.db.schema.Session
|
||||||
import de.steamwar.db.schema.SteamwarUser
|
import de.steamwar.db.schema.SteamwarUser
|
||||||
|
import de.steamwar.db.schema.SteamwarUserTable
|
||||||
import org.jetbrains.exposed.v1.core.eq
|
import org.jetbrains.exposed.v1.core.eq
|
||||||
|
import org.jetbrains.exposed.v1.core.or
|
||||||
import org.jetbrains.exposed.v1.jdbc.selectAll
|
import org.jetbrains.exposed.v1.jdbc.selectAll
|
||||||
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
|
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
|
||||||
import kotlin.time.DurationUnit
|
import kotlin.time.DurationUnit
|
||||||
import kotlin.time.ExperimentalTime
|
import kotlin.time.ExperimentalTime
|
||||||
|
|
||||||
class UserInfoCommand : CliktCommand("info") {
|
class UserInfoCommand : CliktCommand("info") {
|
||||||
val user by requireObject<SteamwarUser>("user")
|
val userId by argument().help("Id, Name, UUID or DiscordId")
|
||||||
|
val user by lazy { findUser(userId) ?: throw CliktError("User not found") }
|
||||||
|
|
||||||
@OptIn(ExperimentalTime::class)
|
@OptIn(ExperimentalTime::class)
|
||||||
override fun run() {
|
override fun run() {
|
||||||
transaction {
|
transaction {
|
||||||
val sessions = Session.selectAll().where { Session.user eq user.id.value }.map { it[Session.start] to it[Session.end] }
|
val sessions =
|
||||||
|
Session.selectAll().where { Session.user eq user.id.value }.map { it[Session.start] to it[Session.end] }
|
||||||
|
|
||||||
val totalPlayed = sessions.map { it.second - it.first }.sumOf { it.toDouble(DurationUnit.HOURS) }
|
val totalPlayed = sessions.map { it.second - it.first }.sumOf { it.toDouble(DurationUnit.HOURS) }
|
||||||
val firstJoin = sessions.minByOrNull { it.first }?.first
|
val firstJoin = sessions.minByOrNull { it.first }?.first
|
||||||
val lastJoin = sessions.maxByOrNull { it.second }?.second
|
val lastJoin = sessions.maxByOrNull { it.second }?.second
|
||||||
|
|
||||||
|
val punishments = user.punishments
|
||||||
|
|
||||||
echo(
|
echo(
|
||||||
table {
|
table {
|
||||||
body {
|
body {
|
||||||
@ -34,11 +44,17 @@ class UserInfoCommand: CliktCommand("info") {
|
|||||||
row("Beigetreten am", firstJoin)
|
row("Beigetreten am", firstJoin)
|
||||||
row("Zuletzt gesehen am", lastJoin)
|
row("Zuletzt gesehen am", lastJoin)
|
||||||
row("Spielzeit", totalPlayed.toString() + "h")
|
row("Spielzeit", totalPlayed.toString() + "h")
|
||||||
row("Punishments", table {
|
row("Punishments", if (punishments.empty()) "Keine" else table {
|
||||||
header { row("Typ", "Ersteller", "Von", "Bis", "Grund") }
|
header { row("Typ", "Ersteller", "Von", "Bis", "Grund") }
|
||||||
body {
|
body {
|
||||||
user.punishments.map {
|
punishments.map {
|
||||||
row(it.type, it.punisher.username, it.starttime.toString(), if (it.perma) "Perma" else it.endtime.toString(), it.reason)
|
row(
|
||||||
|
it.type,
|
||||||
|
it.punisher.username,
|
||||||
|
it.starttime.toString(),
|
||||||
|
if (it.perma) "Perma" else it.endtime.toString(),
|
||||||
|
it.reason
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
40
src/main/kotlin/commands/user/UserSearchCommand.kt
Normal file
40
src/main/kotlin/commands/user/UserSearchCommand.kt
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package de.steamwar.commands.user
|
||||||
|
|
||||||
|
import com.github.ajalt.clikt.core.CliktCommand
|
||||||
|
import com.github.ajalt.clikt.core.Context
|
||||||
|
import com.github.ajalt.clikt.parameters.arguments.argument
|
||||||
|
import com.github.ajalt.clikt.parameters.arguments.help
|
||||||
|
import com.github.ajalt.mordant.table.table
|
||||||
|
import de.steamwar.db.joinedOr
|
||||||
|
import de.steamwar.db.schema.SteamwarUser
|
||||||
|
import de.steamwar.db.schema.SteamwarUserTable
|
||||||
|
import de.steamwar.db.schema.Team
|
||||||
|
import org.jetbrains.exposed.v1.core.eq
|
||||||
|
import org.jetbrains.exposed.v1.core.like
|
||||||
|
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
|
||||||
|
|
||||||
|
class UserSearchCommand : CliktCommand("search") {
|
||||||
|
val query by argument().help("Name, Id, UUID or DiscordId")
|
||||||
|
|
||||||
|
override fun help(context: Context): String = "Search for users"
|
||||||
|
|
||||||
|
override fun run() = transaction {
|
||||||
|
val users = SteamwarUser.find {
|
||||||
|
joinedOr(
|
||||||
|
SteamwarUserTable.username like "%$query%",
|
||||||
|
SteamwarUserTable.uuid like "%$query%",
|
||||||
|
query.toLongOrNull()?.let { SteamwarUserTable.discordId eq it },
|
||||||
|
query.toIntOrNull()?.let { SteamwarUserTable.id eq it }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val teams = mutableMapOf<Int, Team>()
|
||||||
|
|
||||||
|
echo(table {
|
||||||
|
header { row("Id", "Username", "UUID", "Team", "DiscordId") }
|
||||||
|
body {
|
||||||
|
users.map { row(it.id.value, it.username, it.uuid, teams.computeIfAbsent(it.teamId) { _ -> it.team }.name, it.discordId) }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,20 +1,27 @@
|
|||||||
package de.steamwar.db
|
package de.steamwar.db
|
||||||
|
|
||||||
|
import com.github.ajalt.clikt.core.BaseCliktCommand
|
||||||
import com.github.ajalt.clikt.core.CliktError
|
import com.github.ajalt.clikt.core.CliktError
|
||||||
|
import de.steamwar.db.schema.SteamwarUser
|
||||||
|
import de.steamwar.db.schema.SteamwarUserTable
|
||||||
import org.jetbrains.exposed.v1.core.Expression
|
import org.jetbrains.exposed.v1.core.Expression
|
||||||
import org.jetbrains.exposed.v1.core.ExpressionWithColumnType
|
import org.jetbrains.exposed.v1.core.ExpressionWithColumnType
|
||||||
import org.jetbrains.exposed.v1.core.Function
|
import org.jetbrains.exposed.v1.core.Function
|
||||||
import org.jetbrains.exposed.v1.core.IColumnType
|
import org.jetbrains.exposed.v1.core.IColumnType
|
||||||
import org.jetbrains.exposed.v1.core.LongColumnType
|
import org.jetbrains.exposed.v1.core.LongColumnType
|
||||||
|
import org.jetbrains.exposed.v1.core.Op
|
||||||
import org.jetbrains.exposed.v1.core.QueryBuilder
|
import org.jetbrains.exposed.v1.core.QueryBuilder
|
||||||
import org.jetbrains.exposed.v1.core.WindowFunction
|
import org.jetbrains.exposed.v1.core.WindowFunction
|
||||||
import org.jetbrains.exposed.v1.core.WindowFunctionDefinition
|
import org.jetbrains.exposed.v1.core.WindowFunctionDefinition
|
||||||
import org.jetbrains.exposed.v1.core.append
|
import org.jetbrains.exposed.v1.core.append
|
||||||
|
import org.jetbrains.exposed.v1.core.eq
|
||||||
|
import org.jetbrains.exposed.v1.core.or
|
||||||
import org.jetbrains.exposed.v1.jdbc.Database
|
import org.jetbrains.exposed.v1.jdbc.Database
|
||||||
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
|
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.sql.ResultSet
|
import java.sql.ResultSet
|
||||||
import java.util.Properties
|
import java.util.Properties
|
||||||
|
import java.util.UUID
|
||||||
import kotlin.time.ExperimentalTime
|
import kotlin.time.ExperimentalTime
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
|
|
||||||
@ -66,18 +73,11 @@ class Database {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class UnixTimestamp<T: Any, in S>(
|
fun <T: BaseCliktCommand<T>> BaseCliktCommand<T>.findUser(query: String): SteamwarUser? = transaction {
|
||||||
val expr: Expression<in S>,
|
SteamwarUser.find { joinedOr(query.toIntOrNull()?.let { SteamwarUserTable.id eq it }, (SteamwarUserTable.username eq query), SteamwarUserTable.uuid eq query, query.toLongOrNull()?.let { SteamwarUserTable.discordId eq it }) }
|
||||||
columnType: IColumnType<T>
|
.firstOrNull()
|
||||||
) : Function<T?>(columnType), WindowFunction<T?> {
|
?.let { return@transaction it }
|
||||||
override fun toQueryBuilder(queryBuilder: QueryBuilder) = queryBuilder {
|
|
||||||
append("UNIX_TIMESTAMP(", expr, ")")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun over(): WindowFunctionDefinition<T?> {
|
fun joinedOr(vararg expressions: Expression<Boolean>?): Op<Boolean> =
|
||||||
return WindowFunctionDefinition(columnType, this)
|
expressions.filterNotNull().reduce { acc, expression -> acc or expression } as Op<Boolean>
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(ExperimentalTime::class)
|
|
||||||
fun ExpressionWithColumnType<Instant>.unixTimestamp(): UnixTimestamp<Long, Instant> = UnixTimestamp(this, LongColumnType())
|
|
||||||
@ -6,7 +6,7 @@ import org.jetbrains.exposed.v1.dao.IntEntity
|
|||||||
import org.jetbrains.exposed.v1.dao.IntEntityClass
|
import org.jetbrains.exposed.v1.dao.IntEntityClass
|
||||||
|
|
||||||
object SteamwarUserTable: IntIdTable("UserData") {
|
object SteamwarUserTable: IntIdTable("UserData") {
|
||||||
val uuid = uuid("uuid")
|
val uuid = varchar("uuid", 255)
|
||||||
val username = varchar("username", 255)
|
val username = varchar("username", 255)
|
||||||
val team = integer("team").references(TeamTable.id)
|
val team = integer("team").references(TeamTable.id)
|
||||||
val leader = bool("leader")
|
val leader = bool("leader")
|
||||||
@ -14,7 +14,7 @@ object SteamwarUserTable: IntIdTable("UserData") {
|
|||||||
val manualLocale = bool("manuallocale")
|
val manualLocale = bool("manuallocale")
|
||||||
val bedrock = bool("bedrock")
|
val bedrock = bool("bedrock")
|
||||||
val password = varchar("password", 1024)
|
val password = varchar("password", 1024)
|
||||||
val discordId = long("DiscordId")
|
val discordId = long("DiscordId").nullable()
|
||||||
}
|
}
|
||||||
|
|
||||||
class SteamwarUser(id: EntityID<Int>): IntEntity(id) {
|
class SteamwarUser(id: EntityID<Int>): IntEntity(id) {
|
||||||
@ -22,6 +22,7 @@ class SteamwarUser(id: EntityID<Int>): IntEntity(id) {
|
|||||||
|
|
||||||
var uuid by SteamwarUserTable.uuid
|
var uuid by SteamwarUserTable.uuid
|
||||||
var username by SteamwarUserTable.username
|
var username by SteamwarUserTable.username
|
||||||
|
var teamId by SteamwarUserTable.team
|
||||||
var team by Team referencedOn SteamwarUserTable.team
|
var team by Team referencedOn SteamwarUserTable.team
|
||||||
var leader by SteamwarUserTable.leader
|
var leader by SteamwarUserTable.leader
|
||||||
var locale by SteamwarUserTable.locale
|
var locale by SteamwarUserTable.locale
|
||||||
|
|||||||
11
src/main/resources/logback.xml
Normal file
11
src/main/resources/logback.xml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<configuration>
|
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<root level="WARN">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
||||||
Reference in New Issue
Block a user