diff --git a/CommonCore/SQL/src/de/steamwar/sql/PollAnswer.java b/CommonCore/SQL/src/de/steamwar/sql/PollAnswer.java deleted file mode 100644 index 9376ed18..00000000 --- a/CommonCore/SQL/src/de/steamwar/sql/PollAnswer.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * This file is a part of the SteamWar software. - * - * Copyright (C) 2025 SteamWar.de-Serverteam - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package de.steamwar.sql; - -import de.steamwar.sql.internal.Field; -import de.steamwar.sql.internal.SelectStatement; -import de.steamwar.sql.internal.Statement; -import de.steamwar.sql.internal.Table; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.Setter; - -import java.util.HashMap; -import java.util.Map; - -@AllArgsConstructor -public class PollAnswer { - - @Getter - @Setter - private static String currentPoll; - - private static final Table table = new Table<>(PollAnswer.class); - - private static final SelectStatement get = table.select(Table.PRIMARY); - private static final Statement getResults = new Statement("SELECT Count(UserID) AS Times, Answer FROM PollAnswer WHERE Question = ? GROUP BY Answer ORDER BY Times ASC"); - private static final Statement insert = table.insertAll(); - - @Field(keys = {Table.PRIMARY}) - private final int userID; - @Field(keys = {Table.PRIMARY}) - private final String question; - @Field(def = "0") - private int answer; - - public static PollAnswer get(int userID) { - PollAnswer answer = get.select(userID, currentPoll); - if(answer == null) - return new PollAnswer(userID, currentPoll, 0); - return answer; - } - - public static Map getCurrentResults() { - return getResults.select(rs -> { - Map retMap = new HashMap<>(); - while (rs.next()) - retMap.put(rs.getInt("Answer")-1, rs.getInt("Times")); - return retMap; - }, currentPoll); - } - - public boolean hasAnswered(){ - return answer != 0; - } - - public void setAnswer(int answer){ - this.answer = answer; - insert.update(userID, question, answer); - } -} diff --git a/CommonCore/SQL/src/de/steamwar/sql/PollAnswer.kt b/CommonCore/SQL/src/de/steamwar/sql/PollAnswer.kt new file mode 100644 index 00000000..a4c20b26 --- /dev/null +++ b/CommonCore/SQL/src/de/steamwar/sql/PollAnswer.kt @@ -0,0 +1,78 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2025 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.sql + +import de.steamwar.sql.internal.useDb +import org.jetbrains.exposed.v1.core.VarCharColumnType +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.dao.id.CompositeID +import org.jetbrains.exposed.v1.core.dao.id.CompositeIdTable +import org.jetbrains.exposed.v1.core.dao.id.EntityID +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.dao.CompositeEntity +import org.jetbrains.exposed.v1.dao.CompositeEntityClass + +object PollAnswerTable: CompositeIdTable("PollAnswer") { + val userId = reference("UserID", SteamwarUserTable) + val question = varchar("Question", 150) + val answer = integer("Answer") +} + +class PollAnswer(id: EntityID): CompositeEntity(id) { + var userId by PollAnswerTable.userId + private set + var question by PollAnswerTable.question + private set + private var answerId by PollAnswerTable.answer + var answer: Int + get() = answerId + set(value) = useDb { + answerId = value + } + + companion object: CompositeEntityClass(PollAnswerTable) { + @JvmStatic + var currentPoll: String? = null + + @JvmStatic + fun get(userId: Int) = useDb { + find { (PollAnswerTable.userId eq userId) and (PollAnswerTable.question eq currentPoll!!) }.firstOrNull() + ?: new { + this.userId = EntityID(userId, SteamwarUserTable) + this.question = currentPoll!! + this.answerId = 0 + } + } + + @JvmStatic + fun getCurrentResults(): Map = useDb { + exec("SELECT Count(UserID) AS Times, Answer FROM PollAnswer WHERE Question = ? GROUP BY Answer ORDER BY Times ASC", + args = listOf(VarCharColumnType() to currentPoll!!)) { + val result = mutableMapOf() + while (it.next()) { + result[it.getInt("Answer")] = it.getInt("Times") + } + result + } ?: emptyMap() + } + } + + fun hasAnswered() = answerId != 0 +} \ No newline at end of file diff --git a/CommonCore/SQL/src/de/steamwar/sql/Punishment.java b/CommonCore/SQL/src/de/steamwar/sql/Punishment.java deleted file mode 100644 index f5813792..00000000 --- a/CommonCore/SQL/src/de/steamwar/sql/Punishment.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * This file is a part of the SteamWar software. - * - * Copyright (C) 2025 SteamWar.de-Serverteam - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package de.steamwar.sql; - -import de.steamwar.sql.internal.*; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -import java.sql.Timestamp; -import java.time.Instant; -import java.time.format.DateTimeFormatter; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.function.Consumer; -import java.util.stream.Collectors; - -@AllArgsConstructor -public class Punishment { - - static { - SqlTypeMapper.nameEnumMapper(PunishmentType.class); - } - - public static final Timestamp PERMA_TIME = Timestamp.from(Instant.ofEpochSecond(946674800)); - - private static final Table table = new Table<>(Punishment.class, "Punishments"); - private static final SelectStatement getPunishments = new SelectStatement<>(table, "SELECT * FROM Punishments WHERE PunishmentId IN (SELECT MAX(PunishmentId) FROM Punishments WHERE UserId = ? GROUP BY Type)"); - private static final SelectStatement getPunishment = new SelectStatement<>(table, "SELECT * FROM Punishments WHERE UserId = ? AND Type = ? ORDER BY PunishmentId DESC LIMIT 1"); - private static final SelectStatement getAllPunishments = new SelectStatement<>(table, "SELECT * FROM Punishments WHERE UserId = ? ORDER BY `PunishmentId` DESC"); - private static final Statement insert = table.insertFields(true, "UserId", "Punisher", "Type", "EndTime", "Perma", "Reason"); - - public static Punishment getPunishmentOfPlayer(int user, PunishmentType type) { - return getPunishment.select(user, type); - } - - public static Map getPunishmentsOfPlayer(int user) { - return getPunishments.listSelect(user).stream().collect(Collectors.toMap(Punishment::getType, punishment -> punishment)); - } - - public static List getAllPunishmentsOfPlayer(int user) { - return getAllPunishments.listSelect(user); - } - - public static boolean isPunished(SteamwarUser user, PunishmentType type, Consumer callback) { - Punishment punishment = Punishment.getPunishmentOfPlayer(user.getId(), type); - if(punishment == null || !punishment.isCurrent()) { - return false; - } else { - callback.accept(punishment); - return true; - } - } - - public static Punishment createPunishment(int user, int executor, PunishmentType type, String reason, Timestamp endTime, boolean perma) { - if(perma && !endTime.equals(PERMA_TIME)) { - throw new IllegalArgumentException("Permanent punishments must have an end time of `Punishment.PERMA_TIME`"); - } - int punishmentId = insert.insertGetKey(user, executor, type.name(), endTime, perma, reason); - return new Punishment(punishmentId, user, executor, type, Timestamp.from(Instant.now()), endTime, perma, reason); - } - - @Field(keys = {Table.PRIMARY}, autoincrement = true) - private final int punishmentId; - @Field - @Getter - private final int userId; - @Field - @Getter - private final int punisher; - @Field - @Getter - private final PunishmentType type; - @Field - @Getter - private final Timestamp startTime; - @Field - @Getter - private final Timestamp endTime; - @Field - @Getter - private final boolean perma; - @Field - @Getter - private final String reason; - - @Deprecated // Not multiling, misleading title - public String getBantime(Timestamp endTime, boolean perma) { - if (perma) { - return "permanent"; - } else { - return endTime.toLocalDateTime().format(DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm")); - } - } - - public boolean isCurrent() { - return isPerma() || getEndTime().after(new Date()); - } - - @AllArgsConstructor - @RequiredArgsConstructor - @Getter - public enum PunishmentType { - Ban(false, "BAN_TEAM", "BAN_PERMA", "BAN_UNTIL", "UNBAN_ERROR", "UNBAN"), - Mute( false, "MUTE_TEAM", "MUTE_PERMA", "MUTE_UNTIL", "UNMUTE_ERROR", "UNMUTE"), - NoSchemReceiving(true, "NOSCHEMRECEIVING_TEAM", "NOSCHEMRECEIVING_PERMA", "NOSCHEMRECEIVING_UNTIL", "UNNOSCHEMRECEIVING_ERROR", "UNNOSCHEMRECEIVING"), - NoSchemSharing(true, "NOSCHEMSHARING_TEAM", "NOSCHEMSHARING_PERMA", "NOSCHEMSHARING_UNTIL", "UNNOSCHEMSHARING_ERROR", "UNNOSCHEMSHARING"), - NoSchemSubmitting(false, "NOSCHEMSUBMITTING_TEAM", "NOSCHEMSUBMITTING_PERMA", "NOSCHEMSUBMITTING_UNTIL", "UNNOSCHEMSUBMITTING_ERROR", "UNNOSCHEMSUBMITTING"), - NoDevServer(true, "NODEVSERVER_TEAM", "NODEVSERVER_PERMA", "NODEVSERVER_UNTIL", "UNNODEVSERVER_ERROR", "UNNODEVSERVER"), - NoFightServer(true, "NOFIGHTSERVER_TEAM", "NOFIGHTSERVER_PERMA", "NOFIGHTSERVER_UNTIL", "UNNOFIGHTSERVER_ERROR", "UNNOFIGHTSERVER"), - NoTeamServer(true, "NOTEAMSERVER_TEAM", "NOTEAMSERVER_PERMA", "NOTEAMSERVER_UNTIL", "UNNOTEAMSERVER_ERROR", "UNNOTEAMSERVER"), - Note(false, "NOTE_TEAM", null, null, null, null, true); - - private final boolean needsAdmin; - private final String teamMessage; - private final String playerMessagePerma; - private final String playerMessageUntil; - private final String usageNotPunished; - private final String unpunishmentMessage; - private boolean multi = false; - } -} diff --git a/CommonCore/SQL/src/de/steamwar/sql/Punishment.kt b/CommonCore/SQL/src/de/steamwar/sql/Punishment.kt new file mode 100644 index 00000000..a5fa6baa --- /dev/null +++ b/CommonCore/SQL/src/de/steamwar/sql/Punishment.kt @@ -0,0 +1,190 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2025 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.sql + +import de.steamwar.sql.internal.useDb +import org.jetbrains.exposed.v1.core.SortOrder +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.dao.id.EntityID +import org.jetbrains.exposed.v1.core.dao.id.IntIdTable +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.inSubQuery +import org.jetbrains.exposed.v1.core.max +import org.jetbrains.exposed.v1.dao.IntEntity +import org.jetbrains.exposed.v1.dao.IntEntityClass +import org.jetbrains.exposed.v1.javatime.timestamp +import org.jetbrains.exposed.v1.jdbc.select +import java.sql.Timestamp +import java.time.Instant +import java.util.Date +import java.util.function.Consumer + +object PunishmentTable : IntIdTable("Punishment", "PunishmentId") { + val userId = reference("UserId", SteamwarUserTable) + val punisher = reference("Punisher", SteamwarUserTable) + val type = enumerationByName("Type", 32, Punishment.PunishmentType::class) + val startTime = timestamp("StartTime") + val endTime = timestamp("EndTime") + val perma = bool("Perma") + val reason = text("Reason") +} + +class Punishment(id: EntityID) : IntEntity(id) { + companion object : IntEntityClass(PunishmentTable) { + @JvmField + val PERMA_TIME: Timestamp = Timestamp.from(Instant.ofEpochSecond(946674800)) + + @JvmStatic + fun getPunsihmentOfPlayer(user: Int, type: PunishmentType) = useDb { + find { (PunishmentTable.userId eq user) and (PunishmentTable.type eq type) }.orderBy(PunishmentTable.id to SortOrder.DESC).firstOrNull() + } + + @JvmStatic + fun getPunishmentsOfPlayer(user: Int) = useDb { + find { + PunishmentTable.id inSubQuery PunishmentTable.select(PunishmentTable.id.max()) + .where { PunishmentTable.userId eq user }.groupBy( + PunishmentTable.type + ) + }.associateBy { it.type }.toMutableMap() + } + + @JvmStatic + fun getAllPunishmentsOfPlayer(user: Int) = useDb { + find { PunishmentTable.userId eq user }.orderBy(PunishmentTable.id to SortOrder.DESC).toList() + } + + @JvmStatic + fun isPunished(user: SteamwarUser, type: PunishmentType, callback: Consumer): Boolean = useDb { + val punishment = getPunsihmentOfPlayer(user.id.value, type) ?: return@useDb false + + if (punishment.isCurrent()) { + callback.accept(punishment) + return@useDb true + } + + return@useDb false + } + + @JvmStatic + fun createPunishment( + user: Int, + executor: Int, + type: PunishmentType, + reason: String, + endTime: Timestamp, + perma: Boolean + ) = useDb { + new { + this.userId = user + this.punisher = executor + this.type = type + this.startTime = Timestamp.from(Instant.now()) + this.endTime = endTime + this.perma = perma + this.reason = reason + } + } + } + + var userId by PunishmentTable.userId.transform({ EntityID(it, SteamwarUserTable) }, { it.value }) + private set + var punisher by PunishmentTable.punisher.transform({ EntityID(it, SteamwarUserTable) }, { it.value }) + private set + var type by PunishmentTable.type + private set + var startTime by PunishmentTable.startTime.transform({ it.toInstant() }, { Timestamp.from(it) }) + private set + var endTime by PunishmentTable.endTime.transform({ it.toInstant() }, { Timestamp.from(it) }) + private set + var perma by PunishmentTable.perma + private set + var reason by PunishmentTable.reason + private set + + fun isPerma() = perma + + fun isCurrent() = perma || endTime.after(Date()) + + enum class PunishmentType( + val needsAdmin: Boolean, + val teamMessage: String?, + val playerMessagePerma: String?, + val playerMessageUntil: String?, + val usageNotPunished: String?, + val unpunishmentMessage: String?, + val multi: Boolean = false + ) { + Ban(false, "BAN_TEAM", "BAN_PERMA", "BAN_UNTIL", "UNBAN_ERROR", "UNBAN"), + Mute(false, "MUTE_TEAM", "MUTE_PERMA", "MUTE_UNTIL", "UNMUTE_ERROR", "UNMUTE"), + NoSchemReceiving( + true, + "NOSCHEMRECEIVING_TEAM", + "NOSCHEMRECEIVING_PERMA", + "NOSCHEMRECEIVING_UNTIL", + "UNNOSCHEMRECEIVING_ERROR", + "UNNOSCHEMRECEIVING" + ), + NoSchemSharing( + true, + "NOSCHEMSHARING_TEAM", + "NOSCHEMSHARING_PERMA", + "NOSCHEMSHARING_UNTIL", + "UNNOSCHEMSHARING_ERROR", + "UNNOSCHEMSHARING" + ), + NoSchemSubmitting( + false, + "NOSCHEMSUBMITTING_TEAM", + "NOSCHEMSUBMITTING_PERMA", + "NOSCHEMSUBMITTING_UNTIL", + "UNNOSCHEMSUBMITTING_ERROR", + "UNNOSCHEMSUBMITTING" + ), + NoDevServer( + true, + "NODEVSERVER_TEAM", + "NODEVSERVER_PERMA", + "NODEVSERVER_UNTIL", + "UNNODEVSERVER_ERROR", + "UNNODEVSERVER" + ), + NoFightServer( + true, + "NOFIGHTSERVER_TEAM", + "NOFIGHTSERVER_PERMA", + "NOFIGHTSERVER_UNTIL", + "UNNOFIGHTSERVER_ERROR", + "UNNOFIGHTSERVER" + ), + NoTeamServer( + true, + "NOTEAMSERVER_TEAM", + "NOTEAMSERVER_PERMA", + "NOTEAMSERVER_UNTIL", + "UNNOTEAMSERVER_ERROR", + "UNNOTEAMSERVER" + ), + Note(false, "NOTE_TEAM", null, null, null, null, true); + + fun isNeedsAdmin() = needsAdmin + fun isMulti() = multi + } +} \ No newline at end of file diff --git a/CommonCore/SQL/src/de/steamwar/sql/SteamwarUser.kt b/CommonCore/SQL/src/de/steamwar/sql/SteamwarUser.kt index 3ea8aa6e..a4dc42ba 100644 --- a/CommonCore/SQL/src/de/steamwar/sql/SteamwarUser.kt +++ b/CommonCore/SQL/src/de/steamwar/sql/SteamwarUser.kt @@ -208,7 +208,7 @@ class SteamwarUser(id: EntityID): IntEntity(id) { fun getPunishment(punishment: Punishment.PunishmentType) = punishments[punishment] fun isPunished(punishment: Punishment.PunishmentType) = getPunishment(punishment) ?.let { - if (!it.isCurrent) { + if (!it.isCurrent()) { if (punishment == Punishment.PunishmentType.Ban) { BannedUserIPs.unbanIPs(id.value) }