diff --git a/dotman-plugin/src/main/java/net/minevn/dotman/commands/AdminCmd.kt b/dotman-plugin/src/main/java/net/minevn/dotman/commands/AdminCmd.kt index e05096a..34c1227 100644 --- a/dotman-plugin/src/main/java/net/minevn/dotman/commands/AdminCmd.kt +++ b/dotman-plugin/src/main/java/net/minevn/dotman/commands/AdminCmd.kt @@ -22,6 +22,15 @@ import kotlin.math.ceil class AdminCmd { companion object { + /** + * Builds and registers the root "dotman" admin command and its subcommands. + * + * Registers the following subcommands: reload, thongbao, chuyenkhoan (bank location), + * lichsu/history (transaction history), napthucong/manual (manual top-up), + * tracuugd/magiaodich (transaction lookup), and cleardata (clear milestone data). + * Also sets a default action that sends a short header and the subcommand usage to the sender, + * then registers the command with the DotMan plugin instance. + */ fun init() = command { addSubCommand(reload(), "reload") addSubCommand(thongbao(), "thongbao") @@ -293,6 +302,13 @@ class AdminCmd { } } + /** + * Builds the "traCuuGiaoDich" admin subcommand for looking up gateway transaction details by ID. + * + * When executed, this command validates a single transaction ID argument, performs the lookup off the main thread, + * and sends each line of the transaction detail to the command sender. If the ID is missing it sends usage help; + * if no details are found it informs the sender that the transaction does not exist or failed. + */ private fun traCuuGiaoDich() = command { val usage = "" description("Tra cứu thông tin qua mã giao dịch trên cổng gạch thẻ") @@ -316,6 +332,17 @@ class AdminCmd { } } + /** + * Register an admin subcommand that deletes a player's top-up/milestone data. + * + * The subcommand expects a single argument: the target player's name. It resolves + * the player's UUID, then deletes all player data entries whose keys match the + * pattern "DONATE_TOTAL_ALL%". Database operations run off the main thread inside + * a transactional block. The command sends success or error messages back to the + * command sender; if the player cannot be resolved the command reports that and + * aborts the deletion. Any exceptions from the transactional operation are + * rethrown after notifying the sender. + */ private fun clearMilestoneData() = command { val usage = "" description("Xoá dữ liệu top nạp thẻ/milestone của người chơi") diff --git a/dotman-plugin/src/main/java/net/minevn/dotman/database/PlayerDataDAO.kt b/dotman-plugin/src/main/java/net/minevn/dotman/database/PlayerDataDAO.kt index 37b2ac0..83bb9c8 100644 --- a/dotman-plugin/src/main/java/net/minevn/dotman/database/PlayerDataDAO.kt +++ b/dotman-plugin/src/main/java/net/minevn/dotman/database/PlayerDataDAO.kt @@ -11,11 +11,49 @@ abstract class PlayerDataDAO : DataAccess() { abstract fun insertDataScript(): String abstract fun getTopScript(): String - abstract fun getDataScript(): String - abstract fun getSumDataScript(): String - abstract fun getAllDataScript(): String - abstract fun deleteDataByKeyLikeScript(): String + /** + * Returns the SQL script used to retrieve a single player data row by UUID and key. + * + * The returned string must be a prepared SQL statement that accepts two parameters in this order: `uuid`, `key`. + */ +abstract fun getDataScript(): String + /** + * Provides the SQL script used by getSumData to retrieve the summed value for a given key. + * + * The returned SQL must be a prepared-statement string that accepts a single parameter (the key) + * and returns at least one numeric column named "value". getSumData binds the key to the statement + * and reads the first row's "value" column (or uses 0 if no rows are returned). + */ +abstract fun getSumDataScript(): String + /** + * Returns the SQL script used by getAllData to fetch all key/value pairs for a player. + * + * The returned SQL must accept a single parameter (player UUID) and produce rows with + * columns named `key` (String) and `value` (Int). The query's result will be mapped into + * a Map where each row's `key` -> `value` pair is preserved. + */ +abstract fun getAllDataScript(): String + /** + * Provides the SQL script used to delete player data rows whose key matches a pattern. + * + * The returned SQL must be a prepared-statement string that accepts two parameters in this order: + * 1. uuid — the player's UUID + * 2. likePattern — the SQL LIKE pattern to match keys (e.g. "prefix%") + * + * @return The SQL delete statement as a String. + */ +abstract fun deleteDataByKeyLikeScript(): String + /** + * Inserts a player data record using the DAO's SQL insert script. + * + * Prepares the statement returned by [insertDataScript], binds the provided + * UUID, key and value, and uses the current system time as the record timestamp. + * + * @param uuid Player identifier as a string (UUID). + * @param key Data key/name to store. + * @param value Integer value to store for the given key. + */ fun insertData(uuid: String, key: String, value: Int) { insertDataScript().statement { setString(1, uuid) @@ -60,6 +98,15 @@ abstract class PlayerDataDAO : DataAccess() { } } + /** + * Retrieves all stored key/value pairs for the given player UUID. + * + * Executes the DAO's `getAllDataScript()` and returns a map from data key to integer value + * for the specified player. If no records are found, an empty map is returned. + * + * @param uuid Player UUID whose data should be fetched. + * @return A Map where keys are data keys (String) and values are their associated Int values. + */ fun getAllData(uuid: String) = run { getAllDataScript().statement { setString(1, uuid) @@ -70,6 +117,16 @@ abstract class PlayerDataDAO : DataAccess() { } } + /** + * Deletes player data rows whose keys match the provided SQL LIKE pattern and returns how many rows were removed. + * + * Uses the SQL statement provided by [deleteDataByKeyLikeScript()] and binds `uuid` and `likePattern` as the first + * and second parameters respectively. + * + * @param uuid Player UUID whose data rows should be targeted. + * @param likePattern SQL `LIKE` pattern to match keys (e.g. `"score_%"`). Must be a valid pattern for the underlying database. + * @return The number of rows affected (deleted). + */ fun deleteDataByKeyLike(uuid: String, likePattern: String): Int { return deleteDataByKeyLikeScript().statement { setString(1, uuid) diff --git a/dotman-plugin/src/main/java/net/minevn/dotman/database/h2/PlayerDataDAOImpl.kt b/dotman-plugin/src/main/java/net/minevn/dotman/database/h2/PlayerDataDAOImpl.kt index b2d9d60..469b93f 100644 --- a/dotman-plugin/src/main/java/net/minevn/dotman/database/h2/PlayerDataDAOImpl.kt +++ b/dotman-plugin/src/main/java/net/minevn/dotman/database/h2/PlayerDataDAOImpl.kt @@ -42,12 +42,27 @@ class PlayerDataDAOImpl : PlayerDataDAO() { WHERE "key" = ?; """.trimIndent() + /** + * Returns an H2 SQL query that selects all data keys and their values for a single player. + * + * The returned query expects one bind parameter: the player's UUID (for the WHERE "uuid" = ? clause). + * + * @return SQL string that selects "key" and "value" from "dotman_player_data" filtered by UUID. + */ override fun getAllDataScript() = """ SELECT "key", "value" FROM "dotman_player_data" WHERE "uuid" = ?; """.trimIndent() + /** + * Returns an SQL script that deletes player data rows matching a UUID and a key pattern. + * + * The returned statement uses two placeholders: the first for the player's UUID, the second for a `LIKE` pattern + * to match the `"key"` column (e.g. `'score_%'`). + * + * @return The SQL DELETE statement as a String. + */ override fun deleteDataByKeyLikeScript() = """ DELETE FROM "dotman_player_data" WHERE "uuid" = ? AND "key" LIKE ?; diff --git a/dotman-plugin/src/main/java/net/minevn/dotman/database/mysql/PlayerDataDAOImpl.kt b/dotman-plugin/src/main/java/net/minevn/dotman/database/mysql/PlayerDataDAOImpl.kt index 92a0478..15d3236 100644 --- a/dotman-plugin/src/main/java/net/minevn/dotman/database/mysql/PlayerDataDAOImpl.kt +++ b/dotman-plugin/src/main/java/net/minevn/dotman/database/mysql/PlayerDataDAOImpl.kt @@ -35,12 +35,25 @@ class PlayerDataDAOImpl : PlayerDataDAO() { WHERE `key` = ?; """.trimIndent() + /** + * Returns an SQL script that selects all key/value pairs for a specific player UUID. + * + * @return A prepared-statement SQL string: selects `key` and `value` from `dotman_player_data` where `uuid` = ?. + */ override fun getAllDataScript() = """ SELECT `key`, `value` FROM `dotman_player_data` WHERE `uuid` = ?; """.trimIndent() + /** + * Returns a prepared DELETE SQL script that removes rows from `dotman_player_data`. + * + * The script deletes entries for a specific `uuid` where the `key` matches a SQL pattern + * (uses `LIKE`). It uses prepared-statement placeholders in this order: `uuid`, `keyPattern`. + * + * @return A SQL string with `?` placeholders for `uuid` and the `key` pattern. + */ override fun deleteDataByKeyLikeScript() = """ DELETE FROM `dotman_player_data` WHERE `uuid` = ? AND `key` LIKE ?;