From 2b57a5ef9899d85ccebdc731d2a2c9e7f2974348 Mon Sep 17 00:00:00 2001 From: Colin McDonald Date: Fri, 22 Apr 2016 21:04:15 -0400 Subject: [PATCH] Finish up punishment/grant routes, finish GET /dump, begin permission implementation --- src/main/java/net/frozenorb/apiv3/APIv3.java | 3 ++ .../frozenorb/apiv3/models/Punishment.java | 2 +- .../java/net/frozenorb/apiv3/models/User.java | 3 ++ .../net/frozenorb/apiv3/routes/GETDump.java | 48 +++++++++++++++++++ .../apiv3/routes/grants/GETGrants.java | 6 +-- .../apiv3/routes/grants/POSTUserGrant.java | 40 ++++++++++++++-- .../routes/punishments/DELETEPunishment.java | 17 +++++++ .../routes/punishments/GETPunishments.java | 6 +-- .../routes/punishments/POSTUserPunish.java | 33 ++++++++++++- .../apiv3/weirdStuff/ErrorUtils.java | 8 +++- .../apiv3/weirdStuff/Permissions.java | 4 ++ 11 files changed, 156 insertions(+), 14 deletions(-) create mode 100644 src/main/java/net/frozenorb/apiv3/routes/GETDump.java diff --git a/src/main/java/net/frozenorb/apiv3/APIv3.java b/src/main/java/net/frozenorb/apiv3/APIv3.java index 3bec6ad..8c85108 100644 --- a/src/main/java/net/frozenorb/apiv3/APIv3.java +++ b/src/main/java/net/frozenorb/apiv3/APIv3.java @@ -8,6 +8,7 @@ import com.mongodb.MongoCredential; import com.mongodb.ServerAddress; import lombok.Getter; import net.frozenorb.apiv3.models.ServerGroup; +import net.frozenorb.apiv3.routes.GETDump; import net.frozenorb.apiv3.routes.announcements.GETAnnouncements; import net.frozenorb.apiv3.routes.chatFilterList.GETChatFilterList; import net.frozenorb.apiv3.routes.grants.DELETEGrant; @@ -81,6 +82,8 @@ public final class APIv3 { get("/users", new GETUsers(), gson::toJson); get("/staff", new GETStaff(), gson::toJson); + get("/dump/:type", new GETDump(), gson::toJson); + after(new ContentTypeFilter()); } diff --git a/src/main/java/net/frozenorb/apiv3/models/Punishment.java b/src/main/java/net/frozenorb/apiv3/models/Punishment.java index c3c8ff8..1d5a34a 100644 --- a/src/main/java/net/frozenorb/apiv3/models/Punishment.java +++ b/src/main/java/net/frozenorb/apiv3/models/Punishment.java @@ -68,7 +68,7 @@ public final class Punishment { public enum PunishmentType { - BAN, MUTE, WARN + BLACKLIST, BAN, MUTE, WARN } diff --git a/src/main/java/net/frozenorb/apiv3/models/User.java b/src/main/java/net/frozenorb/apiv3/models/User.java index ead4320..97594f2 100644 --- a/src/main/java/net/frozenorb/apiv3/models/User.java +++ b/src/main/java/net/frozenorb/apiv3/models/User.java @@ -30,6 +30,9 @@ public final class User { return APIv3.getDatastore().createQuery(User.class).field("id").equal(id).get(); } + // TODO: FIND ALL USAGES OF THIS AND + // SEE HOW MANY OF THEM (EX NON GET REQUESTS) + // WE CAN DROP public static User byIdOrName(String idOrName) { if (idOrName.length() == 36) { return byId(UUID.fromString(idOrName)); diff --git a/src/main/java/net/frozenorb/apiv3/routes/GETDump.java b/src/main/java/net/frozenorb/apiv3/routes/GETDump.java new file mode 100644 index 0000000..e3a64ec --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/routes/GETDump.java @@ -0,0 +1,48 @@ +package net.frozenorb.apiv3.routes; + +import net.frozenorb.apiv3.APIv3; +import net.frozenorb.apiv3.models.Grant; +import net.frozenorb.apiv3.models.Punishment; +import net.frozenorb.apiv3.weirdStuff.ErrorUtils; +import spark.Request; +import spark.Response; +import spark.Route; + +import java.util.ArrayList; +import java.util.List; + +public final class GETDump implements Route { + + public Object handle(Request req, Response res) { + String type = req.params("type"); + + switch (type.toLowerCase()) { + case "blacklist": + case "ban": + case "mute": + case "warn": + List activePunishments = new ArrayList<>(); + + APIv3.getDatastore().createQuery(Punishment.class).field("type").equal(type.toUpperCase()).forEach((punishment) -> { + if (punishment.isActive()) { + activePunishments.add(punishment); + } + }); + + return activePunishments; + case "grant": + List activeGrants = new ArrayList<>(); + + APIv3.getDatastore().createQuery(Grant.class).forEach((grant) -> { + if (grant.isActive()) { + activeGrants.add(grant); + } + }); + + return activeGrants; + default: + return ErrorUtils.invalidInput(type + " is not a valid type. Not in [blacklist, ban, mute, warn, grant]"); + } + } + +} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/grants/GETGrants.java b/src/main/java/net/frozenorb/apiv3/routes/grants/GETGrants.java index afa0514..33a03c0 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/grants/GETGrants.java +++ b/src/main/java/net/frozenorb/apiv3/routes/grants/GETGrants.java @@ -9,10 +9,10 @@ import spark.Route; public final class GETGrants implements Route { public Object handle(Request req, Response res) { - int limit = Integer.parseInt(req.queryParams("limit")); - int offset = Integer.parseInt(req.queryParams("offset")); + int limit = req.queryParams("limit") == null ? 100 : Integer.parseInt(req.queryParams("limit")); + int offset = req.queryParams("offset") == null ? 0 : Integer.parseInt(req.queryParams("offset")); - return APIv3.getDatastore().createQuery(Grant.class).limit(limit).offset(offset).asList(); + return APIv3.getDatastore().createQuery(Grant.class).order("addedAt").limit(limit).offset(offset).asList(); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/grants/POSTUserGrant.java b/src/main/java/net/frozenorb/apiv3/routes/grants/POSTUserGrant.java index 6ca7c98..9bfe926 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/grants/POSTUserGrant.java +++ b/src/main/java/net/frozenorb/apiv3/routes/grants/POSTUserGrant.java @@ -3,26 +3,60 @@ package net.frozenorb.apiv3.routes.grants; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.Grant; import net.frozenorb.apiv3.models.Rank; +import net.frozenorb.apiv3.models.ServerGroup; import net.frozenorb.apiv3.models.User; +import net.frozenorb.apiv3.weirdStuff.ErrorUtils; +import net.frozenorb.apiv3.weirdStuff.Permissions; import spark.Request; import spark.Response; import spark.Route; -import java.util.*; +import java.util.Date; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; public final class POSTUserGrant implements Route { public Object handle(Request req, Response res) { User target = User.byIdOrName(req.params("id")); + + if (target == null) { + return ErrorUtils.notFound("User", req.params("id")); + } + String reason = req.queryParams("reason"); - Set scopes = new HashSet<>(Arrays.asList(req.queryParams("scopes").split(","))); + + if (reason.trim().isEmpty()) { + return ErrorUtils.invalidInput("A reason must be provided."); + } + + Set scopes = new HashSet<>(/*Arrays.asList(req.queryParams("scopes").split(","))*/); + // TODO + Rank rank = Rank.byId(req.queryParams("rank")); + + if (rank == null) { + return ErrorUtils.notFound("Rank", req.queryParams("rank")); + } + Date expiresAt = new Date(Long.parseLong(req.queryParams("expiresAt"))); + + if (expiresAt.before(new Date())) { + return ErrorUtils.invalidInput("Expiration date cannot be in the past."); + } + User addedBy = User.byId(UUID.fromString(req.queryParams("addedBy"))); + String requiredPermission = Permissions.CREATE_GRANT + "." + rank.getId(); + + if (addedBy == null) { + return ErrorUtils.notFound("User", req.queryParams("addedBy")); + } else if (!addedBy.hasPermissionAnywhere(requiredPermission)) { + return ErrorUtils.unauthorized(requiredPermission); + } Grant grant = new Grant(target, reason, scopes, rank, expiresAt, addedBy); APIv3.getDatastore().save(grant); return grant; } - } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/punishments/DELETEPunishment.java b/src/main/java/net/frozenorb/apiv3/routes/punishments/DELETEPunishment.java index 10299ca..48c0055 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/punishments/DELETEPunishment.java +++ b/src/main/java/net/frozenorb/apiv3/routes/punishments/DELETEPunishment.java @@ -3,6 +3,8 @@ package net.frozenorb.apiv3.routes.punishments; import net.frozenorb.apiv3.models.Punishment; import net.frozenorb.apiv3.models.User; import net.frozenorb.apiv3.weirdStuff.AuditLog; +import net.frozenorb.apiv3.weirdStuff.ErrorUtils; +import net.frozenorb.apiv3.weirdStuff.Permissions; import org.bson.Document; import spark.Request; import spark.Response; @@ -14,7 +16,22 @@ public final class DELETEPunishment implements Route { public Object handle(Request req, Response res) { Punishment punishment = Punishment.byId(req.params("id")); + + if (punishment == null) { + return ErrorUtils.notFound("Punishment", req.params("id")); + } else if (!punishment.isActive()) { + return ErrorUtils.error("Cannot remove an inactive punishment."); + } + User removedBy = User.byId(UUID.fromString(req.queryParams("removedBy"))); + String requiredPermission = Permissions.REMOVE_PUNISHMENT + "." + punishment.getType().name(); + + if (removedBy == null) { + return ErrorUtils.notFound("User", req.queryParams("removedBy")); + } else if (!removedBy.hasPermissionAnywhere(requiredPermission)) { + return ErrorUtils.unauthorized(requiredPermission); + } + String removedByIp = req.queryParams("removedByIp"); String reason = req.queryParams("removalReason"); diff --git a/src/main/java/net/frozenorb/apiv3/routes/punishments/GETPunishments.java b/src/main/java/net/frozenorb/apiv3/routes/punishments/GETPunishments.java index b4f4e07..54b6390 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/punishments/GETPunishments.java +++ b/src/main/java/net/frozenorb/apiv3/routes/punishments/GETPunishments.java @@ -9,10 +9,10 @@ import spark.Route; public final class GETPunishments implements Route { public Object handle(Request req, Response res) { - int limit = Integer.parseInt(req.queryParams("limit")); - int offset = Integer.parseInt(req.queryParams("offset")); + int limit = req.queryParams("limit") == null ? 100 : Integer.parseInt(req.queryParams("limit")); + int offset = req.queryParams("offset") == null ? 0 : Integer.parseInt(req.queryParams("offset")); - return APIv3.getDatastore().createQuery(Punishment.class).limit(limit).offset(offset).asList(); + return APIv3.getDatastore().createQuery(Punishment.class).order("addedAt").limit(limit).offset(offset).asList(); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/punishments/POSTUserPunish.java b/src/main/java/net/frozenorb/apiv3/routes/punishments/POSTUserPunish.java index 16e34e3..90885dd 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/punishments/POSTUserPunish.java +++ b/src/main/java/net/frozenorb/apiv3/routes/punishments/POSTUserPunish.java @@ -4,6 +4,8 @@ import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.Punishment; import net.frozenorb.apiv3.models.Server; import net.frozenorb.apiv3.models.User; +import net.frozenorb.apiv3.weirdStuff.ErrorUtils; +import net.frozenorb.apiv3.weirdStuff.Permissions; import spark.Request; import spark.Response; import spark.Route; @@ -15,13 +17,40 @@ public final class POSTUserPunish implements Route { public Object handle(Request req, Response res) { User target = User.byIdOrName(req.params("id")); + + if (target == null) { + return ErrorUtils.notFound("User", req.params("id")); + } + String reason = req.queryParams("reason"); + + if (reason.trim().isEmpty()) { + return ErrorUtils.invalidInput("A reason must be provided."); + } + Punishment.PunishmentType type = Punishment.PunishmentType.valueOf(req.queryParams("type")); Date expiresAt = new Date(Long.parseLong(req.queryParams("expiresAt"))); - User createdBy = User.byId(UUID.fromString(req.queryParams("createdBy"))); + + if (expiresAt.before(new Date())) { + return ErrorUtils.invalidInput("Expiration date cannot be in the past."); + } + + User addedBy = User.byId(UUID.fromString(req.queryParams("addedBy"))); + String requiredPermission = Permissions.CREATE_PUNISHMENT + "." + type.name(); + + if (addedBy == null) { + return ErrorUtils.notFound("User", req.queryParams("addedBy")); + } else if (!addedBy.hasPermissionAnywhere(requiredPermission)) { + return ErrorUtils.unauthorized(requiredPermission); + } + Server addedOn = Server.byId(req.queryParams("addedOn")); - Punishment punishment = new Punishment(target, reason, type, expiresAt, createdBy, addedOn); + if (addedOn == null) { + return ErrorUtils.notFound("Server", req.queryParams("addedOn")); + } + + Punishment punishment = new Punishment(target, reason, type, expiresAt, addedBy, addedOn); APIv3.getDatastore().save(punishment); return punishment; } diff --git a/src/main/java/net/frozenorb/apiv3/weirdStuff/ErrorUtils.java b/src/main/java/net/frozenorb/apiv3/weirdStuff/ErrorUtils.java index da8d851..e4d7488 100644 --- a/src/main/java/net/frozenorb/apiv3/weirdStuff/ErrorUtils.java +++ b/src/main/java/net/frozenorb/apiv3/weirdStuff/ErrorUtils.java @@ -7,11 +7,15 @@ import org.bson.Document; public class ErrorUtils { public static Document notFound(String itemType, String id) { - return error(itemType + " with id " + id + " cannot be found."); + return error("Not found: " + itemType + " with id " + id + " cannot be found."); } public static Document unauthorized(String permission) { - return error("Unauthorized access. Permission \"" + permission + "\" required."); + return error("Unauthorized access: Permission \"" + permission + "\" required."); + } + + public static Document invalidInput(String reason) { + return error("Invalid input: " + reason); } public static Document error(String reason) { diff --git a/src/main/java/net/frozenorb/apiv3/weirdStuff/Permissions.java b/src/main/java/net/frozenorb/apiv3/weirdStuff/Permissions.java index 269f290..4ab99c3 100644 --- a/src/main/java/net/frozenorb/apiv3/weirdStuff/Permissions.java +++ b/src/main/java/net/frozenorb/apiv3/weirdStuff/Permissions.java @@ -6,5 +6,9 @@ import lombok.experimental.UtilityClass; public class Permissions { public static final String REMOVE_GRANT = "minehq.grant.remove"; // minehq.grant.remove.%RANK% + public static final String CREATE_GRANT = "minehq.grant.create"; // minehq.grant.create.%RANK% + + public static final String REMOVE_PUNISHMENT = "minehq.punishment.remove"; // minehq.punishment.remove.%TYPE% + public static final String CREATE_PUNISHMENT = "minehq.punishment.create"; // minehq.punishment.remove.%TYPE% } \ No newline at end of file