diff --git a/.gitignore b/.gitignore index fd88ec9..7765637 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ # various other potential build files /build /bin +/classes/ /dist /manifest.mf @@ -28,4 +29,4 @@ *.iml *.ipr *.iws -.idea/ \ No newline at end of file +.idea/ diff --git a/README b/README deleted file mode 100644 index d87998e..0000000 --- a/README +++ /dev/null @@ -1,16 +0,0 @@ -/modreq : Make a request -/check <# | p:#>: Check request queue or a specific request -/tp-id: Teleport to a request -/claim <#>: Claim a request -/unclaim <#>: Remove your claim from a request -/done <#>: Mark a request as completed -/reopen <#>: Reopen a closed request -/elevate <#>: Set flag for admin on a request - -modreq: All permissions -modreq.mod: All permissions -modreq.check: Check lists of request -modreq.claim: Claim a request -modreq.done: Finish a request -modreq.teleport: Teleport to a request -modreq.request: Make a request (defaults to true) diff --git a/README.md b/README.md new file mode 100644 index 0000000..a88a23d --- /dev/null +++ b/README.md @@ -0,0 +1,114 @@ +ModReq +====== +ModReq (**Mod**erator **Req**uest) is a help ticket management system for Minecraft. Players make requests with the `/modreq` command, which saves the coordinates of the requesting player and the request text. Staff can see all requests in a work queue and can select which request to handle next. + +Requests can be in one of three states: + * OPEN - The request has been made but is not yet being handled by staff. + * CLAIMED - A staff member has started work on the request. A request can only be claimed by a single staff member at a time. + * CLOSED - The request was completed (or denied). Players can also close their own requests, even if not a staff member. + +ModReq supports two tiers of staff permissions: Moderator and Admin. Admins are assumed to have some superset of Moderator permissions. By default, new requests are visible to all staff members (Moderators and Admins). However, requests can be marked as requiring an Admin to handle them using the `/elevate` command. Elevated requests are hidden from Moderators unless using extra options to the `/check` command. + + +Commands +-------- +Note: In the discussion that follows, `#` signifies a number. + +Many commands support the use of `-`, instead of a request ID number, to signify the request that was most recently claimed by the staff member. + +`/modreq ` + * Make a request. The coordinates of the player making the request are saved by the command. + +`/check #` + * Retrieve a full description of the request with the specified number. + +`/check -` + * Retrieve a full description of the most recently claimed request. + +`/check [--page # | -p # | p:#] [--admin | -a] [--search term | -s term]` + * List all open requests matching specified criteria. Requests are grouped into pages of (by default) 5 requests and `/check` only shows one page of requests at a time. + * `/check` on its own lists all requests visible to the player. Non-staff players will only see open requests that they have made themselves. Moderators will see requests by other players, but not those that have been elevated. Admins will see all requests. + * `--page`, `-p` or `p:` select a different page to show. Pages are numbered starting at 1. + * `--admin` or `-a` allow Admin requests to be visible to Moderators. Without one of these options, moderators will only see open requests that have not been elevated. + * `--search` or `-s` allow a search term to be specified. Only requests whose text include the term will be listed. + +`/tp-id #` or `/tpid #` + * A staff-only command to teleport to the location of a request. + * `/tp-id -` or `/tpi -` will teleport to the location of the most recently claimed request. + +`/claim #` + * A staff-only command to claim exclusive access to a request. + * The request is moved to the CLAIMED state and associated with a staff member. + +`/unclaim #` + * Remove your claim on a request that you have previously claimed with `/claim`. + * The request is returned to the OPEN state and not associated with any staff member. + * `/unclaim -` will unclaim the most recently claimed request. + +`/done # [message]` + * Mark a request as completed, optionally specifying a message that will be sent to the requesting player. + * The request is moved to the CLOSED state. + * `/done - [message]` closes the most recently claimed request, with an optional close message. + +`/reopen #` + * Reopen a closed request. + * The request changes to the OPEN state. + * `/reopen -` attempts to reopen the most recently claimed request. + +`/elevate #` + * Mark the request as requiring handling by an Admin. + * If the request is currently claimed by the staff member running the command, it is unclaimed. + * `/elevate -` attempts to unclaim and elevate the most recently claimed request. + +`/tpinfo #` or `/tpi #` + * A staff command to teleport to and check the details of a request without claiming it. + * This command is shorthand for `/tp-id #` followed by `/check #`. + * `/tpinfo -` or `/tpi -` will teleport to and check the most recently claimed request. + +`/tpc #` + * A staff command that tries to claim a request and, _only if successful_, teleport to and check the details of the request. + * An error message will be shown if another staff member has already claimed or closed the request. + * If you have already claimed the request, the command acts as `/tpi`. + * The command executes `/claim #`, and if successful `/tpi #`. + +`/mr-note add # text` + * A staff command to add a note to a request designated by its ID number. + * The first note attached to a request is numbered 1. Subsequent notes attached to the same request have progressively higher numbers. + * Notes are only visible to staff. + * `/mr-note add - text` adds a note to the most recently claimed request. + +`/mr-note remove # #` + * A staff command to remove a note from a request; the first number is the request ID and the second number is the note ID, which starts at 1. + * Notes are only visible to staff. + * `/mr-note remove - #` removes a note from the most recently claimed request. + +`/mr-reset` + * A staff command to reset the database. + +`/mr-upgrade` + * A staff command to upgrade the database. + + +Permissions +----------- + * `modreq.request` - Permission to submit a request (defaults to true). + * `modreq.mod` - All Moderator permissions. Certain administrative commands are excluded. + * `modreq.check` - Staff permission to check requests. Note that players lacking this permission can still check the status of requests they made themselves. + * `modreq.claim` - Staff permission to claim a request. + * `modreq.done` - Staff permission to close a request that belongs to another player. Non-staff can always close their own requests, even without this permission. This permission is also required to `/reopen` requests. + * `modreq.teleport` - Staff permission to teleport to the location the request was made. + * `modreq.notice` - Staff permission to receive broadcast messages about requests, e.g. new requests made. + * `modreq.cleardb` - Admin permission to clear the request database. + * `modreq.upgrade` - Admin permission to upgrade the request database from an older schema. + * `modreq` - All permissions, including Moderator and Admin permssions (use with caution). + + +Configuration +------------- + * `messages.general.` - Configurable message text sent to ordinary players. Substitution parameters are enclosed in curly braces. + * `messages.mod.` - Configurable message text sent to staff. Substitution parameters are enclosed in curly braces. + * `colour.online` - Colour of online player names in formatted text. + * `colour.offline` - Colour of offline player names in formatted text. + * `max-requests` - The maximum number of open requests an ordinary player can make. + * `page-size` - The number of requests in one page of `/check` output. + * `date-format` - Format specifier for the date and time of a request in `java.text.SimpleDateFormat` syntax. diff --git a/config.yml b/config.yml index a91bf37..9a0b426 100644 --- a/config.yml +++ b/config.yml @@ -4,7 +4,7 @@ messages: search-error: "&CYou must specify a search term." request-number: "&CYou must provide a number for requests." request-filed: "&ARequest has been filed. Please be patient for a moderator to complete your request." - max-requests: "&CYou already have {max_requests} open requests, please wait for them to be completed." + max-requests: "&CYou already have {max_requests} open requests. Please wait for them to be completed." request-error: "&AEither that request doesn't exist, or you do not have permission to view it." no-requests: "&AYou don't have any outstanding requests." request-taken: "&A{mod} is now handling request {request_id}." @@ -36,9 +36,14 @@ messages: flagged: "&ARequest {request_id} has been flagged for admin." reset: "&ADatabase has been reset." already-closed: "&CRequest already closed." + already-claimed: "&CRequest already claimed." note-added: "&ANote added to request {request_id} successfully." note-removed: "&ANote removed from request {request_id} successfully." + note-number: "&CYou must specify a number for the note, starting at 1." + note-missing: "&CRequest {request_id} has no note numbered {note_id}." colour: online: "&A" offline: "&C" max-requests: 5 +page-size: 5 +date-format: "MMM.d@HH:mm:ss" diff --git a/plugin.yml b/plugin.yml index f28410d..753ae65 100644 --- a/plugin.yml +++ b/plugin.yml @@ -25,6 +25,17 @@ commands: usage: | / [#]: Teleport to a request aliases: [tpid] + tpinfo: + description: Teleport to and check a request + permission: modreq.teleport + usage: | + / [#]: Teleport to and check a request + aliases: [tpi] + tpc: + description: Teleport to and claim a request + permission: modreq.teleport + usage: | + / [#]: Teleport to and claim a request claim: description: Claim a request permission: modreq.claim diff --git a/pom.xml b/pom.xml index a9b1c5c..11d7cd2 100644 --- a/pom.xml +++ b/pom.xml @@ -3,17 +3,37 @@ 4.0.0 nu.nerd ModReq - 1.6 + 1.7 jar ModReq + Moderator Request Sytem + https://github.com/NerdNu/ModReq + + scm:git:https://github.com/NerdNu/ModReq.git + scm:git:https://github.com/NerdNu/ModReq.git + https://github.com/NerdNu/ModReq + UTF-8 + + + + spigot-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + znode-releases + znode-releases + http://repo.zno.de/artifactory/libs-release-local + + + org.bukkit bukkit - 1.7.10-R0.1-SNAPSHOT + 1.8.8-R0.1-SNAPSHOT jar compile @@ -23,44 +43,7 @@ 0.1 - - - repobo-rel - repo.bukkit.org Releases - http://repo.bukkit.org/content/repositories/releases/ - - - repobo-snap - repo.bukkit.org Snapshots - http://repo.bukkit.org/content/repositories/snapshots/ - - - - - - repobo-snap - http://repo.bukkit.org/content/groups/public - - - znode-releases - znode-releases - http://repo.zno.de/artifactory/libs-release-local - - - - - bukkit-plugins - http://repo.bukkit.org/content/groups/public - - - Moderator Request Sytem - https://github.com/NerdNu/ModReq - - scm:git:https://github.com/NerdNu/ModReq.git - scm:git:https://github.com/NerdNu/ModReq.git - https://github.com/NerdNu/ModReq - ${basedir}/src @@ -113,6 +96,7 @@ shade + false false Bundle diff --git a/src/nu/nerd/modreq/Configuration.java b/src/nu/nerd/modreq/Configuration.java index f436a93..4fcca7b 100644 --- a/src/nu/nerd/modreq/Configuration.java +++ b/src/nu/nerd/modreq/Configuration.java @@ -7,7 +7,7 @@ public class Configuration { private ModReq plugin; - + public String GENERAL__PAGE_ERROR; public String GENERAL__SEARCH_ERROR; public String GENERAL__REQUEST_NUMBER; @@ -40,23 +40,28 @@ public class Configuration { public String MOD__FLAGGED; public String MOD__RESET; public String MOD__ALREADY_CLOSED; + public String MOD__ALREADY_CLAIMED; public String MOD__NOTE_ADDED; public String MOD__NOTE_REMOVED; + public String MOD__NOTE_NUMBER; + public String MOD__NOTE_MISSING; public String COLOUR_ONLINE; public String COLOUR_OFFLINE; - public Integer MAX_REQUESTS; - + public int MAX_REQUESTS; + public int PAGE_SIZE; + public String DATE_FORMAT; + public Configuration(ModReq plugin) { this.plugin = plugin; } - + public void save() { plugin.saveConfig(); } - + public void load() { plugin.reloadConfig(); - + GENERAL__REQUEST_NUMBER = plugin.getConfig().getString("messages.general.request-number"); GENERAL__REQUEST_FILED = plugin.getConfig().getString("messages.general.request-filed"); GENERAL__MAX_REQUESTS = plugin.getConfig().getString("messages.general.max-requests"); @@ -89,10 +94,15 @@ public void load() { MOD__UNCLAIM = plugin.getConfig().getString("messages.mod.unclaim"); MOD__REQUEST_TAKEN = plugin.getConfig().getString("messages.mod.request-taken"); MOD__ALREADY_CLOSED = plugin.getConfig().getString("messages.mod.already-closed"); + MOD__ALREADY_CLAIMED = plugin.getConfig().getString("messages.mod.already-claimed"); MOD__NOTE_ADDED = plugin.getConfig().getString("messages.mod.note-added"); MOD__NOTE_REMOVED = plugin.getConfig().getString("messages.mod.note-removed"); + MOD__NOTE_NUMBER = plugin.getConfig().getString("messages.mod.note-number"); + MOD__NOTE_MISSING = plugin.getConfig().getString("messages.mod.note-missing"); COLOUR_OFFLINE = plugin.getConfig().getString("colour.offline"); COLOUR_ONLINE = plugin.getConfig().getString("colour.online"); MAX_REQUESTS = plugin.getConfig().getInt("max-requests", 5); + PAGE_SIZE = plugin.getConfig().getInt("page-size", 5); + DATE_FORMAT = plugin.getConfig().getString("date-format"); } } diff --git a/src/nu/nerd/modreq/ModReq.java b/src/nu/nerd/modreq/ModReq.java index e77f41b..6cf0739 100755 --- a/src/nu/nerd/modreq/ModReq.java +++ b/src/nu/nerd/modreq/ModReq.java @@ -1,7 +1,10 @@ package nu.nerd.modreq; import com.avaje.ebean.SqlRow; + import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; @@ -12,24 +15,27 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.UUID; import java.util.logging.Level; import javax.persistence.PersistenceException; + import nu.nerd.modreq.database.Note; import nu.nerd.modreq.database.NoteTable; - import nu.nerd.modreq.database.Request; import nu.nerd.modreq.database.Request.RequestStatus; import nu.nerd.modreq.database.RequestTable; -import org.bukkit.Bukkit; +import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.ConsoleCommandSender; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; import org.bukkit.permissions.Permissible; import org.bukkit.plugin.java.JavaPlugin; @@ -43,9 +49,21 @@ public class ModReq extends JavaPlugin { Configuration config = new Configuration(this); Map environment = new HashMap(); + /** + * Map from UUID of staff member to integer ID of most recently claimed + * request. + * + * This acts as the default request ID when handling "/check -", "/tp-id -" + * and "/tpinfo -", and synonyms. + * + * This collection is saved in most-recent-claims.yml across restarts. + */ + Map claimedIds = new HashMap(); + File claimsFile; + RequestTable reqTable; NoteTable noteTable; - + @Override public void onEnable() { setupDatabase(); @@ -54,9 +72,12 @@ public void onEnable() { getConfig().options().copyDefaults(true); saveConfig(); } - + config.load(); - + + claimsFile = new File(getDataFolder(), "most-recent-claims.yml"); + loadClaimedIds(); + reqTable = new RequestTable(this); noteTable = new NoteTable(this); getServer().getPluginManager().registerEvents(listener, this); @@ -64,7 +85,7 @@ public void onEnable() { @Override public void onDisable() { - // tear down + saveClaimedIds(); } public boolean setupDatabase() { @@ -76,7 +97,7 @@ public boolean setupDatabase() { installDDL(); return true; } - + return false; } @@ -86,11 +107,11 @@ public void resetDatabase() { getLogger().log(Level.INFO, "Backup up existing data into memory"); List rowRequests = getDatabase().createSqlQuery("SELECT id, player_name, assigned_mod, request, request_time, status, request_location, close_message, close_time, close_seen_by_user, flag_for_admin FROM modreq_requests").findList(); List rowNotes = getDatabase().createSqlQuery("SELECT id, player, request_id, note_body FROM modreq_notes").findList(); - + List reqs = new ArrayList(); List notes = new ArrayList(); Set unknownNames = new HashSet(); - + getLogger().log(Level.INFO, "Executing remove ddl"); removeDDL(); @@ -163,12 +184,12 @@ public void resetDatabase() { connection.setDoOutput(true); JSONObject profile = (JSONObject) jsonParser.parse(new InputStreamReader(connection.getInputStream())); - String nameNew = (String) profile.get("name"); + //String nameNew = (String) profile.get("name"); String uuidStringNoDash = (String) profile.get("id"); String uuidString = uuidStringNoDash.replaceFirst( "(\\p{XDigit}{8})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}+)", "$1-$2-$3-$4-$5" ); UUID uuid = UUID.fromString(uuidString); responses.put(name, uuid); - // getLogger().info("New Name = " + nameNew + " UUID = " + uuid); + //getLogger().info("New Name = " + nameNew + " UUID = " + uuid); } catch (Exception e) { getLogger().log(Level.INFO, "Failed to fetch historical uuid for " + name); @@ -257,7 +278,6 @@ public ArrayList> getDatabaseClasses() { @Override public boolean onCommand(CommandSender sender, Command command, String name, String[] args) { - boolean includeElevated = sender.hasPermission("modreq.cleardb"); String senderName = ChatColor.stripColor(sender.getName()); UUID senderUUID = null; Player player = null; @@ -273,381 +293,61 @@ public boolean onCommand(CommandSender sender, Command command, String name, Str if (args.length == 0) { return false; } - - StringBuilder request = new StringBuilder(args[0]); - for (int i = 1; i < args.length; i++) { - request.append(" ").append(args[i]); - } - - if (sender instanceof Player) { - if (reqTable.getNumRequestFromUser(player.getUniqueId()) < config.MAX_REQUESTS) { - Request req = new Request(); - req.setPlayerUUID(player.getUniqueId()); - req.setPlayerName(senderName); - String r = ChatColor.translateAlternateColorCodes('&', request.toString()); - r = ChatColor.stripColor(r); - req.setRequest(r); - req.setRequestTime(System.currentTimeMillis()); - String location = String.format("%s,%f,%f,%f,%f,%f", player.getWorld().getName(), player.getLocation().getX(), player.getLocation().getY(), player.getLocation().getZ(), player.getLocation().getYaw(), player.getLocation().getPitch()); - req.setRequestLocation(location); - req.setStatus(RequestStatus.OPEN); - - reqTable.save(req); - environment.put("request_id", String.valueOf(req.getId())); - messageMods(config.MOD__NEW_REQUEST); - sendMessage(sender, config.GENERAL__REQUEST_FILED); - } else { - environment.put("max_requests", config.MAX_REQUESTS.toString()); - sendMessage(sender, config.GENERAL__MAX_REQUESTS); - } - } + modreq(sender, senderName, player, args); } else if (command.getName().equalsIgnoreCase("check")) { - // Setting page > 0 triggers a page listing. - int page = 1; - int requestId = 0; - int totalRequests = 0; - String searchTerm = null; - UUID limitUUID = null; - boolean showNotes = true; - - for (int i = 0; i < args.length; i++) { - String arg = args[i]; - if (arg.equalsIgnoreCase("--admin") || arg.equalsIgnoreCase("-a")) { - includeElevated = true; - } - else if (arg.startsWith("p:")) { - page = Integer.parseInt(arg.substring(2)); - } - else if (arg.equalsIgnoreCase("--page") || arg.equalsIgnoreCase("-p")) { - if (i+1 > args.length) { - sendMessage(sender, config.GENERAL__PAGE_ERROR); - return true; - } - else { - try { - page = Integer.parseInt(args[i+1]); - i++; - } - catch (NumberFormatException ex) { - sendMessage(sender, config.GENERAL__PAGE_ERROR); - return true; - } - } - } - else if (arg.equalsIgnoreCase("--search") || arg.equalsIgnoreCase("-s")) { - if (i+1 < args.length) { - searchTerm = args[i+1]; - i++; - } - else { - sendMessage(sender, config.GENERAL__SEARCH_ERROR); - return true; - } - } - else { - try { - requestId = Integer.parseInt(arg); - page = 0; - } - catch (NumberFormatException ex) { - sendMessage(sender, config.GENERAL__REQUEST_NUMBER); - return true; - } - } - } - - if (!sender.hasPermission("modreq.check")) { - if (sender instanceof Player) { - limitUUID = senderUUID; - } - showNotes = false; - } - - List requests = new ArrayList(); - - if (page > 0) { - if (limitUUID != null) { - requests.addAll(reqTable.getUserRequests(limitUUID)); - totalRequests = requests.size(); - } else { - requests.addAll(reqTable.getRequestPage(page - 1, 5, includeElevated, searchTerm, RequestStatus.OPEN, RequestStatus.CLAIMED)); - totalRequests = reqTable.getTotalRequest(includeElevated, searchTerm, RequestStatus.OPEN, RequestStatus.CLAIMED); - } - } else if (requestId > 0) { - Request req = reqTable.getRequest(requestId); - List notes = noteTable.getRequestNotes(req); - - if (req != null) { - totalRequests = 1; - if (limitUUID != null && req.getPlayerUUID().equals(limitUUID)) { - requests.add(req); - } else if (limitUUID == null) { - requests.add(req); - } else { - totalRequests = 0; - } - } else { - totalRequests = 0; - } - } - - if (totalRequests == 0) { - if (limitUUID != null) { - if (requestId > 0) { - sendMessage(sender, config.GENERAL__REQUEST_ERROR); - } - else { - sendMessage(sender, config.GENERAL__NO_REQUESTS); - } - } - else { - sendMessage(sender, config.MOD__NO_REQUESTS); - } - } else if (totalRequests == 1 && requestId > 0) { - messageRequestToPlayer(sender, requests.get(0), showNotes); - } else if (totalRequests > 0) { - if (page > 1 && requests.isEmpty()) { - sendMessage(sender, config.MOD__EMPTY_PAGE); - } else { - boolean showPage = true; - if (limitUUID != null) { - showPage = false; - } - messageRequestListToPlayer(sender, requests, page, totalRequests, showPage); - } - } else { - // there was an error. - } + check(sender, senderUUID, args); } else if (command.getName().equalsIgnoreCase("tp-id")) { if (args.length == 0) { return false; } - int requestId = 0; - try { - requestId = Integer.parseInt(args[0]); - - if (sender instanceof Player) { - Request req = reqTable.getRequest(requestId); - if (req != null) { - environment.put("request_id", String.valueOf(req.getId())); - sendMessage(player, config.MOD__TELEPORT); - Location loc = stringToLocation(req.getRequestLocation()); - player.teleport(loc); - } - else { - sendMessage(sender, config.GENERAL__REQUEST_ERROR); - } - } - } - catch (NumberFormatException ex) { - sendMessage(sender, config.GENERAL__REQUEST_NUMBER); + tpId(sender, senderUUID, player, args); + } + else if (command.getName().equalsIgnoreCase("tpinfo")) { + if (args.length == 0) { + return false; } + tpId(sender, senderUUID, player, args); + check(sender, senderUUID, args); } - else if (command.getName().equalsIgnoreCase("claim")) { + else if (command.getName().equalsIgnoreCase("tpc")) { if (args.length == 0) { return false; } - int requestId = 0; - try { - requestId = Integer.parseInt(args[0]); - - if (sender instanceof Player) { - Request req = reqTable.getRequest(requestId); - - if (req.getStatus() == RequestStatus.OPEN) { - req.setStatus(RequestStatus.CLAIMED); - req.setAssignedModUUID(senderUUID); - req.setAssignedMod(senderName); - reqTable.save(req); - - environment.put("mod", senderName); - environment.put("request_id", String.valueOf(requestId)); - messageMods(config.MOD__REQUEST_TAKEN); - environment.remove("mod"); - environment.remove("request_id"); - } - } + if (claim(sender, senderName, senderUUID, args)) { + tpId(sender, senderUUID, player, args); + check(sender, senderUUID, args); } - catch (NumberFormatException ex) { - sendMessage(sender, config.GENERAL__REQUEST_NUMBER); + } + else if (command.getName().equalsIgnoreCase("claim")) { + if (args.length == 0) { + return false; } + claim(sender, senderName, senderUUID, args); } else if (command.getName().equalsIgnoreCase("unclaim")) { if (args.length == 0) { return false; } - int requestId = 0; - - try { - requestId = Integer.parseInt(args[0]); - - if (sender instanceof Player) { - Request req = reqTable.getRequest(requestId); - if (req.getAssignedMod().equalsIgnoreCase(senderName) && req.getStatus() == RequestStatus.CLAIMED) { - req.setStatus(RequestStatus.OPEN); - req.setAssignedModUUID(null); - req.setAssignedMod(null); - reqTable.save(req); - - environment.put("mod", senderName); - environment.put("request_id", String.valueOf(requestId)); - messageMods(config.MOD__UNCLAIM); - environment.remove("mod"); - environment.remove("request_id"); - } - } - } - catch (NumberFormatException ex) { - sendMessage(sender, config.GENERAL__REQUEST_NUMBER); - } + unclaim(sender, senderName, senderUUID, args); } else if (command.getName().equalsIgnoreCase("done")) { if (args.length == 0) { - return false; - } - - int requestId = 0; - - try { - requestId = Integer.parseInt(args[0]); - - String doneMessage = ""; - - if (args.length > 1) { - StringBuilder doneMessageBuilder = new StringBuilder(args[1]); - for (int i = 2; i < args.length; i++) { - doneMessageBuilder.append(" ").append(args[i]); - } - - doneMessage = doneMessageBuilder.toString(); - } - - Request req = reqTable.getRequest(requestId); - - if (req != null && req.getStatus() == RequestStatus.CLOSED) { - sendMessage(sender, config.MOD__ALREADY_CLOSED); - } - else { - if (sender.hasPermission("modreq.done") && req != null) { - String msg = ""; - environment.put("mod", senderName); - environment.put("request_id", String.valueOf(requestId)); - msg = String.format("%sRequest #%d has been completed by %s", ChatColor.GREEN, requestId, senderName); - messageMods(config.MOD__COMPLETED); - environment.remove("request_id"); - environment.remove("mod"); - - if (doneMessage != null && doneMessage.length() != 0) { - msg = String.format("Close Message - %s%s", ChatColor.GRAY, doneMessage); - environment.put("close_message", doneMessage); - messageMods(config.MOD__COMPLETED_MESSAGE); - environment.remove("close_message"); - } - } - else { - if (req.getPlayerUUID() != null && !req.getPlayerUUID().equals(senderUUID)) { - req = null; - sendMessage(sender, config.GENERAL__CLOSE_ERROR); - } - } - - if (req != null) { - req.setStatus(RequestStatus.CLOSED); - req.setCloseTime(System.currentTimeMillis()); - req.setCloseMessage(doneMessage); - req.setAssignedModUUID(senderUUID); - req.setAssignedMod(senderName); - - Player requestCreator = getServer().getPlayerExact(req.getPlayerName()); - if (requestCreator != null) { - if (!requestCreator.getUniqueId().equals(senderUUID)) { - String message = ""; - environment.put("close_message", doneMessage); - environment.put("mod", senderName); - environment.put("request_id", String.valueOf(req.getId())); - if (doneMessage != null && doneMessage.length() != 0) { - sendMessage(requestCreator, config.GENERAL__COMPLETED_MESSAGE); - } else { - sendMessage(requestCreator, config.GENERAL__COMPLETED); - } - environment.put("close_message", doneMessage); - environment.put("mod", senderName); - environment.put("request_id", String.valueOf(req.getId())); - requestCreator.sendMessage(ChatColor.GREEN + message); - environment.remove("close_message"); - environment.remove("mod"); - } - else { - if (!sender.hasPermission("modreq.done")) { - environment.put("request_id", String.valueOf(requestId)); - messageMods(config.MOD__DELETED); - environment.put("request_id", String.valueOf(requestId)); - sendMessage(sender, config.GENERAL__DELETED); - environment.remove("request_id"); - } - } - req.setCloseSeenByUser(true); - } - reqTable.save(req); - } - } - } - catch (NumberFormatException ex) { - sendMessage(sender, config.GENERAL__REQUEST_NUMBER); + return false; } + done(sender, senderName, senderUUID, args); } else if (command.getName().equalsIgnoreCase("reopen")) { if (args.length == 0) { return false; } - int requestId = 0; - - try { - requestId = Integer.parseInt(args[0]); - - if (sender instanceof Player) { - Request req = reqTable.getRequest(requestId); - if ((req.getAssignedModUUID().equals(senderUUID) && req.getStatus() == RequestStatus.CLAIMED) || req.getStatus() == RequestStatus.CLOSED) { - req.setStatus(RequestStatus.OPEN); - req.setAssignedModUUID(null); - req.setAssignedMod(null); - req.setCloseSeenByUser(false); - reqTable.save(req); - - environment.put("mod", sender.getName()); - environment.put("request_id", String.valueOf(requestId)); - messageMods(config.MOD__REOPENED); - environment.remove("mod"); - environment.remove("request_id"); - } - } - } - catch (NumberFormatException ex) { - sendMessage(sender, config.GENERAL__REQUEST_NUMBER); - } + reopen(sender, senderUUID, args); } else if (command.getName().equalsIgnoreCase("elevate")) { if (args.length == 0) { return false; } - int requestId = 0; - - try { - requestId = Integer.parseInt(args[0]); - - Request req = reqTable.getRequest(requestId); - if (req.getStatus() == RequestStatus.OPEN) { - req.setFlagForAdmin(true); - environment.put("request_id", String.valueOf(req.getId())); - messageMods(config.MOD__FLAGGED); - environment.remove("request_id"); - reqTable.save(req); - } - } - catch (NumberFormatException ex) { - sendMessage(sender, config.GENERAL__REQUEST_NUMBER); - } + elevate(sender, senderName, senderUUID, args); } else if ( command.getName().equalsIgnoreCase("mr-reset")) { try { resetDatabase(); @@ -659,141 +359,573 @@ else if (command.getName().equalsIgnoreCase("reopen")) { if (args.length < 3) { return false; } - if (sender.hasPermission("modreq.mod")) { - int reqId; - - try { - reqId = Integer.parseInt(args[1].trim()); - } catch (NumberFormatException e) { - return false; - } - - Request request = reqTable.getRequest(reqId); - if (request == null) { - return false; + return mrNote(sender, senderName, senderUUID, args); + } else if (command.getName().equalsIgnoreCase("mr-upgrade")) { + mrUpgrade(); + } + return true; + } + + private void modreq(CommandSender sender, String senderName, Player player, String[] args) { + if (!(sender instanceof Player)) { + return; + } + + if (reqTable.getNumRequestFromUser(player.getUniqueId()) < config.MAX_REQUESTS) { + Request req = new Request(); + req.setPlayerUUID(player.getUniqueId()); + req.setPlayerName(senderName); + String r = ChatColor.translateAlternateColorCodes('&', concatArgs(args, 0)); + r = ChatColor.stripColor(r); + req.setRequest(r); + req.setRequestTime(System.currentTimeMillis()); + String location = String.format("%s,%f,%f,%f,%f,%f", player.getWorld().getName(), player.getLocation().getX(), player.getLocation().getY(), player.getLocation().getZ(), player.getLocation().getYaw(), player.getLocation().getPitch()); + req.setRequestLocation(location); + req.setStatus(RequestStatus.OPEN); + + reqTable.save(req); + environment.put("request_id", String.valueOf(req.getId())); + messageMods(config.MOD__NEW_REQUEST); + sendMessage(sender, config.GENERAL__REQUEST_FILED); + } else { + environment.put("max_requests", Integer.toString(config.MAX_REQUESTS)); + sendMessage(sender, config.GENERAL__MAX_REQUESTS); + } + } + + private void check(CommandSender sender, UUID senderUUID, String[] args) { + // Setting page > 0 triggers a page listing. + int page = 1; + int requestId = 0; + int totalRequests = 0; + String searchTerm = null; + UUID limitUUID = null; + boolean showNotes = true; + boolean includeElevated = sender.hasPermission("modreq.cleardb"); + + for (int i = 0; i < args.length; i++) { + String arg = args[i]; + if (arg.equalsIgnoreCase("--admin") || arg.equalsIgnoreCase("-a")) { + includeElevated = true; + } + else if (arg.startsWith("p:")) { + page = Integer.parseInt(arg.substring(2)); + } + else if (arg.equalsIgnoreCase("--page") || arg.equalsIgnoreCase("-p")) { + if (i+1 > args.length) { + sendMessage(sender, config.GENERAL__PAGE_ERROR); + return; } - - if (args[0].equalsIgnoreCase("remove")) { - - //kind of hacky but works - int idToRemove; - + else { try { - idToRemove = Integer.parseInt(args[2]); - } catch (NumberFormatException e) { - return false; + page = Integer.parseInt(args[i+1]); + i++; } - - List notes = noteTable.getRequestNotes(request); - - Note noteToRemove = notes.get(idToRemove - 1); - if(noteToRemove == null) { - return false; + catch (NumberFormatException ex) { + sendMessage(sender, config.GENERAL__PAGE_ERROR); + return; } - - noteTable.remove(noteToRemove); - environment.put("request_id", Integer.toString(reqId)); - sender.sendMessage(buildMessage(config.MOD__NOTE_REMOVED)); - environment.remove("request_id"); - } else if (args[0].equalsIgnoreCase("add")) { - - if(reqTable.getRequest(reqId) == null) { - return false; + } + } + else if (arg.equalsIgnoreCase("--search") || arg.equalsIgnoreCase("-s")) { + if (i+1 < args.length) { + searchTerm = args[i+1]; + i++; + } + else { + sendMessage(sender, config.GENERAL__SEARCH_ERROR); + return; + } + } + else if (arg.equals("-")) { + Integer claimedId = claimedIds.get(senderUUID); + if (claimedId != null) { + requestId = claimedId; + page = 0; + } + } + else { + try { + requestId = Integer.parseInt(arg); + page = 0; + } + catch (NumberFormatException ex) { + sendMessage(sender, config.GENERAL__REQUEST_NUMBER); + return; + } + } + } + + if (!sender.hasPermission("modreq.check")) { + if (sender instanceof Player) { + limitUUID = senderUUID; + } + showNotes = false; + } + + List requests = new ArrayList(); + + if (page > 0) { + if (limitUUID != null) { + requests.addAll(reqTable.getUserRequests(limitUUID)); + totalRequests = requests.size(); + } else { + requests.addAll(reqTable.getRequestPage(page - 1, config.PAGE_SIZE, includeElevated, searchTerm, RequestStatus.OPEN, RequestStatus.CLAIMED)); + totalRequests = reqTable.getTotalRequest(includeElevated, searchTerm, RequestStatus.OPEN, RequestStatus.CLAIMED); + } + } else if (requestId > 0) { + Request req = reqTable.getRequest(requestId); + if (req == null) { + sendMessage(sender, config.GENERAL__REQUEST_ERROR); + return; + } else { + totalRequests = 1; + if (limitUUID != null && req.getPlayerUUID().equals(limitUUID)) { + requests.add(req); + } else if (limitUUID == null) { + requests.add(req); + } else { + totalRequests = 0; + } + } + } + + if (totalRequests == 0) { + if (limitUUID != null) { + if (requestId > 0) { + sendMessage(sender, config.GENERAL__REQUEST_ERROR); + } + else { + sendMessage(sender, config.GENERAL__NO_REQUESTS); + } + } + else { + sendMessage(sender, config.MOD__NO_REQUESTS); + } + } else if (totalRequests == 1 && requestId > 0) { + messageRequestToPlayer(sender, requests.get(0), showNotes); + } else if (totalRequests > 0) { + if (page > 1 && requests.isEmpty()) { + sendMessage(sender, config.MOD__EMPTY_PAGE); + } else { + boolean showPage = true; + if (limitUUID != null) { + showPage = false; + } + messageRequestListToPlayer(sender, requests, page, totalRequests, showPage); + } + } else { + // there was an error. + } + } + + private void tpId(CommandSender sender, UUID senderUUID, Player player, String[] args) { + if (!(sender instanceof Player)) { + return; + } + + Request req = getRequest(sender, senderUUID, args[0], true); + if (req == null) { + return; + } + + environment.put("request_id", String.valueOf(req.getId())); + sendMessage(player, config.MOD__TELEPORT); + Location loc = stringToLocation(req.getRequestLocation()); + player.teleport(loc); + } + + /** + * Do the work of the /claim command. + * + * @return true if the request was successfully claimed by the sender now + * or previously; false if closed or already claimed by some + * other player. + */ + private boolean claim(CommandSender sender, String senderName, UUID senderUUID, String[] args) { + Request req = getRequest(sender, senderUUID, args[0], false); + if (req == null) { + return false; + } + int requestId = req.getId(); + + if (req.getStatus() == RequestStatus.OPEN) { + req.setStatus(RequestStatus.CLAIMED); + req.setAssignedModUUID(senderUUID); + req.setAssignedMod(senderName); + reqTable.save(req); + + environment.put("mod", senderName); + environment.put("request_id", String.valueOf(requestId)); + messageMods(config.MOD__REQUEST_TAKEN); + environment.remove("mod"); + environment.remove("request_id"); + claimedIds.put(senderUUID, requestId); + return true; + + } else if (req.getStatus() == RequestStatus.CLOSED) { + sendMessage(sender, config.MOD__ALREADY_CLOSED); + + } else if (req.getStatus() == RequestStatus.CLAIMED) { + if (req.getAssignedModUUID().equals(senderUUID)) { + // Already claimed by command sender. Update most recent claim. + claimedIds.put(senderUUID, requestId); + return true; + } else { + sendMessage(sender, config.MOD__ALREADY_CLAIMED); + } + } + return false; + } + + private void unclaim(CommandSender sender, String senderName, UUID senderUUID, String[] args) { + Request req = getRequest(sender, senderUUID, args[0], true); + if (req == null) { + return; + } + + if (req.getStatus() == RequestStatus.CLAIMED && req.getAssignedModUUID().equals(senderUUID)) { + + req.setStatus(RequestStatus.OPEN); + req.setAssignedModUUID(null); + req.setAssignedMod(null); + reqTable.save(req); + + environment.put("mod", senderName); + environment.put("request_id", String.valueOf(req.getId())); + messageMods(config.MOD__UNCLAIM); + environment.remove("mod"); + environment.remove("request_id"); + } + } + + private void done(CommandSender sender, String senderName, UUID senderUUID, String[] args) { + Request req = getRequest(sender, senderUUID, args[0], true); + if (req == null) { + return; + } + int requestId = req.getId(); + + String doneMessage = concatArgs(args, 1); + boolean successfullyClosed = true; + + if (req.getStatus() == RequestStatus.CLOSED) { + sendMessage(sender, config.MOD__ALREADY_CLOSED); + successfullyClosed = false; + } else { + // Moderator doing /done. + if (sender.hasPermission("modreq.done")) { + environment.put("mod", senderName); + environment.put("request_id", String.valueOf(requestId)); + messageMods(config.MOD__COMPLETED); + environment.remove("request_id"); + environment.remove("mod"); + + if (doneMessage.length() != 0) { + environment.put("close_message", doneMessage); + messageMods(config.MOD__COMPLETED_MESSAGE); + environment.remove("close_message"); + } + } else { + // Player doing /done. + if (req.getPlayerUUID() != null && !req.getPlayerUUID().equals(senderUUID)) { + sendMessage(sender, config.GENERAL__CLOSE_ERROR); + successfullyClosed = false; + } + } + } + + if (successfullyClosed) { + req.setStatus(RequestStatus.CLOSED); + req.setCloseTime(System.currentTimeMillis()); + req.setCloseMessage(doneMessage); + req.setAssignedModUUID(senderUUID); + req.setAssignedMod(senderName); + + Player requestCreator = getServer().getPlayerExact(req.getPlayerName()); + if (requestCreator != null) { + // Message request creator immediately if online. + req.setCloseSeenByUser(true); + + if (requestCreator.getUniqueId().equals(senderUUID)) { + // Request closed by player. + if (!sender.hasPermission("modreq.done")) { + environment.put("request_id", String.valueOf(requestId)); + messageMods(config.MOD__DELETED); + sendMessage(sender, config.GENERAL__DELETED); + environment.remove("request_id"); } - - StringBuilder noteBody = new StringBuilder(args[2]); - for (int i = 3; i < args.length; i++) { - noteBody.append(" ").append(args[i]); + } else { + // Request closed by moderator. + environment.put("close_message", doneMessage); + environment.put("mod", senderName); + environment.put("request_id", String.valueOf(requestId)); + if (doneMessage.length() != 0) { + sendMessage(requestCreator, config.GENERAL__COMPLETED_MESSAGE); + } else { + sendMessage(requestCreator, config.GENERAL__COMPLETED); } - - Note note = new Note(); - note.setNoteBody(noteBody.toString()); - note.setPlayerUUID(senderUUID); - note.setPlayer(senderName); - note.setRequestId(reqId); - noteTable.save(note); - - environment.put("request_id", Integer.toString(reqId)); - sender.sendMessage(buildMessage(config.MOD__NOTE_ADDED)); + environment.remove("close_message"); + environment.remove("mod"); environment.remove("request_id"); } } - } else if ( command.getName().equalsIgnoreCase("mr-upgrade")) { - if (sender.hasPermission("modreq.upgrade")) { -// getLogger().log(Level.INFO, "Upgrading database"); - -// try { -// SqlUpdate update = getDatabase().createSqlUpdate("ALTER TABLE modreq_requests ADD COLUMN player_uuid VARCHAR(40)"); -// getDatabase().execute(update); -// getLogger().log(Level.INFO, "Created player_uuid column on modreq_requests table"); -// } catch (PersistenceException e) { -// // Column already exists -// } + reqTable.save(req); + } + } + + private void reopen(CommandSender sender, UUID senderUUID, String[] args) { + Request req = getRequest(sender, senderUUID, args[0], true); + if (req == null) { + return; + } + + if (req.getStatus() == RequestStatus.CLOSED || + (req.getStatus() == RequestStatus.CLAIMED && req.getAssignedModUUID().equals(senderUUID))) { + req.setStatus(RequestStatus.OPEN); + req.setAssignedModUUID(null); + req.setAssignedMod(null); + req.setCloseSeenByUser(false); + reqTable.save(req); + + environment.put("mod", sender.getName()); + environment.put("request_id", String.valueOf(req.getId())); + messageMods(config.MOD__REOPENED); + environment.remove("mod"); + environment.remove("request_id"); + } + } + + private void elevate(CommandSender sender, String senderName, UUID senderUUID, String[] args) { + unclaim(sender, senderName, senderUUID, args); + + Request req = getRequest(sender, senderUUID, args[0], true); + if (req == null) { + return; + } + if (req.getStatus() == RequestStatus.OPEN) { + req.setFlagForAdmin(true); + environment.put("request_id", String.valueOf(req.getId())); + messageMods(config.MOD__FLAGGED); + environment.remove("request_id"); + reqTable.save(req); + } else if (req.getStatus() == RequestStatus.CLAIMED) { + // When someone else has already claimed, unclaim() won't work. + sendMessage(sender, config.MOD__ALREADY_CLAIMED); + } else if (req.getStatus() == RequestStatus.CLOSED) { + sendMessage(sender, config.MOD__ALREADY_CLOSED); + } + } + + /** + * Handle "/mr-note add req text" and "/mr-note remove req noteid". + * + * @return true if the command has the correct syntax, so usage should not + * be shown. + */ + private boolean mrNote(CommandSender sender, String senderName, UUID senderUUID, String[] args) { + Request request = getRequest(sender, senderUUID, args[1], true); + if (request == null) { + return true; + } + int requestId = request.getId(); + environment.put("request_id", Integer.toString(requestId)); + + if (args[0].equalsIgnoreCase("add")) { + Note note = new Note(); + note.setNoteBody(concatArgs(args, 2)); + note.setPlayerUUID(senderUUID); + note.setPlayer(senderName); + note.setRequestId(requestId); + noteTable.save(note); + + sender.sendMessage(buildMessage(config.MOD__NOTE_ADDED)); + return true; + + } else if (args[0].equalsIgnoreCase("remove")) { + int noteId; + try { + noteId = Integer.parseInt(args[2]); + } catch (NumberFormatException e) { + environment.put("note_id", args[2]); + sender.sendMessage(buildMessage(config.MOD__NOTE_NUMBER)); + return true; + } + environment.put("note_id", Integer.toString(noteId)); + + List notes = noteTable.getRequestNotes(request); + int noteIndex = noteId - 1; + if (noteIndex < 0 || noteIndex >= notes.size()) { + sender.sendMessage(buildMessage(config.MOD__NOTE_MISSING)); + return true; + } + + Note noteToRemove = notes.get(noteIndex); + noteTable.remove(noteToRemove); + sender.sendMessage(buildMessage(config.MOD__NOTE_REMOVED)); + return true; + + } else { + return false; + } + } + + private void mrUpgrade() { +// getLogger().log(Level.INFO, "Upgrading database"); +// try { +// SqlUpdate update = getDatabase().createSqlUpdate("ALTER TABLE modreq_requests ADD COLUMN player_uuid VARCHAR(40)"); +// getDatabase().execute(update); +// getLogger().log(Level.INFO, "Created player_uuid column on modreq_requests table"); +// } catch (PersistenceException e) { +// // Column already exists +// } // -// try { -// SqlUpdate update = getDatabase().createSqlUpdate("ALTER TABLE modreq_requests ADD COLUMN assigned_mod_uuid VARCHAR(40)"); -// getDatabase().execute(update); -// getLogger().log(Level.INFO, "Created assigned_mod_uuid column on modreq_requests table"); -// } catch (PersistenceException e) { -// // Column already exists -// } +// try { +// SqlUpdate update = getDatabase().createSqlUpdate("ALTER TABLE modreq_requests ADD COLUMN assigned_mod_uuid VARCHAR(40)"); +// getDatabase().execute(update); +// getLogger().log(Level.INFO, "Created assigned_mod_uuid column on modreq_requests table"); +// } catch (PersistenceException e) { +// // Column already exists +// } // -// try { -// SqlUpdate update = getDatabase().createSqlUpdate("ALTER TABLE modreq_notes ADD COLUMN player_uuid VARCHAR(40)"); -// getDatabase().execute(update); -// getLogger().log(Level.INFO, "Created player_uuid column on modreq_notes table"); -// } catch (PersistenceException e) { -// // Column already exists -// } +// try { +// SqlUpdate update = getDatabase().createSqlUpdate("ALTER TABLE modreq_notes ADD COLUMN player_uuid VARCHAR(40)"); +// getDatabase().execute(update); +// getLogger().log(Level.INFO, "Created player_uuid column on modreq_notes table"); +// } catch (PersistenceException e) { +// // Column already exists +// } // -// getDatabase().externalModification(name, includeElevated, includeElevated, includeElevated); +// getDatabase().externalModification(name, includeElevated, includeElevated, includeElevated); - BukkitScheduler scheduler = Bukkit.getServer().getScheduler(); - scheduler.scheduleSyncDelayedTask(this, new Runnable() { - @Override - public void run() { - resetDatabase(); - } - }, 0L); - } - } + BukkitScheduler scheduler = Bukkit.getServer().getScheduler(); + scheduler.scheduleSyncDelayedTask(this, new Runnable() { + @Override + public void run() { + resetDatabase(); + } + }, 0L); + } - return true; + /** + * Parse the specified command argument (usually args[0] in onCommand()) + * as an integer request ID and return the corresponding Request. + * + * If useLastClaimedId is true, an ID of "-" is accepted as a reference to + * the most recently claimed request + * + * Errors are messaged to the command sender in the case of a malformed + * request ID, or if the ID does not correspond to a database entry. + * + * @param arg the command argument to parse. + * @param senderUUID UUID of the CommandSender. + * @param useLastClaimedId if true, then an arg of "-" is considered to be + * a synonym for the ID of the most recently claimed request. + * @return the corresponding Request, or null if not found. + */ + private Request getRequest(CommandSender sender, UUID senderUUID, String arg, boolean useLastClaimedId) { + int requestId = 0; + + if (arg.equals("-")) { + if (useLastClaimedId) { + Integer claimedId = claimedIds.get(senderUUID); + if (claimedId != null) { + requestId = claimedId; + } + } + } else { + try { + requestId = Integer.parseInt(arg); + } + catch (NumberFormatException ex) { + } + } + + if (requestId == 0) { + sendMessage(sender, config.GENERAL__REQUEST_NUMBER); + return null; + } + + Request req = reqTable.getRequest(requestId); + if (req == null) { + sendMessage(sender, config.GENERAL__REQUEST_ERROR); + } + return req; + } + + private void loadClaimedIds() { + YamlConfiguration config = new YamlConfiguration(); + try { + if (claimsFile.isFile()) { + config.load(claimsFile); + for (String uuidString : config.getKeys(false)) { + try { + claimedIds.put(UUID.fromString(uuidString), config.getInt(uuidString)); + } catch (Exception ex) { + } + } + } + } catch (FileNotFoundException ex) { + getLogger().warning("cannot read " + claimsFile.getPath()); + } catch (IOException ex) { + getLogger().warning("error reading " + claimsFile.getPath()); + } catch (InvalidConfigurationException ex) { + getLogger().warning("cannot parse " + claimsFile.getPath()); + } + } + + private void saveClaimedIds() { + YamlConfiguration config = new YamlConfiguration(); + for (Entry claim : claimedIds.entrySet()) { + config.set(claim.getKey().toString(), claim.getValue()); + } + + try { + config.save(claimsFile); + } catch (IOException ex) { + getLogger().warning("most recently claimed requests could not be saved in " + claimsFile.getPath()); + } + } + + private String concatArgs(String[] args, int first) { + StringBuilder builder = new StringBuilder(); + String sep = ""; + for (int i = first; i < args.length; ++i) { + builder.append(sep).append(args[i]); + sep = " "; + } + return builder.toString(); } private Location stringToLocation(String requestLocation) { - Location loc; - double x, y, z; - float pitch, yaw; - String world; String[] split = requestLocation.split(","); - world = split[0]; - x = Double.parseDouble(split[1]); - y = Double.parseDouble(split[2]); - z = Double.parseDouble(split[3]); - if (split.length > 4) { - yaw = Float.parseFloat(split[4]); - pitch = Float.parseFloat(split[5]); - loc = new Location(getServer().getWorld(world), x, y, z, yaw, pitch); - } else { - loc = new Location(getServer().getWorld(world), x, y, z); - } - return loc; + String world = split[0]; + double x = Double.parseDouble(split[1]); + double y = Double.parseDouble(split[2]); + double z = Double.parseDouble(split[3]); + + if (split.length > 4) { + float yaw = Float.parseFloat(split[4]); + float pitch = Float.parseFloat(split[5]); + return new Location(getServer().getWorld(world), x, y, z, yaw, pitch); + } else { + return new Location(getServer().getWorld(world), x, y, z); + } } private String timestampToDateString(long timestamp) { Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(timestamp); - SimpleDateFormat format = new SimpleDateFormat("MMM.d@k.m.s"); + SimpleDateFormat format = new SimpleDateFormat(config.DATE_FORMAT); return format.format(cal.getTime()); } - + public String buildMessage(String inputMessage) { String message = inputMessage; - - for (Map.Entry entry : environment.entrySet()) { - String key = (String)entry.getKey(); - String value = (String)entry.getValue(); + + for (Map.Entry entry : environment.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); if (key.equalsIgnoreCase("player")) { if (getServer().getPlayerExact(value) != null) { value = config.COLOUR_ONLINE + value; @@ -802,11 +934,11 @@ public String buildMessage(String inputMessage) { value = config.COLOUR_OFFLINE + value; } } - + message = message.replace("{" + key + "}", value); } - - + + message = ChatColor.translateAlternateColorCodes('&', message); return message; } @@ -815,7 +947,7 @@ private void messageRequestToPlayer(CommandSender sender, Request req, boolean s List messages = new ArrayList(); Location loc = stringToLocation(req.getRequestLocation()); String location = String.format("%s, %d, %d, %d", loc.getWorld().getName(), Math.round(loc.getX()), Math.round(loc.getY()), Math.round(loc.getZ())); - + environment.put("status", req.getStatus().toString()); environment.put("request_id", String.valueOf(req.getId())); if (req.getStatus() == RequestStatus.CLAIMED) { @@ -838,45 +970,35 @@ private void messageRequestToPlayer(CommandSender sender, Request req, boolean s environment.put("request_message", req.getRequest()); messages.add(buildMessage(config.GENERAL__ITEM__REQUEST)); environment.remove("request_message"); - + if (showNotes) { List notes = noteTable.getRequestNotes(req); - + int i = 1; for (Note note : notes) { environment.put("id", Integer.toString(i)); environment.put("user", note.getPlayer()); environment.put("message", note.getNoteBody()); messages.add(buildMessage(config.GENERAL__ITEM__NOTE)); - + i++; } environment.remove("id"); environment.remove("player"); environment.remove("message"); } - + sender.sendMessage(messages.toArray(new String[1])); } private void messageRequestListToPlayer(CommandSender sender, List reqs, int page, int totalRequests, boolean showPage) { List messages = new ArrayList(); - + environment.put("num_requests", String.valueOf(totalRequests)); messages.add(buildMessage(config.GENERAL__LIST__HEADER)); environment.remove("num_requests"); for (Request r : reqs) { - ChatColor onlineStatus = ChatColor.RED; - String message = ""; int noteCount = noteTable.getNoteCount(r); - if (r.getRequest().length() > 20) { - message = r.getRequest().substring(0, 17) + "..."; - } else { - message = r.getRequest(); - } - if (getServer().getPlayerExact(r.getPlayerName()) != null) { - onlineStatus = ChatColor.GREEN; - } try { environment.put("request_id", String.valueOf(r.getId())); environment.put("note_count", noteCount>0?ChatColor.RED+" ["+Integer.toString(noteCount)+"]":""); @@ -900,16 +1022,16 @@ private void messageRequestListToPlayer(CommandSender sender, List reqs ex.printStackTrace(); } } - + if (showPage) { - int numpages = (int)Math.ceil(totalRequests / config.MAX_REQUESTS.floatValue()); + int numpages = (int)Math.ceil(totalRequests / (float) config.PAGE_SIZE); environment.put("page", String.valueOf(page)); environment.put("num_pages", String.valueOf(numpages)); messages.add(buildMessage(config.GENERAL__LIST__FOOTER)); environment.remove("page"); environment.remove("num_pages"); } - + sender.sendMessage(messages.toArray(new String[1])); } diff --git a/src/nu/nerd/modreq/ModReqListener.java b/src/nu/nerd/modreq/ModReqListener.java index f55eb71..8fd3bef 100644 --- a/src/nu/nerd/modreq/ModReqListener.java +++ b/src/nu/nerd/modreq/ModReqListener.java @@ -5,9 +5,7 @@ import nu.nerd.modreq.database.Request; import nu.nerd.modreq.database.Request.RequestStatus; -import org.bukkit.Bukkit; import org.bukkit.ChatColor; -import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; @@ -28,9 +26,9 @@ public void onPlayerJoin(PlayerJoinEvent event) { event.getPlayer().sendMessage(ChatColor.GREEN + "There are " + open + " open mod requests. Type /check to see them."); } } - + List missedClosed = plugin.reqTable.getMissedClosedRequests(event.getPlayer().getUniqueId()); - + for (Request req : missedClosed) { String doneMessage = req.getCloseMessage(); String message = ""; @@ -41,7 +39,7 @@ public void onPlayerJoin(PlayerJoinEvent event) { } event.getPlayer().sendMessage(ChatColor.GREEN + message); req.setCloseSeenByUser(true); - + plugin.reqTable.save(req); } } diff --git a/src/nu/nerd/modreq/database/RequestTable.java b/src/nu/nerd/modreq/database/RequestTable.java index db714b6..a4af62e 100644 --- a/src/nu/nerd/modreq/database/RequestTable.java +++ b/src/nu/nerd/modreq/database/RequestTable.java @@ -58,7 +58,7 @@ public int getNumRequestFromUser(UUID uuid) { public int getTotalRequest(boolean includeElevated, String searchTerm, RequestStatus ... statuses) { int retVal = 0; - ExpressionList expressions = plugin.getDatabase().find(Request.class).where().in("status", statuses); + ExpressionList expressions = plugin.getDatabase().find(Request.class).where().in("status", (Object[]) statuses); if (searchTerm != null) { @@ -89,7 +89,7 @@ public List getAllRequests() { public List getRequestPage(int page, int perPage, boolean includeElevated, String searchTerm, RequestStatus ... statuses) { List retVal = new ArrayList(); - ExpressionList expressions = plugin.getDatabase().find(Request.class).where().in("status", statuses); + ExpressionList expressions = plugin.getDatabase().find(Request.class).where().in("status", (Object[]) statuses); if (searchTerm != null) {