Reapply "Improve Performance"

This reverts commit 0a7a753c48.

Signed-off-by: Chaoscaot <max@maxsp.de>

# Conflicts:
#	WebsiteBackend/src/de/steamwar/routes/AuditLog.kt
This commit is contained in:
2025-12-02 21:59:34 +01:00
parent a089d42d9a
commit b576c36c2d
2 changed files with 119 additions and 34 deletions
@@ -32,6 +32,7 @@ import io.ktor.server.routing.Route
import io.ktor.server.routing.get import io.ktor.server.routing.get
import io.ktor.server.routing.route import io.ktor.server.routing.route
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import org.jetbrains.exposed.v1.core.Alias
import org.jetbrains.exposed.v1.core.JoinType import org.jetbrains.exposed.v1.core.JoinType
import org.jetbrains.exposed.v1.core.SortOrder import org.jetbrains.exposed.v1.core.SortOrder
import org.jetbrains.exposed.v1.core.alias import org.jetbrains.exposed.v1.core.alias
@@ -41,8 +42,10 @@ import org.jetbrains.exposed.v1.core.isNull
import org.jetbrains.exposed.v1.core.less import org.jetbrains.exposed.v1.core.less
import org.jetbrains.exposed.v1.core.like import org.jetbrains.exposed.v1.core.like
import org.jetbrains.exposed.v1.core.or import org.jetbrains.exposed.v1.core.or
import org.jetbrains.exposed.v1.jdbc.Query
import org.jetbrains.exposed.v1.jdbc.andWhere import org.jetbrains.exposed.v1.jdbc.andWhere
import org.jetbrains.exposed.v1.jdbc.select import org.jetbrains.exposed.v1.jdbc.select
import org.jetbrains.exposed.v1.jdbc.selectAll
import java.time.Instant import java.time.Instant
fun Route.configureAuditLog() { fun Route.configureAuditLog() {
@@ -127,34 +130,30 @@ data class PagedAuditLog(val rows: Long, val entries: List<AuditLogEntry>) {
*AuditLogTable.columns.toTypedArray() *AuditLogTable.columns.toTypedArray()
) )
actionText?.let {
query.andWhere { (AuditLogTable.actionText like "%$it%") }
}
serverText?.let {
query.andWhere { (AuditLogTable.server like "%$it%") }
}
fullText?.let {
query.andWhere { (AuditLogTable.actionText like "%$it%") or (AuditLogTable.server like "%$it%") }
}
actor?.let { query.andWhere { AuditLogTable.actor inList actor } }
actionType?.let { query.andWhere { AuditLogTable.action inList actionType } }
timeGreater?.let { query.andWhere { AuditLogTable.time greater timeGreater } }
timeLess?.let { query.andWhere { AuditLogTable.time less timeLess } }
serverOwner?.let { query.andWhere { AuditLogTable.serverOwner inList serverOwner } }
if (velocity == true) query.andWhere { AuditLogTable.serverOwner.isNull() }
PagedAuditLog( PagedAuditLog(
query.count(), AuditLogTable.selectAll().addAuditLogFilters(
actionText,
serverText,
fullText,
actor,
actionType,
timeGreater,
timeLess,
serverOwner,
velocity
).count(),
query query
.addAuditLogFilters(
actionText,
serverText,
fullText,
actor,
actionType,
timeGreater,
timeLess,
serverOwner,
velocity
)
.limit(limit) .limit(limit)
.offset((page * limit).toLong()) .offset((page * limit).toLong())
.orderBy(AuditLogTable.time, SortOrder.valueOf(sorting.uppercase())) .orderBy(AuditLogTable.time, SortOrder.valueOf(sorting.uppercase()))
@@ -171,6 +170,36 @@ data class PagedAuditLog(val rows: Long, val entries: List<AuditLogEntry>) {
}, },
) )
} }
private fun Query.addAuditLogFilters(
actionText: String? = null,
serverText: String? = null,
fullText: String? = null,
actor: Set<Int>? = null,
actionType: Set<AuditLog.Type>? = null,
timeGreater: Instant? = null,
timeLess: Instant? = null,
serverOwner: Set<Int>? = null,
velocity: Boolean? = null,
): Query {
actionText?.let {
andWhere { (AuditLogTable.actionText like "%$it%") }
}
serverText?.let {
andWhere { (AuditLogTable.server like "%$it%") }
}
fullText?.let {
andWhere { (AuditLogTable.actionText like "%$it%") or (AuditLogTable.server like "%$it%") }
}
actor?.let { andWhere { AuditLogTable.actor inList actor } }
actionType?.let { andWhere { AuditLogTable.action inList actionType } }
timeGreater?.let { andWhere { AuditLogTable.time greater timeGreater } }
timeLess?.let { andWhere { AuditLogTable.time less timeLess } }
serverOwner?.let { andWhere { AuditLogTable.serverOwner inList serverOwner } }
if (velocity == true) andWhere { AuditLogTable.serverOwner.isNull() }
return this
}
} }
} }
+64 -8
View File
@@ -25,6 +25,7 @@ import de.steamwar.plugins.SWAuthPrincipal
import de.steamwar.plugins.SWPermissionCheck import de.steamwar.plugins.SWPermissionCheck
import de.steamwar.sql.SchematicType import de.steamwar.sql.SchematicType
import de.steamwar.sql.SteamwarUser import de.steamwar.sql.SteamwarUser
import de.steamwar.sql.SteamwarUserTable
import de.steamwar.sql.Team import de.steamwar.sql.Team
import de.steamwar.sql.UserPerm import de.steamwar.sql.UserPerm
import de.steamwar.sql.internal.useDb import de.steamwar.sql.internal.useDb
@@ -36,6 +37,13 @@ import io.ktor.server.response.*
import io.ktor.server.routing.* import io.ktor.server.routing.*
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import org.bspfsystems.yamlconfiguration.file.YamlConfiguration import org.bspfsystems.yamlconfiguration.file.YamlConfiguration
import org.jetbrains.exposed.v1.core.ResultRow
import org.jetbrains.exposed.v1.core.eq
import org.jetbrains.exposed.v1.core.inList
import org.jetbrains.exposed.v1.core.like
import org.jetbrains.exposed.v1.jdbc.Query
import org.jetbrains.exposed.v1.jdbc.andWhere
import org.jetbrains.exposed.v1.jdbc.selectAll
import java.io.File import java.io.File
import java.net.InetSocketAddress import java.net.InetSocketAddress
import java.util.* import java.util.*
@@ -44,8 +52,39 @@ import java.util.*
data class ResponseSchematicType(val name: String, val db: String) data class ResponseSchematicType(val name: String, val db: String)
@Serializable @Serializable
data class ResponseUser(val name: String, val uuid: String) { data class ResponseUser(
constructor(user: SteamwarUser) : this(user.userName, user.uuid.toString()) val name: String, val uuid: String, val id: Int?, val perms: List<String>?, val prefix: String?
) {
constructor(user: SteamwarUser, includeId: Boolean = false, includePerms: Boolean = false) : this(
user.userName,
user.uuid.toString(),
if (includeId) user.getId() else null,
if (includePerms) user.perms().map { it.name } else null,
if (includePerms) user.prefix().chatPrefix else null,
)
constructor(row: ResultRow, includeId: Boolean = false, includePerms: Boolean = false, prefixes: MutableSet<UserPerm> = mutableSetOf()) : this(
row[SteamwarUserTable.username],
row[SteamwarUserTable.uuid],
if (includeId) row[SteamwarUserTable.id].value else null,
if (includePerms) UserPerm.getPerms(row[SteamwarUserTable.id].value).also { prefixes.addAll(it) }.map { it.name } else null,
if (includePerms) prefixes.firstOrNull { UserPerm.prefixes.containsKey(it) }?.let { UserPerm.prefixes[it]!!.chatPrefix } else null
)
}
@Serializable
data class ResponseUserList(val entries: List<ResponseUser>, val rows: Long)
private fun Query.addUserFilter(
name: String? = null,
uuid: UUID? = null,
team: Set<Int>? = null,
): Query {
name?.let { andWhere { (SteamwarUserTable.username like "%$it%") } }
uuid?.let { andWhere { (SteamwarUserTable.uuid eq it.toString()) } }
team?.let { andWhere { (SteamwarUserTable.team inList team) } }
return this
} }
fun Route.configureDataRoutes() { fun Route.configureDataRoutes() {
@@ -57,18 +96,32 @@ fun Route.configureDataRoutes() {
} }
get("/users") { get("/users") {
val name = call.request.queryParameters["name"] val name = call.request.queryParameters["name"]
val uuid = call.request.queryParameters["uuid"]?.let { catchException { UUID.fromString(it) } }
val team = call.request.queryParameters.getAll("team")?.map { it.toInt() }?.toSet()
val limit = call.request.queryParameters["limit"]?.toIntOrNull() ?: 100 val limit = call.request.queryParameters["limit"]?.toIntOrNull() ?: 100
val page = call.request.queryParameters["page"]?.toIntOrNull() ?: 0 val page = call.request.queryParameters["page"]?.toIntOrNull() ?: 0
val includePerms = call.request.queryParameters["includePerms"]?.toBoolean() ?: false val includePerms = call.request.queryParameters["includePerms"]?.toBoolean() ?: false
val includeId = call.request.queryParameters["includeId"]?.toBoolean() ?: false val includeId = call.request.queryParameters["includeId"]?.toBoolean() ?: false
call.respond(
useDb {
ResponseUserList(
SteamwarUserTable.selectAll().addUserFilter(name, uuid, team).limit(limit)
.offset((page * limit).toLong())
.map { ResponseUser(it, includeId, includePerms) },
SteamwarUserTable.selectAll().addUserFilter(name, uuid, team).count()
)
}
)
} }
get("/teams") { get("/teams") {
call.respond(Team.getAll().map { ResponseTeam(it) }) call.respond(Team.getAll().map { ResponseTeam(it) })
} }
get("/schematicTypes") { get("/schematicTypes") {
call.respond(SchematicType.values().filter { !it.check() }.map { ResponseSchematicType(it.name(), it.toDB()) }) call.respond(SchematicType.values().filter { !it.check() }
.map { ResponseSchematicType(it.name(), it.toDB()) })
} }
get("/gamemodes") { get("/gamemodes") {
call.respond( call.respond(
@@ -102,11 +155,14 @@ fun Route.configureDataRoutes() {
} }
get("/team") { get("/team") {
call.respond( call.respond(
listOf(UserPerm.PREFIX_ADMIN, UserPerm.PREFIX_DEVELOPER, UserPerm.PREFIX_MODERATOR, UserPerm.PREFIX_SUPPORTER, UserPerm.PREFIX_BUILDER) listOf(
.associateWith { SteamwarUser.getUsersWithPerm(it) } UserPerm.PREFIX_ADMIN,
.mapKeys { UserPerm.prefixes[it.key]!!.chatPrefix } UserPerm.PREFIX_DEVELOPER,
.mapValues { it.value.map { ResponseUser(it) } } UserPerm.PREFIX_MODERATOR,
) UserPerm.PREFIX_SUPPORTER,
UserPerm.PREFIX_BUILDER
).associateWith { SteamwarUser.getUsersWithPerm(it) }.mapKeys { UserPerm.prefixes[it.key]!!.chatPrefix }
.mapValues { it.value.map { ResponseUser(it) } })
} }
get("/skin/{uuid}") { get("/skin/{uuid}") {
val uuid = call.parameters["uuid"] val uuid = call.parameters["uuid"]