forked from SteamWar/SteamWar
Format code
This commit is contained in:
@@ -74,7 +74,8 @@ data class CacheConfig(val lastUpdate: MutableMap<String, Long>) {
|
||||
fun isOutdated(uuid: String): Boolean {
|
||||
return config.lastUpdate[uuid]?.let {
|
||||
it < Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli()
|
||||
} ?: true
|
||||
}
|
||||
?: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ val SWPermissionCheck = createRouteScopedPlugin("SWAuth", ::SWAuthConfig) {
|
||||
pluginConfig.apply {
|
||||
on(AuthenticationChecked) { call ->
|
||||
if (call.request.httpMethod in allowedMethods) {
|
||||
if(mustAuth) {
|
||||
if (mustAuth) {
|
||||
val token = call.principal<SWAuthPrincipal>()
|
||||
|
||||
if (token == null) {
|
||||
|
||||
@@ -52,7 +52,8 @@ fun Application.configurePlugins() {
|
||||
global {
|
||||
rateLimiter(limit = 60, refillPeriod = 60.seconds)
|
||||
requestKey {
|
||||
it.request.headers["X-Forwarded-For"] ?: it.request.local.remoteHost
|
||||
it.request.headers["X-Forwarded-For"]
|
||||
?: it.request.local.remoteHost
|
||||
}
|
||||
requestWeight { applicationCall, _ ->
|
||||
if (!applicationCall.request.headers.contains("X-Forwarded-For")) {
|
||||
@@ -100,10 +101,12 @@ fun Application.configurePlugins() {
|
||||
cookie.maxAgeInSeconds = 60 * 60 * 24 * 7
|
||||
cookie.httpOnly = true
|
||||
cookie.secure = true
|
||||
transform(SessionTransportTransformerEncrypt(
|
||||
config.sessionEncryptSecret.toByteArray(),
|
||||
config.sessionSignSecret.toByteArray()
|
||||
))
|
||||
transform(
|
||||
SessionTransportTransformerEncrypt(
|
||||
config.sessionEncryptSecret.toByteArray(),
|
||||
config.sessionSignSecret.toByteArray()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
install(ContentNegotiation) {
|
||||
|
||||
@@ -25,5 +25,6 @@ import io.ktor.server.request.*
|
||||
import java.util.*
|
||||
|
||||
fun ApplicationRequest.getUser(key: String = "id"): SteamwarUser? {
|
||||
return SteamwarUser.get(call.parameters[key]?.let { catchException { UUID.fromString(it) } } ?: return null)
|
||||
return SteamwarUser.get(call.parameters[key]?.let { catchException { UUID.fromString(it) } }
|
||||
?: return null)
|
||||
}
|
||||
@@ -56,9 +56,12 @@ fun Route.configureAuditLog() {
|
||||
val serverOwner = call.request.queryParameters.getAll("serverOwner")?.map { it.toInt() }?.toSet()
|
||||
val velocity = call.request.queryParameters["velocity"]?.toBoolean()
|
||||
|
||||
val page = call.request.queryParameters["page"]?.toIntOrNull() ?: 0
|
||||
val limit = call.request.queryParameters["limit"]?.toIntOrNull() ?: 100
|
||||
val sorting = call.request.queryParameters["sorting"] ?: "DESC"
|
||||
val page = call.request.queryParameters["page"]?.toIntOrNull()
|
||||
?: 0
|
||||
val limit = call.request.queryParameters["limit"]?.toIntOrNull()
|
||||
?: 100
|
||||
val sorting = call.request.queryParameters["sorting"]
|
||||
?: "DESC"
|
||||
|
||||
call.respond(
|
||||
PagedAuditLog.filter(
|
||||
@@ -97,41 +100,30 @@ data class PagedAuditLog(val rows: Long, val entries: List<AuditLogEntry>) {
|
||||
page: Int = 0,
|
||||
limit: Int = 100,
|
||||
sorting: String = "DESC"
|
||||
) = useDb {
|
||||
val actorTable = SteamwarUserTable.alias("actor")
|
||||
val serverOwnerTable = SteamwarUserTable.alias("serverOwner")
|
||||
) =
|
||||
useDb {
|
||||
val actorTable = SteamwarUserTable.alias("actor")
|
||||
val serverOwnerTable = SteamwarUserTable.alias("serverOwner")
|
||||
|
||||
val query = AuditLogTable.join(
|
||||
actorTable,
|
||||
JoinType.INNER,
|
||||
onColumn = actorTable[SteamwarUserTable.id],
|
||||
otherColumn = AuditLogTable.actor
|
||||
)
|
||||
.join(
|
||||
serverOwnerTable,
|
||||
JoinType.LEFT,
|
||||
onColumn = serverOwnerTable[SteamwarUserTable.id],
|
||||
otherColumn = AuditLogTable.serverOwner
|
||||
)
|
||||
.select(
|
||||
actorTable[SteamwarUserTable.username], serverOwnerTable[SteamwarUserTable.username],
|
||||
*AuditLogTable.columns.toTypedArray()
|
||||
val query = AuditLogTable.join(
|
||||
actorTable,
|
||||
JoinType.INNER,
|
||||
onColumn = actorTable[SteamwarUserTable.id],
|
||||
otherColumn = AuditLogTable.actor
|
||||
)
|
||||
.join(
|
||||
serverOwnerTable,
|
||||
JoinType.LEFT,
|
||||
onColumn = serverOwnerTable[SteamwarUserTable.id],
|
||||
otherColumn = AuditLogTable.serverOwner
|
||||
)
|
||||
.select(
|
||||
actorTable[SteamwarUserTable.username], serverOwnerTable[SteamwarUserTable.username],
|
||||
*AuditLogTable.columns.toTypedArray()
|
||||
)
|
||||
|
||||
PagedAuditLog(
|
||||
AuditLogTable.selectAll().addAuditLogFilters(
|
||||
actionText,
|
||||
serverText,
|
||||
fullText,
|
||||
actor,
|
||||
actionType,
|
||||
timeGreater,
|
||||
timeLess,
|
||||
serverOwner,
|
||||
velocity
|
||||
).count(),
|
||||
query
|
||||
.addAuditLogFilters(
|
||||
PagedAuditLog(
|
||||
AuditLogTable.selectAll().addAuditLogFilters(
|
||||
actionText,
|
||||
serverText,
|
||||
fullText,
|
||||
@@ -141,23 +133,35 @@ data class PagedAuditLog(val rows: Long, val entries: List<AuditLogEntry>) {
|
||||
timeLess,
|
||||
serverOwner,
|
||||
velocity
|
||||
)
|
||||
.limit(limit)
|
||||
.offset((page * limit).toLong())
|
||||
.orderBy(AuditLogTable.time, SortOrder.valueOf(sorting.uppercase()))
|
||||
.map {
|
||||
AuditLogEntry(
|
||||
it[AuditLogTable.id].value,
|
||||
it[AuditLogTable.time].toEpochMilli(),
|
||||
it[AuditLogTable.server],
|
||||
it[serverOwnerTable[SteamwarUserTable.username]],
|
||||
it[actorTable[SteamwarUserTable.username]],
|
||||
it[AuditLogTable.action],
|
||||
it[AuditLogTable.actionText]
|
||||
).count(),
|
||||
query
|
||||
.addAuditLogFilters(
|
||||
actionText,
|
||||
serverText,
|
||||
fullText,
|
||||
actor,
|
||||
actionType,
|
||||
timeGreater,
|
||||
timeLess,
|
||||
serverOwner,
|
||||
velocity
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
.limit(limit)
|
||||
.offset((page * limit).toLong())
|
||||
.orderBy(AuditLogTable.time, SortOrder.valueOf(sorting.uppercase()))
|
||||
.map {
|
||||
AuditLogEntry(
|
||||
it[AuditLogTable.id].value,
|
||||
it[AuditLogTable.time].toEpochMilli(),
|
||||
it[AuditLogTable.server],
|
||||
it[serverOwnerTable[SteamwarUserTable.username]],
|
||||
it[actorTable[SteamwarUserTable.username]],
|
||||
it[AuditLogTable.action],
|
||||
it[AuditLogTable.actionText]
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private fun Query.addAuditLogFilters(
|
||||
actionText: String? = null,
|
||||
|
||||
@@ -55,7 +55,8 @@ fun Route.configureAuth() {
|
||||
|
||||
SteamwarUser.clear()
|
||||
val user = SteamwarUser.get(request.name)
|
||||
val valid = user?.verifyPassword(request.password) ?: false
|
||||
val valid = user?.verifyPassword(request.password)
|
||||
?: false
|
||||
|
||||
if (!valid) {
|
||||
call.respond(HttpStatusCode.Forbidden, ResponseError("Invalid username or password", "invalid"))
|
||||
|
||||
@@ -95,11 +95,15 @@ fun Route.configureDataRoutes() {
|
||||
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 page = call.request.queryParameters["page"]?.toIntOrNull() ?: 0
|
||||
val limit = call.request.queryParameters["limit"]?.toIntOrNull()
|
||||
?: 100
|
||||
val page = call.request.queryParameters["page"]?.toIntOrNull()
|
||||
?: 0
|
||||
|
||||
val includePerms = call.request.queryParameters["includePerms"]?.toBoolean() ?: false
|
||||
val includeId = call.request.queryParameters["includeId"]?.toBoolean() ?: false
|
||||
val includePerms = call.request.queryParameters["includePerms"]?.toBoolean()
|
||||
?: false
|
||||
val includeId = call.request.queryParameters["includeId"]?.toBoolean()
|
||||
?: false
|
||||
|
||||
call.respond(
|
||||
useDb {
|
||||
@@ -145,7 +149,12 @@ fun Route.configureDataRoutes() {
|
||||
call.respond(server)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
call.respond(HttpStatusCode.InternalServerError, ResponseError(e.message ?: "Unknown error"))
|
||||
call.respond(
|
||||
HttpStatusCode.InternalServerError, ResponseError(
|
||||
e.message
|
||||
?: "Unknown error"
|
||||
)
|
||||
)
|
||||
return@get
|
||||
}
|
||||
}
|
||||
@@ -182,9 +191,10 @@ fun Route.configureDataRoutes() {
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <T> catchException(yield: () -> T): T? = try {
|
||||
yield()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
null
|
||||
}
|
||||
inline fun <T> catchException(yield: () -> T): T? =
|
||||
try {
|
||||
yield()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
null
|
||||
}
|
||||
|
||||
@@ -89,11 +89,13 @@ data class CreateEventFight(
|
||||
fun Route.configureEventFightRoutes() {
|
||||
route("/fights") {
|
||||
get {
|
||||
val event = call.receiveEvent() ?: return@get
|
||||
val event = call.receiveEvent()
|
||||
?: return@get
|
||||
call.respond(EventFight.getEvent(event.eventID).map { ResponseEventFight(it) })
|
||||
}
|
||||
post {
|
||||
val event = call.receiveEvent() ?: return@post
|
||||
val event = call.receiveEvent()
|
||||
?: return@post
|
||||
|
||||
val fight = call.receiveNullable<CreateEventFight>()
|
||||
if (fight == null) {
|
||||
@@ -117,19 +119,26 @@ fun Route.configureEventFightRoutes() {
|
||||
}
|
||||
route("/{fight}") {
|
||||
put {
|
||||
val fight = call.receiveFight() ?: return@put
|
||||
val fight = call.receiveFight()
|
||||
?: return@put
|
||||
val updateFight = call.receiveNullable<UpdateEventFight>()
|
||||
if (updateFight == null) {
|
||||
call.respond(HttpStatusCode.BadRequest, ResponseError("Invalid body"))
|
||||
return@put
|
||||
}
|
||||
|
||||
val teamBlue = updateFight.blueTeam ?: fight.teamBlue
|
||||
val teamRed = updateFight.redTeam ?: fight.teamRed
|
||||
val start = updateFight.start?.let { Timestamp.from(Instant.ofEpochMilli(it)) } ?: fight.startTime
|
||||
val spielmodus = updateFight.spielmodus ?: fight.spielmodus
|
||||
val map = updateFight.map ?: fight.map
|
||||
val spectatePort = updateFight.spectatePort ?: fight.spectatePort
|
||||
val teamBlue = updateFight.blueTeam
|
||||
?: fight.teamBlue
|
||||
val teamRed = updateFight.redTeam
|
||||
?: fight.teamRed
|
||||
val start = updateFight.start?.let { Timestamp.from(Instant.ofEpochMilli(it)) }
|
||||
?: fight.startTime
|
||||
val spielmodus = updateFight.spielmodus
|
||||
?: fight.spielmodus
|
||||
val map = updateFight.map
|
||||
?: fight.map
|
||||
val spectatePort = updateFight.spectatePort
|
||||
?: fight.spectatePort
|
||||
|
||||
if (updateFight.group != null) {
|
||||
if (updateFight.group == -1) {
|
||||
@@ -147,7 +156,8 @@ fun Route.configureEventFightRoutes() {
|
||||
call.respond(HttpStatusCode.OK, ResponseEventFight(fight))
|
||||
}
|
||||
delete {
|
||||
val fight = call.receiveFight() ?: return@delete
|
||||
val fight = call.receiveFight()
|
||||
?: return@delete
|
||||
fight.delete()
|
||||
call.respond(HttpStatusCode.OK)
|
||||
}
|
||||
|
||||
@@ -43,33 +43,48 @@ data class UpdateEventGroup(
|
||||
fun Route.configureEventGroups() {
|
||||
route("/groups") {
|
||||
get {
|
||||
val event = call.receiveEvent() ?: return@get
|
||||
val event = call.receiveEvent()
|
||||
?: return@get
|
||||
call.respond(EventGroup.get(event).map { ResponseGroups(it) })
|
||||
}
|
||||
post {
|
||||
val event = call.receiveEvent() ?: return@post
|
||||
val event = call.receiveEvent()
|
||||
?: return@post
|
||||
val createEventGroup = call.receive<CreateEventGroup>()
|
||||
val group = EventGroup.create(event, createEventGroup.name, createEventGroup.type)
|
||||
call.respond(ResponseGroups(group))
|
||||
}
|
||||
route("/{group}") {
|
||||
get {
|
||||
val group = call.receiveEventGroup() ?: return@get
|
||||
val group = call.receiveEventGroup()
|
||||
?: return@get
|
||||
call.respond(ResponseGroups(group))
|
||||
}
|
||||
put {
|
||||
val group = call.receiveEventGroup() ?: return@put
|
||||
val group = call.receiveEventGroup()
|
||||
?: return@put
|
||||
val updateEventGroup = call.receive<UpdateEventGroup>()
|
||||
val name = updateEventGroup.name ?: group.name
|
||||
val type = updateEventGroup.type ?: group.type
|
||||
val pointsPerWin = updateEventGroup.pointsPerWin ?: group.pointsPerWin
|
||||
val pointsPerLoss = updateEventGroup.pointsPerLoss ?: group.pointsPerLoss
|
||||
val pointsPerDraw = updateEventGroup.pointsPerDraw ?: group.pointsPerDraw
|
||||
val name = updateEventGroup.name
|
||||
?: group.name
|
||||
val type = updateEventGroup.type
|
||||
?: group.type
|
||||
val pointsPerWin = updateEventGroup.pointsPerWin
|
||||
?: group.pointsPerWin
|
||||
val pointsPerLoss = updateEventGroup.pointsPerLoss
|
||||
?: group.pointsPerLoss
|
||||
val pointsPerDraw = updateEventGroup.pointsPerDraw
|
||||
?: group.pointsPerDraw
|
||||
group.update(name, type, pointsPerWin, pointsPerLoss, pointsPerDraw)
|
||||
call.respond(ResponseGroups(EventGroup.byId(group.getId()).orElse(null) ?: return@put))
|
||||
call.respond(
|
||||
ResponseGroups(
|
||||
EventGroup.byId(group.getId()).orElse(null)
|
||||
?: return@put
|
||||
)
|
||||
)
|
||||
}
|
||||
delete {
|
||||
val group = call.receiveEventGroup() ?: return@delete
|
||||
val group = call.receiveEventGroup()
|
||||
?: return@delete
|
||||
group.delete()
|
||||
call.respond(HttpStatusCode.NoContent)
|
||||
}
|
||||
|
||||
@@ -30,11 +30,13 @@ import java.util.*
|
||||
fun Route.configureEventRefereesRouting() {
|
||||
route("/referees") {
|
||||
get {
|
||||
val event = call.receiveEvent() ?: return@get
|
||||
val event = call.receiveEvent()
|
||||
?: return@get
|
||||
call.respond(Referee.get(event.eventID).map { ResponseUser(SteamwarUser.byId(it)!!) })
|
||||
}
|
||||
put {
|
||||
val event = call.receiveEvent() ?: return@put
|
||||
val event = call.receiveEvent()
|
||||
?: return@put
|
||||
val referees = call.receive<List<String>>()
|
||||
referees.forEach {
|
||||
Referee.add(event.eventID, SteamwarUser.get(UUID.fromString(it))!!.getId())
|
||||
@@ -42,7 +44,8 @@ fun Route.configureEventRefereesRouting() {
|
||||
call.respond(Referee.get(event.eventID).map { ResponseUser(SteamwarUser.byId(it)!!) })
|
||||
}
|
||||
delete {
|
||||
val event = call.receiveEvent() ?: return@delete
|
||||
val event = call.receiveEvent()
|
||||
?: return@delete
|
||||
val referees = call.receive<List<String>>()
|
||||
referees.forEach {
|
||||
Referee.remove(event.eventID, SteamwarUser.get(UUID.fromString(it))!!.getId())
|
||||
|
||||
@@ -41,18 +41,23 @@ data class UpdateFromRelation(val fromType: EventRelation.FromType, val fromId:
|
||||
fun Route.configureEventRelations() {
|
||||
route("/relations") {
|
||||
get {
|
||||
val event = call.receiveEvent() ?: return@get
|
||||
val event = call.receiveEvent()
|
||||
?: return@get
|
||||
|
||||
call.respond(EventRelation.get(event).map { ResponseRelation(it) })
|
||||
}
|
||||
post {
|
||||
val create = call.receive<CreateEventRelation>()
|
||||
|
||||
val fight = EventFight.byId(create.fightId) ?: return@post call.respond(HttpStatusCode.NotFound)
|
||||
val fight = EventFight.byId(create.fightId)
|
||||
?: return@post call.respond(HttpStatusCode.NotFound)
|
||||
|
||||
when (create.fromType) {
|
||||
EventRelation.FromType.FIGHT -> EventFight.byId(create.fromId) ?: return@post call.respond(HttpStatusCode.BadRequest)
|
||||
EventRelation.FromType.GROUP -> EventGroup.byId(create.fromId) ?: return@post call.respond(HttpStatusCode.BadRequest)
|
||||
EventRelation.FromType.FIGHT -> EventFight.byId(create.fromId)
|
||||
?: return@post call.respond(HttpStatusCode.BadRequest)
|
||||
|
||||
EventRelation.FromType.GROUP -> EventGroup.byId(create.fromId)
|
||||
?: return@post call.respond(HttpStatusCode.BadRequest)
|
||||
}
|
||||
|
||||
val relation = EventRelation.create(fight, create.team, create.fromType, create.fromId, create.fromPlace)
|
||||
@@ -61,19 +66,26 @@ fun Route.configureEventRelations() {
|
||||
}
|
||||
route("/{relation}") {
|
||||
get {
|
||||
val relation = call.receiveEventRelation() ?: return@get
|
||||
val relation = call.receiveEventRelation()
|
||||
?: return@get
|
||||
call.respond(ResponseRelation(relation))
|
||||
}
|
||||
put {
|
||||
val relation = call.receiveEventRelation() ?: return@put
|
||||
val relation = call.receiveEventRelation()
|
||||
?: return@put
|
||||
val update = call.receive<UpdateEventRelation>()
|
||||
|
||||
update.from?.let {
|
||||
when(it.fromType) {
|
||||
EventRelation.FromType.FIGHT -> relation.setFromFight(EventFight.byId(it.fromId) ?: return@put call.respond(HttpStatusCode.BadRequest),
|
||||
when (it.fromType) {
|
||||
EventRelation.FromType.FIGHT -> relation.setFromFight(
|
||||
EventFight.byId(it.fromId)
|
||||
?: return@put call.respond(HttpStatusCode.BadRequest),
|
||||
it.fromPlace
|
||||
)
|
||||
EventRelation.FromType.GROUP -> relation.setFromGroup(EventGroup.byId(it.fromId).orElse(null) ?: return@put call.respond(HttpStatusCode.BadRequest),
|
||||
|
||||
EventRelation.FromType.GROUP -> relation.setFromGroup(
|
||||
EventGroup.byId(it.fromId).orElse(null)
|
||||
?: return@put call.respond(HttpStatusCode.BadRequest),
|
||||
it.fromPlace
|
||||
)
|
||||
}
|
||||
@@ -84,7 +96,8 @@ fun Route.configureEventRelations() {
|
||||
call.respond(ResponseRelation(EventRelation.get(relation.id)))
|
||||
}
|
||||
delete {
|
||||
val relation = call.receiveEventRelation() ?: return@delete
|
||||
val relation = call.receiveEventRelation()
|
||||
?: return@delete
|
||||
relation.delete()
|
||||
call.respond(HttpStatusCode.NoContent)
|
||||
}
|
||||
|
||||
@@ -29,11 +29,13 @@ import io.ktor.server.routing.*
|
||||
fun Route.configureEventTeams() {
|
||||
route("/teams") {
|
||||
get {
|
||||
val event = call.receiveEvent() ?: return@get
|
||||
val event = call.receiveEvent()
|
||||
?: return@get
|
||||
call.respond(TeamTeilnahme.getTeams(event.eventID).map { ResponseTeam(it) })
|
||||
}
|
||||
put {
|
||||
val event = call.receiveEvent() ?: return@put
|
||||
val event = call.receiveEvent()
|
||||
?: return@put
|
||||
val team = call.receive<List<Int>>()
|
||||
team.forEach {
|
||||
TeamTeilnahme.teilnehmen(it, event.eventID)
|
||||
@@ -41,7 +43,8 @@ fun Route.configureEventTeams() {
|
||||
call.respond(HttpStatusCode.NoContent)
|
||||
}
|
||||
delete {
|
||||
val event = call.receiveEvent() ?: return@delete
|
||||
val event = call.receiveEvent()
|
||||
?: return@delete
|
||||
val team = call.receive<List<Int>>()
|
||||
team.forEach {
|
||||
TeamTeilnahme.notTeilnehmen(it, event.eventID)
|
||||
|
||||
@@ -162,13 +162,15 @@ fun Route.configureEventsRoute() {
|
||||
}
|
||||
route("/{id}") {
|
||||
get {
|
||||
val event = call.receiveEvent() ?: return@get
|
||||
val event = call.receiveEvent()
|
||||
?: return@get
|
||||
call.respond(
|
||||
ExtendedResponseEvent(event)
|
||||
)
|
||||
}
|
||||
get("/csv") {
|
||||
val event = call.receiveEvent() ?: return@get
|
||||
val event = call.receiveEvent()
|
||||
?: return@get
|
||||
|
||||
val fights = EventFight.getEvent(event.eventID)
|
||||
val csv = StringBuilder();
|
||||
@@ -200,23 +202,30 @@ fun Route.configureEventsRoute() {
|
||||
call.respondText(csv.toString())
|
||||
}
|
||||
put {
|
||||
val event = call.receiveEvent() ?: return@put
|
||||
val event = call.receiveEvent()
|
||||
?: return@put
|
||||
|
||||
val updateEvent = call.receiveNullable<UpdateEvent>()
|
||||
if (updateEvent == null) {
|
||||
call.respond(HttpStatusCode.BadRequest, ResponseError("Invalid body"))
|
||||
return@put
|
||||
}
|
||||
val eventName = updateEvent.name ?: event.eventName
|
||||
val deadline = updateEvent.deadline?.let { Timestamp.from(Instant.ofEpochMilli(it)) } ?: event.deadline
|
||||
val start = updateEvent.start?.let { Timestamp.from(Instant.ofEpochMilli(it)) } ?: event.start
|
||||
val end = updateEvent.end?.let { Timestamp.from(Instant.ofEpochMilli(it)) } ?: event.end
|
||||
val maxTeamMembers = updateEvent.maxTeamMembers ?: event.maximumTeamMembers
|
||||
val eventName = updateEvent.name
|
||||
?: event.eventName
|
||||
val deadline = updateEvent.deadline?.let { Timestamp.from(Instant.ofEpochMilli(it)) }
|
||||
?: event.deadline
|
||||
val start = updateEvent.start?.let { Timestamp.from(Instant.ofEpochMilli(it)) }
|
||||
?: event.start
|
||||
val end = updateEvent.end?.let { Timestamp.from(Instant.ofEpochMilli(it)) }
|
||||
?: event.end
|
||||
val maxTeamMembers = updateEvent.maxTeamMembers
|
||||
?: event.maximumTeamMembers
|
||||
|
||||
val schemType =
|
||||
if (updateEvent.schemType == "null") null else updateEvent.schemType?.let { SchematicType.fromDB(it) }
|
||||
?: event.schematicType
|
||||
val publicSchemsOnly = updateEvent.publicSchemsOnly ?: event.publicSchemsOnly()
|
||||
val publicSchemsOnly = updateEvent.publicSchemsOnly
|
||||
?: event.publicSchemsOnly()
|
||||
|
||||
if (updateEvent.addReferee != null) {
|
||||
updateEvent.addReferee.forEach {
|
||||
|
||||
@@ -149,7 +149,8 @@ fun Route.configurePage() {
|
||||
permission = UserPerm.MODERATION
|
||||
}
|
||||
get {
|
||||
val branch = call.request.queryParameters["branch"] ?: "master"
|
||||
val branch = call.request.queryParameters["branch"]
|
||||
?: "master"
|
||||
|
||||
call.respond(filesInDirectory("/src/content", branch) {
|
||||
it.endsWith(".md") || it.endsWith(".json")
|
||||
@@ -157,16 +158,18 @@ fun Route.configurePage() {
|
||||
}
|
||||
post {
|
||||
val req = call.receive<CreatePageRequest>()
|
||||
if(req.path.startsWith("src/content/")) {
|
||||
if (req.path.startsWith("src/content/")) {
|
||||
call.respond(HttpStatusCode.BadRequest, "Invalid path")
|
||||
return@post
|
||||
}
|
||||
val res = client.post("repos/SteamWar/Website/contents/src/content/${req.path}") {
|
||||
contentType(ContentType.Application.Json)
|
||||
setBody(CreateGiteaPageRequest(
|
||||
"Create page ${req.path}",
|
||||
Base64.getEncoder().encodeToString((
|
||||
if (req.path.endsWith(".md")) """
|
||||
setBody(
|
||||
CreateGiteaPageRequest(
|
||||
"Create page ${req.path}",
|
||||
Base64.getEncoder().encodeToString(
|
||||
(
|
||||
if (req.path.endsWith(".md")) """
|
||||
---
|
||||
title: ${req.title?.removeSuffix(".md") ?: "Enter Title"}
|
||||
description: Enter Description
|
||||
@@ -178,10 +181,15 @@ fun Route.configurePage() {
|
||||
|
||||
# ${req.path}
|
||||
""" else "{}"
|
||||
).trimIndent().toByteArray()),
|
||||
call.request.queryParameters["branch"] ?: "master",
|
||||
Identity(call.principal<SWAuthPrincipal>()!!.user.userName, "admin-tool@steamwar.de"
|
||||
)))
|
||||
).trimIndent().toByteArray()
|
||||
),
|
||||
call.request.queryParameters["branch"]
|
||||
?: "master",
|
||||
Identity(
|
||||
call.principal<SWAuthPrincipal>()!!.user.userName, "admin-tool@steamwar.de"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
call.respond(res.status)
|
||||
}
|
||||
@@ -219,10 +227,13 @@ fun Route.configurePage() {
|
||||
}
|
||||
route("{id}") {
|
||||
get {
|
||||
val id = call.parameters["id"]?.toIntOrNull() ?: return@get call.respond(HttpStatusCode.BadRequest, "Invalid id")
|
||||
val path = pathPageIdMap.entries.find { it.value == id }?.key ?: return@get call.respond(HttpStatusCode.NotFound, "Page not found")
|
||||
val id = call.parameters["id"]?.toIntOrNull()
|
||||
?: return@get call.respond(HttpStatusCode.BadRequest, "Invalid id")
|
||||
val path = pathPageIdMap.entries.find { it.value == id }?.key
|
||||
?: return@get call.respond(HttpStatusCode.NotFound, "Page not found")
|
||||
|
||||
val branch = call.request.queryParameters["branch"] ?: "master"
|
||||
val branch = call.request.queryParameters["branch"]
|
||||
?: "master"
|
||||
val res = client.get("repos/SteamWar/Website/contents/$path?ref=$branch")
|
||||
val fileJson = Json.parseToJsonElement(res.bodyAsText())
|
||||
if (fileJson is JsonArray) {
|
||||
@@ -235,8 +246,10 @@ fun Route.configurePage() {
|
||||
delete {
|
||||
val data = call.receive<DeletePageRequest>()
|
||||
|
||||
val path = pathPageIdMap.entries.find { it.value == call.parameters["id"]?.toIntOrNull() }?.key ?: return@delete call.respond(HttpStatusCode.NotFound, "Page not found")
|
||||
val branch = call.request.queryParameters["branch"] ?: "master"
|
||||
val path = pathPageIdMap.entries.find { it.value == call.parameters["id"]?.toIntOrNull() }?.key
|
||||
?: return@delete call.respond(HttpStatusCode.NotFound, "Page not found")
|
||||
val branch = call.request.queryParameters["branch"]
|
||||
?: "master"
|
||||
|
||||
@Serializable
|
||||
data class DeleteGiteaPageRequest(val sha: String, val message: String, val branch: String, val author: Identity)
|
||||
@@ -253,11 +266,17 @@ fun Route.configurePage() {
|
||||
data class UpdateGiteaPageRequest(val content: String, val sha: String, val message: String, val branch: String, val author: Identity)
|
||||
|
||||
val data = call.receive<UpdatePageRequest>()
|
||||
val path = pathPageIdMap.entries.find { it.value == call.parameters["id"]?.toIntOrNull() }?.key ?: return@put call.respond(HttpStatusCode.NotFound, "Page not found")
|
||||
val path = pathPageIdMap.entries.find { it.value == call.parameters["id"]?.toIntOrNull() }?.key
|
||||
?: return@put call.respond(HttpStatusCode.NotFound, "Page not found")
|
||||
|
||||
val res = client.put("repos/SteamWar/Website/contents/$path") {
|
||||
contentType(ContentType.Application.Json)
|
||||
setBody(UpdateGiteaPageRequest(data.content, data.sha, data.message, (call.request.queryParameters["branch"] ?: "master"), Identity(call.principal<SWAuthPrincipal>()!!.user.userName, "admin-tool@steamwar.de")))
|
||||
setBody(
|
||||
UpdateGiteaPageRequest(
|
||||
data.content, data.sha, data.message, (call.request.queryParameters["branch"]
|
||||
?: "master"), Identity(call.principal<SWAuthPrincipal>()!!.user.userName, "admin-tool@steamwar.de")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
call.respond(res.status)
|
||||
@@ -265,7 +284,8 @@ fun Route.configurePage() {
|
||||
}
|
||||
route("images") {
|
||||
get {
|
||||
val branch = call.request.queryParameters["branch"] ?: "master"
|
||||
val branch = call.request.queryParameters["branch"]
|
||||
?: "master"
|
||||
|
||||
call.respond(filesInDirectory("/src/images", branch))
|
||||
}
|
||||
@@ -274,12 +294,17 @@ fun Route.configurePage() {
|
||||
|
||||
client.post("repos/SteamWar/Website/contents/src/images/${req.name}") {
|
||||
contentType(ContentType.Application.Json)
|
||||
setBody(CreateGiteaPageRequest(
|
||||
"Add Image ${req.name}",
|
||||
req.data,
|
||||
call.request.queryParameters["branch"] ?: "master",
|
||||
Identity(call.principal<SWAuthPrincipal>()!!.user.userName, "admin-tool@steamwar.de"
|
||||
)))
|
||||
setBody(
|
||||
CreateGiteaPageRequest(
|
||||
"Add Image ${req.name}",
|
||||
req.data,
|
||||
call.request.queryParameters["branch"]
|
||||
?: "master",
|
||||
Identity(
|
||||
call.principal<SWAuthPrincipal>()!!.user.userName, "admin-tool@steamwar.de"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
call.respond(HttpStatusCode.Created)
|
||||
|
||||
@@ -72,25 +72,28 @@ val nbt = Nbt()
|
||||
fun Route.configureSchematic() {
|
||||
route("/download/{code}") {
|
||||
get {
|
||||
val node = call.receiveSchematic() ?: return@get
|
||||
val node = call.receiveSchematic()
|
||||
?: return@get
|
||||
|
||||
val user = call.principal<SWAuthPrincipal>()?.user
|
||||
if(user != null && !node.accessibleByUser(user)) {
|
||||
if (user != null && !node.accessibleByUser(user)) {
|
||||
call.respond(HttpStatusCode.Forbidden)
|
||||
SWException.log("User ${user.userName} tried to download schematic ${node.name} without permission", user.id.toString())
|
||||
return@get
|
||||
}
|
||||
|
||||
val data = NodeData.getLatest(node) ?: run {
|
||||
call.respond(HttpStatusCode.InternalServerError)
|
||||
return@get
|
||||
}
|
||||
val data = NodeData.getLatest(node)
|
||||
?: run {
|
||||
call.respond(HttpStatusCode.InternalServerError)
|
||||
return@get
|
||||
}
|
||||
|
||||
call.response.header("Content-Disposition", "attachment; filename=\"${node.name}${data.nodeFormat.fileEnding}\"")
|
||||
call.respondBytes(data.schemData(false).readAllBytes(), contentType = ContentType.Application.OctetStream, status = HttpStatusCode.OK)
|
||||
}
|
||||
get("/info") {
|
||||
val node = call.receiveSchematic() ?: return@get
|
||||
val node = call.receiveSchematic()
|
||||
?: return@get
|
||||
|
||||
call.respond(ResponseSchematic(node))
|
||||
}
|
||||
@@ -103,18 +106,22 @@ fun Route.configureSchematic() {
|
||||
val schemName = file.name.substringBeforeLast(".")
|
||||
|
||||
if (SchematicNode.invalidSchemName(arrayOf(schemName))) {
|
||||
call.respond(HttpStatusCode.BadRequest, ResponseError(
|
||||
error = "INVALID_NAME"
|
||||
))
|
||||
call.respond(
|
||||
HttpStatusCode.BadRequest, ResponseError(
|
||||
error = "INVALID_NAME"
|
||||
)
|
||||
)
|
||||
return@post
|
||||
}
|
||||
|
||||
val schemType = file.name.substringAfterLast(".")
|
||||
|
||||
if (schemType != "schem" && schemType != "schematic") {
|
||||
call.respond(HttpStatusCode.BadRequest, ResponseError(
|
||||
error = "INVALID_SUFFIX"
|
||||
))
|
||||
call.respond(
|
||||
HttpStatusCode.BadRequest, ResponseError(
|
||||
error = "INVALID_SUFFIX"
|
||||
)
|
||||
)
|
||||
return@post
|
||||
}
|
||||
|
||||
@@ -149,39 +156,47 @@ fun Route.configureSchematic() {
|
||||
.value
|
||||
|
||||
if (fawe.equals("2.12.3-SNAPSHOT")) {
|
||||
SWException.log("Schematic with Bugged Version Uploaded", """
|
||||
SWException.log(
|
||||
"Schematic with Bugged Version Uploaded", """
|
||||
Schematic=$schemName
|
||||
User=${user.userName}
|
||||
Id=${user.id}
|
||||
""".trimIndent())
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
} catch (_: Exception) {}
|
||||
} catch (_: Exception) {
|
||||
}
|
||||
}
|
||||
|
||||
NodeData.saveFromStream(node, content.inputStream(), version)
|
||||
|
||||
call.respond(ResponseSchematic(node))
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.BadRequest, ResponseError(
|
||||
error = e.message ?: "GENERIC", code = "UPLOAD_ERROR"
|
||||
))
|
||||
call.respond(
|
||||
HttpStatusCode.BadRequest, ResponseError(
|
||||
error = e.message
|
||||
?: "GENERIC", code = "UPLOAD_ERROR"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun ApplicationCall.receiveSchematic(fieldName: String = "code", delete: Boolean = false): SchematicNode? {
|
||||
val code = parameters[fieldName] ?: run {
|
||||
respond(HttpStatusCode.BadRequest)
|
||||
return null
|
||||
}
|
||||
val code = parameters[fieldName]
|
||||
?: run {
|
||||
respond(HttpStatusCode.BadRequest)
|
||||
return null
|
||||
}
|
||||
|
||||
val dl = NodeDownload.get(code) ?: run {
|
||||
respond(HttpStatusCode.NotFound)
|
||||
return null
|
||||
}
|
||||
val dl = NodeDownload.get(code)
|
||||
?: run {
|
||||
respond(HttpStatusCode.NotFound)
|
||||
return null
|
||||
}
|
||||
|
||||
if(dl.timestamp.toInstant().plus(Duration.of(5, ChronoUnit.MINUTES)).isBefore(Instant.now())) {
|
||||
if (dl.timestamp.toInstant().plus(Duration.of(5, ChronoUnit.MINUTES)).isBefore(Instant.now())) {
|
||||
respond(HttpStatusCode.Gone)
|
||||
return null
|
||||
}
|
||||
@@ -190,10 +205,11 @@ suspend fun ApplicationCall.receiveSchematic(fieldName: String = "code", delete:
|
||||
dl.delete()
|
||||
}
|
||||
|
||||
val node = SchematicNode.getSchematicNode(dl.nodeId) ?: run {
|
||||
respond(HttpStatusCode.NotFound)
|
||||
return null
|
||||
}
|
||||
val node = SchematicNode.getSchematicNode(dl.nodeId)
|
||||
?: run {
|
||||
respond(HttpStatusCode.NotFound)
|
||||
return null
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
@@ -31,11 +31,15 @@ import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class UserStats(val eventFightParticipation: Int, val eventParticipation: Int, val acceptedSchematics: Int, val fights: Int, val playtime: Double) {
|
||||
constructor(user: SteamwarUser): this(
|
||||
getEventFightParticipation(user) ?: 0,
|
||||
getEventParticipation(user) ?: 0,
|
||||
getAcceptedSchematics(user) ?: 0,
|
||||
getFightCount(user) ?: 0,
|
||||
constructor(user: SteamwarUser) : this(
|
||||
getEventFightParticipation(user)
|
||||
?: 0,
|
||||
getEventParticipation(user)
|
||||
?: 0,
|
||||
getAcceptedSchematics(user)
|
||||
?: 0,
|
||||
getFightCount(user)
|
||||
?: 0,
|
||||
user.getOnlinetime() / 3600.0
|
||||
)
|
||||
}
|
||||
@@ -43,7 +47,8 @@ data class UserStats(val eventFightParticipation: Int, val eventParticipation: I
|
||||
fun Route.configureStats() {
|
||||
route("/stats") {
|
||||
get("/ranked/{gamemode}") {
|
||||
val gamemode = call.parameters["gamemode"] ?: return@get call.respond(HttpStatusCode.NotFound)
|
||||
val gamemode = call.parameters["gamemode"]
|
||||
?: return@get call.respond(HttpStatusCode.NotFound)
|
||||
|
||||
@Serializable
|
||||
data class RankedUser(val name: String, val elo: Int)
|
||||
|
||||
@@ -84,7 +84,8 @@ fun Route.configureUserPerms() {
|
||||
)
|
||||
}
|
||||
put("/prefix/{prefix}") {
|
||||
val (user, prefix) = call.receivePermission("prefix", isPrefix = true) ?: return@put
|
||||
val (user, prefix) = call.receivePermission("prefix", isPrefix = true)
|
||||
?: return@put
|
||||
|
||||
user.perms().filter { it.name.startsWith("PREFIX_") }.forEach {
|
||||
UserPerm.removePerm(user, it)
|
||||
@@ -94,7 +95,8 @@ fun Route.configureUserPerms() {
|
||||
call.respond(HttpStatusCode.Accepted)
|
||||
}
|
||||
put("/{perm}") {
|
||||
val (user, permission) = call.receivePermission() ?: return@put
|
||||
val (user, permission) = call.receivePermission()
|
||||
?: return@put
|
||||
|
||||
if (!user.hasPerm(permission)) {
|
||||
UserPerm.addPerm(user, permission)
|
||||
@@ -104,7 +106,8 @@ fun Route.configureUserPerms() {
|
||||
call.respond(HttpStatusCode.NoContent)
|
||||
}
|
||||
delete("/{perm}") {
|
||||
val (user, permission) = call.receivePermission() ?: return@delete
|
||||
val (user, permission) = call.receivePermission()
|
||||
?: return@delete
|
||||
|
||||
if (user.hasPerm(permission)) {
|
||||
UserPerm.removePerm(user, permission)
|
||||
|
||||
@@ -22,8 +22,10 @@ package de.steamwar.sql
|
||||
import de.steamwar.sql.internal.SQLConfig
|
||||
import java.util.logging.Logger
|
||||
|
||||
class SQLConfigImpl: SQLConfig {
|
||||
override fun getLogger(): Logger = Logger.getGlobal()
|
||||
class SQLConfigImpl : SQLConfig {
|
||||
override fun getLogger(): Logger =
|
||||
Logger.getGlobal()
|
||||
|
||||
override fun maxConnections(): Int = 1
|
||||
override fun maxConnections(): Int =
|
||||
1
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ package de.steamwar.sql
|
||||
|
||||
import java.io.File
|
||||
|
||||
class SQLWrapperImpl: SQLWrapper<String> {
|
||||
class SQLWrapperImpl : SQLWrapper<String> {
|
||||
override fun getSchemTypesFolder(): File {
|
||||
return File("/configs/GameModes")
|
||||
}
|
||||
|
||||
@@ -30,24 +30,26 @@ private val getNum: (ResultSet) -> Int? = {
|
||||
private const val eventFightParticipation =
|
||||
"SELECT FightPlayer.UserID, COUNT(UserID) as num FROM FightPlayer INNER JOIN Fight on FightPlayer.FightID = Fight.FightID WHERE Fight.Server LIKE '%vs%' AND FightPlayer.UserID = ? GROUP BY FightPlayer.UserID"
|
||||
|
||||
fun getEventFightParticipation(user: SteamwarUser) = useDb {
|
||||
exec(
|
||||
eventFightParticipation, args = listOf(
|
||||
IntegerColumnType() to user.getId()
|
||||
)
|
||||
) { getNum(it) }
|
||||
}
|
||||
fun getEventFightParticipation(user: SteamwarUser) =
|
||||
useDb {
|
||||
exec(
|
||||
eventFightParticipation, args = listOf(
|
||||
IntegerColumnType() to user.getId()
|
||||
)
|
||||
) { getNum(it) }
|
||||
}
|
||||
|
||||
private const val eventParticipation =
|
||||
"SELECT FightPlayer.UserID, COUNT(DISTINCT EventID) as num FROM FightPlayer INNER JOIN Fight F on FightPlayer.FightID = F.FightID INNER JOIN EventFight EF on F.FightID = EF.Fight WHERE F.FightID = FightPlayer.FightID AND FightPlayer.FightID = EF.Fight AND F.Server LIKE '%vs%' AND FightPlayer.UserID = ? GROUP BY FightPlayer.UserID"
|
||||
|
||||
fun getEventParticipation(user: SteamwarUser) = useDb {
|
||||
exec(
|
||||
eventParticipation, args = listOf(
|
||||
IntegerColumnType() to user.getId()
|
||||
)
|
||||
) { getNum(it) }
|
||||
}
|
||||
fun getEventParticipation(user: SteamwarUser) =
|
||||
useDb {
|
||||
exec(
|
||||
eventParticipation, args = listOf(
|
||||
IntegerColumnType() to user.getId()
|
||||
)
|
||||
) { getNum(it) }
|
||||
}
|
||||
|
||||
private const val acceptedSchematics =
|
||||
"SELECT NodeOwner, COUNT(DISTINCT NodeId) AS num FROM SchematicNode WHERE NodeType != 'normal' AND NodeType IS NOT NULL AND NodeType NOT LIKE 'c%' AND NodeOwner = ?"
|
||||
@@ -60,19 +62,22 @@ private val fightCount = "SELECT COUNT(*) AS num FROM FightPlayer WHERE UserID =
|
||||
fun getFightCount(user: SteamwarUser) =
|
||||
useDb { exec(fightCount, args = listOf(IntegerColumnType() to user.getId())) { getNum(it) } }
|
||||
|
||||
fun getRankedList(gamemode: String): List<Pair<String, Int>> = useDb {
|
||||
emptyList()
|
||||
}
|
||||
fun getRankedList(gamemode: String): List<Pair<String, Int>> =
|
||||
useDb {
|
||||
emptyList()
|
||||
}
|
||||
|
||||
private const val fightList =
|
||||
"SELECT DATE(StartTime) AS Datum, GameMode AS Modus, COUNT(*) AS Anzahl FROM Fight WHERE DATE(StartTime) >= DATE(NOW()) - INTERVAL 1 WEEK GROUP BY Datum, GameMode ORDER BY Datum ASC"
|
||||
|
||||
fun getFightList(): List<Triple<String, String, Int>> = useDb {
|
||||
exec(fightList) {
|
||||
val list = mutableListOf<Triple<String, String, Int>>()
|
||||
while (it.next()) {
|
||||
list.add(Triple(it.getString("Datum"), it.getString("Modus"), it.getInt("Anzahl")))
|
||||
fun getFightList(): List<Triple<String, String, Int>> =
|
||||
useDb {
|
||||
exec(fightList) {
|
||||
val list = mutableListOf<Triple<String, String, Int>>()
|
||||
while (it.next()) {
|
||||
list.add(Triple(it.getString("Datum"), it.getString("Modus"), it.getInt("Anzahl")))
|
||||
}
|
||||
list
|
||||
}
|
||||
list
|
||||
}
|
||||
} ?: emptyList()
|
||||
?: emptyList()
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<property name="LOG_FILE" value="api" />
|
||||
<property name="LOG_FILE" value="api"/>
|
||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>logs/${LOG_FILE}.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
|
||||
Reference in New Issue
Block a user