diff --git a/backend/src/main/java/com/alttd/altitudeweb/AltitudeWebApplication.java b/backend/src/main/java/com/alttd/altitudeweb/AltitudeWebApplication.java index 7684e7b..3a839ce 100644 --- a/backend/src/main/java/com/alttd/altitudeweb/AltitudeWebApplication.java +++ b/backend/src/main/java/com/alttd/altitudeweb/AltitudeWebApplication.java @@ -1,5 +1,8 @@ package com.alttd.altitudeweb; +import com.alttd.altitudeweb.setup.Connection; +import com.alttd.altitudeweb.setup.InitializeLiteBans; +import com.alttd.altitudeweb.setup.InitializeWebDb; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -8,6 +11,7 @@ public class AltitudeWebApplication { public static void main(String[] args) { SpringApplication.run(AltitudeWebApplication.class, args); + Connection.initDatabases(); } } diff --git a/backend/src/main/java/com/alttd/altitudeweb/controllers/history/HistoryApiController.java b/backend/src/main/java/com/alttd/altitudeweb/controllers/history/HistoryApiController.java index 5c0dfc6..c4849c1 100644 --- a/backend/src/main/java/com/alttd/altitudeweb/controllers/history/HistoryApiController.java +++ b/backend/src/main/java/com/alttd/altitudeweb/controllers/history/HistoryApiController.java @@ -1,7 +1,7 @@ package com.alttd.altitudeweb.controllers.history; import com.alttd.altitudeweb.api.HistoryApi; -import com.alttd.altitudeweb.database.Connection; +import com.alttd.altitudeweb.setup.Connection; import com.alttd.altitudeweb.database.Databases; import com.alttd.altitudeweb.database.litebans.*; import com.alttd.altitudeweb.model.PunishmentHistoryDto; @@ -19,71 +19,52 @@ import java.util.concurrent.CompletableFuture; public class HistoryApiController implements HistoryApi { @Override - public ResponseEntity getHistoryForUsers(String userType, String type, String user) throws Exception { - UserType userTypeEnum = UserType.getUserType(userType); - HistoryType historyTypeEnum = HistoryType.getHistoryType(type); - PunishmentHistoryDto punishmentHistory = new PunishmentHistoryDto(); - CompletableFuture> historyRecords = new CompletableFuture<>(); - Connection.getConnection(Databases.LITE_BANS, configuration -> configuration.addMapper(NameHistoryMapper.class)) - .thenApply(connection -> { - connection.runQuery(sqlSession -> { - log.debug("Loading user names for type {}", type); - List temp = sqlSession.getMapper(NameHistoryMapper.class) - .getRecent(historyTypeEnum, userTypeEnum, user); - historyRecords.complete(temp); - }); - return connection; - }); - historyRecords.join().forEach(historyRecord -> { - PunishmentHistoryInnerDto innerDto = new PunishmentHistoryInnerDto() - .uuid(historyRecord.getUuid()) - .username(historyRecord.getPunishedName()) - .reason(historyRecord.getReason()) - .punishmentUserUuid(historyRecord.getBannedByUuid()) - .punishmentUser(historyRecord.getBannedByName()) - .removedBy(historyRecord.getRemovedByName()) - .punishmentTime(historyRecord.getTime()) - .expiryTime(historyRecord.getUntil()) - .removedReason(historyRecord.getRemovedByReason()) - .type(historyRecord.getType()); - punishmentHistory.add(innerDto); - }); - - return ResponseEntity.ok().body(punishmentHistory); + public ResponseEntity getHistoryForAll(String userType, String type, Integer page) { + return getHistoryForUsers(userType, type, "", page); } @Override - public ResponseEntity getHistoryForUuid(String userType, String type, String uuid) throws Exception { + public ResponseEntity getHistoryForUsers(String userType, String type, String user, Integer page) { UserType userTypeEnum = UserType.getUserType(userType); HistoryType historyTypeEnum = HistoryType.getHistoryType(type); PunishmentHistoryDto punishmentHistory = new PunishmentHistoryDto(); CompletableFuture> historyRecords = new CompletableFuture<>(); - Connection.getConnection(Databases.LITE_BANS, configuration -> configuration.addMapper(UUIDHistoryMapper.class)) - .thenApply(connection -> { - connection.runQuery(sqlSession -> { - log.debug("Loading user names for type {}", type); - List temp = sqlSession.getMapper(UUIDHistoryMapper.class) - .getRecent(historyTypeEnum, userTypeEnum, UUID.fromString(uuid)); - historyRecords.complete(temp); - }); - return connection; - }); - historyRecords.join().forEach(historyRecord -> { - PunishmentHistoryInnerDto innerDto = new PunishmentHistoryInnerDto() - .uuid(historyRecord.getUuid()) - .username(historyRecord.getPunishedName()) - .reason(historyRecord.getReason()) - .punishmentUserUuid(historyRecord.getBannedByUuid()) - .punishmentUser(historyRecord.getBannedByName()) - .removedBy(historyRecord.getRemovedByName()) - .punishmentTime(historyRecord.getTime()) - .expiryTime(historyRecord.getUntil()) - .removedReason(historyRecord.getRemovedByReason()) - .type(historyRecord.getType()); - punishmentHistory.add(innerDto); - }); - return ResponseEntity.ok().body(punishmentHistory); + Connection.getConnection(Databases.LITE_BANS) + .runQuery(sqlSession -> { + log.debug("Loading history through name for type {}", type); + try { + List temp = sqlSession.getMapper(NameHistoryMapper.class) + .getRecent(historyTypeEnum, userTypeEnum, user, page); + historyRecords.complete(temp); + } catch (Exception e) { + log.error("Failed to load history through name for type {}", type, e); + historyRecords.completeExceptionally(e); + } + }); + return mapPunishmentHistory(punishmentHistory, historyRecords); + } + + @Override + public ResponseEntity getHistoryForUuid(String userType, String type, String uuid, Integer page) { + UserType userTypeEnum = UserType.getUserType(userType); + HistoryType historyTypeEnum = HistoryType.getHistoryType(type); + PunishmentHistoryDto punishmentHistory = new PunishmentHistoryDto(); + CompletableFuture> historyRecords = new CompletableFuture<>(); + + Connection.getConnection(Databases.LITE_BANS) + .runQuery(sqlSession -> { + log.debug("Loading history through uuid for type {}", type); + try { + List temp = sqlSession.getMapper(UUIDHistoryMapper.class) + .getRecent(historyTypeEnum, userTypeEnum, UUID.fromString(uuid), page); + historyRecords.complete(temp); + } catch (Exception e) { + log.error("Failed to load history through uuid for type {}", type, e); + historyRecords.completeExceptionally(e); + } + }); + return mapPunishmentHistory(punishmentHistory, historyRecords); } @Override @@ -91,16 +72,37 @@ public class HistoryApiController implements HistoryApi { UserType userTypeEnum = UserType.getUserType(userType); HistoryType historyTypeEnum = HistoryType.getHistoryType(type); CompletableFuture> playerGroupFuture = new CompletableFuture<>(); - Connection.getConnection(Databases.LITE_BANS, configuration -> configuration.addMapper(RecentNamesMapper.class)) - .thenApply(connection -> { - connection.runQuery(sqlSession -> { - log.debug("Loading user names for type {}", type); + + Connection.getConnection(Databases.LITE_BANS) + .runQuery(sqlSession -> { + log.debug("Loading user names for type {}", type); + try { List temp = sqlSession.getMapper(RecentNamesMapper.class) .getRecent(historyTypeEnum, userTypeEnum); playerGroupFuture.complete(temp); - }); - return connection; + } catch (Exception e) { + log.error("Failed to load user names for type {}", type, e); + playerGroupFuture.completeExceptionally(e); + } }); return ResponseEntity.ok().body(playerGroupFuture.join()); } + + private ResponseEntity mapPunishmentHistory(PunishmentHistoryDto punishmentHistory, CompletableFuture> historyRecords) { + historyRecords.join().forEach(historyRecord -> { + PunishmentHistoryInnerDto innerDto = new PunishmentHistoryInnerDto() + .uuid(historyRecord.getUuid()) + .username(historyRecord.getPunishedName()) + .reason(historyRecord.getReason()) + .punishmentUserUuid(historyRecord.getBannedByUuid()) + .punishmentUser(historyRecord.getBannedByName()) + .removedBy(historyRecord.getRemovedByName()) + .punishmentTime(historyRecord.getTime()) + .expiryTime(historyRecord.getUntil()) + .removedReason(historyRecord.getRemovedByReason()) + .type(historyRecord.getType()); + punishmentHistory.add(innerDto); + }); + return ResponseEntity.ok().body(punishmentHistory); + } } diff --git a/backend/src/main/java/com/alttd/altitudeweb/controllers/team/TeamApiController.java b/backend/src/main/java/com/alttd/altitudeweb/controllers/team/TeamApiController.java index 43cf166..e29d669 100644 --- a/backend/src/main/java/com/alttd/altitudeweb/controllers/team/TeamApiController.java +++ b/backend/src/main/java/com/alttd/altitudeweb/controllers/team/TeamApiController.java @@ -1,7 +1,7 @@ package com.alttd.altitudeweb.controllers.team; import com.alttd.altitudeweb.api.TeamApi; -import com.alttd.altitudeweb.database.Connection; +import com.alttd.altitudeweb.setup.Connection; import com.alttd.altitudeweb.database.Databases; import com.alttd.altitudeweb.database.luckperms.Player; import com.alttd.altitudeweb.database.luckperms.TeamMemberMapper; @@ -22,14 +22,16 @@ public class TeamApiController implements TeamApi { public ResponseEntity getTeamMembers(String group) { TeamMembersDto teamMemberDtos = new TeamMembersDto(); CompletableFuture> playerGroupFuture = new CompletableFuture<>(); - Connection.getConnection(Databases.LUCK_PERMS, configuration -> configuration.addMapper(TeamMemberMapper.class)) - .thenApply(connection -> { - connection.runQuery(sqlSession -> { - log.debug("Loading team members for group {}", group); + Connection.getConnection(Databases.LUCK_PERMS) + .runQuery(sqlSession -> { + log.debug("Loading team members for group {}", group); + try { List players = sqlSession.getMapper(TeamMemberMapper.class).getTeamMembers("group." + group); playerGroupFuture.complete(players); - }); - return connection; + } catch (Exception e) { + log.error("Failed to load team members for group {}", group, e); + playerGroupFuture.completeExceptionally(e); + } }); List join = playerGroupFuture.join(); join.forEach(player -> teamMemberDtos.add(new PlayerDto(player.username(), player.uuid().toString()))); diff --git a/database/src/main/java/com/alttd/altitudeweb/Main.java b/database/src/main/java/com/alttd/altitudeweb/Main.java index cf6f067..6873669 100644 --- a/database/src/main/java/com/alttd/altitudeweb/Main.java +++ b/database/src/main/java/com/alttd/altitudeweb/Main.java @@ -2,5 +2,6 @@ package com.alttd.altitudeweb; public class Main { public static void main(String[] args) { + } } diff --git a/database/src/main/java/com/alttd/altitudeweb/database/litebans/NameHistoryMapper.java b/database/src/main/java/com/alttd/altitudeweb/database/litebans/NameHistoryMapper.java index f65826c..b3d70db 100644 --- a/database/src/main/java/com/alttd/altitudeweb/database/litebans/NameHistoryMapper.java +++ b/database/src/main/java/com/alttd/altitudeweb/database/litebans/NameHistoryMapper.java @@ -5,10 +5,64 @@ import org.apache.ibatis.annotations.Result; import org.apache.ibatis.annotations.Results; import org.apache.ibatis.annotations.Select; -import java.util.ArrayList; import java.util.List; public interface NameHistoryMapper { + + int PAGE_SIZE = 100; + + /** + * Retrieves a list of all types of recent punishment history records filtered based on the given parameters sorted + * in descending time order. This result does NOT contain kicks history + * + * @param partialName a partial or complete name of the user to filter the records, case-insensitive + * @param nameColumn the column name in the database indicating the name to use for filtering + * @param limit the maximum number of records to fetch + * @param offset the starting offset position of the result set + * + * @return a list of {@link HistoryRecord} objects that match the specified filters, ordered by time in descending + * order + */ + @Results({ + @Result(property = "uuid", column = "uuid"), + @Result(property = "punishedName", column = "punished_name"), + @Result(property = "reason", column = "reason"), + @Result(property = "bannedByUuid", column = "banned_by_uuid"), + @Result(property = "bannedByName", column = "banned_by_name"), + @Result(property = "removedByName", column = "removed_by_name"), + @Result(property = "time", column = "time"), + @Result(property = "until", column = "until"), + @Result(property = "removedByReason", column = "removed_by_reason"), + @Result(property = "type", column = "type") + }) + @Select(""" + SELECT all_punishments.uuid, user_lookup.name AS punished_name, reason, banned_by_uuid, banned_by_name, + removed_by_name, time, until, removed_by_reason, type + FROM all_punishments + INNER JOIN user_lookup + ON user_lookup.uuid = all_punishments.uuid + WHERE all_punishments.${name_column} LIKE #{partialName} + ORDER BY time DESC + LIMIT #{limit} OFFSET #{offset} + """) + List getRecentAllHistory(@Param("partialName") String partialName, + @Param("name_column") String nameColumn, + @Param("limit") int limit, + @Param("offset") int offset); + + /** + * Retrieves a list of a specific type of recent punishment history records filtered based on the provided + * parameters. The records are sorted in descending order by time and limited to a specified range. + * + * @param tableName the name of the database table to query the history records from + * @param partialName a partial or complete name of the user to filter the records, case-insensitive + * @param nameColumn the column name in the database indicating the name to use for filtering + * @param limit the maximum number of records to fetch + * @param offset the starting offset position of the result set + * + * @return a list of {@link HistoryRecord} objects that match the specified filters, sorted by time in descending + * order + */ @Results({ @Result(property = "uuid", column = "uuid"), @Result(property = "punishedName", column = "punished_name"), @@ -21,69 +75,67 @@ public interface NameHistoryMapper { @Result(property = "removedByReason", column = "removed_by_reason") }) @Select(""" - SELECT punishment.uuid, user_table.name AS punished_name, reason, banned_by_uuid, banned_by_name, + SELECT punishment.uuid, user_lookup.name AS punished_name, reason, banned_by_uuid, banned_by_name, removed_by_name, time, until, removed_by_reason FROM ${tableName} AS punishment - INNER JOIN ( - SELECT history_1.uuid, history_1.name - FROM litebans.litebans_history history_1 - INNER JOIN ( - SELECT uuid, MAX(id) as max_id - FROM litebans.litebans_history - GROUP BY uuid - ) history_2 ON history_1.uuid = history_2.uuid AND history_1.id = history_2.max_id - ) AS user_table ON punishment.uuid = user_table.uuid - WHERE LOWER(punishment.${name_column}) LIKE #{partialName} + INNER JOIN user_lookup ON user_lookup.uuid = punishment.uuid + WHERE punishment.${name_column} LIKE #{partialName} + LIMIT #{limit} OFFSET #{offset} """) - List getRecentHistory(@Param("tableName") String tableName, @Param("partialName") String partialName, - @Param("name_column") String nameColumn); + List getRecentHistory(@Param("tableName") String tableName, + @Param("partialName") String partialName, + @Param("name_column") String nameColumn, + @Param("limit") int limit, + @Param("offset") int offset); - default List getRecent(HistoryType historyType, UserType userType, String partialName) { + default List getRecent(HistoryType historyType, UserType userType, String partialName, + int page) { return switch (historyType) { - case ALL -> getRecentAll(userType, partialName); - case BANS -> getRecentBans(userType, partialName); - case MUTES -> getRecentMutes(userType, partialName); - case KICKS -> getRecentKicks(userType, partialName); - case WARNS -> getRecentWarns(userType, partialName); + case ALL -> getRecentAll(userType, partialName, page); + case BANS -> getRecentBans(userType, partialName, page); + case MUTES -> getRecentMutes(userType, partialName, page); + case KICKS -> getRecentKicks(userType, partialName, page); + case WARNS -> getRecentWarns(userType, partialName, page); }; } - private List getRecent(String tableName, UserType userType, String partialName) { - switch (userType) { - case PLAYER -> { - return getRecentHistory(tableName, partialName.toLowerCase() + "%", "name"); - } - case STAFF -> { - return getRecentHistory(tableName, partialName.toLowerCase() + "%", "banned_by_name"); - } - default -> throw new IllegalArgumentException("Invalid user type"); - } + private List getRecent(String tableName, UserType userType, String partialName, + int page) { + int offset = page * PAGE_SIZE; + int limit = PAGE_SIZE; + return switch (userType) { + case PLAYER -> getRecentHistory(tableName, partialName.toLowerCase() + "%", "name", + limit, offset); + case STAFF -> getRecentHistory(tableName, partialName.toLowerCase() + "%", "banned_by_name", + limit, offset); + }; } - private List getRecentBans(UserType userType, String partialName) { - return addType(getRecent("litebans_bans", userType, partialName), "ban"); + private List getRecentAll(UserType userType, String partialName, int page) { + int offset = page * PAGE_SIZE; + int limit = PAGE_SIZE; + return switch (userType) { + case PLAYER -> getRecentAllHistory(partialName.toLowerCase() + "%", "name", + limit, offset); + case STAFF -> getRecentAllHistory(partialName.toLowerCase() + "%", "banned_by_name", + limit, offset); + }; } - private List getRecentKicks(UserType userType, String partialName) { - return addType(getRecent("litebans_kicks", userType, partialName), "kick"); + private List getRecentBans(UserType userType, String partialName, int page) { + return addType(getRecent("litebans_bans", userType, partialName, page), "ban"); } - private List getRecentMutes(UserType userType, String partialName) { - return addType(getRecent("litebans_mutes", userType, partialName), "mute"); + private List getRecentKicks(UserType userType, String partialName, int page) { + return addType(getRecent("litebans_kicks", userType, partialName, page), "kick"); } - private List getRecentWarns(UserType userType, String partialName) { - return addType(getRecent("litebans_warnings", userType, partialName), "warn"); + private List getRecentMutes(UserType userType, String partialName, int page) { + return addType(getRecent("litebans_mutes", userType, partialName, page), "mute"); } - private List getRecentAll(UserType userType, String partialName) { - List all = new ArrayList<>(); - all.addAll(getRecentBans(userType, partialName)); - // Removed recent kicks as we do not show those -// all.addAll(getRecentKicks(userType, partialName)); - all.addAll(getRecentMutes(userType, partialName)); - all.addAll(getRecentWarns(userType, partialName)); - return all; + private List getRecentWarns(UserType userType, String partialName, int page) { + return addType(getRecent("litebans_warnings", userType, partialName, page), "warn"); } private List addType(List historyRecords, String type) { diff --git a/database/src/main/java/com/alttd/altitudeweb/database/litebans/RecentNamesMapper.java b/database/src/main/java/com/alttd/altitudeweb/database/litebans/RecentNamesMapper.java index 4085c1f..a50ddd3 100644 --- a/database/src/main/java/com/alttd/altitudeweb/database/litebans/RecentNamesMapper.java +++ b/database/src/main/java/com/alttd/altitudeweb/database/litebans/RecentNamesMapper.java @@ -8,18 +8,12 @@ import java.util.List; public interface RecentNamesMapper { @Select(""" - SELECT DISTINCT user_table.name AS punished_name + SELECT DISTINCT user_lookup.name AS punished_name FROM ${tableName} AS punishment - INNER JOIN ( - SELECT history_1.uuid, history_1.name - FROM litebans.litebans_history history_1 - INNER JOIN ( - SELECT uuid, MAX(id) as max_id - FROM litebans.litebans_history - GROUP BY uuid - ) history_2 ON history_1.uuid = history_2.uuid AND history_1.id = history_2.max_id - ) AS user_table ON punishment.${uuid_column} = user_table.uuid + INNER JOIN user_lookup + ON user_lookup.uuid = punishment.${uuid_column} WHERE punishment.time > UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 1 YEAR)) * 1000 + ORDER BY user_lookup.name """) List getRecentHistory(@Param("tableName") String tableName, @Param("uuid_column") String uuidColumn); diff --git a/database/src/main/java/com/alttd/altitudeweb/database/litebans/UUIDHistoryMapper.java b/database/src/main/java/com/alttd/altitudeweb/database/litebans/UUIDHistoryMapper.java index d48f0d5..81e77dc 100644 --- a/database/src/main/java/com/alttd/altitudeweb/database/litebans/UUIDHistoryMapper.java +++ b/database/src/main/java/com/alttd/altitudeweb/database/litebans/UUIDHistoryMapper.java @@ -6,11 +6,39 @@ import org.apache.ibatis.annotations.Result; import org.apache.ibatis.annotations.Results; import org.apache.ibatis.annotations.Select; -import java.util.ArrayList; import java.util.List; import java.util.UUID; public interface UUIDHistoryMapper { + + int PAGE_SIZE = 100; + + @Results({ + @Result(property = "uuid", column = "uuid", javaType = UUID.class, typeHandler = UUIDTypeHandler.class), + @Result(property = "punishedName", column = "punished_name"), + @Result(property = "reason", column = "reason"), + @Result(property = "bannedByUuid", column = "banned_by_uuid", javaType = UUID.class, typeHandler = UUIDTypeHandler.class), + @Result(property = "bannedByName", column = "banned_by_name"), + @Result(property = "removedByName", column = "removed_by_name"), + @Result(property = "time", column = "time"), + @Result(property = "until", column = "until"), + @Result(property = "removedByReason", column = "removed_by_reason"), + @Result(property = "type", column = "type") + }) + @Select(""" + SELECT all_punishments.uuid, user_lookup.name AS punished_name, reason, banned_by_uuid, banned_by_name, + removed_by_name, time, until, removed_by_reason, type + FROM all_punishments + INNER JOIN user_lookup + ON user_lookup.uuid = all_punishments.uuid + WHERE all_punishments.${uuid_column} = #{uuid} + LIMIT #{limit} OFFSET #{offset} + """) + List getRecentAllHistory(@Param("uuid") String uuid, + @Param("uuid_column") String uuidColumn, + @Param("limit") int limit, + @Param("offset") int offset); + @Results({ @Result(property = "uuid", column = "uuid", javaType = UUID.class, typeHandler = UUIDTypeHandler.class), @Result(property = "punishedName", column = "punished_name"), @@ -23,69 +51,63 @@ public interface UUIDHistoryMapper { @Result(property = "removedByReason", column = "removed_by_reason") }) @Select(""" - SELECT punishment.uuid, user_table.name AS punished_name, reason, banned_by_uuid, banned_by_name, + SELECT punishment.uuid, user_lookup.name AS punished_name, reason, banned_by_uuid, banned_by_name, removed_by_name, time, until, removed_by_reason FROM ${tableName} AS punishment - INNER JOIN ( - SELECT history_1.uuid, history_1.name - FROM litebans.litebans_history history_1 - INNER JOIN ( - SELECT uuid, MAX(id) as max_id - FROM litebans.litebans_history - GROUP BY uuid - ) history_2 ON history_1.uuid = history_2.uuid AND history_1.id = history_2.max_id - ) AS user_table ON punishment.uuid = user_table.uuid - WHERE punishment.uuid = #{uuid} + INNER JOIN user_lookup ON user_lookup.uuid = punishment.uuid + WHERE punishment.${uuid_column} = #{uuid} + LIMIT #{limit} OFFSET #{offset} """) - List getRecentHistory(@Param("tableName") String tableName, @Param("uuid") String uuid, - @Param("uuid_column") String uuidColumn); + List getRecentHistory(@Param("tableName") String tableName, + @Param("uuid") String uuid, + @Param("uuid_column") String uuidColumn, + @Param("limit") int limit, + @Param("offset") int offset); - default List getRecent(HistoryType historyType, UserType userType, UUID uuid) { + default List getRecent(HistoryType historyType, UserType userType, UUID uuid, int page) { return switch (historyType) { - case ALL -> getRecentAll(userType, uuid); - case BANS -> getRecentBans(userType, uuid); - case MUTES -> getRecentMutes(userType, uuid); - case KICKS -> getRecentKicks(userType, uuid); - case WARNS -> getRecentKicks(userType, uuid); + case ALL -> getRecentAll(userType, uuid, page); + case BANS -> getRecentBans(userType, uuid, page); + case MUTES -> getRecentMutes(userType, uuid, page); + case KICKS -> getRecentKicks(userType, uuid, page); + case WARNS -> getRecentWarns(userType, uuid, page); }; } - private List getRecent(String tableName, UserType userType, UUID uuid) { - switch (userType) { - case PLAYER -> { - return getRecentHistory(tableName, uuid.toString(), "uuid"); - } - case STAFF -> { - return getRecentHistory(tableName, uuid.toString(), "banned_by_uuid"); - } - default -> throw new IllegalArgumentException("Invalid user type"); - } + private List getRecent(String tableName, UserType userType, UUID uuid, int page) { + int offset = page * PAGE_SIZE; + int limit = PAGE_SIZE; + return switch (userType) { + case PLAYER -> getRecentHistory(tableName, uuid.toString(), "uuid", limit, offset); + case STAFF -> getRecentHistory(tableName, uuid.toString(), "banned_by_uuid", limit, offset); + }; } - private List getRecentBans(UserType userType, UUID uuid) { - return addType(getRecent("litebans_bans", userType, uuid), "ban"); + private List getRecentAll(UserType userType, UUID uuid, int page) { + int offset = page * PAGE_SIZE; + int limit = PAGE_SIZE; + return switch (userType) { + case PLAYER -> getRecentAllHistory(uuid.toString(), "name", + limit, offset); + case STAFF -> getRecentAllHistory(uuid.toString(), "banned_by_name", + limit, offset); + }; } - private List getRecentKicks(UserType userType, UUID uuid) { - return addType(getRecent("litebans_kicks", userType, uuid), "kick"); + private List getRecentBans(UserType userType, UUID uuid, int page) { + return addType(getRecent("litebans_bans", userType, uuid, page), "ban"); } - private List getRecentMutes(UserType userType, UUID uuid) { - return addType(getRecent("litebans_mutes", userType, uuid), "mute"); + private List getRecentKicks(UserType userType, UUID uuid, int page) { + return addType(getRecent("litebans_kicks", userType, uuid, page), "kick"); } - private List getRecentWarns(UserType userType, UUID uuid) { - return addType(getRecent("litebans_warnings", userType, uuid), "warn"); + private List getRecentMutes(UserType userType, UUID uuid, int page) { + return addType(getRecent("litebans_mutes", userType, uuid, page), "mute"); } - private List getRecentAll(UserType userType, UUID uuid) { - List all = new ArrayList<>(); - all.addAll(getRecentBans(userType, uuid)); - // Removed recent kicks as we do not show those -// all.addAll(getRecentKicks(userType, uuid)); - all.addAll(getRecentMutes(userType, uuid)); - all.addAll(getRecentWarns(userType, uuid)); - return all; + private List getRecentWarns(UserType userType, UUID uuid, int page) { + return addType(getRecent("litebans_warnings", userType, uuid, page), "warn"); } private List addType(List historyRecords, String type) { diff --git a/database/src/main/java/com/alttd/altitudeweb/database/Connection.java b/database/src/main/java/com/alttd/altitudeweb/setup/Connection.java similarity index 88% rename from database/src/main/java/com/alttd/altitudeweb/database/Connection.java rename to database/src/main/java/com/alttd/altitudeweb/setup/Connection.java index 4f2b012..6ee74b3 100644 --- a/database/src/main/java/com/alttd/altitudeweb/database/Connection.java +++ b/database/src/main/java/com/alttd/altitudeweb/setup/Connection.java @@ -1,5 +1,6 @@ -package com.alttd.altitudeweb.database; +package com.alttd.altitudeweb.setup; +import com.alttd.altitudeweb.database.Databases; import com.alttd.altitudeweb.database.web_db.DatabaseSettings; import com.alttd.altitudeweb.database.web_db.SettingsMapper; import lombok.extern.slf4j.Slf4j; @@ -28,12 +29,25 @@ public class Connection { this.addMappers = addMappers; } + public static void initDatabases() { + InitializeWebDb.init(); + InitializeLiteBans.init(); + InitializeLuckPerms.init(); + } + @FunctionalInterface public interface AddMappers { void apply(Configuration configuration); } - public static CompletableFuture getConnection(Databases database, AddMappers addMappers) { + public static Connection getConnection(Databases database) { + if (connections.containsKey(database)) { + return connections.get(database); + } + throw new RuntimeException("Database " + database + " has not been initialized"); + } + + protected static CompletableFuture getConnection(Databases database, AddMappers addMappers) { if (connections.containsKey(database)) { return CompletableFuture.completedFuture(connections.get(database)); } diff --git a/database/src/main/java/com/alttd/altitudeweb/setup/InitializeLiteBans.java b/database/src/main/java/com/alttd/altitudeweb/setup/InitializeLiteBans.java new file mode 100644 index 0000000..8b3d47b --- /dev/null +++ b/database/src/main/java/com/alttd/altitudeweb/setup/InitializeLiteBans.java @@ -0,0 +1,71 @@ +package com.alttd.altitudeweb.setup; + +import com.alttd.altitudeweb.database.Databases; +import com.alttd.altitudeweb.database.litebans.NameHistoryMapper; +import com.alttd.altitudeweb.database.litebans.RecentNamesMapper; +import com.alttd.altitudeweb.database.litebans.UUIDHistoryMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.session.SqlSession; + +import java.sql.SQLException; +import java.sql.Statement; + +@Slf4j +public class InitializeLiteBans { + + protected static void init() { + log.info("Initializing LiteBans"); + Connection.getConnection(Databases.LITE_BANS, (configuration) -> { + configuration.addMapper(RecentNamesMapper.class); + configuration.addMapper(NameHistoryMapper.class); + configuration.addMapper(UUIDHistoryMapper.class); + }).join() + .runQuery(sqlSession -> { + createAllPunishmentsView(sqlSession); + createUserLookupView(sqlSession); + }); + log.debug("Initialized LiteBans"); + } + + private static void createAllPunishmentsView(SqlSession sqlSession) { + String query = """ + CREATE VIEW IF NOT EXISTS all_punishments AS + SELECT uuid, reason, banned_by_uuid, banned_by_name, removed_by_name, time, until, removed_by_reason, + 'ban' as type + FROM litebans_bans + UNION ALL + SELECT uuid, reason, banned_by_uuid, banned_by_name, removed_by_name, time, until, removed_by_reason, + 'mute' as type + FROM litebans_mutes + UNION ALL + SELECT uuid, reason, banned_by_uuid, banned_by_name, removed_by_name, time, until, removed_by_reason, + 'warn' as type + FROM litebans_warnings + ORDER BY time DESC; + """; + try (Statement statement = sqlSession.getConnection().createStatement()) { + statement.execute(query); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + private static void createUserLookupView(SqlSession sqlSession) { + String query = """ + CREATE VIEW IF NOT EXISTS user_lookup AS + SELECT history_1.uuid, history_1.name + FROM litebans.litebans_history history_1 + INNER JOIN ( + SELECT uuid, MAX(id) as max_id + FROM litebans.litebans_history + GROUP BY uuid + ) history_2 ON history_1.uuid = history_2.uuid AND history_1.id = history_2.max_id + """; + try (Statement statement = sqlSession.getConnection().createStatement()) { + statement.execute(query); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/database/src/main/java/com/alttd/altitudeweb/setup/InitializeLuckPerms.java b/database/src/main/java/com/alttd/altitudeweb/setup/InitializeLuckPerms.java new file mode 100644 index 0000000..3bdc1fd --- /dev/null +++ b/database/src/main/java/com/alttd/altitudeweb/setup/InitializeLuckPerms.java @@ -0,0 +1,18 @@ +package com.alttd.altitudeweb.setup; + +import com.alttd.altitudeweb.database.Databases; +import com.alttd.altitudeweb.database.luckperms.TeamMemberMapper; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class InitializeLuckPerms { + + protected static void init() { + log.info("Initializing LuckPerms"); + Connection.getConnection(Databases.LUCK_PERMS, (configuration) -> { + configuration.addMapper(TeamMemberMapper.class); + }).join(); + log.debug("Initialized LuckPerms"); + } + +} diff --git a/database/src/main/java/com/alttd/altitudeweb/setup/InitializeWebDb.java b/database/src/main/java/com/alttd/altitudeweb/setup/InitializeWebDb.java new file mode 100644 index 0000000..5eefb0b --- /dev/null +++ b/database/src/main/java/com/alttd/altitudeweb/setup/InitializeWebDb.java @@ -0,0 +1,43 @@ +package com.alttd.altitudeweb.setup; + +import com.alttd.altitudeweb.database.Databases; +import com.alttd.altitudeweb.database.web_db.SettingsMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.session.SqlSession; + +import java.sql.SQLException; +import java.sql.Statement; + +@Slf4j +public class InitializeWebDb { + + protected static void init() { + log.info("Initializing LiteBans"); + Connection.getConnection(Databases.DEFAULT, (configuration) -> { + configuration.addMapper(SettingsMapper.class); + }).join() + .runQuery(InitializeWebDb::createSettingsTable); + log.debug("Initialized LuckPerms"); + } + + private static void createSettingsTable(SqlSession sqlSession) { + String query = """ + CREATE TABLE IF NOT EXISTS db_connection_settings + ( + internal_name VARCHAR(255) NOT NULL, + name VARCHAR(255) NOT NULL, + username VARCHAR(255) NOT NULL, + password VARCHAR(255) NOT NULL, + host VARCHAR(255) NOT NULL, + port INT NOT NULL, + CONSTRAINT pk_internal_name PRIMARY KEY (internal_name) + ); + """; + try (Statement statement = sqlSession.getConnection().createStatement()) { + statement.execute(query); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/open_api/src/main/resources/api.yml b/open_api/src/main/resources/api.yml index a6726e1..7d49844 100644 --- a/open_api/src/main/resources/api.yml +++ b/open_api/src/main/resources/api.yml @@ -16,7 +16,9 @@ paths: $ref: './schemas/team/team.yml#/getTeam' /history/{userType}/search/{type}: $ref: './schemas/bans/bans.yml#/getUserNames' - /history/{userType}/name/{type}/{user}: + /history/{userType}/name/{type}/{user}/{page}: $ref: './schemas/bans/bans.yml#/getHistoryForUsers' - /history/{userType}/uuid/{type}/{uuid}: + /history/{userType}/name/{type}/{page}: + $ref: './schemas/bans/bans.yml#/getHistoryForAll' + /history/{userType}/uuid/{type}/{uuid}/{page}: $ref: './schemas/bans/bans.yml#/getHistoryForUuid' diff --git a/open_api/src/main/resources/schemas/bans/bans.yml b/open_api/src/main/resources/schemas/bans/bans.yml index 5bbda03..8f73c70 100644 --- a/open_api/src/main/resources/schemas/bans/bans.yml +++ b/open_api/src/main/resources/schemas/bans/bans.yml @@ -29,14 +29,41 @@ getHistoryForUsers: tags: - history summary: Get history for users - description: > + description: > Get all users with punishment history of the specified type, - where the user name starts with the search query + where the user name starts with the search query, 100 records at a time operationId: getHistoryForUsers parameters: - $ref: '#/components/parameters/UserType' - $ref: '#/components/parameters/HistoryType' - $ref: '#/components/parameters/User' + - $ref: '#/components/parameters/Page' + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/PunishmentHistory' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: "../generic/errors.yml#/components/schemas/ApiError" +getHistoryForAll: + get: + tags: + - history + summary: Get history for users + description: > + Get all users with punishment history of the specified type, + where the user name starts with the search query, 100 records at a time + operationId: getHistoryForAll + parameters: + - $ref: '#/components/parameters/UserType' + - $ref: '#/components/parameters/HistoryType' + - $ref: '#/components/parameters/Page' responses: '200': description: Successful operation @@ -55,14 +82,15 @@ getHistoryForUuid: tags: - history summary: Get user - description: > + description: > Get all users with punishment history of the specified type, - where the user uuid matches + where the user uuid matches, 100 records at a time operationId: getHistoryForUuid parameters: - $ref: '#/components/parameters/UserType' - $ref: '#/components/parameters/HistoryType' - $ref: '#/components/parameters/Uuid' + - $ref: '#/components/parameters/Page' responses: '200': description: Successful operation @@ -108,11 +136,25 @@ components: type: string enum: [ player, staff ] description: Indicates if this is a staff history or a player history look up + Page: + name: page + in: path + required: true + schema: + type: integer + description: The page that should be retrieved schemas: PunishmentHistory: type: array items: type: object + required: + - username + - uuid + - reason + - type + - punishmentTime + - punishmentUserUuid properties: username: type: string