From 1b0f8b373ebd9540c0b094f219801f989cd6b6f0 Mon Sep 17 00:00:00 2001 From: totemo Date: Sun, 15 Nov 2015 09:42:18 +1030 Subject: [PATCH 01/10] Additional build-related location to ignore. --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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/ From ad1a0c700056d514013304d3874be925194db54b Mon Sep 17 00:00:00 2001 From: totemo Date: Sun, 15 Nov 2015 09:58:42 +1030 Subject: [PATCH 02/10] Updated to a working state after the demise of the Bukkit project. * Removed references to bukkit.org repositories. * Switched to API version 1.8.8-R0.1-SNAPSHOT in order to use Spigot repository. * Suppressed generation of dependency-reduced-pom.xml (Maven Shade plugin). --- pom.xml | 60 +++++++++++++++++++++------------------------------------ 1 file changed, 22 insertions(+), 38 deletions(-) diff --git a/pom.xml b/pom.xml index a9b1c5c..cae896c 100644 --- a/pom.xml +++ b/pom.xml @@ -6,14 +6,34 @@ 1.6 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 From 8624423c474d70eaff4ec69fbaf02188052445a5 Mon Sep 17 00:00:00 2001 From: totemo Date: Sun, 15 Nov 2015 12:52:47 +1030 Subject: [PATCH 03/10] Fix compiler warnings. --- src/nu/nerd/modreq/ModReqListener.java | 8 +++----- src/nu/nerd/modreq/database/RequestTable.java | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) 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) { From 732eefb5ea32c5da27221a4e46d275f3d6b06b54 Mon Sep 17 00:00:00 2001 From: totemo Date: Sun, 15 Nov 2015 12:53:31 +1030 Subject: [PATCH 04/10] Add commands to perform composite actions. * /tpinfo - does /tp-id and the /check * /tpi - is an alias of /tpinfo * /tpc - does /claim and only if that succeeds does /tpinfo In addition, clean up some compiler warnings, particularly those concerning unused variables. --- config.yml | 1 + plugin.yml | 11 + src/nu/nerd/modreq/Configuration.java | 12 +- src/nu/nerd/modreq/ModReq.java | 481 ++++++++++++++------------ 4 files changed, 276 insertions(+), 229 deletions(-) diff --git a/config.yml b/config.yml index a91bf37..63d5eaf 100644 --- a/config.yml +++ b/config.yml @@ -36,6 +36,7 @@ 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." colour: 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/src/nu/nerd/modreq/Configuration.java b/src/nu/nerd/modreq/Configuration.java index f436a93..e3779d0 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,24 @@ 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 COLOUR_ONLINE; public String COLOUR_OFFLINE; public Integer MAX_REQUESTS; - + 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,6 +90,7 @@ 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"); COLOUR_OFFLINE = plugin.getConfig().getString("colour.offline"); diff --git a/src/nu/nerd/modreq/ModReq.java b/src/nu/nerd/modreq/ModReq.java index e77f41b..99af4a7 100755 --- a/src/nu/nerd/modreq/ModReq.java +++ b/src/nu/nerd/modreq/ModReq.java @@ -45,7 +45,7 @@ public class ModReq extends JavaPlugin { RequestTable reqTable; NoteTable noteTable; - + @Override public void onEnable() { setupDatabase(); @@ -54,9 +54,9 @@ public void onEnable() { getConfig().options().copyDefaults(true); saveConfig(); } - + config.load(); - + reqTable = new RequestTable(this); noteTable = new NoteTable(this); getServer().getPluginManager().registerEvents(listener, this); @@ -76,7 +76,7 @@ public boolean setupDatabase() { installDDL(); return true; } - + return false; } @@ -86,11 +86,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 +163,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 +257,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; @@ -278,7 +277,7 @@ public boolean onCommand(CommandSender sender, Command command, String name, Str 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(); @@ -303,186 +302,45 @@ public boolean onCommand(CommandSender sender, Command command, String name, Str } } 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, player, args); + } + else if (command.getName().equalsIgnoreCase("tpinfo")) { + if (args.length == 0) { + return false; } + tpId(sender, 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, 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) { @@ -490,7 +348,7 @@ else if (command.getName().equalsIgnoreCase("unclaim")) { req.setAssignedModUUID(null); req.setAssignedMod(null); reqTable.save(req); - + environment.put("mod", senderName); environment.put("request_id", String.valueOf(requestId)); messageMods(config.MOD__UNCLAIM); @@ -507,40 +365,37 @@ 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"); @@ -603,10 +458,10 @@ else if (command.getName().equalsIgnoreCase("reopen")) { 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) { @@ -615,7 +470,7 @@ else if (command.getName().equalsIgnoreCase("reopen")) { 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); @@ -632,10 +487,10 @@ else if (command.getName().equalsIgnoreCase("reopen")) { return false; } int requestId = 0; - + try { requestId = Integer.parseInt(args[0]); - + Request req = reqTable.getRequest(requestId); if (req.getStatus() == RequestStatus.OPEN) { req.setFlagForAdmin(true); @@ -661,58 +516,58 @@ else if (command.getName().equalsIgnoreCase("reopen")) { } 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; } - + if (args[0].equalsIgnoreCase("remove")) { - + //kind of hacky but works int idToRemove; - + try { idToRemove = Integer.parseInt(args[2]); } catch (NumberFormatException e) { return false; } - + List notes = noteTable.getRequestNotes(request); - + Note noteToRemove = notes.get(idToRemove - 1); if(noteToRemove == null) { return false; } - + 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; } - + StringBuilder noteBody = new StringBuilder(args[2]); for (int i = 3; i < args.length; i++) { noteBody.append(" ").append(args[i]); } - + 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("request_id"); @@ -761,6 +616,194 @@ public void run() { return true; } + 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; + } + else { + try { + page = Integer.parseInt(args[i+1]); + i++; + } + catch (NumberFormatException ex) { + sendMessage(sender, config.GENERAL__PAGE_ERROR); + return; + } + } + } + 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 { + 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, 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); + + 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. + } + } + + private void tpId(CommandSender sender, Player player, String[] args) { + 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); + } + } + + /** + * 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) { + 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"); + 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. Succeed. + return true; + } else { + sendMessage(sender, config.MOD__ALREADY_CLAIMED); + } + } + } + } + catch (NumberFormatException ex) { + sendMessage(sender, config.GENERAL__REQUEST_NUMBER); + } + return false; + } + private Location stringToLocation(String requestLocation) { Location loc; double x, y, z; @@ -787,13 +830,13 @@ private String timestampToDateString(long timestamp) { SimpleDateFormat format = new SimpleDateFormat("MMM.d@k.m.s"); 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 +845,11 @@ public String buildMessage(String inputMessage) { value = config.COLOUR_OFFLINE + value; } } - + message = message.replace("{" + key + "}", value); } - - + + message = ChatColor.translateAlternateColorCodes('&', message); return message; } @@ -815,7 +858,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 +881,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,7 +933,7 @@ private void messageRequestListToPlayer(CommandSender sender, List reqs ex.printStackTrace(); } } - + if (showPage) { int numpages = (int)Math.ceil(totalRequests / config.MAX_REQUESTS.floatValue()); environment.put("page", String.valueOf(page)); @@ -909,7 +942,7 @@ private void messageRequestListToPlayer(CommandSender sender, List reqs environment.remove("page"); environment.remove("num_pages"); } - + sender.sendMessage(messages.toArray(new String[1])); } From ab098e0a5a8b27eac2f9e746ffdfce48c179d84c Mon Sep 17 00:00:00 2001 From: totemo Date: Sun, 15 Nov 2015 13:01:06 +1030 Subject: [PATCH 05/10] Switch README to Markdown format. --- README => README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename README => README.md (100%) diff --git a/README b/README.md similarity index 100% rename from README rename to README.md From b51aa72f8170e0b95ad6417f0ab3a91009b8f427 Mon Sep 17 00:00:00 2001 From: totemo Date: Sun, 15 Nov 2015 14:05:55 +1030 Subject: [PATCH 06/10] More detailed documentation and better formatting. --- README.md | 113 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 97 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index d87998e..f9b679c 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,97 @@ -/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) +ModReq +====== +Overview +-------- +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. + + +Commands +-------- +Note: In the discussion that follows, `#` signifies an number. + +### `/modreq` + +`/modreq ` + * Make a request. The coordinates of the player making the request are saved by the command. + +### `/check` + +`/check #` + * Retrieve a full description of the request with the specified number. + +`/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` + +`/tp-id #` + * A staff-only command to teleport to the location of a request. + +### `/claim` + +`/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` + +`/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. + +### `/done` + +`/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. + * Typical setups will grant non-staff players the `modreq.done` permission so that they can cancel their own requests using this command. + +### `/reopen` + +`/reopen #` + * Reopen a closed request. + * The request changes to the OPEN state. + +### `/elevate` + +`/elevate #` + * Mark the request as requiring handling by an Admin. + +### `/tpinfo` or `/tpi` + +`/tpi #` +`/tpinfo #` + * 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 #`. + +### `/tpc` + +`/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 #`. + +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. + * `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). From f3d75d720ddb39e1e083e3f4a9dfc1cce55a80cb Mon Sep 17 00:00:00 2001 From: totemo Date: Sun, 15 Nov 2015 14:12:34 +1030 Subject: [PATCH 07/10] Better formatting. --- README.md | 32 +++++--------------------------- 1 file changed, 5 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index f9b679c..6ce8aec 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,22 @@ ModReq ====== -Overview --------- -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. +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. +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 an number. -### `/modreq` - `/modreq ` * Make a request. The coordinates of the player making the request are saved by the command. -### `/check` - `/check #` * Retrieve a full description of the request with the specified number. @@ -33,56 +27,40 @@ Note: In the discussion that follows, `#` signifies an number. * `--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` - -`/tp-id #` +`/tp-id #` or `/tpid #` * A staff-only command to teleport to the location of a request. -### `/claim` - `/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` - `/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. -### `/done` - `/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. * Typical setups will grant non-staff players the `modreq.done` permission so that they can cancel their own requests using this command. -### `/reopen` - `/reopen #` * Reopen a closed request. * The request changes to the OPEN state. -### `/elevate` - `/elevate #` * Mark the request as requiring handling by an Admin. -### `/tpinfo` or `/tpi` - -`/tpi #` -`/tpinfo #` +`/tpi #` or `/tpinfo #` * 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 #`. -### `/tpc` - `/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 #`. + Permissions ----------- * `modreq.request` - Permission to submit a request (defaults to true). From 45df9e97c00506edc5d0c10981570910e5e6f4df Mon Sep 17 00:00:00 2001 From: totemo Date: Mon, 16 Nov 2015 05:34:31 +1030 Subject: [PATCH 08/10] Major refactoring, bug fixes, enhancements and improved documentation. * Most commands now support "-" instead of a request number, to signify the request most recently claimed by the staff member, e.g. "/tpi -". * Each staff member's most recently claimed request number is remembered across restarts with a file. * Factored out duplicated code for concatenating arguments into strings. * Factored out duplicated code for looking up the request by number and handling errors related to that. * Fixed numerous NullPointerExceptions in version 1.6. Examples include: anywhere that a non-existent request is referenced, e.g. /check 99999 or /reopen 99999, and incorrect handling in certain states, e.g. if request 123 is open and not claimed, /unclaim 123 will NPE. * Added new error messages for /mr-note. * Corrected documentation of the modreq.done permission. * Added documentation on the use of "-" instead of an explicit request number. --- README.md | 34 +- config.yml | 2 + src/nu/nerd/modreq/Configuration.java | 4 + src/nu/nerd/modreq/ModReq.java | 759 +++++++++++++++----------- 4 files changed, 463 insertions(+), 336 deletions(-) diff --git a/README.md b/README.md index 6ce8aec..b99e138 100644 --- a/README.md +++ b/README.md @@ -14,12 +14,17 @@ Commands -------- Note: In the discussion that follows, `#` signifies an 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. @@ -29,6 +34,7 @@ Note: In the discussion that follows, `#` signifies an number. `/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. @@ -37,22 +43,27 @@ Note: In the discussion that follows, `#` signifies an number. `/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. - * Typical setups will grant non-staff players the `modreq.done` permission so that they can cancel their own requests using this command. + * `/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. -`/tpi #` or `/tpinfo #` +`/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. @@ -60,6 +71,23 @@ Note: In the discussion that follows, `#` signifies an number. * 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 ----------- @@ -67,7 +95,7 @@ Permissions * `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. + * `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. diff --git a/config.yml b/config.yml index 63d5eaf..1961299 100644 --- a/config.yml +++ b/config.yml @@ -39,6 +39,8 @@ messages: 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" diff --git a/src/nu/nerd/modreq/Configuration.java b/src/nu/nerd/modreq/Configuration.java index e3779d0..c6cce2a 100644 --- a/src/nu/nerd/modreq/Configuration.java +++ b/src/nu/nerd/modreq/Configuration.java @@ -43,6 +43,8 @@ public class Configuration { 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; @@ -93,6 +95,8 @@ public void load() { 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); diff --git a/src/nu/nerd/modreq/ModReq.java b/src/nu/nerd/modreq/ModReq.java index 99af4a7..b5cfaa7 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,6 +49,18 @@ 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; @@ -57,6 +75,9 @@ public void onEnable() { 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() { @@ -272,34 +293,7 @@ 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")) { check(sender, senderUUID, args); @@ -308,13 +302,13 @@ else if (command.getName().equalsIgnoreCase("tp-id")) { if (args.length == 0) { return false; } - tpId(sender, player, args); + tpId(sender, senderUUID, player, args); } else if (command.getName().equalsIgnoreCase("tpinfo")) { if (args.length == 0) { return false; } - tpId(sender, player, args); + tpId(sender, senderUUID, player, args); check(sender, senderUUID, args); } else if (command.getName().equalsIgnoreCase("tpc")) { @@ -322,7 +316,7 @@ else if (command.getName().equalsIgnoreCase("tpc")) { return false; } if (claim(sender, senderName, senderUUID, args)) { - tpId(sender, player, args); + tpId(sender, senderUUID, player, args); check(sender, senderUUID, args); } } @@ -336,173 +330,24 @@ 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) { - environment.put("mod", senderName); - environment.put("request_id", String.valueOf(requestId)); - messageMods(config.MOD__COMPLETED); - environment.remove("request_id"); - environment.remove("mod"); - - if (doneMessage != null && doneMessage.length() != 0) { - 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(); @@ -514,108 +359,40 @@ 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; - } - - if (args[0].equalsIgnoreCase("remove")) { - - //kind of hacky but works - int idToRemove; - - try { - idToRemove = Integer.parseInt(args[2]); - } catch (NumberFormatException e) { - return false; - } - - List notes = noteTable.getRequestNotes(request); - - Note noteToRemove = notes.get(idToRemove - 1); - if(noteToRemove == null) { - return false; - } - - 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; - } - - StringBuilder noteBody = new StringBuilder(args[2]); - for (int i = 3; i < args.length; i++) { - noteBody.append(" ").append(args[i]); - } - - 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("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 -// } -// -// 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 -// } -// -// getDatabase().externalModification(name, includeElevated, includeElevated, includeElevated); - - BukkitScheduler scheduler = Bukkit.getServer().getScheduler(); - scheduler.scheduleSyncDelayedTask(this, new Runnable() { - @Override - public void run() { - resetDatabase(); - } - }, 0L); - } + 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", config.MAX_REQUESTS.toString()); + 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; @@ -660,6 +437,13 @@ else if (arg.equalsIgnoreCase("--search") || arg.equalsIgnoreCase("-s")) { return; } } + else if (arg.equals("-")) { + Integer claimedId = claimedIds.get(senderUUID); + if (claimedId != null) { + requestId = claimedId; + page = 0; + } + } else { try { requestId = Integer.parseInt(arg); @@ -691,8 +475,10 @@ else if (arg.equalsIgnoreCase("--search") || arg.equalsIgnoreCase("-s")) { } } else if (requestId > 0) { Request req = reqTable.getRequest(requestId); - - if (req != null) { + if (req == null) { + sendMessage(sender, config.GENERAL__REQUEST_ERROR); + return; + } else { totalRequests = 1; if (limitUUID != null && req.getPlayerUUID().equals(limitUUID)) { requests.add(req); @@ -701,8 +487,6 @@ else if (arg.equalsIgnoreCase("--search") || arg.equalsIgnoreCase("-s")) { } else { totalRequests = 0; } - } else { - totalRequests = 0; } } @@ -735,27 +519,20 @@ else if (arg.equalsIgnoreCase("--search") || arg.equalsIgnoreCase("-s")) { } } - private void tpId(CommandSender sender, Player player, String[] args) { - 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); - } - } + private void tpId(CommandSender sender, UUID senderUUID, Player player, String[] args) { + if (!(sender instanceof Player)) { + return; } - catch (NumberFormatException ex) { - sendMessage(sender, config.GENERAL__REQUEST_NUMBER); + + 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); } /** @@ -766,42 +543,358 @@ private void tpId(CommandSender sender, Player player, String[] args) { * other player. */ private boolean claim(CommandSender sender, String senderName, UUID senderUUID, String[] args) { - int requestId = 0; - try { - requestId = Integer.parseInt(args[0]); + Request req = getRequest(sender, senderUUID, args[0], false); + if (req == null) { + return false; + } + int requestId = req.getId(); - 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"); + 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(); - if (req.getStatus() == RequestStatus.OPEN) { - req.setStatus(RequestStatus.CLAIMED); - req.setAssignedModUUID(senderUUID); - req.setAssignedMod(senderName); - reqTable.save(req); + 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"); + } + } else { + // Request closed by moderator. + environment.put("close_message", doneMessage); environment.put("mod", senderName); environment.put("request_id", String.valueOf(requestId)); - messageMods(config.MOD__REQUEST_TAKEN); - environment.remove("mod"); - environment.remove("request_id"); - 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. Succeed. - return true; + if (doneMessage.length() != 0) { + sendMessage(requestCreator, config.GENERAL__COMPLETED_MESSAGE); } else { - sendMessage(sender, config.MOD__ALREADY_CLAIMED); + sendMessage(requestCreator, config.GENERAL__COMPLETED); } + environment.remove("close_message"); + environment.remove("mod"); + environment.remove("request_id"); } } + reqTable.save(req); + } + } + + private void reopen(CommandSender sender, UUID senderUUID, String[] args) { + Request req = getRequest(sender, senderUUID, args[0], true); + if (req == null) { + return; } - catch (NumberFormatException ex) { + + 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_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); + + BukkitScheduler scheduler = Bukkit.getServer().getScheduler(); + scheduler.scheduleSyncDelayedTask(this, new Runnable() { + @Override + public void run() { + resetDatabase(); + } + }, 0L); + } + + /** + * 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; } - return false; + + 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) { From 26910d271e51c6c1a16e0fb65901697bbf2555c1 Mon Sep 17 00:00:00 2001 From: totemo Date: Mon, 16 Nov 2015 06:36:35 +1030 Subject: [PATCH 09/10] * Allow the /check page size to be configured separately from the maximum number of requests a player can have open. * Make the date/time format to be configurable and set a more reasonable default. * Documented configuration options in the README. --- README.md | 13 +++++++++- config.yml | 4 +++- src/nu/nerd/modreq/Configuration.java | 6 ++++- src/nu/nerd/modreq/ModReq.java | 34 ++++++++++++--------------- 4 files changed, 35 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index b99e138..a88a23d 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ ModReq supports two tiers of staff permissions: Moderator and Admin. Admins are Commands -------- -Note: In the discussion that follows, `#` signifies an number. +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. @@ -101,3 +101,14 @@ Permissions * `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 1961299..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}." @@ -45,3 +45,5 @@ colour: online: "&A" offline: "&C" max-requests: 5 +page-size: 5 +date-format: "MMM.d@HH:mm:ss" diff --git a/src/nu/nerd/modreq/Configuration.java b/src/nu/nerd/modreq/Configuration.java index c6cce2a..4fcca7b 100644 --- a/src/nu/nerd/modreq/Configuration.java +++ b/src/nu/nerd/modreq/Configuration.java @@ -47,7 +47,9 @@ public class Configuration { 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; @@ -100,5 +102,7 @@ public void load() { 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 b5cfaa7..6cf0739 100755 --- a/src/nu/nerd/modreq/ModReq.java +++ b/src/nu/nerd/modreq/ModReq.java @@ -388,7 +388,7 @@ private void modreq(CommandSender sender, String senderName, Player player, Stri messageMods(config.MOD__NEW_REQUEST); sendMessage(sender, config.GENERAL__REQUEST_FILED); } else { - environment.put("max_requests", config.MAX_REQUESTS.toString()); + environment.put("max_requests", Integer.toString(config.MAX_REQUESTS)); sendMessage(sender, config.GENERAL__MAX_REQUESTS); } } @@ -470,7 +470,7 @@ else if (arg.equals("-")) { requests.addAll(reqTable.getUserRequests(limitUUID)); totalRequests = requests.size(); } else { - requests.addAll(reqTable.getRequestPage(page - 1, 5, includeElevated, searchTerm, RequestStatus.OPEN, RequestStatus.CLAIMED)); + 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) { @@ -898,29 +898,25 @@ private String concatArgs(String[] args, int first) { } 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); + 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); } - return loc; } 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()); } @@ -1028,7 +1024,7 @@ private void messageRequestListToPlayer(CommandSender sender, List reqs } 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)); From 2b503633d28ca1af22e74c8df0e6833bb6b5345b Mon Sep 17 00:00:00 2001 From: totemo Date: Mon, 16 Nov 2015 06:39:23 +1030 Subject: [PATCH 10/10] Bumped the version number to 1.7. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index cae896c..11d7cd2 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 nu.nerd ModReq - 1.6 + 1.7 jar ModReq Moderator Request Sytem