diff --git a/src/de/steamwar/sql/BannedUserIPs.java b/src/de/steamwar/sql/BannedUserIPs.java index f765b76..9a31099 100644 --- a/src/de/steamwar/sql/BannedUserIPs.java +++ b/src/de/steamwar/sql/BannedUserIPs.java @@ -37,6 +37,7 @@ public class BannedUserIPs { private static final SelectStatement getByID = table.selectFields("UserID"); private static final SelectStatement getByIP = new SelectStatement<>(table, "SELECT * FROM BannedUserIPs WHERE IP = ? ORDER BY Timestamp DESC"); private static final Statement banIP = table.insert(Table.PRIMARY); + private static final Statement unbanIPs = table.deleteFields("UserID"); @Getter @Field(keys = {Table.PRIMARY}) @@ -58,4 +59,8 @@ public class BannedUserIPs { public static void banIP(int userID, String ip){ banIP.update(userID, ip); } + + public static void unbanIPs(int userID) { + unbanIPs.update(userID); + } } diff --git a/src/de/steamwar/sql/EventFight.java b/src/de/steamwar/sql/EventFight.java index 60e4831..eed7f51 100644 --- a/src/de/steamwar/sql/EventFight.java +++ b/src/de/steamwar/sql/EventFight.java @@ -26,18 +26,41 @@ import de.steamwar.sql.internal.Table; import lombok.AllArgsConstructor; import lombok.Getter; +import java.sql.Timestamp; +import java.util.*; + +import static java.time.temporal.ChronoUnit.SECONDS; + @AllArgsConstructor -public class EventFight { +public class EventFight implements Comparable { private static final Table table = new Table<>(EventFight.class); private static final SelectStatement byId = table.select(Table.PRIMARY); + private static final SelectStatement allComing = new SelectStatement<>(table, "SELECT * FROM EventFight WHERE StartTime > now() ORDER BY StartTime ASC"); + private static final SelectStatement event = new SelectStatement<>(table, "SELECT * FROM EventFight WHERE EventID = ? ORDER BY StartTime ASC"); + private static final Statement reschedule = table.update(Table.PRIMARY, "StartTime"); private static final Statement setResult = table.update(Table.PRIMARY, "Ergebnis"); private static final Statement setFight = table.update(Table.PRIMARY, "Fight"); + private static final Queue fights = new PriorityQueue<>(); + public static EventFight get(int fightID) { return byId.select(fightID); } + public static void loadAllComingFights() { + fights.clear(); + fights.addAll(allComing.listSelect()); + } + + public static List getEvent(int eventID) { + return event.listSelect(eventID); + } + + public static Queue getFights() { + return fights; + } + @Getter @Field private final int eventID; @@ -46,6 +69,15 @@ public class EventFight { private final int fightID; @Getter @Field + private Timestamp startTime; + @Getter + @Field + private final String spielmodus; + @Getter + @Field + private final String map; + @Getter + @Field private final int teamBlue; @Getter @Field @@ -69,4 +101,32 @@ public class EventFight { this.fight = fight; setFight.update(fight, fightID); } + + public boolean hasFinished() { + return fight != 0; + } + + public void reschedule() { + startTime = Timestamp.from(new Date().toInstant().plus(30, SECONDS)); + reschedule.update(startTime, fightID); + } + + @Override + public int hashCode(){ + return fightID; + } + + @Override + public boolean equals(Object o){ + if(o == null) + return false; + if(!(o instanceof EventFight)) + return false; + return fightID == ((EventFight) o).fightID; + } + + @Override + public int compareTo(EventFight o) { + return startTime.compareTo(o.startTime); + } } diff --git a/src/de/steamwar/sql/Fight.java b/src/de/steamwar/sql/Fight.java index 0a26a88..8576184 100644 --- a/src/de/steamwar/sql/Fight.java +++ b/src/de/steamwar/sql/Fight.java @@ -20,26 +20,49 @@ 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 java.sql.Timestamp; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; @AllArgsConstructor public class Fight { private static final Table table = new Table<>(Fight.class); + private static final SelectStatement getPage = new SelectStatement<>(table, "SELECT f.*, (b.NodeId IS NULL OR b.AllowReplay) AND (r.NodeId IS NULL OR r.AllowReplay) AS ReplayAllowed, (SELECT COUNT(1) FROM Replay WHERE Replay.FightID = f.FightID) as ReplayAvailable FROM Fight f LEFT OUTER JOIN SchematicNode b ON f.BlueSchem = b.NodeId LEFT OUTER JOIN SchematicNode r ON f.RedSchem = r.NodeId ORDER BY FightID DESC LIMIT ?, ?"); private static final Statement insert = table.insertFields(true, "GameMode", "Server", "StartTime", "Duration", "BlueLeader", "RedLeader", "BlueSchem", "RedSchem", "Win", "WinCondition"); + public static List getPage(int page, int elementsPerPage) { + List fights = getPage.listSelect(page * elementsPerPage, elementsPerPage); + + List fightPlayers = FightPlayer.batchGet(fights.stream().map(f -> f.fightID).toArray(Integer[]::new)); + for(Fight fight : fights) { + fight.initPlayers(fightPlayers); + } + + SteamwarUser.batchCache(fightPlayers.stream().map(FightPlayer::getUserID).collect(Collectors.toSet())); + return fights; + } + + public static int create(String gamemode, String server, Timestamp starttime, int duration, int blueleader, int redleader, Integer blueschem, Integer redschem, int win, String wincondition){ + return insert.insertGetKey(gamemode, server, starttime, duration, blueleader, redleader, blueschem, redschem, win, wincondition); + } + + @Getter @Field(keys = {Table.PRIMARY}, autoincrement = true) private final int fightID; @Field private final String gameMode; + @Getter @Field private final String server; + @Getter @Field private final Timestamp startTime; @Field @@ -52,15 +75,50 @@ public class Fight { private final Integer blueSchem; @Field(nullable = true) private final Integer redSchem; + @Getter @Field private final int win; @Field private final String wincondition; + @Field // Virtual field for easy select + private final boolean replayAllowed; + @Field // Virtual field for easy select + private final boolean replayAvailable; + @Getter private final List bluePlayers = new ArrayList<>(); + @Getter private final List redPlayers = new ArrayList<>(); - public static int create(String gamemode, String server, Timestamp starttime, int duration, int blueleader, int redleader, Integer blueschem, Integer redschem, int win, String wincondition){ - return insert.insertGetKey(gamemode, server, starttime, duration, blueleader, redleader, blueschem, redschem, win, wincondition); + public SchematicType getSchemType() { + return SchematicType.fromDB(gameMode); + } + + public SteamwarUser getBlueLeader() { + return SteamwarUser.get(blueLeader); + } + + public SteamwarUser getRedLeader() { + return SteamwarUser.get(redLeader); + } + + public boolean replayAllowed() { + return replayExists() && replayAllowed; + } + + public boolean replayExists() { + return getSchemType() != null && replayAvailable; + } + + private void initPlayers(List fightPlayers) { + for(FightPlayer fp : fightPlayers) { + if(fp.getFightID() != fightID) + continue; + + if(fp.getTeam() == 1) + bluePlayers.add(fp); + else + redPlayers.add(fp); + } } } diff --git a/src/de/steamwar/sql/Mod.java b/src/de/steamwar/sql/Mod.java new file mode 100644 index 0000000..2a4e698 --- /dev/null +++ b/src/de/steamwar/sql/Mod.java @@ -0,0 +1,101 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2023 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 java.util.List; + +@AllArgsConstructor +public class Mod { + + static { + SqlTypeMapper.ordinalEnumMapper(Platform.class); + SqlTypeMapper.ordinalEnumMapper(ModType.class); + } + + private static final Table table = new Table<>(Mod.class, "Mods"); + private static final SelectStatement get = table.select(Table.PRIMARY); + private static final SelectStatement findFirst = new SelectStatement<>(table, "SELECT * FROM Mods WHERE ModType = 0 LIMIT 1"); + private static final SelectStatement getPageOfType = new SelectStatement<>(table, "SELECT * FROM Mods WHERE ModType = ? ORDER BY ModName DESC LIMIT ?, ?"); + private static final Statement insert = table.insert(Table.PRIMARY); + private static final Statement set = table.update(Table.PRIMARY, "ModType"); + + public static Mod get(String name, Platform platform) { + return get.select(platform, name); + } + + public static Mod getOrCreate(String name, Platform platform) { + Mod mod = get(name, platform); + if(mod != null) + return mod; + + insert.update(platform, name); + return new Mod(platform, name, ModType.UNKLASSIFIED); + } + + public static List getAllModsFiltered(int page, int elementsPerPage, Mod.ModType filter) { + return Mod.getPageOfType.listSelect(filter, page * elementsPerPage, elementsPerPage); + } + + public static Mod findFirstMod() { + return findFirst.select(); + } + + @Getter + @Field(keys = {Table.PRIMARY}) + private final Platform platform; + @Getter + @Field(keys = {Table.PRIMARY}) + private final String modName; + @Getter + @Field(def = "0") + private ModType modType; + + public void setModType(Mod.ModType modType) { + set.update(modType, platform, modName); + this.modType = modType; + } + + public enum Platform { + FORGE, + LABYMOD, + FABRIC + } + + public enum ModType { + UNKLASSIFIED("7"), + GREEN("a"), + YELLOW("e"), + RED("c"), + YOUTUBER_ONLY("6"); + + ModType(String colorcode) { + this.colorcode = colorcode; + } + private final String colorcode; + + public String getColorCode() { + return colorcode; + } + } +} diff --git a/src/de/steamwar/sql/Punishment.java b/src/de/steamwar/sql/Punishment.java index 086f445..5960dce 100644 --- a/src/de/steamwar/sql/Punishment.java +++ b/src/de/steamwar/sql/Punishment.java @@ -19,16 +19,16 @@ package de.steamwar.sql; -import de.steamwar.sql.internal.Field; -import de.steamwar.sql.internal.SelectStatement; -import de.steamwar.sql.internal.SqlTypeMapper; -import de.steamwar.sql.internal.Table; +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; @@ -40,13 +40,48 @@ public class Punishment { 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, Punishment.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 @@ -67,24 +102,6 @@ public class Punishment { @Getter private final String 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 boolean isPunished(SteamwarUser user, Punishment.PunishmentType type, Consumer callback) { - Punishment punishment = Punishment.getPunishmentOfPlayer(user.getId(), type); - if(punishment == null || !punishment.isCurrent()) { - return false; - } else { - callback.accept(punishment); - return true; - } - } - @Deprecated // Not multiling, misleading title public String getBantime(Timestamp endTime, boolean perma) { if (perma) { @@ -94,15 +111,12 @@ public class Punishment { } } - public int getUserId() { - return userId; - } - 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"), @@ -110,7 +124,10 @@ public class Punishment { NoSchemReceiving(false, "NOSCHEMRECEIVING_TEAM", "NOSCHEMRECEIVING_PERMA", "NOSCHEMRECEIVING_UNTIL", "UNNOSCHEMRECEIVING_ERROR", "UNNOSCHEMRECEIVING"), NoSchemSharing(false, "NOSCHEMSHARING_TEAM", "NOSCHEMSHARING_PERMA", "NOSCHEMSHARING_UNTIL", "UNNOSCHEMSHARING_ERROR", "UNNOSCHEMSHARING"), NoSchemSubmitting(true, "NOSCHEMSUBMITTING_TEAM", "NOSCHEMSUBMITTING_PERMA", "NOSCHEMSUBMITTING_UNTIL", "UNNOSCHEMSUBMITTING_ERROR", "UNNOSCHEMSUBMITTING"), - NoDevServer(true, "NODEVSERVER_TEAM", "NODEVSERVER_PERMA", "NODEVSERVER_UNTIL", "UNNODEVSERVER_ERROR", "UNNODEVSERVER"); + NoDevServer(true, "NODEVSERVER_TEAM", "NODEVSERVER_PERMA", "NODEVSERVER_UNTIL", "UNNODEVSERVER_ERROR", "UNNODEVSERVER"), + NoFightServer(false, "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; @@ -118,5 +135,6 @@ public class Punishment { private final String playerMessageUntil; private final String usageNotPunished; private final String unpunishmentMessage; + private boolean multi = false; } } diff --git a/src/de/steamwar/sql/SchemElo.java b/src/de/steamwar/sql/SchemElo.java index 64090ce..1f795d6 100644 --- a/src/de/steamwar/sql/SchemElo.java +++ b/src/de/steamwar/sql/SchemElo.java @@ -21,14 +21,32 @@ 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; @AllArgsConstructor public class SchemElo { + public static final int ELO_DEFAULT = 1000; + private static final Table table = new Table<>(SchemElo.class); private static final SelectStatement select = table.select(Table.PRIMARY); + private static final Statement setElo = table.insertAll(); + + public static int getElo(SchematicNode node, int season) { + SchemElo elo = select.select(node, season); + return elo != null ? elo.elo : 0; + } + + public static int getCurrentElo(int schemID) { + SchemElo elo = select.select(schemID, Season.getSeason()); + return elo != null ? elo.elo : ELO_DEFAULT; + } + + public static void setElo(int schemID, int elo) { + setElo.update(schemID, elo, Season.getSeason()); + } @Field(keys = {Table.PRIMARY}) private final int schemId; @@ -36,9 +54,4 @@ public class SchemElo { private final int elo; @Field(keys = {Table.PRIMARY}) private final int season; - - public static int getElo(SchematicNode node, int season) { - SchemElo elo = select.select(node, season); - return elo != null ? elo.elo : 0; - } } diff --git a/src/de/steamwar/sql/SteamwarUser.java b/src/de/steamwar/sql/SteamwarUser.java index 874643f..dfbbcd0 100644 --- a/src/de/steamwar/sql/SteamwarUser.java +++ b/src/de/steamwar/sql/SteamwarUser.java @@ -22,7 +22,10 @@ package de.steamwar.sql; import de.steamwar.sql.internal.*; import lombok.Getter; +import java.sql.Timestamp; import java.util.*; +import java.util.function.BiConsumer; +import java.util.function.Consumer; public class SteamwarUser { @@ -44,12 +47,17 @@ public class SteamwarUser { private static final SelectStatement byDiscord = table.selectFields("DiscordId"); private static final SelectStatement byTeam = table.selectFields("Team"); private static final SelectStatement getServerTeam = new SelectStatement<>(table, "SELECT * FROM UserData WHERE UserGroup != 'Member' AND UserGroup != 'YouTuber'"); + private static final SelectStatement batchGet = new SelectStatement<>(table, "SELECT * FROM UserData WHERE id IN ?"); + private static final Statement updateName = table.update(Table.PRIMARY, "UserName"); private static final Statement updateLocale = table.update(Table.PRIMARY, "Locale", "ManualLocale"); private static final Statement updateTeam = table.update(Table.PRIMARY, "Team"); private static final Statement updateLeader = table.update(Table.PRIMARY, "Leader"); private static final Statement updateDiscord = table.update(Table.PRIMARY, "DiscordId"); + private static final Statement getPlaytime = new Statement("SELECT SUM(UNIX_TIMESTAMP(EndTime) - UNIX_TIMESTAMP(StartTime)) as Playtime FROM Session WHERE UserID = ?"); + private static final Statement getFirstjoin = new Statement("SELECT MIN(StartTime) AS FirstJoin FROM Session WHERE UserID = ?"); + private static final Map usersById = new HashMap<>(); private static final Map usersByUUID = new HashMap<>(); private static final Map usersByName = new HashMap<>(); @@ -69,67 +77,6 @@ public class SteamwarUser { usersByUUID.remove(user.getUUID()); } - @Getter - @Field(keys = {Table.PRIMARY}, autoincrement = true) - private final int id; - @Field(keys = {"uuid"}) - private final UUID uuid; - @Getter - @Field - private String userName; - @Getter - @Field(def = "'Member'") - private final UserGroup userGroup; - @Getter - @Field(def = "0") - private int team; - @Field(def = "0") - private boolean leader; - @Field(nullable = true) - private Locale locale; - @Field(def = "0") - private boolean manualLocale; - @Field(keys = {"discordId"}, nullable = true) - private Long discordId; - - public SteamwarUser(int id, UUID uuid, String userName, UserGroup userGroup, int team, boolean leader, Locale locale, boolean manualLocale, Long discordId) { - this.id = id; - this.uuid = uuid; - this.userName = userName; - this.userGroup = userGroup; - this.team = team; - this.leader = leader; - this.locale = locale; - this.manualLocale = manualLocale; - this.discordId = discordId != null && discordId != 0 ? discordId : null; - - usersById.put(id, this); - usersByName.put(userName.toLowerCase(), this); - usersByUUID.put(uuid, this); - if (this.discordId != null) { - usersByDiscord.put(discordId, this); - } - } - - public UUID getUUID() { - return uuid; - } - - public Locale getLocale() { - if(locale != null) - return locale; - return Locale.getDefault(); - } - - public void setLocale(Locale locale, boolean manualLocale) { - if (locale == null || (this.manualLocale && !manualLocale)) - return; - - this.locale = locale; - this.manualLocale = manualLocale; - updateLocale.update(locale.toLanguageTag(), manualLocale, id); - } - public static SteamwarUser get(String userName){ SteamwarUser user = usersByName.get(userName.toLowerCase()); if(user != null) @@ -157,8 +104,22 @@ public class SteamwarUser { return byDiscord.select(discordId); } - public static void createOrUpdateUsername(UUID uuid, String userName) { - insert.update(uuid, userName); + public static SteamwarUser getOrCreate(UUID uuid, String name, Consumer newPlayer, BiConsumer nameUpdate) { + SteamwarUser user = SteamwarUser.get(uuid); + + if (user != null) { + if (!user.userName.equals(name)) { + updateName.update(name, user.id); + nameUpdate.accept(user.userName, name); + user.userName = name; + } + } else { + insert.update(uuid, name); + newPlayer.accept(uuid); + return get(uuid); + } + + return user; } public static List getServerTeam() { @@ -168,4 +129,137 @@ public class SteamwarUser { public static List getTeam(int teamId) { return byTeam.listSelect(teamId); } + + public static void batchCache(Set ids) { + ids.removeIf(usersById::containsKey); + if(ids.isEmpty()) + return; + + batchGet.listSelect((Object) ids.toArray()); + } + + @Getter + @Field(keys = {Table.PRIMARY}, autoincrement = true) + private final int id; + @Field(keys = {"uuid"}) + private final UUID uuid; + @Getter + @Field + private String userName; + @Getter + @Field(def = "'Member'") + private final UserGroup userGroup; + @Getter + @Field(def = "0") + private int team; + @Getter + @Field(def = "0") + private boolean leader; + @Field(nullable = true) + private Locale locale; + @Field(def = "0") + private boolean manualLocale; + @Getter + @Field(keys = {"discordId"}, nullable = true) + private Long discordId; + + private final Map punishments; + + public SteamwarUser(int id, UUID uuid, String userName, UserGroup userGroup, int team, boolean leader, Locale locale, boolean manualLocale, Long discordId) { + this.id = id; + this.uuid = uuid; + this.userName = userName; + this.userGroup = userGroup; + this.team = team; + this.leader = leader; + this.locale = locale; + this.manualLocale = manualLocale; + this.discordId = discordId != null && discordId != 0 ? discordId : null; + + usersById.put(id, this); + usersByName.put(userName.toLowerCase(), this); + usersByUUID.put(uuid, this); + if (this.discordId != null) { + usersByDiscord.put(discordId, this); + } + punishments = Punishment.getPunishmentsOfPlayer(id); //TODO load always on Subservers? + } + + public UUID getUUID() { + return uuid; + } + + public Locale getLocale() { + if(locale != null) + return locale; + return Locale.getDefault(); + } + + public Punishment getPunishment(Punishment.PunishmentType type) { + return punishments.getOrDefault(type, null); + } + + public boolean isPunished(Punishment.PunishmentType punishment) { + if (!punishments.containsKey(punishment)) { + return false; + } + if (!punishments.get(punishment).isCurrent()) { + if (punishment == Punishment.PunishmentType.Ban) { + BannedUserIPs.unbanIPs(id); + } + punishments.remove(punishment); + return false; + } + return true; + } + + public double getOnlinetime() { + return getPlaytime.select(rs -> { + if (rs.next() && rs.getBigDecimal("Playtime") != null) + return rs.getBigDecimal("Playtime").doubleValue(); + return 0.0; + }, id); + } + + public Timestamp getFirstjoin() { + return getFirstjoin.select(rs -> { + if (rs.next()) + return rs.getTimestamp("FirstJoin"); + return null; + }, id); + } + + public void punish(Punishment.PunishmentType punishment, Timestamp time, String banReason, int from, boolean perma) { + punishments.remove(punishment); + punishments.put(punishment, Punishment.createPunishment(id, from, punishment, banReason, time, perma)); + } + + public void setTeam(int team) { + this.team = team; + updateTeam.update(team, id); + setLeader(false); + } + + public void setLeader(boolean leader) { + this.leader = leader; + updateLeader.update(leader, id); + } + + public void setLocale(Locale locale, boolean manualLocale) { + if (locale == null || (this.manualLocale && !manualLocale)) + return; + + this.locale = locale; + this.manualLocale = manualLocale; + updateLocale.update(locale.toLanguageTag(), manualLocale, id); + } + + public void setDiscordId(Long discordId) { + usersByDiscord.remove(this.discordId); + this.discordId = discordId; + updateDiscord.update(discordId, id); + if (discordId != null) { + usersByDiscord.put(discordId, this); + } + } } diff --git a/src/de/steamwar/sql/Tutorial.java b/src/de/steamwar/sql/Tutorial.java new file mode 100644 index 0000000..3249bfe --- /dev/null +++ b/src/de/steamwar/sql/Tutorial.java @@ -0,0 +1,94 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2023 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 java.util.List; +import java.util.stream.Collectors; + +@AllArgsConstructor +public class Tutorial { + + private static final Table table = new Table<>(Tutorial.class); + private static final SelectStatement by_popularity = new SelectStatement<>(table, "SELECT t.*, AVG(r.Stars) AS Stars FROM Tutorial t LEFT OUTER JOIN TutorialRating r ON t.TutorialID = r.TutorialID WHERE t.Released = ? GROUP BY t.TutorialID ORDER BY SUM(r.Stars) DESC LIMIT ?, ?"); + private static final SelectStatement own = new SelectStatement<>(table, "SELECT t.*, AVG(r.Stars) AS Stars FROM Tutorial t LEFT OUTER JOIN TutorialRating r ON t.TutorialID = r.TutorialID WHERE t.Creator = ? GROUP BY t.TutorialID ORDER BY t.TutorialID ASC LIMIT ?, ?"); + private static final SelectStatement by_creator_name = new SelectStatement<>(table, "SELECT t.*, AVG(r.Stars) AS Stars FROM Tutorial t LEFT OUTER JOIN TutorialRating r ON t.TutorialID = r.TutorialID WHERE t.Creator = ? AND t.Name = ? GROUP BY t.TutorialID"); + private static final SelectStatement by_id = new SelectStatement<>(table, "SELECT t.*, AVG(r.Stars) AS Stars FROM Tutorial t LEFT OUTER JOIN TutorialRating r ON t.TutorialID = r.TutorialID WHERE t.TutorialID = ? GROUP BY t.TutorialID"); + private static final Statement rate = new Statement("INSERT INTO TutorialRating (TutorialID, UserID, Stars) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE Stars = VALUES(Stars)"); + private static final Statement create = new Statement("INSERT INTO Tutorial (Creator, Name, Item) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE Item = VALUES(Item), Released = 0"); + private static final Statement release = table.update(Table.PRIMARY, "released"); + private static final Statement delete = table.delete(Table.PRIMARY); + + public static List getPage(int page, int elementsPerPage, boolean released) { + List tutorials = by_popularity.listSelect(released, page * elementsPerPage, elementsPerPage); + SteamwarUser.batchCache(tutorials.stream().map(tutorial -> tutorial.creator).collect(Collectors.toSet())); + return tutorials; + } + + public static List getOwn(int user, int page, int elementsPerPage) { + return own.listSelect(user, page * elementsPerPage, elementsPerPage); + } + + public static Tutorial create(int creator, String name, String item) { + create.update(creator, name, item); + return by_creator_name.select(creator, name); + } + + public static Tutorial get(int id) { + return by_id.select(id); + } + + @Getter + @Field(keys = {Table.PRIMARY}, autoincrement = true) + private final int id; + @Getter + @Field(keys = {"CreatorName"}) + private final int creator; + @Getter + @Field(keys = {"CreatorName"}) + private final String name; + @Getter + @Field(def = "'BOOK'") + private final String item; + @Getter + @Field(def = "0") + private final boolean released; + @Getter + @Field(def = "0") // Not really a field, but necessary for select generation + private final double stars; + + public void release() { + release.update(1, id); + } + + public void delete() { + delete.update(id); + } + + public void rate(int user, int rating) { + rate.update(id, user, rating); + } +}