Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions dotman-plugin/src/main/java/net/minevn/dotman/commands/AdminCmd.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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 = "<mã giao dịch>"
description("Tra cứu thông tin qua mã giao dịch trên cổng gạch thẻ")
Expand All @@ -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 = "<tên người chơi>"
description("Xoá dữ liệu top nạp thẻ/milestone của người chơi")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 ?;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 ?;
Expand Down
Loading