From 60a622fc43c579df17fce19f7e928caa7589c0c4 Mon Sep 17 00:00:00 2001 From: Colin McDonald Date: Thu, 9 Jun 2016 22:39:23 -0400 Subject: [PATCH] Push a bunch of experimental code (this doesn't currently work/compile) --- apiv3.properties | 2 - pom.xml | 88 +++--- src/main/java/net/frozenorb/apiv3/APIv3.java | 261 +++++++++--------- src/main/java/net/frozenorb/apiv3/Main.java | 4 +- .../net/frozenorb/apiv3/actors/UserActor.java | 2 +- .../frozenorb/apiv3/auditLog/AuditLog.java | 3 +- .../apiv3/filters/ActorAttributeFilter.java | 57 ++-- .../apiv3/filters/AuthorizationFilter.java | 16 +- .../apiv3/filters/ContentTypeFilter.java | 13 - .../apiv3/filters/LoggingFilter.java | 21 -- .../apiv3/filters/MetricsAfterFilter.java | 16 -- .../apiv3/filters/MetricsBeforeFilter.java | 13 - .../apiv3/filters/MetricsHandler.java | 14 + .../frozenorb/apiv3/models/AuditLogEntry.java | 42 ++- .../net/frozenorb/apiv3/models/Grant.java | 75 ++--- .../frozenorb/apiv3/models/IPLogEntry.java | 52 +++- .../apiv3/models/NotificationTemplate.java | 58 ++-- .../frozenorb/apiv3/models/Punishment.java | 85 +++--- .../java/net/frozenorb/apiv3/models/Rank.java | 56 ++-- .../net/frozenorb/apiv3/models/Server.java | 60 ++-- .../frozenorb/apiv3/models/ServerGroup.java | 55 ++-- .../java/net/frozenorb/apiv3/models/User.java | 177 +++++------- .../frozenorb/apiv3/models/UserMetaEntry.java | 52 +++- .../net/frozenorb/apiv3/routes/GETDump.java | 22 +- .../net/frozenorb/apiv3/routes/GETWhoAmI.java | 7 +- .../net/frozenorb/apiv3/routes/NotFound.java | 17 -- .../frozenorb/apiv3/routes/POSTMetrics.java | 7 +- .../announcements/GETAnnouncements.java | 4 +- .../apiv3/routes/auditLog/GETAuditLog.java | 2 +- .../chatFilterList/GETChatFilterList.java | 3 +- .../apiv3/routes/grants/DELETEGrant.java | 6 +- .../apiv3/routes/grants/GETGrant.java | 2 +- .../apiv3/routes/grants/GETGrants.java | 2 +- .../apiv3/routes/grants/GETUserGrants.java | 5 +- .../apiv3/routes/grants/POSTUserGrant.java | 29 +- .../apiv3/routes/ipLog/GETUserIPLog.java | 5 +- .../DELETENotificationTemplate.java | 4 +- .../GETNotificationTemplate.java | 2 +- .../GETNotificationTemplates.java | 2 +- .../POSTNotificationTemplate.java | 4 +- .../routes/punishments/DELETEPunishment.java | 21 +- .../routes/punishments/GETPunishment.java | 5 +- .../routes/punishments/GETPunishments.java | 6 +- .../punishments/GETUserPunishments.java | 11 +- .../routes/punishments/POSTUserPunish.java | 34 ++- .../apiv3/routes/ranks/DELETERank.java | 10 +- .../frozenorb/apiv3/routes/ranks/GETRank.java | 5 +- .../apiv3/routes/ranks/GETRanks.java | 5 +- .../apiv3/routes/ranks/POSTRank.java | 6 +- .../serverGroups/DELETEServerGroup.java | 10 +- .../routes/serverGroups/GETServerGroup.java | 5 +- .../routes/serverGroups/GETServerGroups.java | 5 +- .../routes/serverGroups/POSTServerGroup.java | 6 +- .../apiv3/routes/servers/DELETEServer.java | 10 +- .../apiv3/routes/servers/GETServer.java | 5 +- .../apiv3/routes/servers/GETServers.java | 5 +- .../apiv3/routes/servers/POSTServer.java | 14 +- .../routes/servers/POSTServerHeartbeat.java | 23 +- .../apiv3/routes/users/DELETEUserMeta.java | 24 +- .../routes/users/DELETEUserPunishment.java | 21 +- .../apiv3/routes/users/GETStaff.java | 14 +- .../frozenorb/apiv3/routes/users/GETUser.java | 5 +- .../apiv3/routes/users/GETUserDetails.java | 22 +- .../apiv3/routes/users/GETUserMeta.java | 17 +- .../routes/users/GETUserRequiresTOTP.java | 30 +- .../routes/users/GETUserVerifyPassword.java | 15 +- .../routes/users/POSTUserConfirmRegister.java | 25 +- .../apiv3/routes/users/POSTUserLeave.java | 17 +- .../apiv3/routes/users/POSTUserLogin.java | 18 +- .../apiv3/routes/users/POSTUserNotify.java | 27 +- .../apiv3/routes/users/POSTUserRegister.java | 26 +- .../apiv3/routes/users/POSTUserSetupTOTP.java | 16 +- .../routes/users/POSTUserVerifyTOTP.java | 27 +- .../apiv3/routes/users/PUTUserMeta.java | 17 +- .../apiv3/unsorted/BlockingCallback.java | 29 ++ .../unsorted/LoggingExceptionHandler.java | 27 -- .../net/frozenorb/apiv3/utils/ErrorUtils.java | 13 +- .../frozenorb/apiv3/utils/MojangUtils.java | 47 ++-- .../apiv3/utils/PermissionUtils.java | 2 +- .../net/frozenorb/apiv3/utils/SyncUtils.java | 27 ++ 80 files changed, 1156 insertions(+), 841 deletions(-) delete mode 100644 src/main/java/net/frozenorb/apiv3/filters/ContentTypeFilter.java delete mode 100644 src/main/java/net/frozenorb/apiv3/filters/LoggingFilter.java delete mode 100644 src/main/java/net/frozenorb/apiv3/filters/MetricsAfterFilter.java delete mode 100644 src/main/java/net/frozenorb/apiv3/filters/MetricsBeforeFilter.java create mode 100644 src/main/java/net/frozenorb/apiv3/filters/MetricsHandler.java delete mode 100644 src/main/java/net/frozenorb/apiv3/routes/NotFound.java create mode 100644 src/main/java/net/frozenorb/apiv3/unsorted/BlockingCallback.java delete mode 100644 src/main/java/net/frozenorb/apiv3/unsorted/LoggingExceptionHandler.java create mode 100644 src/main/java/net/frozenorb/apiv3/utils/SyncUtils.java diff --git a/apiv3.properties b/apiv3.properties index 18a9727..e307d26 100644 --- a/apiv3.properties +++ b/apiv3.properties @@ -8,9 +8,7 @@ mongo.username= mongo.password= redis.address=localhost redis.port=6379 -http.address=0.0.0.0 http.port=80 -http.workerThreads= twillio.accountSID=AC9e2f88c5690134d29a56f698de3cd740 twillio.authToken=982592505a171d3be6b0722f5ecacc0e mandrill.apiKey=0OYtwymqJP6oqvszeJu0vQ diff --git a/pom.xml b/pom.xml index e8340c0..2ce866f 100644 --- a/pom.xml +++ b/pom.xml @@ -58,6 +58,7 @@ + io.vertx vertx-core @@ -68,36 +69,39 @@ vertx-web LATEST + + com.google.guava guava 19.0 - - redis.clients - jedis - 2.8.1 - com.google.code.gson gson 2.6.2 - - com.indeed - java-dogstatsd-client - 2.0.12 - - - com.bugsnag - bugsnag - 2.0.0 - + + org.mongodb - mongo-java-driver - 3.2.2 + mongodb-driver-async + 3.0.4 + + eu.dozd + mongo-mapper + 1.0.1 + + + + + redis.clients + jedis + 2.8.1 + + + com.cribbstechnologies.clients mandrillClient @@ -108,46 +112,34 @@ twilio-java-sdk 6.3.0 - - org.mindrot - jbcrypt - 0.3m - - - org.mongodb.morphia - morphia - 1.1.0 - - - org.mongodb.morphia - morphia-logging-slf4j - 1.1.0 - - - org.slf4j - slf4j-simple - 1.6.4 - - - org.apache.httpcomponents - httpcore - 4.4 - + + com.warrenstrange googleauth 0.5.0 + + - com.squareup.okhttp3 - okhttp - 3.2.0 + com.indeed + java-dogstatsd-client + 2.0.12 - com.squareup.okio - okio - 1.8.0 + com.bugsnag + bugsnag + 2.0.0 + + + + org.slf4j + slf4j-simple + 1.6.4 + + + org.projectlombok lombok diff --git a/src/main/java/net/frozenorb/apiv3/APIv3.java b/src/main/java/net/frozenorb/apiv3/APIv3.java index 41e0d09..a82c07c 100644 --- a/src/main/java/net/frozenorb/apiv3/APIv3.java +++ b/src/main/java/net/frozenorb/apiv3/APIv3.java @@ -6,23 +6,36 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import com.mongodb.*; -import com.mongodb.client.MongoDatabase; +import com.mongodb.Block; +import com.mongodb.MongoCredential; +import com.mongodb.ServerAddress; +import com.mongodb.async.client.MongoClient; +import com.mongodb.async.client.MongoClientSettings; +import com.mongodb.async.client.MongoClients; +import com.mongodb.async.client.MongoDatabase; +import com.mongodb.connection.ClusterSettings; import com.timgroup.statsd.NonBlockingStatsDClient; import com.timgroup.statsd.StatsDClient; +import eu.dozd.mongo.MongoMapper; +import io.vertx.core.AbstractVerticle; +import io.vertx.core.http.HttpClient; +import io.vertx.core.http.HttpServer; import io.vertx.ext.web.Router; import io.vertx.ext.web.RoutingContext; +import io.vertx.ext.web.handler.BodyHandler; +import io.vertx.ext.web.handler.LoggerHandler; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import net.frozenorb.apiv3.actors.ActorType; -import net.frozenorb.apiv3.filters.*; +import net.frozenorb.apiv3.filters.ActorAttributeFilter; +import net.frozenorb.apiv3.filters.AuthorizationFilter; +import net.frozenorb.apiv3.filters.MetricsHandler; import net.frozenorb.apiv3.models.Grant; import net.frozenorb.apiv3.models.IPLogEntry; import net.frozenorb.apiv3.models.Punishment; import net.frozenorb.apiv3.models.User; import net.frozenorb.apiv3.routes.GETDump; import net.frozenorb.apiv3.routes.GETWhoAmI; -import net.frozenorb.apiv3.routes.NotFound; import net.frozenorb.apiv3.routes.POSTMetrics; import net.frozenorb.apiv3.routes.announcements.GETAnnouncements; import net.frozenorb.apiv3.routes.auditLog.GETAuditLog; @@ -48,16 +61,11 @@ import net.frozenorb.apiv3.serialization.DateTypeAdapter; import net.frozenorb.apiv3.serialization.FollowAnnotationExclusionStrategy; import net.frozenorb.apiv3.serialization.ObjectIdTypeAdapter; import net.frozenorb.apiv3.unsorted.BugsnagSLF4JLogger; -import net.frozenorb.apiv3.unsorted.LoggingExceptionHandler; import net.frozenorb.apiv3.utils.IPUtils; import net.frozenorb.apiv3.utils.UUIDUtils; import org.bson.Document; +import org.bson.codecs.configuration.CodecRegistries; import org.bson.types.ObjectId; -import org.mongodb.morphia.Datastore; -import org.mongodb.morphia.Morphia; -import org.mongodb.morphia.converters.UUIDConverter; -import org.mongodb.morphia.logging.MorphiaLoggerFactory; -import org.mongodb.morphia.logging.slf4j.SLF4JLoggerImplFactory; import redis.clients.jedis.JedisPool; import java.io.FileInputStream; @@ -66,13 +74,11 @@ import java.util.*; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -import static spark.Spark.*; -import static spark.route.RouteOverview.enableRouteOverview; - @Slf4j -public final class APIv3 { +public final class APIv3 extends AbstractVerticle { - @Getter private static Datastore datastore; + @Getter private static HttpClient httpClient; + @Getter private static MongoDatabase database; @Getter private static Properties config = new Properties(); @Getter private static JedisPool redisPool; @Getter private static StatsDClient statsD; @@ -82,7 +88,8 @@ public final class APIv3 { .setExclusionStrategies(new FollowAnnotationExclusionStrategy()) .create(); - APIv3() { + @Override + public void start() { setupConfig(); System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", config.getProperty("logging.level")); @@ -90,10 +97,9 @@ public final class APIv3 { setupRedis(); setupMetrics(); setupBugsnag(); - setupHttp(); + setupHttpServer(); //convertData("158.69.126.126", true); - LoggingFilter.setDebug(Boolean.valueOf(config.getProperty("logging.debug"))); } private void setupConfig() { @@ -108,28 +114,33 @@ public final class APIv3 { ImmutableList credentials = ImmutableList.of(); if (!config.getProperty("mongo.username").isEmpty()) { - credentials = ImmutableList.of(MongoCredential.createCredential( - config.getProperty("mongo.username"), - config.getProperty("mongo.database"), - config.getProperty("mongo.password").toCharArray() - )); + credentials = ImmutableList.of( + MongoCredential.createCredential( + config.getProperty("mongo.username"), + config.getProperty("mongo.database"), + config.getProperty("mongo.password").toCharArray() + ) + ); } - MongoClient mongoClient = new MongoClient(new ServerAddress( - config.getProperty("mongo.address"), - Integer.parseInt(config.getProperty("mongo.port"))), - credentials - ); + ClusterSettings clusterSettings = ClusterSettings + .builder() + .hosts(ImmutableList.of( + new ServerAddress( + config.getProperty("mongo.address"), + Integer.parseInt(config.getProperty("mongo.port")) + ) + )) + .build(); + MongoClientSettings settings = MongoClientSettings + .builder() + .codecRegistry(CodecRegistries.fromProviders(MongoMapper.getProviders())) + .credentialList(credentials) + .clusterSettings(clusterSettings).build(); - MorphiaLoggerFactory.reset(); - MorphiaLoggerFactory.registerLogger(SLF4JLoggerImplFactory.class); - - Morphia morphia = new Morphia(); - morphia.mapPackage("net.frozenorb.apiv3.models"); - morphia.getMapper().getConverters().addConverter(new UUIDConverter()); - - datastore = morphia.createDatastore(mongoClient, config.getProperty("mongo.database")); - datastore.ensureIndexes(); + MongoClient client = MongoClients.create(settings); + database = client.getDatabase(config.getProperty("mongo.database")); + // TODO: Indexes } private void setupRedis() { @@ -160,103 +171,105 @@ public final class APIv3 { bugsnag.setLogger(new BugsnagSLF4JLogger()); } - private void setupHttp() { - Router.router() - ipAddress(config.getProperty("http.address")); - port(Integer.parseInt(config.getProperty("http.port"))); - String workerThreads = config.getProperty("http.workerThreads"); + private void setupHttpServer() { + HttpServer webServer = vertx.createHttpServer(); + Router mainRouter = Router.router(vertx); - if (!workerThreads.isEmpty()) { - threadPool(Integer.parseInt(workerThreads)); - } - - before(new MetricsBeforeFilter()); - before(new ContentTypeFilter()); - before(new ActorAttributeFilter()); - before(new AuthorizationFilter()); - after(new MetricsAfterFilter()); - after(new LoggingFilter()); - exception(Exception.class, new LoggingExceptionHandler()); + mainRouter.route().handler(new MetricsHandler()); + mainRouter.route().handler(new ActorAttributeFilter()); + mainRouter.route().handler(new AuthorizationFilter()); + mainRouter.route().handler(LoggerHandler.create()); + mainRouter.route().handler(BodyHandler.create()); // TODO: The commented out routes - post("/metrics", new POSTMetrics(), gson::toJson); - get("/announcements", new GETAnnouncements(), gson::toJson); - get("/auditLog", new GETAuditLog(), gson::toJson); - get("/chatFilterList", new GETChatFilterList(), gson::toJson); - get("/dump/:type", new GETDump(), gson::toJson); - get("/whoami", new GETWhoAmI(), gson::toJson); - enableRouteOverview("/routes"); + mainRouter.post("/metrics").blockingHandler(new POSTMetrics()); + mainRouter.get("/announcements").blockingHandler(new GETAnnouncements()); + mainRouter.get("/auditLog").blockingHandler(new GETAuditLog()); + mainRouter.get("/chatFilterList").blockingHandler(new GETChatFilterList()); + mainRouter.get("/dump/:type").blockingHandler(new GETDump()); + mainRouter.get("/whoami").blockingHandler(new GETWhoAmI()); - get("/grant/:id", new GETGrant(), gson::toJson); - get("/grants", new GETGrants(), gson::toJson); - delete("/grant/:id", new DELETEGrant(), gson::toJson); + mainRouter.get("/grant/:id").blockingHandler(new GETGrant()); + mainRouter.get("/grants").blockingHandler(new GETGrants()); + mainRouter.delete("/grant/:id").blockingHandler(new DELETEGrant()); - get("/notificationTemplate/:id", new GETNotificationTemplate(), gson::toJson); - get("/notificationTemplates", new GETNotificationTemplates(), gson::toJson); - post("/notificationTemplate", new POSTNotificationTemplate(), gson::toJson); - //put("/notificationTemplate/:id", new PUTNotificationTemplate(), gson::toJson); - delete("/notificationTemplate/:id", new DELETENotificationTemplate(), gson::toJson); + mainRouter.get("/notificationTemplate/:id").blockingHandler(new GETNotificationTemplate()); + mainRouter.get("/notificationTemplates").blockingHandler(new GETNotificationTemplates()); + mainRouter.post("/notificationTemplate").blockingHandler(new POSTNotificationTemplate()); + //mainRouter.put("/notificationTemplate/:id").blockingHandler(new PUTNotificationTemplate()); + mainRouter.delete("/notificationTemplate/:id").blockingHandler(new DELETENotificationTemplate()); - get("/punishment/:id", new GETPunishment(), gson::toJson); - get("/punishments", new GETPunishments(), gson::toJson); - delete("/punishment/:id", new DELETEPunishment(), gson::toJson); + mainRouter.get("/punishment/:id").blockingHandler(new GETPunishment()); + mainRouter.get("/punishments").blockingHandler(new GETPunishments()); + mainRouter.delete("/punishment/:id").blockingHandler(new DELETEPunishment()); - get("/rank/:id", new GETRank(), gson::toJson); - get("/ranks", new GETRanks(), gson::toJson); - post("/rank", new POSTRank(), gson::toJson); - //put("/rank/:id", new PUTRank(), gson::toJson); - delete("/rank/:id", new DELETERank(), gson::toJson); + mainRouter.get("/rank/:id").blockingHandler(new GETRank()); + mainRouter.get("/ranks").blockingHandler(new GETRanks()); + mainRouter.post("/rank").blockingHandler(new POSTRank()); + //put("/rank/:id").blockingHandler(new PUTRank()); + mainRouter.delete("/rank/:id").blockingHandler(new DELETERank()); - get("/serverGroup/:id", new GETServerGroup(), gson::toJson); - get("/serverGroups", new GETServerGroups(), gson::toJson); - post("/serverGroup", new POSTServerGroup(), gson::toJson); - //put("/serverGroup/:id", new PUTServerGroup(), gson::toJson); - delete("/serverGroup/:id", new DELETEServerGroup(), gson::toJson); + mainRouter.get("/serverGroup/:id").blockingHandler(new GETServerGroup()); + mainRouter.get("/serverGroups").blockingHandler(new GETServerGroups()); + mainRouter.post("/serverGroup").blockingHandler(new POSTServerGroup()); + //put("/serverGroup/:id").blockingHandler(new PUTServerGroup()); + mainRouter.delete("/serverGroup/:id").blockingHandler(new DELETEServerGroup()); - get("/server/:id", new GETServer(), gson::toJson); - get("/servers", new GETServers(), gson::toJson); - post("/server/heartbeat", new POSTServerHeartbeat(), gson::toJson); - post("/server", new POSTServer(), gson::toJson); - //put("/server/:id", new PUTServer(), gson::toJson); - delete("/server/:id", new DELETEServer(), gson::toJson); + mainRouter.get("/server/:id").blockingHandler(new GETServer()); + mainRouter.get("/servers").blockingHandler(new GETServers()); + mainRouter.post("/server/heartbeat").blockingHandler(new POSTServerHeartbeat()); + mainRouter.post("/server").blockingHandler(new POSTServer()); + //put("/server/:id").blockingHandler(new PUTServer()); + mainRouter.delete("/server/:id").blockingHandler(new DELETEServer()); - get("/staff", new GETStaff(), gson::toJson); - get("/user/:id/details", new GETUserDetails(), gson::toJson); - get("/user/:id/meta/:serverGroup", new GETUserMeta(), gson::toJson); - get("/user/:id/grants", new GETUserGrants(), gson::toJson); - get("/user/:id/punishments", new GETUserPunishments(), gson::toJson); - get("/user/:id/ipLog", new GETUserIPLog(), gson::toJson); - get("/user/:id/requiresTOTP", new GETUserRequiresTOTP(), gson::toJson); - get("/user/:id/verifyPassword", new GETUserVerifyPassword(), gson::toJson); - get("/user/:id", new GETUser(), gson::toJson); - post("/user/:id/verifyTOTP", new POSTUserVerifyTOTP(), gson::toJson); - post("/user/:id/grant", new POSTUserGrant(), gson::toJson); - post("/user/:id/punish", new POSTUserPunish(), gson::toJson); - post("/user/:id/login", new POSTUserLogin(), gson::toJson); - post("/user/:id/leave", new POSTUserLeave(), gson::toJson); - post("/user/:id/notify", new POSTUserNotify(), gson::toJson); - post("/user/:id/register", new POSTUserRegister(), gson::toJson); - post("/user/:id/setupTOTP", new POSTUserSetupTOTP(), gson::toJson); - post("/user/confirmRegister/:emailToken", new POSTUserConfirmRegister(), gson::toJson); - put("/user/:id/meta/:serverGroup", new PUTUserMeta(), gson::toJson); - delete("/user/:id/meta/:serverGroup", new DELETEUserMeta(), gson::toJson); - delete("/user/:id/punishment", new DELETEUserPunishment(), gson::toJson); + mainRouter.get("/staff").blockingHandler(new GETStaff()); + mainRouter.get("/user/:id/details").blockingHandler(new GETUserDetails()); + mainRouter.get("/user/:id/meta/:serverGroup").blockingHandler(new GETUserMeta()); + mainRouter.get("/user/:id/grants").blockingHandler(new GETUserGrants()); + mainRouter.get("/user/:id/punishments").blockingHandler(new GETUserPunishments()); + mainRouter.get("/user/:id/ipLog").blockingHandler(new GETUserIPLog()); + mainRouter.get("/user/:id/requiresTOTP").blockingHandler(new GETUserRequiresTOTP()); + mainRouter.get("/user/:id/verifyPassword").blockingHandler(new GETUserVerifyPassword()); + mainRouter.get("/user/:id").blockingHandler(new GETUser()); + mainRouter.post("/user/:id/verifyTOTP").blockingHandler(new POSTUserVerifyTOTP()); + mainRouter.post("/user/:id/grant").blockingHandler(new POSTUserGrant()); + mainRouter.post("/user/:id/punish").blockingHandler(new POSTUserPunish()); + mainRouter.post("/user/:id/login").blockingHandler(new POSTUserLogin()); + mainRouter.post("/user/:id/leave").blockingHandler(new POSTUserLeave()); + mainRouter.post("/user/:id/notify").blockingHandler(new POSTUserNotify()); + mainRouter.post("/user/:id/register").blockingHandler(new POSTUserRegister()); + mainRouter.post("/user/:id/setupTOTP").blockingHandler(new POSTUserSetupTOTP()); + mainRouter.post("/user/confirmRegister/:emailToken").blockingHandler(new POSTUserConfirmRegister()); + mainRouter.put("/user/:id/meta/:serverGroup").blockingHandler(new PUTUserMeta()); + mainRouter.delete("/user/:id/meta/:serverGroup").blockingHandler(new DELETEUserMeta()); + mainRouter.delete("/user/:id/punishment").blockingHandler(new DELETEUserPunishment()); - // There's no way to do a JSON 404 page w/o doing this :( - get("/*", new NotFound(), gson::toJson); - post("/*", new NotFound(), gson::toJson); - put("/*", new NotFound(), gson::toJson); - delete("/*", new NotFound(), gson::toJson); + mainRouter.getRoutes().forEach((route) -> { + System.out.println(route.getClass() + "||" + route.getPath()); + }); + + int port = Integer.parseInt(config.getProperty("http.port")); + webServer.requestHandler(mainRouter::accept).listen(port); } - public static void respond(RoutingContext ctx, Object response) { + private void setupHttpClient() { + httpClient = vertx.createHttpClient(); + } + + public static void respondJson(RoutingContext ctx, Object response) { + respondJson(ctx, 200, response); + } + + public static void respondJson(RoutingContext ctx, int code, Object response) { + ctx.response().putHeader("Content-Type", "application/json"); + ctx.response().setStatusCode(code); ctx.response().end(gson.toJson(response)); } private void convertData(String oldIp, boolean forReal) { // A lot of unneeded .toString()'s and cloning objects is our ghetto null validation. - MongoDatabase importFrom = new MongoClient(oldIp).getDatabase("minehq"); + MongoDatabase importFrom = MongoClients.create(oldIp).getDatabase("minehq"); Map mongoIdToUUID = new HashMap<>(); AtomicInteger skippedUsers = new AtomicInteger(); AtomicInteger skippedPunishments = new AtomicInteger(); @@ -299,12 +312,12 @@ public final class APIv3 { ); if (forReal) { - APIv3.getDatastore().save(created); + created.insert(); } log.info("Created user " + created.getLastUsername() + " (" + created.getId() + ")"); } - }); + }, (a, b) -> {}); importFrom.getCollection("punishment").find().forEach(new Block() { @@ -322,6 +335,8 @@ public final class APIv3 { return; } + com.mongodb. + Punishment created = new Punishment( new ObjectId().toString(), target, @@ -339,12 +354,12 @@ public final class APIv3 { ); if (forReal) { - APIv3.getDatastore().save(created); + created.insert(); } log.info("Created punishment " + created.getId() + " (" + created.getType() + ")"); } - }); + }, (a, b) -> {}); importFrom.getCollection("grant").find().forEach(new Block() { @@ -382,12 +397,12 @@ public final class APIv3 { ); if (forReal) { - APIv3.getDatastore().save(created); + created.insert(); } log.info("Created grant " + created.getId() + " (" + created.getRank() + ")"); } - }); + }, (a, b) -> {}); importFrom.getCollection("iplog").find().forEach(new Block() { @@ -423,12 +438,12 @@ public final class APIv3 { ); if (forReal) { - APIv3.getDatastore().save(created); + created.insert(); } log.info("Created ip log entry " + created.getId() + " (" + created.getUser() + " - " + created.getUserIp() + ")"); } - }); + }, (a, b) -> {}); log.info("Skipped " + skippedUsers.get() + " users, " + skippedPunishments.get() + " punishments, " + skippedGrants.get() + " grants, and " + skippedIpLogs.get() + " ip logs"); } diff --git a/src/main/java/net/frozenorb/apiv3/Main.java b/src/main/java/net/frozenorb/apiv3/Main.java index 9239ac2..1c60617 100644 --- a/src/main/java/net/frozenorb/apiv3/Main.java +++ b/src/main/java/net/frozenorb/apiv3/Main.java @@ -1,9 +1,11 @@ package net.frozenorb.apiv3; +import io.vertx.core.Vertx; + final class Main { public static void main(String[] args) { - new APIv3(); + Vertx.vertx().deployVerticle(new APIv3()); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/actors/UserActor.java b/src/main/java/net/frozenorb/apiv3/actors/UserActor.java index f0bd997..0da25d3 100644 --- a/src/main/java/net/frozenorb/apiv3/actors/UserActor.java +++ b/src/main/java/net/frozenorb/apiv3/actors/UserActor.java @@ -23,7 +23,7 @@ public final class UserActor implements Actor { if (cachedAuthorized != null) { return cachedAuthorized; } else { - String highestRankId = user.getHighestRank().getId(); + String highestRankId = user.getHighestRankAnywhere().getId(); cachedAuthorized = permittedUserRanks.contains(highestRankId.toLowerCase()); return cachedAuthorized; } diff --git a/src/main/java/net/frozenorb/apiv3/auditLog/AuditLog.java b/src/main/java/net/frozenorb/apiv3/auditLog/AuditLog.java index a8eef3c..24a33c1 100644 --- a/src/main/java/net/frozenorb/apiv3/auditLog/AuditLog.java +++ b/src/main/java/net/frozenorb/apiv3/auditLog/AuditLog.java @@ -17,8 +17,9 @@ public class AuditLog { } public static void log(User performedBy, String performedByIp, Actor actor, AuditLogActionType actionType, Map actionData) { + AuditLogEntry entry = new AuditLogEntry(performedBy, performedByIp, actor, actionType, actionData); + entry.insert(); APIv3.getStatsD().incrementCounter("apiv3.auditLog.insertions"); - APIv3.getDatastore().save(new AuditLogEntry(performedBy, performedByIp, actor, actionType, actionData)); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/filters/ActorAttributeFilter.java b/src/main/java/net/frozenorb/apiv3/filters/ActorAttributeFilter.java index 293e754..3c47fbf 100644 --- a/src/main/java/net/frozenorb/apiv3/filters/ActorAttributeFilter.java +++ b/src/main/java/net/frozenorb/apiv3/filters/ActorAttributeFilter.java @@ -1,52 +1,53 @@ package net.frozenorb.apiv3.filters; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.actors.*; import net.frozenorb.apiv3.models.Server; import net.frozenorb.apiv3.models.User; import net.frozenorb.apiv3.utils.ErrorUtils; -import spark.Filter; -import spark.Request; -import spark.Response; -import spark.Spark; import java.util.Base64; -public final class ActorAttributeFilter implements Filter { +public final class ActorAttributeFilter implements Handler { - public void handle(Request req, Response res) { - String authHeader = req.headers("Authorization"); - String mhqAuthHeader = req.headers("MHQ-Authorization"); + // TODO: MAKE THIS ASYNC + public void handle(RoutingContext ctx) { + String authHeader = ctx.request().getHeader("Authorization"); + String mhqAuthHeader = ctx.request().getHeader("MHQ-Authorization"); if (authHeader != null) { - req.attribute("actor", processBasicAuthorization(authHeader, res)); + processBasicAuthorization(authHeader, ctx); } else if (mhqAuthHeader != null) { - req.attribute("actor", processMHQAuthorization(mhqAuthHeader)); + processMHQAuthorization(mhqAuthHeader, ctx); } else { - req.attribute("actor", new UnknownActor()); + ctx.put("actor", new UnknownActor()); + ctx.next(); } } @SuppressWarnings("deprecation") // We purposely get the User by their last username. - private Actor processBasicAuthorization(String authHeader, Response res) { + private void processBasicAuthorization(String authHeader, RoutingContext ctx) { String encodedHeader = authHeader.substring("Basic ".length()); String[] credentials = new String(Base64.getDecoder().decode(encodedHeader.getBytes())).split(":"); if (credentials.length == 2) { - User user = User.byLastUsername(credentials[0]); + User user = User.findByLastUsername(credentials[0]); String password = credentials[1]; if (user != null && user.getPassword() != null && user.checkPassword(password)) { - return new UserActor(user); + ctx.put("actor", new UserActor(user)); + ctx.next(); + return; } } - res.header("WWW-Authenticate", "Basic realm=\"MineHQ\""); - Spark.halt(401, APIv3.getGson().toJson(ErrorUtils.error("Failed to authorize as " + credentials[0] + "."))); - return null; + ctx.response().putHeader("WWW-Authenticate", "Basic realm=\"MineHQ\""); + ErrorUtils.respondGeneric(ctx, "Failed to authorize as " + credentials[0] + "."); } - private Actor processMHQAuthorization(String authHeader) { + private void processMHQAuthorization(String authHeader, RoutingContext ctx) { String[] split = authHeader.split(" "); if (split.length >= 2) { @@ -57,33 +58,39 @@ public final class ActorAttributeFilter implements Filter { String properKey = APIv3.getConfig().getProperty("auth.websiteApiKey"); if (givenKey.equals(properKey)) { - return new WebsiteActor(); + ctx.put("actor", new WebsiteActor()); + ctx.next(); + return; } } else if (type.equals("Server") && split.length == 3) { - Server server = Server.byId(split[1]); + Server server = Server.findById(split[1]); if (server == null) { - Spark.halt(401, APIv3.getGson().toJson(ErrorUtils.respondNotFound("Server", split[1]))); + ErrorUtils.respondNotFound(ctx, "Server", split[1]); + return; } String givenKey = split[2]; String properKey = server.getApiKey(); if (givenKey.equals(properKey)) { - return new ServerActor(server); + ctx.put("actor", new ServerActor(server)); + ctx.next(); + return; } } else if (type.equals("BungeeCord") && split.length == 2) { String givenKey = split[1]; String properKey = APIv3.getConfig().getProperty("auth.bungeeCordApiKey"); if (givenKey.equals(properKey)) { - return new BungeeCordActor(); + ctx.put("actor", new BungeeCordActor()); + ctx.next(); + return; } } } - Spark.halt(401, APIv3.getGson().toJson(ErrorUtils.error("Failed to authorize."))); - return null; + ErrorUtils.respondGeneric(ctx, "Failed to authorize."); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/filters/AuthorizationFilter.java b/src/main/java/net/frozenorb/apiv3/filters/AuthorizationFilter.java index 407a5bf..b078397 100644 --- a/src/main/java/net/frozenorb/apiv3/filters/AuthorizationFilter.java +++ b/src/main/java/net/frozenorb/apiv3/filters/AuthorizationFilter.java @@ -1,22 +1,22 @@ package net.frozenorb.apiv3.filters; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.actors.Actor; import net.frozenorb.apiv3.utils.ErrorUtils; -import spark.Filter; -import spark.Request; -import spark.Response; -import spark.Spark; -public final class AuthorizationFilter implements Filter { +public final class AuthorizationFilter implements Handler { - public void handle(Request req, Response res) { + public void handle(RoutingContext ctx) { Actor actor = ctx.get("actor"); if (!actor.isAuthorized()) { APIv3.getStatsD().incrementCounter("apiv3.http.unauthorized"); - res.header("WWW-Authenticate", "Basic realm=\"MineHQ\""); - Spark.halt(401, APIv3.getGson().toJson(ErrorUtils.error("Unauthorized access: Please authorize as an approved actor. You're currently authorized as " + actor.getName()))); + ctx.response().putHeader("WWW-Authenticate", "Basic realm=\"MineHQ\""); + ErrorUtils.respondGeneric(ctx, "Unauthorized access: Please authorize as an approved actor. You're currently authorized as " + actor.getName()); + } else { + ctx.next(); } } diff --git a/src/main/java/net/frozenorb/apiv3/filters/ContentTypeFilter.java b/src/main/java/net/frozenorb/apiv3/filters/ContentTypeFilter.java deleted file mode 100644 index 1f02c07..0000000 --- a/src/main/java/net/frozenorb/apiv3/filters/ContentTypeFilter.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.frozenorb.apiv3.filters; - -import spark.Filter; -import spark.Request; -import spark.Response; - -public final class ContentTypeFilter implements Filter { - - public void handle(Request req, Response res) { - res.type("application/json"); - } - -} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/filters/LoggingFilter.java b/src/main/java/net/frozenorb/apiv3/filters/LoggingFilter.java deleted file mode 100644 index 55b2667..0000000 --- a/src/main/java/net/frozenorb/apiv3/filters/LoggingFilter.java +++ /dev/null @@ -1,21 +0,0 @@ -package net.frozenorb.apiv3.filters; - -import lombok.Getter; -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; -import net.frozenorb.apiv3.actors.Actor; -import spark.Filter; -import spark.Request; -import spark.Response; - -@Slf4j -public final class LoggingFilter implements Filter { - - @Getter @Setter private static boolean debug = false; - - public void handle(Request req, Response res) { - Actor actor = ctx.get("actor"); - log.info("(" + actor.getName() + " - " + actor.getType() + ") " + req.requestMethod().toUpperCase() + " " + req.pathInfo() + (debug ? "\n" + res.body() : "")); - } - -} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/filters/MetricsAfterFilter.java b/src/main/java/net/frozenorb/apiv3/filters/MetricsAfterFilter.java deleted file mode 100644 index 8bf5d4a..0000000 --- a/src/main/java/net/frozenorb/apiv3/filters/MetricsAfterFilter.java +++ /dev/null @@ -1,16 +0,0 @@ -package net.frozenorb.apiv3.filters; - -import net.frozenorb.apiv3.APIv3; -import spark.Filter; -import spark.Request; -import spark.Response; - -public final class MetricsAfterFilter implements Filter { - - public void handle(Request req, Response res) { - long started = req.attribute("requestStarted"); - APIv3.getStatsD().recordExecutionTime("apiv3.http.executionTime", System.currentTimeMillis() - started); - APIv3.getStatsD().incrementCounter("apiv3.http.requests"); - } - -} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/filters/MetricsBeforeFilter.java b/src/main/java/net/frozenorb/apiv3/filters/MetricsBeforeFilter.java deleted file mode 100644 index 059c8b8..0000000 --- a/src/main/java/net/frozenorb/apiv3/filters/MetricsBeforeFilter.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.frozenorb.apiv3.filters; - -import spark.Filter; -import spark.Request; -import spark.Response; - -public final class MetricsBeforeFilter implements Filter { - - public void handle(Request req, Response res) { - req.attribute("requestStarted", System.currentTimeMillis()); - } - -} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/filters/MetricsHandler.java b/src/main/java/net/frozenorb/apiv3/filters/MetricsHandler.java new file mode 100644 index 0000000..5d0fa69 --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/filters/MetricsHandler.java @@ -0,0 +1,14 @@ +package net.frozenorb.apiv3.filters; + +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import net.frozenorb.apiv3.APIv3; + +public final class MetricsHandler implements Handler { + + public void handle(RoutingContext ctx) { + APIv3.getStatsD().incrementCounter("apiv3.http.requests"); + ctx.next(); + } + +} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/models/AuditLogEntry.java b/src/main/java/net/frozenorb/apiv3/models/AuditLogEntry.java index 93989cc..fe6a990 100644 --- a/src/main/java/net/frozenorb/apiv3/models/AuditLogEntry.java +++ b/src/main/java/net/frozenorb/apiv3/models/AuditLogEntry.java @@ -1,31 +1,55 @@ package net.frozenorb.apiv3.models; import com.google.common.collect.ImmutableMap; +import com.mongodb.async.client.MongoCollection; +import eu.dozd.mongo.annotation.Entity; +import eu.dozd.mongo.annotation.Id; import lombok.Getter; +import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.actors.Actor; import net.frozenorb.apiv3.actors.ActorType; +import net.frozenorb.apiv3.auditLog.AuditLog; import net.frozenorb.apiv3.auditLog.AuditLogActionType; +import net.frozenorb.apiv3.unsorted.BlockingCallback; +import net.frozenorb.apiv3.utils.SyncUtils; +import org.bson.Document; import org.bson.types.ObjectId; -import org.mongodb.morphia.annotations.Entity; -import org.mongodb.morphia.annotations.Id; -import org.mongodb.morphia.annotations.Indexed; import java.util.Date; +import java.util.List; import java.util.Map; import java.util.UUID; -@Entity(value = "auditLog", noClassnameStored = true) +@Entity public final class AuditLogEntry { + private static final MongoCollection auditLogCollection = APIv3.getDatabase().getCollection("auditLog", AuditLogEntry.class); + @Getter @Id private String id; - @Getter @Indexed private UUID user; + @Getter private UUID user; @Getter private String userIp; - @Getter @Indexed private Date performedAt; + @Getter private Date performedAt; @Getter private String actorName; @Getter private ActorType actorType; @Getter private AuditLogActionType type; @Getter private Map metadata; + public static List findAll() { + return SyncUtils.blockMulti(auditLogCollection.find()); + } + + public static AuditLogEntry findById(String id) { + return SyncUtils.blockOne(auditLogCollection.find(new Document("_id", id))); + } + + public static List findByUser(User user) { + return findByUser(user.getId()); + } + + public static List findByUser(UUID user) { + return SyncUtils.blockMulti(auditLogCollection.find(new Document("user", user))); + } + public AuditLogEntry() {} // For Morphia public AuditLogEntry(User user, String userIp, Actor actor, AuditLogActionType type, Map metadata) { @@ -39,4 +63,10 @@ public final class AuditLogEntry { this.metadata = ImmutableMap.copyOf(metadata); } + public void insert() { + BlockingCallback callback = new BlockingCallback<>(); + auditLogCollection.insertOne(this, callback); + callback.get(); + } + } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/models/Grant.java b/src/main/java/net/frozenorb/apiv3/models/Grant.java index 772a8e9..7960b16 100644 --- a/src/main/java/net/frozenorb/apiv3/models/Grant.java +++ b/src/main/java/net/frozenorb/apiv3/models/Grant.java @@ -1,56 +1,59 @@ package net.frozenorb.apiv3.models; import com.google.common.collect.Collections2; +import com.mongodb.async.client.MongoCollection; +import com.mongodb.client.result.DeleteResult; +import com.mongodb.client.result.UpdateResult; +import eu.dozd.mongo.annotation.Entity; +import eu.dozd.mongo.annotation.Id; import lombok.AllArgsConstructor; import lombok.Getter; import net.frozenorb.apiv3.APIv3; -import net.frozenorb.apiv3.utils.UUIDUtils; +import net.frozenorb.apiv3.unsorted.BlockingCallback; +import net.frozenorb.apiv3.utils.SyncUtils; +import org.bson.Document; import org.bson.types.ObjectId; -import org.mongodb.morphia.annotations.Entity; -import org.mongodb.morphia.annotations.Id; -import org.mongodb.morphia.annotations.Indexed; import java.util.*; -@Entity(value = "grants", noClassnameStored = true) +@Entity @AllArgsConstructor public final class Grant { + private static final MongoCollection grantsCollection = APIv3.getDatabase().getCollection("grants", Grant.class); + @Getter @Id private String id; - @Getter @Indexed private UUID user; + @Getter private UUID user; @Getter private String reason; @Getter private Set scopes = new HashSet<>(); // So on things w/o scopes we still load properly (Morphia drops empty sets) - @Getter @Indexed private String rank; + @Getter private String rank; @Getter private Date expiresAt; @Getter private UUID addedBy; - @Getter @Indexed private Date addedAt; + @Getter private Date addedAt; @Getter private UUID removedBy; @Getter private Date removedAt; @Getter private String removalReason; - public static Grant byId(String id) { - return APIv3.getDatastore().createQuery(Grant.class).field("id").equal(id).get(); + public static List findAll() { + return SyncUtils.blockMulti(grantsCollection.find()); } - public static Map> byUserGrouped(Iterable ids) { - Map> result = new HashMap<>(); - Set uuidsToSearch = new HashSet<>(); + public static List findByRank(Iterable ranks) { + return SyncUtils.blockMulti(grantsCollection.find(new Document("rank", new Document("$in", ranks)))); + } - for (UUID id : ids) { - result.put(id, new ArrayList<>()); + public static Grant findById(String id) { + return SyncUtils.blockOne(grantsCollection.find(new Document("_id", id))); + } - if (UUIDUtils.isAcceptableUUID(id)) { - uuidsToSearch.add(id); - } - } + public static List findByUser(User user) { + return findByUser(user.getId()); + } - APIv3.getDatastore().createQuery(Grant.class).field("user").in(uuidsToSearch).forEach((grant) -> { - result.get(grant.getUser()).add(grant); - }); - - return result; + public static List findByUser(UUID user) { + return SyncUtils.blockMulti(grantsCollection.find(new Document("user", user))); } public Grant() {} // For Morphia @@ -66,14 +69,6 @@ public final class Grant { this.addedAt = new Date(); } - public void delete(User removedBy, String reason) { - this.removedBy = removedBy.getId(); - this.removedAt = new Date(); - this.removalReason = reason; - - APIv3.getDatastore().save(this); - } - public boolean isActive() { return !(isExpired() || isRemoved()); } @@ -98,4 +93,20 @@ public final class Grant { return scopes.isEmpty(); } + public void insert() { + BlockingCallback callback = new BlockingCallback<>(); + grantsCollection.insertOne(this, callback); + callback.get(); + } + + public void delete(User removedBy, String reason) { + this.removedBy = removedBy.getId(); + this.removedAt = new Date(); + this.removalReason = reason; + + BlockingCallback callback = new BlockingCallback<>(); + grantsCollection.deleteOne(new Document("_id", id), callback); + callback.get(); + } + } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/models/IPLogEntry.java b/src/main/java/net/frozenorb/apiv3/models/IPLogEntry.java index 0e77799..3a52456 100644 --- a/src/main/java/net/frozenorb/apiv3/models/IPLogEntry.java +++ b/src/main/java/net/frozenorb/apiv3/models/IPLogEntry.java @@ -1,31 +1,57 @@ package net.frozenorb.apiv3.models; +import com.mongodb.async.client.MongoCollection; +import eu.dozd.mongo.annotation.Entity; +import eu.dozd.mongo.annotation.Id; import lombok.AllArgsConstructor; import lombok.Getter; import net.frozenorb.apiv3.APIv3; +import net.frozenorb.apiv3.unsorted.BlockingCallback; +import net.frozenorb.apiv3.utils.SyncUtils; +import org.bson.Document; import org.bson.types.ObjectId; -import org.mongodb.morphia.annotations.*; import java.util.Date; +import java.util.List; import java.util.UUID; -@Entity(value = "ipLog", noClassnameStored = true) +@Entity @AllArgsConstructor -@Indexes( - @Index(fields = { - @Field("user"), - @Field("userIp") - }) -) public final class IPLogEntry { + private static final MongoCollection ipLogCollection = APIv3.getDatabase().getCollection("ipLog", IPLogEntry.class); + @Getter @Id private String id; - @Getter @Indexed private UUID user; - @Getter @Indexed private String userIp; + @Getter private UUID user; + @Getter private String userIp; @Getter private Date firstSeenAt; @Getter private Date lastSeenAt; @Getter private int uses; + public static List findAll() { + return SyncUtils.blockMulti(ipLogCollection.find()); + } + + public static IPLogEntry findById(String id) { + return SyncUtils.blockOne(ipLogCollection.find(new Document("_id", id))); + } + + public static List findByUser(User user) { + return findByUser(user.getId()); + } + + public static List findByUser(UUID user) { + return SyncUtils.blockMulti(ipLogCollection.find(new Document("user", user))); + } + + public static IPLogEntry findByUserAndIp(User user, String userIp) { + return findByUserAndIp(user.getId(), userIp); + } + + public static IPLogEntry findByUserAndIp(UUID user, String userIp) { + return SyncUtils.blockOne(ipLogCollection.find(new Document("user", user).append("userIp", userIp))); + } + public IPLogEntry() {} // For Morphia public IPLogEntry(User user, String userIp) { @@ -40,8 +66,12 @@ public final class IPLogEntry { public void used() { this.lastSeenAt = new Date(); this.uses++; + } - APIv3.getDatastore().save(this); + public void insert() { + BlockingCallback callback = new BlockingCallback<>(); + ipLogCollection.insertOne(this, callback); + callback.get(); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/models/NotificationTemplate.java b/src/main/java/net/frozenorb/apiv3/models/NotificationTemplate.java index 1cffe9f..cf56f6c 100644 --- a/src/main/java/net/frozenorb/apiv3/models/NotificationTemplate.java +++ b/src/main/java/net/frozenorb/apiv3/models/NotificationTemplate.java @@ -1,26 +1,35 @@ package net.frozenorb.apiv3.models; +import com.mongodb.async.client.MongoCollection; +import com.mongodb.client.result.DeleteResult; +import com.mongodb.client.result.UpdateResult; +import eu.dozd.mongo.annotation.Entity; +import eu.dozd.mongo.annotation.Id; import lombok.Getter; +import lombok.Setter; import net.frozenorb.apiv3.APIv3; -import org.mongodb.morphia.annotations.Entity; -import org.mongodb.morphia.annotations.Id; +import net.frozenorb.apiv3.unsorted.BlockingCallback; +import net.frozenorb.apiv3.utils.SyncUtils; +import org.bson.Document; import java.util.List; import java.util.Map; -@Entity(value = "notificationTemplates", noClassnameStored = true) +@Entity public final class NotificationTemplate { - @Getter @Id private String id; - @Getter private String subject; - @Getter private String body; + private static final MongoCollection notificationTemplatesCollection = APIv3.getDatabase().getCollection("notificationTemplates", NotificationTemplate.class); - public static NotificationTemplate byId(String id) { - return APIv3.getDatastore().createQuery(NotificationTemplate.class).field("id").equal(id).get(); + @Getter @Id private String id; + @Getter @Setter private String subject; + @Getter @Setter private String body; + + public static List findAll() { + return SyncUtils.blockMulti(notificationTemplatesCollection.find()); } - public static List values() { - return APIv3.getDatastore().createQuery(NotificationTemplate.class).asList(); + public static NotificationTemplate findById(String id) { + return SyncUtils.blockOne(notificationTemplatesCollection.find(new Document("_id", id))); } public NotificationTemplate() {} // For Morphia @@ -31,17 +40,6 @@ public final class NotificationTemplate { this.body = body; } - public void update(String subject, String body) { - this.subject = subject; - this.body = body; - - APIv3.getDatastore().save(this); - } - - public void delete() { - APIv3.getDatastore().delete(this); - } - public String fillSubject(Map replacements) { return fill(subject, replacements); } @@ -61,4 +59,22 @@ public final class NotificationTemplate { return working; } + public void insert() { + BlockingCallback callback = new BlockingCallback<>(); + notificationTemplatesCollection.insertOne(this, callback); + callback.get(); + } + + public void save() { + BlockingCallback callback = new BlockingCallback<>(); + notificationTemplatesCollection.replaceOne(new Document("_id", id), this, callback); + callback.get(); + } + + public void delete() { + BlockingCallback callback = new BlockingCallback<>(); + notificationTemplatesCollection.deleteOne(new Document("_id", id), callback); + callback.get(); + } + } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/models/Punishment.java b/src/main/java/net/frozenorb/apiv3/models/Punishment.java index 909d419..643ce5b 100644 --- a/src/main/java/net/frozenorb/apiv3/models/Punishment.java +++ b/src/main/java/net/frozenorb/apiv3/models/Punishment.java @@ -1,37 +1,37 @@ package net.frozenorb.apiv3.models; -import com.google.common.collect.ImmutableSet; +import com.mongodb.async.client.MongoCollection; +import com.mongodb.client.result.DeleteResult; +import eu.dozd.mongo.annotation.Entity; +import eu.dozd.mongo.annotation.Id; import lombok.AllArgsConstructor; import lombok.Getter; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.actors.Actor; import net.frozenorb.apiv3.actors.ActorType; +import net.frozenorb.apiv3.unsorted.BlockingCallback; +import net.frozenorb.apiv3.utils.SyncUtils; import net.frozenorb.apiv3.utils.TimeUtils; -import net.frozenorb.apiv3.utils.UUIDUtils; +import org.bson.Document; import org.bson.types.ObjectId; -import org.mongodb.morphia.annotations.*; import java.util.*; -@Entity(value = "punishments", noClassnameStored = true) +@Entity @AllArgsConstructor -@Indexes( - @Index(fields = { - @Field("user"), - @Field("type") - }) -) public final class Punishment { + private static final MongoCollection punishmentsCollection = APIv3.getDatabase().getCollection("punishments", Punishment.class); + @Getter @Id private String id; - @Getter @Indexed private UUID user; + @Getter private UUID user; @Getter private String reason; - @Getter @Indexed private PunishmentType type; // Type is indexed for the rank dump + @Getter private PunishmentType type; @Getter private Date expiresAt; @Getter private Map metadata; @Getter private UUID addedBy; - @Getter @Indexed private Date addedAt; + @Getter private Date addedAt; @Getter private String actorName; @Getter private ActorType actorType; @@ -39,31 +39,32 @@ public final class Punishment { @Getter private Date removedAt; @Getter private String removalReason; - public static Punishment byId(String id) { - return APIv3.getDatastore().createQuery(Punishment.class).field("id").equal(id).get(); + public static List findAll() { + return SyncUtils.blockMulti(punishmentsCollection.find()); } - public static Map> byUserGrouped(Iterable ids) { - return byUserGrouped(ids, ImmutableSet.copyOf(PunishmentType.values())); + public static List findByType(Iterable types) { + return SyncUtils.blockMulti(punishmentsCollection.find(new Document("type", new Document("$in", types)))); } - public static Map> byUserGrouped(Iterable ids, Iterable types) { - Map> result = new HashMap<>(); - Set uuidsToSearch = new HashSet<>(); + public static Punishment findById(String id) { + return SyncUtils.blockOne(punishmentsCollection.find(new Document("_id", id))); + } - for (UUID id : ids) { - result.put(id, new ArrayList<>()); + public static List findByUser(User user) { + return findByUser(user.getId()); + } - if (UUIDUtils.isAcceptableUUID(id)) { - uuidsToSearch.add(id); - } - } + public static List findByUser(UUID user) { + return SyncUtils.blockMulti(punishmentsCollection.find(new Document("user", user))); + } - APIv3.getDatastore().createQuery(Punishment.class).field("user").in(uuidsToSearch).field("type").in(types).forEach((punishment) -> { - result.get(punishment.getUser()).add(punishment); - }); + public static List findByUserAndType(User user, Iterable types) { + return findByUserAndType(user.getId(), types); + } - return result; + public static List findByUserAndType(UUID user, Iterable types) { + return SyncUtils.blockMulti(punishmentsCollection.find(new Document("user", user).append("type", new Document("$in", types)))); } public Punishment() {} // For Morphia @@ -81,14 +82,6 @@ public final class Punishment { this.metadata = metadata; } - public void delete(User removedBy, String reason) { - this.removedBy = removedBy.getId(); - this.removedAt = new Date(); - this.removalReason = reason; - - APIv3.getDatastore().save(this); - } - public boolean isActive() { return !(isExpired() || isRemoved()); } @@ -124,6 +117,22 @@ public final class Punishment { } } + public void insert() { + BlockingCallback callback = new BlockingCallback<>(); + punishmentsCollection.insertOne(this, callback); + callback.get(); + } + + public void delete(User removedBy, String reason) { + this.removedBy = removedBy.getId(); + this.removedAt = new Date(); + this.removalReason = reason; + + BlockingCallback callback = new BlockingCallback<>(); + punishmentsCollection.deleteOne(new Document("_id", id), callback); + callback.get(); + } + public enum PunishmentType { BLACKLIST, BAN, MUTE, WARN diff --git a/src/main/java/net/frozenorb/apiv3/models/Rank.java b/src/main/java/net/frozenorb/apiv3/models/Rank.java index 18373bc..f035a7e 100644 --- a/src/main/java/net/frozenorb/apiv3/models/Rank.java +++ b/src/main/java/net/frozenorb/apiv3/models/Rank.java @@ -1,11 +1,17 @@ package net.frozenorb.apiv3.models; import com.google.common.collect.ImmutableList; +import com.google.common.primitives.Ints; +import com.mongodb.async.client.MongoCollection; +import com.mongodb.client.result.DeleteResult; +import com.mongodb.client.result.UpdateResult; +import eu.dozd.mongo.annotation.Entity; +import eu.dozd.mongo.annotation.Id; import lombok.Getter; import net.frozenorb.apiv3.APIv3; -import org.mongodb.morphia.annotations.Entity; -import org.mongodb.morphia.annotations.Id; -import org.mongodb.morphia.annotations.Indexed; +import net.frozenorb.apiv3.unsorted.BlockingCallback; +import net.frozenorb.apiv3.utils.SyncUtils; +import org.bson.Document; import java.util.ArrayList; import java.util.HashMap; @@ -13,9 +19,11 @@ import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; -@Entity(value = "ranks", noClassnameStored = true) +@Entity public final class Rank { + private static final MongoCollection ranksCollection = APIv3.getDatabase().getCollection("ranks", Rank.class); + private static Map rankCache = null; private static List rankAltCache = null; private static long rankCacheUpdated = 0; @@ -25,18 +33,18 @@ public final class Rank { @Getter private String displayName; @Getter private String gameColor; @Getter private String websiteColor; - @Getter @Indexed private boolean staffRank; + @Getter private boolean staffRank; - public static Rank byId(String id) { - updateCacheIfNeeded(); - return rankCache.get(id); - } - - public static List values() { + public static List findAll() { updateCacheIfNeeded(); return ImmutableList.copyOf(rankAltCache); } + public static Rank findById(String id) { + updateCacheIfNeeded(); + return rankCache.get(id); + } + public Rank() {} // For Morphia public Rank(String id, int weight, String displayName, String gameColor, String websiteColor, boolean staffRank) { @@ -48,16 +56,14 @@ public final class Rank { this.staffRank = staffRank; } - public void delete() { - APIv3.getDatastore().delete(this); - } - private static void updateCacheIfNeeded() { if (rankCache == null || (System.currentTimeMillis() - rankCacheUpdated) > TimeUnit.MINUTES.toMillis(1)) { Map working = new HashMap<>(); List workingAlt = new ArrayList<>(); + List allRanks = SyncUtils.blockMulti(ranksCollection.find()); + allRanks.sort((a, b) -> Ints.compare(a.getWeight(), b.getWeight())); - for (Rank rank : APIv3.getDatastore().createQuery(Rank.class).order("weight").asList()) { + for (Rank rank : allRanks) { working.put(rank.getId(), rank); workingAlt.add(rank); } @@ -68,4 +74,22 @@ public final class Rank { } } + public void insert() { + BlockingCallback callback = new BlockingCallback<>(); + ranksCollection.insertOne(this, callback); + callback.get(); + } + + public void save() { + BlockingCallback callback = new BlockingCallback<>(); + ranksCollection.replaceOne(new Document("_id", id), this, callback); + callback.get(); + } + + public void delete() { + BlockingCallback callback = new BlockingCallback<>(); + ranksCollection.deleteOne(new Document("_id", id), callback); + callback.get(); + } + } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/models/Server.java b/src/main/java/net/frozenorb/apiv3/models/Server.java index 6fb5b3a..b5b9727 100644 --- a/src/main/java/net/frozenorb/apiv3/models/Server.java +++ b/src/main/java/net/frozenorb/apiv3/models/Server.java @@ -1,19 +1,27 @@ package net.frozenorb.apiv3.models; +import com.google.common.collect.ImmutableSet; +import com.mongodb.async.client.MongoCollection; +import com.mongodb.client.result.DeleteResult; +import com.mongodb.client.result.UpdateResult; +import eu.dozd.mongo.annotation.Entity; +import eu.dozd.mongo.annotation.Id; import lombok.Getter; import lombok.Setter; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.serialization.ExcludeFromReplies; -import org.mongodb.morphia.annotations.Entity; -import org.mongodb.morphia.annotations.Id; -import org.mongodb.morphia.annotations.Indexed; +import net.frozenorb.apiv3.unsorted.BlockingCallback; +import net.frozenorb.apiv3.utils.SyncUtils; +import org.bson.Document; import java.util.*; import java.util.concurrent.TimeUnit; -@Entity(value = "servers", noClassnameStored = true) +@Entity public final class Server { + private static final MongoCollection serversCollection = APIv3.getDatabase().getCollection("servers", Server.class); + private static Map serverCache = null; private static List serverCacheAlt = null; private static long serverCacheUpdated = 0; @@ -21,22 +29,22 @@ public final class Server { @Getter @Id private String id; @Getter private String displayName; @Getter @ExcludeFromReplies String apiKey; - @Getter @Indexed private String serverGroup; + @Getter private String serverGroup; @Getter private String serverIp; @Getter @Setter private Date lastUpdatedAt; @Getter @Setter private double lastTps; @Getter @Setter @ExcludeFromReplies private Set players; - public static Server byId(String id) { - updateCacheIfNeeded(); - return serverCache.get(id); - } - - public static List values() { + public static List findAll() { updateCacheIfNeeded(); return serverCacheAlt; } + public static Server findById(String id) { + updateCacheIfNeeded(); + return serverCache.get(id); + } + public Server() {} // For Morphia public Server(String id, String displayName, String apiKey, ServerGroup serverGroup, String serverIp) { @@ -50,16 +58,12 @@ public final class Server { this.players = new HashSet<>(); } - public void delete() { - APIv3.getDatastore().delete(this); - } - private static void updateCacheIfNeeded() { if (serverCache == null || (System.currentTimeMillis() - serverCacheUpdated) > TimeUnit.MINUTES.toMillis(1)) { Map working = new HashMap<>(); List workingAlt = new ArrayList<>(); - for (Server server : APIv3.getDatastore().createQuery(Server.class).asList()) { + for (Server server : SyncUtils.blockMulti(serversCollection.find())) { working.put(server.getId(), server); workingAlt.add(server); } @@ -70,4 +74,28 @@ public final class Server { } } + public void receivedHeartbeat(double tps, Iterable players) { + this.lastUpdatedAt = new Date(); + this.lastTps = tps; + this.players = ImmutableSet.copyOf(players); + } + + public void insert() { + BlockingCallback callback = new BlockingCallback<>(); + serversCollection.insertOne(this, callback); + callback.get(); + } + + public void save() { + BlockingCallback callback = new BlockingCallback<>(); + serversCollection.replaceOne(new Document("_id", id), this, callback); + callback.get(); + } + + public void delete() { + BlockingCallback callback = new BlockingCallback<>(); + serversCollection.deleteOne(new Document("_id", id), callback); + callback.get(); + } + } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/models/ServerGroup.java b/src/main/java/net/frozenorb/apiv3/models/ServerGroup.java index 0e9ab6d..8c5ade2 100644 --- a/src/main/java/net/frozenorb/apiv3/models/ServerGroup.java +++ b/src/main/java/net/frozenorb/apiv3/models/ServerGroup.java @@ -1,44 +1,51 @@ package net.frozenorb.apiv3.models; import com.google.gson.annotations.SerializedName; +import com.mongodb.async.client.MongoCollection; +import com.mongodb.client.result.DeleteResult; +import com.mongodb.client.result.UpdateResult; +import eu.dozd.mongo.annotation.Entity; +import eu.dozd.mongo.annotation.Id; import lombok.Getter; import lombok.Setter; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.serialization.ExcludeFromReplies; +import net.frozenorb.apiv3.unsorted.BlockingCallback; import net.frozenorb.apiv3.utils.PermissionUtils; -import org.mongodb.morphia.annotations.Entity; -import org.mongodb.morphia.annotations.Id; -import org.mongodb.morphia.annotations.Property; +import net.frozenorb.apiv3.utils.SyncUtils; +import org.bson.Document; import java.util.*; import java.util.concurrent.TimeUnit; -@Entity(value = "serverGroups", noClassnameStored = true) +@Entity public final class ServerGroup { + private static final MongoCollection serverGroupsCollection = APIv3.getDatabase().getCollection("serverGroups", ServerGroup.class); + private static Map serverGroupCache = null; private static List serverGroupAltCache = null; private static long serverGroupCacheUpdated = 0; @Getter @Id private String id; @Getter private String image; - // We rename this to public, we just can't name it that because it's a Java identifier. - @Getter @Property("public") @SerializedName("public") private boolean isPublic; + // We rename this to public (only to gson), we just can't name it that because it's a Java identifier. + @Getter @SerializedName("public") private boolean isPublic; // We define these HashSets up here because, in the event they're // empty, Morphia will load them as null, not empty sets. @Getter @Setter @ExcludeFromReplies private Set announcements = new HashSet<>(); @Getter @Setter @ExcludeFromReplies private Map> permissions = new HashMap<>(); - public static ServerGroup byId(String id) { - updateCacheIfNeeded(); - return serverGroupCache.get(id); - } - - public static List values() { + public static List findAll() { updateCacheIfNeeded(); return serverGroupAltCache; } + public static ServerGroup findById(String id) { + updateCacheIfNeeded(); + return serverGroupCache.get(id); + } + public ServerGroup() {} // For Morphia public ServerGroup(String id, String image, boolean isPublic) { @@ -51,16 +58,12 @@ public final class ServerGroup { return PermissionUtils.mergeUpTo(permissions, userRank); } - public void delete() { - APIv3.getDatastore().delete(this); - } - private static void updateCacheIfNeeded() { if (serverGroupCache == null || (System.currentTimeMillis() - serverGroupCacheUpdated) > TimeUnit.MINUTES.toMillis(1)) { Map working = new HashMap<>(); List workingAlt = new ArrayList<>(); - for (ServerGroup serverGroup : APIv3.getDatastore().createQuery(ServerGroup.class).asList()) { + for (ServerGroup serverGroup : SyncUtils.blockMulti(serverGroupsCollection.find())) { working.put(serverGroup.getId(), serverGroup); workingAlt.add(serverGroup); } @@ -71,4 +74,22 @@ public final class ServerGroup { } } + public void insert() { + BlockingCallback callback = new BlockingCallback<>(); + serverGroupsCollection.insertOne(this, callback); + callback.get(); + } + + public void save() { + BlockingCallback callback = new BlockingCallback<>(); + serverGroupsCollection.replaceOne(new Document("_id", id), this, callback); + callback.get(); + } + + public void delete() { + BlockingCallback callback = new BlockingCallback<>(); + serverGroupsCollection.deleteOne(new Document("_id", id), callback); + callback.get(); + } + } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/models/User.java b/src/main/java/net/frozenorb/apiv3/models/User.java index 18afd78..6e27e32 100644 --- a/src/main/java/net/frozenorb/apiv3/models/User.java +++ b/src/main/java/net/frozenorb/apiv3/models/User.java @@ -4,30 +4,35 @@ import com.google.common.base.Charsets; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.hash.Hashing; +import com.mongodb.async.client.MongoCollection; +import com.mongodb.client.result.UpdateResult; +import eu.dozd.mongo.annotation.Entity; +import eu.dozd.mongo.annotation.Id; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.serialization.ExcludeFromReplies; +import net.frozenorb.apiv3.unsorted.BlockingCallback; import net.frozenorb.apiv3.utils.MojangUtils; import net.frozenorb.apiv3.utils.PermissionUtils; +import net.frozenorb.apiv3.utils.SyncUtils; import net.frozenorb.apiv3.utils.UUIDUtils; import org.bson.Document; -import org.mongodb.morphia.annotations.Entity; -import org.mongodb.morphia.annotations.Id; -import org.mongodb.morphia.annotations.Indexed; import java.util.*; -@Entity(value = "users", noClassnameStored = true) +@Entity @AllArgsConstructor -public final class User { +public final class User { + + private static final MongoCollection usersCollection = APIv3.getDatabase().getCollection("users", User.class); @Getter @Id private UUID id; - @Getter @Indexed private String lastUsername; + @Getter private String lastUsername; @Getter @ExcludeFromReplies private Map aliases = new HashMap<>(); - @Getter @Setter @ExcludeFromReplies private String totpSecret; - @Getter @Indexed @ExcludeFromReplies @Setter private String emailToken; + @Getter @ExcludeFromReplies @Setter private String totpSecret; + @Getter @ExcludeFromReplies @Setter private String emailToken; @Getter @ExcludeFromReplies @Setter private Date emailTokenSetAt; @Getter @ExcludeFromReplies private String password; @Getter @Setter private String email; @@ -37,48 +42,36 @@ public final class User { @Getter private Date firstSeenAt; @Getter private boolean online; - public static User byId(String id) { - try { - return byId(UUID.fromString(id)); - } catch (Exception ex) { - return null; - } + public static List findAll() { + return SyncUtils.blockMulti(usersCollection.find()); } - public static User byId(UUID id) { + public static User findById(String id) { + UUID uuid; + + try { + uuid = UUID.fromString(id); + } catch (IllegalArgumentException ex) { + return null; + } + + return findById(uuid); + } + + public static User findById(UUID id) { if (UUIDUtils.isAcceptableUUID(id)) { - return APIv3.getDatastore().createQuery(User.class).field("id").equal(id).get(); + return SyncUtils.blockOne(usersCollection.find(new Document("_id", id))); } else { return null; } } - public static Map byIdGrouped(Iterable ids) { - Map result = new HashMap<>(); - Set uuidsToSearch = new HashSet<>(); - - for (UUID id : ids) { - result.put(id, null); - - if (UUIDUtils.isAcceptableUUID(id)) { - uuidsToSearch.add(id); - } - } - - APIv3.getDatastore().createQuery(User.class).field("id").in(uuidsToSearch).forEach((user) -> { - result.put(user.getId(), user); - }); - - return result; + public static User findByEmailToken(String emailToken) { + return SyncUtils.blockOne(usersCollection.find(new Document("emailToken", emailToken))); } - public static User byEmailToken(String name) { - return APIv3.getDatastore().createQuery(User.class).field("emailToken").equal(name).get(); - } - - @Deprecated - public static User byLastUsername(String lastUsername) { - return APIv3.getDatastore().createQuery(User.class).field("lastUsername").equal(lastUsername).get(); + public static User findByLastUsername(String lastUsername) { + return SyncUtils.blockOne(usersCollection.find(new Document("lastUsername", lastUsername))); } public User() {} // For Morphia @@ -98,18 +91,8 @@ public final class User { updateUsername(lastUsername); } - public boolean hasPermissionScoped(String permission, ServerGroup scope) { - Rank highestRank = getHighestRank(scope); - Map scopedPermissions = PermissionUtils.mergePermissions( - PermissionUtils.getDefaultPermissions(highestRank), - scope.calculatePermissions(highestRank) - ); - - return scopedPermissions.containsKey(permission) && scopedPermissions.get(permission); - } - public boolean hasPermissionAnywhere(String permission) { - Map globalPermissions = PermissionUtils.getDefaultPermissions(getHighestRank()); + Map globalPermissions = PermissionUtils.getDefaultPermissions(getHighestRankAnywhere()); for (Map.Entry serverGroupEntry : getHighestRanks().entrySet()) { ServerGroup serverGroup = serverGroupEntry.getKey(); @@ -124,48 +107,7 @@ public final class User { return globalPermissions.containsKey(permission) && globalPermissions.get(permission); } - public List getGrants() { - return APIv3.getDatastore().createQuery(Grant.class).field("user").equal(id).asList(); - } - - public List getIPLog() { - return APIv3.getDatastore().createQuery(IPLogEntry.class).field("user").equal(id).asList(); - } - - public IPLogEntry getIPLogEntry(String ip) { - IPLogEntry existing = APIv3.getDatastore().createQuery(IPLogEntry.class).field("user").equal(id).field("userIp").equal(ip).get(); - - if (existing == null) { - existing = new IPLogEntry(this, ip); - APIv3.getDatastore().save(existing); - } - - return existing; - } - - public List getPunishments() { - return APIv3.getDatastore().createQuery(Punishment.class).field("user").equal(id).asList(); - } - - public List getPunishments(Iterable types) { - return APIv3.getDatastore().createQuery(Punishment.class).field("user").equal(id).field("type").in(types).asList(); - } - - public UserMetaEntry getMeta(ServerGroup group) { - return APIv3.getDatastore().createQuery(UserMetaEntry.class).field("user").equal(id).field("serverGroup").equal(group.getId()).get(); - } - - public void saveMeta(ServerGroup group, Document data) { - UserMetaEntry entry = getMeta(group); - - if (entry == null) { - APIv3.getDatastore().save(new UserMetaEntry(this, group, data)); - } else { - entry.setData(data); - APIv3.getDatastore().save(entry); - } - } - + // TODO: Clean public boolean seenOnServer(Server server) { if (online && server.getId().equals(this.lastSeenOn)) { return false; @@ -192,14 +134,13 @@ public final class User { User withNewUsername; - while ((withNewUsername = User.byLastUsername(username)) != null) { + while ((withNewUsername = User.findByLastUsername(username)) != null) { String newUsername = MojangUtils.getName(withNewUsername.getId()); withNewUsername.updateUsername(newUsername); } } this.aliases.put(username, new Date()); - APIv3.getDatastore().save(this); } public void setPassword(String input) { @@ -218,16 +159,17 @@ public final class User { return hashed.equals(password); } - public Rank getHighestRank() { - return getHighestRank(null); + public Rank getHighestRankAnywhere() { + return getHighestRankScoped(null); } - public Rank getHighestRank(ServerGroup serverGroup) { - return getHighestRank(serverGroup, getGrants()); + public Rank getHighestRankScoped(ServerGroup serverGroup) { + return getHighestRankScoped(serverGroup, Grant.findByUser(this)); } + // TODO: Clean // This is only used to help batch requests to mongo - public Rank getHighestRank(ServerGroup serverGroup, Iterable grants) { + public Rank getHighestRankScoped(ServerGroup serverGroup, Iterable grants) { Rank highest = null; for (Grant grant : grants) { @@ -235,7 +177,7 @@ public final class User { continue; } - Rank rank = Rank.byId(grant.getRank()); + Rank rank = Rank.findById(grant.getRank()); if (highest == null || rank.getWeight() > highest.getWeight()) { highest = rank; @@ -245,16 +187,17 @@ public final class User { if (highest != null) { return highest; } else { - return Rank.byId("default"); + return Rank.findById("default"); } } + // TODO: Clean public Map getHighestRanks() { Map highestRanks = new HashMap<>(); - Rank defaultRank = Rank.byId("default"); - List userGrants = getGrants(); + Rank defaultRank = Rank.findById("default"); + List userGrants = Grant.findByUser(this); - for (ServerGroup serverGroup : ServerGroup.values()) { + for (ServerGroup serverGroup : ServerGroup.findAll()) { Rank highest = defaultRank; for (Grant grant : userGrants) { @@ -262,7 +205,7 @@ public final class User { continue; } - Rank rank = Rank.byId(grant.getRank()); + Rank rank = Rank.findById(grant.getRank()); if (highest == null || rank.getWeight() > highest.getWeight()) { highest = rank; @@ -276,19 +219,19 @@ public final class User { } public Map getLoginInfo(Server server) { - return getLoginInfo( + return createLoginInfo( server, - getPunishments(ImmutableSet.of( + Punishment.findByUserAndType(this, ImmutableSet.of( Punishment.PunishmentType.BLACKLIST, Punishment.PunishmentType.BAN, Punishment.PunishmentType.MUTE )), - getGrants() + Grant.findByUser(this) ); } // This is only used to help batch requests to mongo - public Map getLoginInfo(Server server, Iterable punishments, Iterable grants) { + public Map createLoginInfo(Server server, Iterable punishments, Iterable grants) { Punishment activeMute = null; String accessDenialReason = null; @@ -304,7 +247,7 @@ public final class User { } } - Rank highestRank = getHighestRank(ServerGroup.byId(server.getServerGroup()), grants); + Rank highestRank = getHighestRankScoped(ServerGroup.findById(server.getServerGroup()), grants); // Generics are weird, yes we have to do this. ImmutableMap.Builder result = ImmutableMap.builder() @@ -323,4 +266,16 @@ public final class User { return result.build(); } + public void insert() { + BlockingCallback callback = new BlockingCallback<>(); + usersCollection.insertOne(this, callback); + callback.get(); + } + + public void save() { + BlockingCallback callback = new BlockingCallback<>(); + usersCollection.replaceOne(new Document("_id", id), this, callback); + callback.get(); + } + } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/models/UserMetaEntry.java b/src/main/java/net/frozenorb/apiv3/models/UserMetaEntry.java index 319fc51..bee4fed 100644 --- a/src/main/java/net/frozenorb/apiv3/models/UserMetaEntry.java +++ b/src/main/java/net/frozenorb/apiv3/models/UserMetaEntry.java @@ -1,25 +1,49 @@ package net.frozenorb.apiv3.models; import com.google.common.collect.ImmutableMap; +import com.mongodb.async.client.MongoCollection; +import com.mongodb.client.result.DeleteResult; +import com.mongodb.client.result.UpdateResult; +import eu.dozd.mongo.annotation.Entity; +import eu.dozd.mongo.annotation.Id; import lombok.Getter; import lombok.Setter; import net.frozenorb.apiv3.APIv3; +import net.frozenorb.apiv3.unsorted.BlockingCallback; +import net.frozenorb.apiv3.utils.SyncUtils; +import org.bson.Document; import org.bson.types.ObjectId; -import org.mongodb.morphia.annotations.Entity; -import org.mongodb.morphia.annotations.Id; -import org.mongodb.morphia.annotations.Indexed; +import java.util.List; import java.util.Map; import java.util.UUID; -@Entity(value = "userMeta", noClassnameStored = true) +@Entity public final class UserMetaEntry { + private static final MongoCollection userMetaCollection = APIv3.getDatabase().getCollection("userMeta", UserMetaEntry.class); + @Getter @Id private String id; - @Getter @Indexed private UUID user; - @Getter @Indexed private String serverGroup; + @Getter private UUID user; + @Getter private String serverGroup; @Getter @Setter private Map data; + public static List findAll() { + return SyncUtils.blockMulti(userMetaCollection.find()); + } + + public static UserMetaEntry findById(String id) { + return SyncUtils.blockOne(userMetaCollection.find(new Document("_id", id))); + } + + public static UserMetaEntry findByUserAndGroup(User user, ServerGroup serverGroup) { + return findByUserAndGroup(user.getId(), serverGroup); + } + + public static UserMetaEntry findByUserAndGroup(UUID user, ServerGroup serverGroup) { + return SyncUtils.blockOne(userMetaCollection.find(new Document("user", user).append("serverGroup", serverGroup.getId()))); + } + public UserMetaEntry() {} // For Morphia public UserMetaEntry(User user, ServerGroup serverGroup, Map data) { @@ -29,8 +53,22 @@ public final class UserMetaEntry { this.data = ImmutableMap.copyOf(data); } + public void insert() { + BlockingCallback callback = new BlockingCallback<>(); + userMetaCollection.insertOne(this, callback); + callback.get(); + } + + public void save() { + BlockingCallback callback = new BlockingCallback<>(); + userMetaCollection.replaceOne(new Document("_id", id), this, callback); + callback.get(); + } + public void delete() { - APIv3.getDatastore().delete(this); + BlockingCallback callback = new BlockingCallback<>(); + userMetaCollection.deleteOne(new Document("_id", id), callback); + callback.get(); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/GETDump.java b/src/main/java/net/frozenorb/apiv3/routes/GETDump.java index 72d16b6..449e054 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/GETDump.java +++ b/src/main/java/net/frozenorb/apiv3/routes/GETDump.java @@ -1,6 +1,7 @@ package net.frozenorb.apiv3.routes; import com.google.common.collect.ImmutableSet; +import io.vertx.core.Handler; import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.Grant; @@ -28,7 +29,8 @@ public final class GETDump implements Handler { List banCache = new ArrayList<>(); List blacklistCache = new ArrayList<>(); - APIv3.getDatastore().createQuery(Punishment.class).field("type").in(ImmutableSet.of( + Punishment.findByType + (ImmutableSet.of( Punishment.PunishmentType.BAN, Punishment.PunishmentType.BLACKLIST )).forEach((punishment) -> { @@ -50,7 +52,7 @@ public final class GETDump implements Handler { if (tick == 0 || tick % 2 == 0) { Map> grantCache = new HashMap<>(); - APIv3.getDatastore().createQuery(Grant.class).forEach((grant) -> { + Grant.findAll().forEach((grant) -> { if (grant.isActive()) { List users = grantCache.get(grant.getRank()); @@ -88,21 +90,25 @@ public final class GETDump implements Handler { switch (type.toLowerCase()) { case "ban": - return banCache; + APIv3.respondJson(ctx, banCache); + return; case "blacklist": - return blacklistCache; + APIv3.respondJson(ctx, blacklistCache); + return; case "accessdeniable": // Lowercase d because we convert to lowercase above List result = new ArrayList<>(); result.addAll(banCache); result.addAll(blacklistCache); - return result; + APIv3.respondJson(ctx, result); + return; case "grant": - return grantCache; + APIv3.respondJson(ctx, grantCache); + return; default: - ErrorUtils.respondInvalidInput(ctx, "type", type + " is not a valid type. Not in [ban, blacklist, accessDeniable, grant]"); - return + ErrorUtils.respondInvalidInput(ctx, type + " is not a valid type. Not in [ban, blacklist, accessDeniable, grant]"); + return; } } diff --git a/src/main/java/net/frozenorb/apiv3/routes/GETWhoAmI.java b/src/main/java/net/frozenorb/apiv3/routes/GETWhoAmI.java index 6301ccd..0649b92 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/GETWhoAmI.java +++ b/src/main/java/net/frozenorb/apiv3/routes/GETWhoAmI.java @@ -1,6 +1,9 @@ package net.frozenorb.apiv3.routes; import com.google.common.collect.ImmutableMap; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.actors.Actor; public final class GETWhoAmI implements Handler { @@ -8,11 +11,11 @@ public final class GETWhoAmI implements Handler { public void handle(RoutingContext ctx) { Actor actor = ctx.get("actor"); - return ImmutableMap.of( + APIv3.respondJson(ctx, ImmutableMap.of( "name", actor.getName(), "type", actor.getType(), "authorized", actor.isAuthorized() - ); + )); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/NotFound.java b/src/main/java/net/frozenorb/apiv3/routes/NotFound.java deleted file mode 100644 index da5b900..0000000 --- a/src/main/java/net/frozenorb/apiv3/routes/NotFound.java +++ /dev/null @@ -1,17 +0,0 @@ -package net.frozenorb.apiv3.routes; - -import lombok.extern.slf4j.Slf4j; -import net.frozenorb.apiv3.APIv3; -import net.frozenorb.apiv3.utils.ErrorUtils; -import spark.Spark; - -@Slf4j -public final class NotFound implements Handler { - - public void handle(RoutingContext ctx) { - log.info(req.requestMethod().toUpperCase() + " " + req.url()); - Spark.halt(404, APIv3.getGson().toJson(ErrorUtils.respondNotFound("Route", req.url()))); - return null; - } - -} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/POSTMetrics.java b/src/main/java/net/frozenorb/apiv3/routes/POSTMetrics.java index a6708f8..1756ee9 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/POSTMetrics.java +++ b/src/main/java/net/frozenorb/apiv3/routes/POSTMetrics.java @@ -1,13 +1,14 @@ package net.frozenorb.apiv3.routes; import com.google.common.collect.ImmutableMap; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import net.frozenorb.apiv3.APIv3; public final class POSTMetrics implements Handler { public void handle(RoutingContext ctx) { - //LibratoBatch batch = new LibratoBatch(); - - return ImmutableMap.of(); + APIv3.respondJson(ctx, ImmutableMap.of()); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/announcements/GETAnnouncements.java b/src/main/java/net/frozenorb/apiv3/routes/announcements/GETAnnouncements.java index 3bb43e8..dd6b553 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/announcements/GETAnnouncements.java +++ b/src/main/java/net/frozenorb/apiv3/routes/announcements/GETAnnouncements.java @@ -21,9 +21,9 @@ public final class GETAnnouncements implements Handler { } Server sender = ((ServerActor) actor).getServer(); - ServerGroup senderGroup = ServerGroup.byId(sender.getServerGroup()); + ServerGroup senderGroup = ServerGroup.findById(sender.getServerGroup()); - APIv3.respond(ctx, senderGroup.getAnnouncements()); + APIv3.respondJson(ctx, senderGroup.getAnnouncements()); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/auditLog/GETAuditLog.java b/src/main/java/net/frozenorb/apiv3/routes/auditLog/GETAuditLog.java index 32df4bc..1f3ce08 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/auditLog/GETAuditLog.java +++ b/src/main/java/net/frozenorb/apiv3/routes/auditLog/GETAuditLog.java @@ -13,7 +13,7 @@ public final class GETAuditLog implements Handler { int limit = ctx.request().getParam("limit") == null ? 100 : Integer.parseInt(ctx.request().getParam("limit")); int offset = ctx.request().getParam("offset") == null ? 0 : Integer.parseInt(ctx.request().getParam("offset")); - APIv3.respond(ctx, APIv3.getDatastore().createQuery(AuditLogEntry.class).order("performedAt").limit(limit).offset(offset).asList()); + APIv3.respondJson(ctx, APIv3.getDatastore().createQuery(AuditLogEntry.class).order("performedAt").limit(limit).offset(offset).asList()); } catch (NumberFormatException ex) { ErrorUtils.respondInvalidInput(ctx, "limit/offset must be numerical inputs."); } diff --git a/src/main/java/net/frozenorb/apiv3/routes/chatFilterList/GETChatFilterList.java b/src/main/java/net/frozenorb/apiv3/routes/chatFilterList/GETChatFilterList.java index 8c4e414..879edbf 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/chatFilterList/GETChatFilterList.java +++ b/src/main/java/net/frozenorb/apiv3/routes/chatFilterList/GETChatFilterList.java @@ -1,7 +1,6 @@ package net.frozenorb.apiv3.routes.chatFilterList; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; import io.vertx.core.Handler; import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; @@ -9,7 +8,7 @@ import net.frozenorb.apiv3.APIv3; public final class GETChatFilterList implements Handler { public void handle(RoutingContext ctx) { - APIv3.respond(ctx, ImmutableMap.of()); + APIv3.respondJson(ctx, ImmutableMap.of()); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/grants/DELETEGrant.java b/src/main/java/net/frozenorb/apiv3/routes/grants/DELETEGrant.java index ed3116a..4dc0c67 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/grants/DELETEGrant.java +++ b/src/main/java/net/frozenorb/apiv3/routes/grants/DELETEGrant.java @@ -13,7 +13,7 @@ import net.frozenorb.apiv3.utils.ErrorUtils; public final class DELETEGrant implements Handler { public void handle(RoutingContext ctx) { - Grant grant = Grant.byId(ctx.request().getParam("id")); + Grant grant = Grant.findById(ctx.request().getParam("id")); if (grant == null) { ErrorUtils.respondNotFound(ctx, "Grant", ctx.request().getParam("id")); @@ -23,7 +23,7 @@ public final class DELETEGrant implements Handler { return; } - User removedBy = User.byId(ctx.request().getParam("removedBy")); + User removedBy = User.findById(ctx.request().getParam("removedBy")); if (removedBy == null) { ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("removedBy")); @@ -39,7 +39,7 @@ public final class DELETEGrant implements Handler { grant.delete(removedBy, reason); AuditLog.log(removedBy, "", ctx.get("actor"), AuditLogActionType.DELETE_GRANT, ImmutableMap.of()); - APIv3.respond(ctx, grant); + APIv3.respondJson(ctx, grant); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/grants/GETGrant.java b/src/main/java/net/frozenorb/apiv3/routes/grants/GETGrant.java index 7be04ae..d544499 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/grants/GETGrant.java +++ b/src/main/java/net/frozenorb/apiv3/routes/grants/GETGrant.java @@ -8,7 +8,7 @@ import net.frozenorb.apiv3.models.Grant; public final class GETGrant implements Handler { public void handle(RoutingContext ctx) { - APIv3.respond(ctx, Grant.byId(ctx.request().getParam("id"))); + APIv3.respondJson(ctx, Grant.findById(ctx.request().getParam("id"))); } } \ 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 e3403c8..f7120f0 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/grants/GETGrants.java +++ b/src/main/java/net/frozenorb/apiv3/routes/grants/GETGrants.java @@ -13,7 +13,7 @@ public final class GETGrants implements Handler { int limit = ctx.request().getParam("limit") == null ? 100 : Integer.parseInt(ctx.request().getParam("limit")); int offset = ctx.request().getParam("offset") == null ? 0 : Integer.parseInt(ctx.request().getParam("offset")); - APIv3.respond(ctx, APIv3.getDatastore().createQuery(Grant.class).order("addedAt").limit(limit).offset(offset).asList()); + APIv3.respondJson(ctx, APIv3.getDatastore().createQuery(Grant.class).order("addedAt").limit(limit).offset(offset).asList()); } catch (NumberFormatException ex) { ErrorUtils.respondInvalidInput(ctx, "limit and offset must be numerical inputs."); } diff --git a/src/main/java/net/frozenorb/apiv3/routes/grants/GETUserGrants.java b/src/main/java/net/frozenorb/apiv3/routes/grants/GETUserGrants.java index 028d17b..36e392a 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/grants/GETUserGrants.java +++ b/src/main/java/net/frozenorb/apiv3/routes/grants/GETUserGrants.java @@ -3,20 +3,21 @@ package net.frozenorb.apiv3.routes.grants; import io.vertx.core.Handler; import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; +import net.frozenorb.apiv3.models.Grant; import net.frozenorb.apiv3.models.User; import net.frozenorb.apiv3.utils.ErrorUtils; public final class GETUserGrants implements Handler { public void handle(RoutingContext ctx) { - User target = User.byId(ctx.request().getParam("id")); + User target = User.findById(ctx.request().getParam("id")); if (target == null) { ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id")); return; } - APIv3.respond(ctx, target.getGrants()); + APIv3.respondJson(ctx, Grant.findByUser(target)); } } \ 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 6c12062..709bc5f 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/grants/POSTUserGrant.java +++ b/src/main/java/net/frozenorb/apiv3/routes/grants/POSTUserGrant.java @@ -1,5 +1,7 @@ package net.frozenorb.apiv3.routes.grants; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.Grant; import net.frozenorb.apiv3.models.Rank; @@ -14,16 +16,18 @@ import java.util.Set; public final class POSTUserGrant implements Handler { public void handle(RoutingContext ctx) { - User target = User.byId(ctx.request().getParam("id")); + User target = User.findById(ctx.request().getParam("id")); if (target == null) { - return ErrorUtils.respondNotFound("User", ctx.request().getParam("id")); + ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id")); + return; } String reason = ctx.request().getParam("reason"); if (reason == null || reason.trim().isEmpty()) { - return ErrorUtils.respondRequiredInput("reason"); + ErrorUtils.respondRequiredInput(ctx, "reason"); + return; } Set scopes = new HashSet<>(); @@ -31,20 +35,22 @@ public final class POSTUserGrant implements Handler { if (!scopesUnparsed.isEmpty()) { for (String serverGroupId : scopesUnparsed.split(",")) { - ServerGroup serverGroup = ServerGroup.byId(serverGroupId); + ServerGroup serverGroup = ServerGroup.findById(serverGroupId); if (serverGroup == null) { - return ErrorUtils.respondNotFound("Server group", serverGroupId); + ErrorUtils.respondNotFound(ctx, "Server group", serverGroupId); + return; } scopes.add(serverGroup); } } - Rank rank = Rank.byId(ctx.request().getParam("rank")); + Rank rank = Rank.findById(ctx.request().getParam("rank")); if (rank == null) { - return ErrorUtils.respondNotFound("Rank", ctx.request().getParam("rank")); + ErrorUtils.respondNotFound(ctx, "Rank", ctx.request().getParam("rank")); + return; } Date expiresAt; @@ -56,15 +62,16 @@ public final class POSTUserGrant implements Handler { } if (expiresAt != null && expiresAt.before(new Date())) { - return ErrorUtils.respondInvalidInput("Expiration date cannot be in the past."); + ErrorUtils.respondInvalidInput(ctx, "Expiration date cannot be in the past."); + return; } // We purposely don't do a null check, grants don't have to have a source. - User addedBy = User.byId(ctx.request().getParam("addedBy")); + User addedBy = User.findById(ctx.request().getParam("addedBy")); Grant grant = new Grant(target, reason, scopes, rank, expiresAt, addedBy); - APIv3.getDatastore().save(grant); - return grant; + grant.insert(); + APIv3.respondJson(ctx, grant); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/ipLog/GETUserIPLog.java b/src/main/java/net/frozenorb/apiv3/routes/ipLog/GETUserIPLog.java index 863a7d4..1addce1 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/ipLog/GETUserIPLog.java +++ b/src/main/java/net/frozenorb/apiv3/routes/ipLog/GETUserIPLog.java @@ -3,20 +3,21 @@ package net.frozenorb.apiv3.routes.ipLog; import io.vertx.core.Handler; import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; +import net.frozenorb.apiv3.models.IPLogEntry; import net.frozenorb.apiv3.models.User; import net.frozenorb.apiv3.utils.ErrorUtils; public final class GETUserIPLog implements Handler { public void handle(RoutingContext ctx) { - User target = User.byId(ctx.request().getParam("id")); + User target = User.findById(ctx.request().getParam("id")); if (target == null) { ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id")); return; } - APIv3.respond(ctx, target.getIPLog()); + APIv3.respondJson(ctx, IPLogEntry.findByUser(target)); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/notificationTemplate/DELETENotificationTemplate.java b/src/main/java/net/frozenorb/apiv3/routes/notificationTemplate/DELETENotificationTemplate.java index 95fe657..8afc202 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/notificationTemplate/DELETENotificationTemplate.java +++ b/src/main/java/net/frozenorb/apiv3/routes/notificationTemplate/DELETENotificationTemplate.java @@ -9,7 +9,7 @@ import net.frozenorb.apiv3.utils.ErrorUtils; public final class DELETENotificationTemplate implements Handler { public void handle(RoutingContext ctx) { - NotificationTemplate notificationTemplate = NotificationTemplate.byId(ctx.request().getParam("id")); + NotificationTemplate notificationTemplate = NotificationTemplate.findById(ctx.request().getParam("id")); if (notificationTemplate == null) { ErrorUtils.respondNotFound(ctx, "Notification template", ctx.request().getParam("id")); @@ -17,7 +17,7 @@ public final class DELETENotificationTemplate implements Handler } notificationTemplate.delete(); - APIv3.respond(ctx, notificationTemplate); + APIv3.respondJson(ctx, notificationTemplate); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/notificationTemplate/GETNotificationTemplate.java b/src/main/java/net/frozenorb/apiv3/routes/notificationTemplate/GETNotificationTemplate.java index 9e55dbf..58bf102 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/notificationTemplate/GETNotificationTemplate.java +++ b/src/main/java/net/frozenorb/apiv3/routes/notificationTemplate/GETNotificationTemplate.java @@ -8,7 +8,7 @@ import net.frozenorb.apiv3.models.NotificationTemplate; public final class GETNotificationTemplate implements Handler { public void handle(RoutingContext ctx) { - APIv3.respond(ctx, NotificationTemplate.byId(ctx.request().getParam("id"))); + APIv3.respondJson(ctx, NotificationTemplate.findById(ctx.request().getParam("id"))); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/notificationTemplate/GETNotificationTemplates.java b/src/main/java/net/frozenorb/apiv3/routes/notificationTemplate/GETNotificationTemplates.java index 3c6f162..2dcd2fc 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/notificationTemplate/GETNotificationTemplates.java +++ b/src/main/java/net/frozenorb/apiv3/routes/notificationTemplate/GETNotificationTemplates.java @@ -8,7 +8,7 @@ import net.frozenorb.apiv3.models.NotificationTemplate; public final class GETNotificationTemplates implements Handler { public void handle(RoutingContext ctx) { - APIv3.respond(ctx, NotificationTemplate.values()); + APIv3.respondJson(ctx, NotificationTemplate.findAll()); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/notificationTemplate/POSTNotificationTemplate.java b/src/main/java/net/frozenorb/apiv3/routes/notificationTemplate/POSTNotificationTemplate.java index 9aa8c4c..d913b96 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/notificationTemplate/POSTNotificationTemplate.java +++ b/src/main/java/net/frozenorb/apiv3/routes/notificationTemplate/POSTNotificationTemplate.java @@ -13,8 +13,8 @@ public final class POSTNotificationTemplate implements Handler { String body = ctx.request().getParam("body"); NotificationTemplate notificationTemplate = new NotificationTemplate(id, subject, body); - APIv3.getDatastore().save(notificationTemplate); - APIv3.respond(ctx, notificationTemplate); + notificationTemplate.insert(); + APIv3.respondJson(ctx, notificationTemplate); } } \ 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 bd578e1..c517ea4 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/punishments/DELETEPunishment.java +++ b/src/main/java/net/frozenorb/apiv3/routes/punishments/DELETEPunishment.java @@ -1,6 +1,9 @@ package net.frozenorb.apiv3.routes.punishments; import com.google.common.collect.ImmutableMap; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.auditLog.AuditLog; import net.frozenorb.apiv3.auditLog.AuditLogActionType; import net.frozenorb.apiv3.models.Punishment; @@ -10,29 +13,33 @@ import net.frozenorb.apiv3.utils.ErrorUtils; public final class DELETEPunishment implements Handler { public void handle(RoutingContext ctx) { - Punishment punishment = Punishment.byId(ctx.request().getParam("id")); + Punishment punishment = Punishment.findById(ctx.request().getParam("id")); if (punishment == null) { - return ErrorUtils.respondNotFound("Punishment", ctx.request().getParam("id")); + ErrorUtils.respondNotFound(ctx, "Punishment", ctx.request().getParam("id")); + return; } else if (!punishment.isActive()) { - return ErrorUtils.respondInvalidInput("Cannot remove an inactive punishment."); + ErrorUtils.respondInvalidInput(ctx, "Cannot remove an inactive punishment."); + return; } - User removedBy = User.byId(ctx.request().getParam("removedBy")); + User removedBy = User.findById(ctx.request().getParam("removedBy")); if (removedBy == null) { - return ErrorUtils.respondNotFound("User", ctx.request().getParam("removedBy")); + ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("removedBy")); + return; } String reason = ctx.request().getParam("reason"); if (reason == null || reason.trim().isEmpty()) { - return ErrorUtils.respondRequiredInput("reason"); + ErrorUtils.respondRequiredInput(ctx, "reason"); + return; } punishment.delete(removedBy, reason); AuditLog.log(removedBy, "", ctx.get("actor"), AuditLogActionType.DELETE_PUNISHMENT, ImmutableMap.of()); - return punishment; + APIv3.respondJson(ctx, punishment); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/punishments/GETPunishment.java b/src/main/java/net/frozenorb/apiv3/routes/punishments/GETPunishment.java index 1315bd4..f502ffa 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/punishments/GETPunishment.java +++ b/src/main/java/net/frozenorb/apiv3/routes/punishments/GETPunishment.java @@ -1,11 +1,14 @@ package net.frozenorb.apiv3.routes.punishments; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.Punishment; public final class GETPunishment implements Handler { public void handle(RoutingContext ctx) { - return Punishment.byId(ctx.request().getParam("id")); + APIv3.respondJson(ctx, Punishment.findById(ctx.request().getParam("id"))); } } \ No newline at end of file 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 821dfb1..1e0a41a 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/punishments/GETPunishments.java +++ b/src/main/java/net/frozenorb/apiv3/routes/punishments/GETPunishments.java @@ -1,5 +1,7 @@ package net.frozenorb.apiv3.routes.punishments; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.Punishment; import net.frozenorb.apiv3.utils.ErrorUtils; @@ -11,9 +13,9 @@ public final class GETPunishments implements Handler { int limit = ctx.request().getParam("limit") == null ? 100 : Integer.parseInt(ctx.request().getParam("limit")); int offset = ctx.request().getParam("offset") == null ? 0 : Integer.parseInt(ctx.request().getParam("offset")); - return APIv3.getDatastore().createQuery(Punishment.class).order("addedAt").limit(limit).offset(offset).asList(); + APIv3.respondJson(ctx, APIv3.getDatastore().createQuery(Punishment.class).order("addedAt").limit(limit).offset(offset).asList()); } catch (NumberFormatException ex) { - return ErrorUtils.respondInvalidInput("limit and offset must be numerical inputs."); + ErrorUtils.respondInvalidInput(ctx, "limit and offset must be numerical inputs."); } } diff --git a/src/main/java/net/frozenorb/apiv3/routes/punishments/GETUserPunishments.java b/src/main/java/net/frozenorb/apiv3/routes/punishments/GETUserPunishments.java index 79d5774..f55ace0 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/punishments/GETUserPunishments.java +++ b/src/main/java/net/frozenorb/apiv3/routes/punishments/GETUserPunishments.java @@ -1,18 +1,23 @@ package net.frozenorb.apiv3.routes.punishments; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import net.frozenorb.apiv3.APIv3; +import net.frozenorb.apiv3.models.Punishment; import net.frozenorb.apiv3.models.User; import net.frozenorb.apiv3.utils.ErrorUtils; public final class GETUserPunishments implements Handler { public void handle(RoutingContext ctx) { - User target = User.byId(ctx.request().getParam("id")); + User target = User.findById(ctx.request().getParam("id")); if (target == null) { - return ErrorUtils.respondNotFound("User", ctx.request().getParam("id")); + ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id")); + return; } - return target.getPunishments(); + APIv3.respondJson(ctx, Punishment.findByUser(target)); } } \ 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 483c29c..8cb4dd9 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/punishments/POSTUserPunish.java +++ b/src/main/java/net/frozenorb/apiv3/routes/punishments/POSTUserPunish.java @@ -2,6 +2,8 @@ package net.frozenorb.apiv3.routes.punishments; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.Punishment; import net.frozenorb.apiv3.models.User; @@ -15,24 +17,27 @@ import java.util.Map; public final class POSTUserPunish implements Handler { public void handle(RoutingContext ctx) { - User target = User.byId(ctx.request().getParam("id")); + User target = User.findById(ctx.request().getParam("id")); if (target == null) { - return ErrorUtils.respondNotFound("User", ctx.request().getParam("id")); + ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id")); + return; } String reason = ctx.request().getParam("reason"); if (reason == null || reason.trim().isEmpty()) { - return ErrorUtils.respondRequiredInput("reason"); + ErrorUtils.respondRequiredInput(ctx, "reason"); + return; } Punishment.PunishmentType type = Punishment.PunishmentType.valueOf(ctx.request().getParam("type")); if (type != Punishment.PunishmentType.WARN) { - for (Punishment punishment : target.getPunishments(ImmutableSet.of(type))) { + for (Punishment punishment : Punishment.findByUserAndType(target, ImmutableSet.of(type))) { if (punishment.isActive()) { - return ErrorUtils.error("A punishment by " + User.byId(punishment.getAddedBy()).getLastUsername() + " already covers this user."); + ErrorUtils.respondGeneric(ctx, "A punishment by " + User.findById(punishment.getAddedBy()).getLastUsername() + " already covers this user."); + return; } } } @@ -46,30 +51,33 @@ public final class POSTUserPunish implements Handler { } if (expiresAt != null && expiresAt.before(new Date())) { - return ErrorUtils.respondInvalidInput("Expiration date cannot be in the past."); + ErrorUtils.respondInvalidInput(ctx, "Expiration date cannot be in the past."); + return; } - Map meta = Document.parse(req.body()); + Map meta = Document.parse(ctx.getBodyAsString()); if (meta == null) { - return ErrorUtils.respondRequiredInput("request body meta"); + ErrorUtils.respondRequiredInput(ctx, "request body meta"); + return; } // We purposely don't do a null check, grants don't have to have a source. - User addedBy = User.byId(ctx.request().getParam("addedBy")); + User addedBy = User.findById(ctx.request().getParam("addedBy")); if (target.hasPermissionAnywhere(Permissions.PROTECTED_PUNISHMENT)) { - return ErrorUtils.error(target.getLastSeenOn() + " is protected from punishments."); + ErrorUtils.respondGeneric(ctx, target.getLastSeenOn() + " is protected from punishments."); + return; } Punishment punishment = new Punishment(target, reason, type, expiresAt, addedBy, ctx.get("actor"), meta); String accessDenialReason = punishment.getAccessDenialReason(); - APIv3.getDatastore().save(punishment); + punishment.insert(); - return ImmutableMap.of( + APIv3.respondJson(ctx, ImmutableMap.of( "punishment", punishment, "accessDenialReason", accessDenialReason == null ? "" : accessDenialReason - ); + )); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/ranks/DELETERank.java b/src/main/java/net/frozenorb/apiv3/routes/ranks/DELETERank.java index b9e1092..ed97e39 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/ranks/DELETERank.java +++ b/src/main/java/net/frozenorb/apiv3/routes/ranks/DELETERank.java @@ -1,19 +1,23 @@ package net.frozenorb.apiv3.routes.ranks; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.Rank; import net.frozenorb.apiv3.utils.ErrorUtils; public final class DELETERank implements Handler { public void handle(RoutingContext ctx) { - Rank rank = Rank.byId(ctx.request().getParam("id")); + Rank rank = Rank.findById(ctx.request().getParam("id")); if (rank == null) { - return ErrorUtils.respondNotFound("Rank", ctx.request().getParam("id")); + ErrorUtils.respondNotFound(ctx, "Rank", ctx.request().getParam("id")); + return; } rank.delete(); - return rank; + APIv3.respondJson(ctx, rank); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/ranks/GETRank.java b/src/main/java/net/frozenorb/apiv3/routes/ranks/GETRank.java index 91a692f..f80c8ba 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/ranks/GETRank.java +++ b/src/main/java/net/frozenorb/apiv3/routes/ranks/GETRank.java @@ -1,11 +1,14 @@ package net.frozenorb.apiv3.routes.ranks; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.Rank; public final class GETRank implements Handler { public void handle(RoutingContext ctx) { - return Rank.byId(ctx.request().getParam("id")); + APIv3.respondJson(ctx, Rank.findById(ctx.request().getParam("id"))); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/ranks/GETRanks.java b/src/main/java/net/frozenorb/apiv3/routes/ranks/GETRanks.java index d8dd68e..637b65e 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/ranks/GETRanks.java +++ b/src/main/java/net/frozenorb/apiv3/routes/ranks/GETRanks.java @@ -1,11 +1,14 @@ package net.frozenorb.apiv3.routes.ranks; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.Rank; public final class GETRanks implements Handler { public void handle(RoutingContext ctx) { - return Rank.values(); + APIv3.respondJson(ctx, Rank.findAll()); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/ranks/POSTRank.java b/src/main/java/net/frozenorb/apiv3/routes/ranks/POSTRank.java index e7ed2e8..0ad21c9 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/ranks/POSTRank.java +++ b/src/main/java/net/frozenorb/apiv3/routes/ranks/POSTRank.java @@ -1,5 +1,7 @@ package net.frozenorb.apiv3.routes.ranks; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.Rank; @@ -14,8 +16,8 @@ public final class POSTRank implements Handler { boolean staffRank = Boolean.parseBoolean(ctx.request().getParam("staffRank")); Rank rank = new Rank(id, weight, displayName, gameColor, websiteColor, staffRank); - APIv3.getDatastore().save(rank); - return rank; + rank.insert(); + APIv3.respondJson(ctx, rank); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/serverGroups/DELETEServerGroup.java b/src/main/java/net/frozenorb/apiv3/routes/serverGroups/DELETEServerGroup.java index 1fa5451..f8d3315 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/serverGroups/DELETEServerGroup.java +++ b/src/main/java/net/frozenorb/apiv3/routes/serverGroups/DELETEServerGroup.java @@ -1,19 +1,23 @@ package net.frozenorb.apiv3.routes.serverGroups; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.ServerGroup; import net.frozenorb.apiv3.utils.ErrorUtils; public final class DELETEServerGroup implements Handler { public void handle(RoutingContext ctx) { - ServerGroup serverGroup = ServerGroup.byId(ctx.request().getParam("id")); + ServerGroup serverGroup = ServerGroup.findById(ctx.request().getParam("id")); if (serverGroup == null) { - return ErrorUtils.respondNotFound("Server group", ctx.request().getParam("id")); + ErrorUtils.respondNotFound(ctx, "Server group", ctx.request().getParam("id")); + return; } serverGroup.delete(); - return serverGroup; + APIv3.respondJson(ctx, serverGroup); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/serverGroups/GETServerGroup.java b/src/main/java/net/frozenorb/apiv3/routes/serverGroups/GETServerGroup.java index 39ba0ea..0f288ce 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/serverGroups/GETServerGroup.java +++ b/src/main/java/net/frozenorb/apiv3/routes/serverGroups/GETServerGroup.java @@ -1,11 +1,14 @@ package net.frozenorb.apiv3.routes.serverGroups; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.ServerGroup; public final class GETServerGroup implements Handler { public void handle(RoutingContext ctx) { - return ServerGroup.byId(ctx.request().getParam("id")); + APIv3.respondJson(ctx, ServerGroup.findById(ctx.request().getParam("id"))); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/serverGroups/GETServerGroups.java b/src/main/java/net/frozenorb/apiv3/routes/serverGroups/GETServerGroups.java index 1788dda..a5e9e72 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/serverGroups/GETServerGroups.java +++ b/src/main/java/net/frozenorb/apiv3/routes/serverGroups/GETServerGroups.java @@ -1,11 +1,14 @@ package net.frozenorb.apiv3.routes.serverGroups; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.ServerGroup; public final class GETServerGroups implements Handler { public void handle(RoutingContext ctx) { - return ServerGroup.values(); + APIv3.respondJson(ctx, ServerGroup.findAll()); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/serverGroups/POSTServerGroup.java b/src/main/java/net/frozenorb/apiv3/routes/serverGroups/POSTServerGroup.java index 3055f8e..72de2c4 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/serverGroups/POSTServerGroup.java +++ b/src/main/java/net/frozenorb/apiv3/routes/serverGroups/POSTServerGroup.java @@ -1,5 +1,7 @@ package net.frozenorb.apiv3.routes.serverGroups; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.ServerGroup; @@ -11,8 +13,8 @@ public final class POSTServerGroup implements Handler { boolean isPublic = Boolean.valueOf(ctx.request().getParam("public")); ServerGroup serverGroup = new ServerGroup(id, image, isPublic); - APIv3.getDatastore().save(serverGroup); - return serverGroup; + serverGroup.insert(); + APIv3.respondJson(ctx, serverGroup); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/servers/DELETEServer.java b/src/main/java/net/frozenorb/apiv3/routes/servers/DELETEServer.java index 83cf362..24ff866 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/servers/DELETEServer.java +++ b/src/main/java/net/frozenorb/apiv3/routes/servers/DELETEServer.java @@ -1,19 +1,23 @@ package net.frozenorb.apiv3.routes.servers; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.Server; import net.frozenorb.apiv3.utils.ErrorUtils; public final class DELETEServer implements Handler { public void handle(RoutingContext ctx) { - Server server = Server.byId(ctx.request().getParam("id")); + Server server = Server.findById(ctx.request().getParam("id")); if (server == null) { - return ErrorUtils.respondNotFound("Server", ctx.request().getParam("id")); + ErrorUtils.respondNotFound(ctx, "Server", ctx.request().getParam("id")); + return; } server.delete(); - return server; + APIv3.respondJson(ctx, server); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/servers/GETServer.java b/src/main/java/net/frozenorb/apiv3/routes/servers/GETServer.java index 973528c..0a1b3e8 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/servers/GETServer.java +++ b/src/main/java/net/frozenorb/apiv3/routes/servers/GETServer.java @@ -1,11 +1,14 @@ package net.frozenorb.apiv3.routes.servers; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.Server; public final class GETServer implements Handler { public void handle(RoutingContext ctx) { - return Server.byId(ctx.request().getParam("id")); + APIv3.respondJson(ctx, Server.findById(ctx.request().getParam("id"))); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/servers/GETServers.java b/src/main/java/net/frozenorb/apiv3/routes/servers/GETServers.java index 52cb5ad..8dc2452 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/servers/GETServers.java +++ b/src/main/java/net/frozenorb/apiv3/routes/servers/GETServers.java @@ -1,11 +1,14 @@ package net.frozenorb.apiv3.routes.servers; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.Server; public final class GETServers implements Handler { public void handle(RoutingContext ctx) { - return Server.values(); + APIv3.respondJson(ctx, Server.findAll()); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/servers/POSTServer.java b/src/main/java/net/frozenorb/apiv3/routes/servers/POSTServer.java index a534f03..69e2f5f 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/servers/POSTServer.java +++ b/src/main/java/net/frozenorb/apiv3/routes/servers/POSTServer.java @@ -1,5 +1,7 @@ package net.frozenorb.apiv3.routes.servers; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.Server; import net.frozenorb.apiv3.models.ServerGroup; @@ -12,20 +14,22 @@ public final class POSTServer implements Handler { String id = ctx.request().getParam("id"); String displayName = ctx.request().getParam("displayName"); String apiKey = ctx.request().getParam("apiKey"); - ServerGroup group = ServerGroup.byId(ctx.request().getParam("group")); + ServerGroup group = ServerGroup.findById(ctx.request().getParam("group")); String ip = ctx.request().getParam("ip"); if (group == null) { - return ErrorUtils.respondNotFound("Server group", ctx.request().getParam("group")); + ErrorUtils.respondNotFound(ctx, "Server group", ctx.request().getParam("group")); + return; } if (!IPUtils.isValidIP(ip)) { - return ErrorUtils.respondInvalidInput("IP address \"" + ip + "\" is not valid."); + ErrorUtils.respondInvalidInput(ctx, "IP address \"" + ip + "\" is not valid."); + return; } Server server = new Server(id, displayName, apiKey, group, ip); - APIv3.getDatastore().save(server); - return server; + server.insert(); + APIv3.respondJson(ctx, server); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/servers/POSTServerHeartbeat.java b/src/main/java/net/frozenorb/apiv3/routes/servers/POSTServerHeartbeat.java index bbd3721..2a34f3e 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/servers/POSTServerHeartbeat.java +++ b/src/main/java/net/frozenorb/apiv3/routes/servers/POSTServerHeartbeat.java @@ -1,6 +1,8 @@ package net.frozenorb.apiv3.routes.servers; import com.google.common.collect.ImmutableMap; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; import lombok.extern.slf4j.Slf4j; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.actors.Actor; @@ -21,16 +23,17 @@ public final class POSTServerHeartbeat implements Handler { Actor actor = ctx.get("actor"); if (actor.getType() != ActorType.SERVER) { - return ErrorUtils.respondServerOnly(); + ErrorUtils.respondServerOnly(ctx); + return; } Server actorServer = Server.byId(actor.getName()); ServerGroup actorServerGroup = ServerGroup.byId(actorServer.getServerGroup()); - Document reqJson = Document.parse(req.body()); + Document reqJson = Document.parse(ctx.getBodyAsString()); Map onlinePlayersNames = new HashMap<>(); - Map onlinePlayersUsers = new HashMap<>(); - Map> onlinePlayersGrants = new HashMap<>(); - Map> onlinePlayersPunishments = new HashMap<>(); + Map onlinePlayersUsers; + Map> onlinePlayersGrants; + Map> onlinePlayersPunishments; Map playersResponse = new HashMap<>(); // This code is messy, but we have to do db ops in parallel to avoid @@ -71,7 +74,7 @@ public final class POSTServerHeartbeat implements Handler { UUID uuid = entry.getKey(); User user = entry.getValue(); - playersResponse.put(uuid.toString(), user.getLoginInfo(actorServer, onlinePlayersPunishments.get(uuid), onlinePlayersGrants.get(uuid))); + playersResponse.put(uuid.toString(), user.prepareLoginInfo(actorServer, onlinePlayersPunishments.get(uuid), onlinePlayersGrants.get(uuid))); } for (Object event : (List) reqJson.get("events")) { @@ -92,7 +95,7 @@ public final class POSTServerHeartbeat implements Handler { Map> permissionsResponse = new HashMap<>(); - for (Rank rank : Rank.values()) { + for (Rank rank : Rank.findAll()) { Map scopedPermissions = PermissionUtils.mergePermissions( PermissionUtils.getDefaultPermissions(rank), actorServerGroup.calculatePermissions(rank) @@ -104,12 +107,12 @@ public final class POSTServerHeartbeat implements Handler { actorServer.setPlayers(onlinePlayersNames.keySet()); actorServer.setLastTps(reqJson.getDouble("lastTps")); actorServer.setLastUpdatedAt(new Date()); - APIv3.getDatastore().save(actorServer); + actorServer.save(); - return ImmutableMap.of( + APIv3.respondJson(ctx, ImmutableMap.of( "players", playersResponse, "permissions", permissionsResponse - ); + )); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/users/DELETEUserMeta.java b/src/main/java/net/frozenorb/apiv3/routes/users/DELETEUserMeta.java index e7c9cd6..03716b5 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/users/DELETEUserMeta.java +++ b/src/main/java/net/frozenorb/apiv3/routes/users/DELETEUserMeta.java @@ -1,29 +1,39 @@ package net.frozenorb.apiv3.routes.users; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.ServerGroup; import net.frozenorb.apiv3.models.User; import net.frozenorb.apiv3.models.UserMetaEntry; import net.frozenorb.apiv3.utils.ErrorUtils; +import org.bson.Document; public final class DELETEUserMeta implements Handler { public void handle(RoutingContext ctx) { - User user = User.byId(ctx.request().getParam("id")); + User user = User.findById(ctx.request().getParam("id")); if (user == null) { - return ErrorUtils.respondNotFound("User", ctx.request().getParam("id")); + ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id")); + return; } - ServerGroup serverGroup = ServerGroup.byId(ctx.request().getParam("serverGroup")); + ServerGroup serverGroup = ServerGroup.findById(ctx.request().getParam("serverGroup")); if (serverGroup == null) { - return ErrorUtils.respondNotFound("Server group", ctx.request().getParam("serverGroup")); + ErrorUtils.respondNotFound(ctx, "Server group", ctx.request().getParam("serverGroup")); + return; } - UserMetaEntry userMetaEntry = user.getMeta(serverGroup); + UserMetaEntry userMetaEntry = UserMetaEntry.findByUserAndGroup(user, serverGroup); - userMetaEntry.delete(); - return userMetaEntry.getData(); + if (userMetaEntry != null) { + userMetaEntry.delete(); + APIv3.respondJson(ctx, userMetaEntry.getData()); + } else { + APIv3.respondJson(ctx, new Document()); + } } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/users/DELETEUserPunishment.java b/src/main/java/net/frozenorb/apiv3/routes/users/DELETEUserPunishment.java index ecfc385..f35b6cb 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/users/DELETEUserPunishment.java +++ b/src/main/java/net/frozenorb/apiv3/routes/users/DELETEUserPunishment.java @@ -2,6 +2,9 @@ package net.frozenorb.apiv3.routes.users; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.auditLog.AuditLog; import net.frozenorb.apiv3.auditLog.AuditLogActionType; import net.frozenorb.apiv3.models.Punishment; @@ -11,34 +14,38 @@ import net.frozenorb.apiv3.utils.ErrorUtils; public final class DELETEUserPunishment implements Handler { public void handle(RoutingContext ctx) { - User target = User.byId(ctx.request().getParam("id")); + User target = User.findById(ctx.request().getParam("id")); if (target == null) { - return ErrorUtils.respondNotFound("User", ctx.request().getParam("id")); + ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id")); + return; } Punishment.PunishmentType type = Punishment.PunishmentType.valueOf(ctx.request().getParam("type").toUpperCase()); - User removedBy = User.byId(ctx.request().getParam("removedBy")); + User removedBy = User.findById(ctx.request().getParam("removedBy")); if (removedBy == null) { - return ErrorUtils.respondNotFound("User", ctx.request().getParam("removedBy")); + ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("removedBy")); + return; } String reason = ctx.request().getParam("reason"); if (reason == null || reason.trim().isEmpty()) { - return ErrorUtils.respondRequiredInput("reason"); + ErrorUtils.respondRequiredInput(ctx, "reason"); + return; } for (Punishment punishment : target.getPunishments(ImmutableSet.of(type))) { if (punishment.isActive()) { punishment.delete(removedBy, reason); AuditLog.log(removedBy, "", ctx.get("actor"), AuditLogActionType.DELETE_PUNISHMENT, ImmutableMap.of()); - return punishment; + APIv3.respondJson(ctx, punishment); + return; } } - return ErrorUtils.error("User provided has no active punishments"); + ErrorUtils.respondGeneric(ctx, "User provided has no active punishments"); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/users/GETStaff.java b/src/main/java/net/frozenorb/apiv3/routes/users/GETStaff.java index 55291f2..3a5a398 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/users/GETStaff.java +++ b/src/main/java/net/frozenorb/apiv3/routes/users/GETStaff.java @@ -1,5 +1,7 @@ package net.frozenorb.apiv3.routes.users; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.Grant; import net.frozenorb.apiv3.models.Rank; @@ -12,22 +14,22 @@ public final class GETStaff implements Handler { public void handle(RoutingContext ctx) { Map staffRanks = new HashMap<>(); - Rank.values().forEach(rank -> { + Rank.findAll().forEach(rank -> { if (rank.isStaffRank()) { staffRanks.put(rank.getId(), rank); } }); Map> result = new TreeMap<>((first, second) -> { - Rank firstRank = Rank.byId(first); - Rank secondRank = Rank.byId(second); + Rank firstRank = staffRanks.get(first); + Rank secondRank = staffRanks.get(second); return Integer.compare(firstRank.getWeight(), secondRank.getWeight()); }); - APIv3.getDatastore().createQuery(Grant.class).field("rank").in(staffRanks.keySet()).forEach(grant -> { + Grant.findByRank(staffRanks.values()).forEach(grant -> { if (grant.isActive()) { - User user = User.byId(grant.getUser()); + User user = User.findById(grant.getUser()); Rank rank = staffRanks.get(grant.getRank()); if (!result.containsKey(rank.getId())) { @@ -38,7 +40,7 @@ public final class GETStaff implements Handler { } }); - return result; + APIv3.respondJson(ctx, result); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/users/GETUser.java b/src/main/java/net/frozenorb/apiv3/routes/users/GETUser.java index f18c8ce..a0065e0 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/users/GETUser.java +++ b/src/main/java/net/frozenorb/apiv3/routes/users/GETUser.java @@ -1,11 +1,14 @@ package net.frozenorb.apiv3.routes.users; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.User; public final class GETUser implements Handler { public void handle(RoutingContext ctx) { - return User.byId(ctx.request().getParam("id")); + APIv3.respondJson(ctx, User.findById(ctx.request().getParam("id"))); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/users/GETUserDetails.java b/src/main/java/net/frozenorb/apiv3/routes/users/GETUserDetails.java index c4cf2ff..4283ba3 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/users/GETUserDetails.java +++ b/src/main/java/net/frozenorb/apiv3/routes/users/GETUserDetails.java @@ -1,27 +1,35 @@ package net.frozenorb.apiv3.routes.users; import com.google.common.collect.ImmutableMap; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import net.frozenorb.apiv3.APIv3; +import net.frozenorb.apiv3.models.Grant; +import net.frozenorb.apiv3.models.IPLogEntry; +import net.frozenorb.apiv3.models.Punishment; import net.frozenorb.apiv3.models.User; import net.frozenorb.apiv3.utils.ErrorUtils; public final class GETUserDetails implements Handler { public void handle(RoutingContext ctx) { - User user = User.byId(ctx.request().getParam("id")); + User user = User.findById(ctx.request().getParam("id")); if (user == null) { - return ErrorUtils.respondNotFound("User", ctx.request().getParam("id")); + ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id")); + return; } // Too many fields to use .of() - return ImmutableMap.builder() + APIv3.respondJson(ctx, ImmutableMap.builder() .put("user", user) - .put("grants", user.getGrants()) - .put("ipLog", user.getIPLog()) - .put("punishments", user.getPunishments()) + .put("grants", Grant.findByUser(user)) + .put("ipLog", IPLogEntry.findByUser(user)) + .put("punishments", Punishment.findByUser(user)) .put("aliases", user.getAliases()) .put("totpSetup", user.getTotpSecret() != null) - .build(); + .build() + ); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/users/GETUserMeta.java b/src/main/java/net/frozenorb/apiv3/routes/users/GETUserMeta.java index 4d1e38e..948dc60 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/users/GETUserMeta.java +++ b/src/main/java/net/frozenorb/apiv3/routes/users/GETUserMeta.java @@ -1,5 +1,8 @@ package net.frozenorb.apiv3.routes.users; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.ServerGroup; import net.frozenorb.apiv3.models.User; import net.frozenorb.apiv3.models.UserMetaEntry; @@ -8,20 +11,22 @@ import net.frozenorb.apiv3.utils.ErrorUtils; public final class GETUserMeta implements Handler { public void handle(RoutingContext ctx) { - User user = User.byId(ctx.request().getParam("id")); + User user = User.findById(ctx.request().getParam("id")); if (user == null) { - return ErrorUtils.respondNotFound("User", ctx.request().getParam("id")); + ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id")); + return; } - ServerGroup serverGroup = ServerGroup.byId(ctx.request().getParam("serverGroup")); + ServerGroup serverGroup = ServerGroup.findById(ctx.request().getParam("serverGroup")); if (serverGroup == null) { - return ErrorUtils.respondNotFound("Server group", ctx.request().getParam("serverGroup")); + ErrorUtils.respondNotFound(ctx, "Server group", ctx.request().getParam("serverGroup")); + return; } - UserMetaEntry userMetaEntry = user.getMeta(serverGroup); - return userMetaEntry.getData(); + UserMetaEntry userMetaEntry = UserMetaEntry.findByUserAndGroup(user, serverGroup); + APIv3.respondJson(ctx, userMetaEntry.getData()); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/users/GETUserRequiresTOTP.java b/src/main/java/net/frozenorb/apiv3/routes/users/GETUserRequiresTOTP.java index f8b080f..fefe302 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/users/GETUserRequiresTOTP.java +++ b/src/main/java/net/frozenorb/apiv3/routes/users/GETUserRequiresTOTP.java @@ -1,6 +1,9 @@ package net.frozenorb.apiv3.routes.users; import com.google.common.collect.ImmutableMap; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.User; import net.frozenorb.apiv3.utils.ErrorUtils; import net.frozenorb.apiv3.utils.IPUtils; @@ -9,36 +12,39 @@ import net.frozenorb.apiv3.utils.TOTPUtils; public final class GETUserRequiresTOTP implements Handler { public void handle(RoutingContext ctx) { - User user = User.byId(ctx.request().getParam("id")); + User user = User.findById(ctx.request().getParam("id")); if (user == null) { - return ErrorUtils.respondNotFound("User", ctx.request().getParam("id")); + ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id")); + return; } if (user.getTotpSecret() == null) { - return ImmutableMap.of( + APIv3.respondJson(ctx, ImmutableMap.of( "required", false, "message", "User does not have TOTP setup." - ); + )); + return; } String userIp = ctx.request().getParam("userIp"); if (!IPUtils.isValidIP(userIp)) { - return ErrorUtils.respondInvalidInput("IP address \"" + userIp + "\" is not valid."); + ErrorUtils.respondInvalidInput(ctx, "IP address \"" + userIp + "\" is not valid."); + return; } if (TOTPUtils.isPreAuthorized(user, userIp)) { - return ImmutableMap.of( + APIv3.respondJson(ctx, ImmutableMap.of( "required", false, "message", "User's IP has already been validated" - ); + )); + } else { + APIv3.respondJson(ctx, ImmutableMap.of( + "required", true, + "message", "User has no TOTP exemptions." + )); } - - return ImmutableMap.of( - "required", true, - "message", "User has no TOTP exemptions." - ); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/users/GETUserVerifyPassword.java b/src/main/java/net/frozenorb/apiv3/routes/users/GETUserVerifyPassword.java index cd6794d..fa362ab 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/users/GETUserVerifyPassword.java +++ b/src/main/java/net/frozenorb/apiv3/routes/users/GETUserVerifyPassword.java @@ -1,27 +1,32 @@ package net.frozenorb.apiv3.routes.users; import com.google.common.collect.ImmutableMap; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.User; import net.frozenorb.apiv3.utils.ErrorUtils; public final class GETUserVerifyPassword implements Handler { public void handle(RoutingContext ctx) { - User user = User.byId(ctx.request().getParam("id")); + User user = User.findById(ctx.request().getParam("id")); if (user == null) { - return ErrorUtils.respondNotFound("User", ctx.request().getParam("id")); + ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id")); + return; } if (user.getPassword() == null) { - return ErrorUtils.respondInvalidInput("User provided does not have password set."); + ErrorUtils.respondInvalidInput(ctx, "User provided does not have password set."); + return; } boolean authorized = user.checkPassword(ctx.request().getParam("password")); - return ImmutableMap.of( + APIv3.respondJson(ctx, ImmutableMap.of( "authorized", authorized - ); + )); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/users/POSTUserConfirmRegister.java b/src/main/java/net/frozenorb/apiv3/routes/users/POSTUserConfirmRegister.java index af17685..39242a2 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/users/POSTUserConfirmRegister.java +++ b/src/main/java/net/frozenorb/apiv3/routes/users/POSTUserConfirmRegister.java @@ -2,6 +2,8 @@ package net.frozenorb.apiv3.routes.users; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.User; import net.frozenorb.apiv3.utils.ErrorUtils; @@ -20,37 +22,42 @@ public final class POSTUserConfirmRegister implements Handler { "nicole chelsea biteme matthew access yankees 987654321 dallas austin thunder taylor matrix").split(" ")); public void handle(RoutingContext ctx) { - User user = User.byEmailToken(ctx.request().getParam("emailToken")); + User user = User.findByEmailToken(ctx.request().getParam("emailToken")); if (user == null) { - return ErrorUtils.respondNotFound("Email token", ctx.request().getParam("emailToken")); + ErrorUtils.respondNotFound(ctx, "Email token", ctx.request().getParam("emailToken")); + return; } // We can't check email != null as that's set while we're pending // confirmation, we have to check the token. if (user.getEmailToken() == null) { - return ErrorUtils.error("User provided already has email set."); + ErrorUtils.respondGeneric(ctx, "User provided already has email set."); + return; } if ((System.currentTimeMillis() - user.getEmailTokenSetAt().getTime()) > TimeUnit.DAYS.toMillis(2)) { - return ErrorUtils.error("Email token is expired"); + ErrorUtils.respondGeneric(ctx, "Email token is expired"); + return; } String password = ctx.request().getParam("password"); if (password.length() < 8) { - return ErrorUtils.error("Your password is too short."); + ErrorUtils.respondGeneric(ctx, "Your password is too short."); + return; } else if (commonPasswords.contains(password)) { - return ErrorUtils.error("Your password is too common. Please use a more secure password."); + ErrorUtils.respondGeneric(ctx, "Your password is too common. Please use a more secure password."); + return; } user.setEmailToken(null); user.setPassword(password); - APIv3.getDatastore().save(user); + user.save(); - return ImmutableMap.of( + APIv3.respondJson(ctx, ImmutableMap.of( "success", true - ); + )); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/users/POSTUserLeave.java b/src/main/java/net/frozenorb/apiv3/routes/users/POSTUserLeave.java index 8e2a6e5..802c71c 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/users/POSTUserLeave.java +++ b/src/main/java/net/frozenorb/apiv3/routes/users/POSTUserLeave.java @@ -1,24 +1,25 @@ package net.frozenorb.apiv3.routes.users; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.User; import net.frozenorb.apiv3.utils.ErrorUtils; -import spark.Request; -import spark.Response; public class POSTUserLeave implements Handler { @Override - public Object handle(Request req, Response res) throws Exception { - User user = User.byId(ctx.request().getParam("id")); + public void handle(RoutingContext ctx) { + User user = User.findById(ctx.request().getParam("id")); if (user == null) { - return ErrorUtils.respondNotFound("User", ctx.request().getParam("id")); + ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id")); + return; } user.leftServer(); - APIv3.getDatastore().save(user); - return user; + user.save(); + APIv3.respondJson(ctx, user); } -} +} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/users/POSTUserLogin.java b/src/main/java/net/frozenorb/apiv3/routes/users/POSTUserLogin.java index 9fbc900..05264fc 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/users/POSTUserLogin.java +++ b/src/main/java/net/frozenorb/apiv3/routes/users/POSTUserLogin.java @@ -1,5 +1,8 @@ package net.frozenorb.apiv3.routes.users; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.actors.Actor; import net.frozenorb.apiv3.actors.ActorType; import net.frozenorb.apiv3.models.Server; @@ -16,20 +19,23 @@ public final class POSTUserLogin implements Handler { UUID uuid = UUID.fromString(ctx.request().getParam("id")); if (!UUIDUtils.isAcceptableUUID(uuid)) { - return ErrorUtils.respondInvalidInput("UUID \"" + uuid + "\" is not valid - must be version 4 UUID."); + ErrorUtils.respondInvalidInput(ctx, "UUID \"" + uuid + "\" is not valid - must be version 4 UUID."); + return; } - User user = User.byId(uuid); + User user = User.findById(uuid); String username = ctx.request().getParam("username"); String userIp = ctx.request().getParam("userIp"); Actor actor = ctx.get("actor"); if (actor.getType() != ActorType.SERVER) { - return ErrorUtils.respondServerOnly(); + ErrorUtils.respondServerOnly(ctx); + return; } if (!IPUtils.isValidIP(userIp)) { - return ErrorUtils.respondInvalidInput("IP address \"" + userIp + "\" is not valid."); + ErrorUtils.respondInvalidInput(ctx, "IP address \"" + userIp + "\" is not valid."); + return; } if (user == null) { @@ -37,11 +43,11 @@ public final class POSTUserLogin implements Handler { user = new User(uuid, username); } - Server actorServer = Server.byId(actor.getName()); + Server actorServer = Server.findById(actor.getName()); user.getIPLogEntry(userIp).used(); user.updateUsername(username); - return user.getLoginInfo(actorServer); + APIv3.respondJson(ctx, user.getLoginInfo(actorServer)); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/users/POSTUserNotify.java b/src/main/java/net/frozenorb/apiv3/routes/users/POSTUserNotify.java index d79d783..f9454b7 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/users/POSTUserNotify.java +++ b/src/main/java/net/frozenorb/apiv3/routes/users/POSTUserNotify.java @@ -1,6 +1,9 @@ package net.frozenorb.apiv3.routes.users; import com.google.common.collect.ImmutableMap; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.NotificationTemplate; import net.frozenorb.apiv3.models.User; import net.frozenorb.apiv3.unsorted.Notification; @@ -12,43 +15,47 @@ import java.util.Map; public final class POSTUserNotify implements Handler { public void handle(RoutingContext ctx) { - User user = User.byId(ctx.request().getParam("id")); + User user = User.findById(ctx.request().getParam("id")); if (user == null) { - return ErrorUtils.respondNotFound("User", ctx.request().getParam("id")); + ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id")); + return; } if (user.getEmail() == null) { - return ErrorUtils.error("User provided does not have email set."); + ErrorUtils.respondGeneric(ctx, "User provided does not have email set."); + return; } - NotificationTemplate template = NotificationTemplate.byId(ctx.request().getParam("template")); + NotificationTemplate template = NotificationTemplate.findById(ctx.request().getParam("template")); if (template == null) { - return ErrorUtils.respondNotFound("Notification template", ctx.request().getParam("template")); + ErrorUtils.respondNotFound(ctx, "Notification template", ctx.request().getParam("template")); + return; } Map subjectReplacements = new HashMap<>(); Map bodyReplacements = new HashMap<>(); - req.queryMap("subject").toMap().forEach((key, values) -> { + //TODO: Probably make this use the body as json + /*req.queryMap("subject").toMap().forEach((key, values) -> { subjectReplacements.put(key, values[0]); }); req.queryMap("body").toMap().forEach((key, values) -> { bodyReplacements.put(key, values[0]); - }); + });*/ try { Notification notification = new Notification(template, subjectReplacements, bodyReplacements); notification.sendAsEmail(user.getEmail()); - return ImmutableMap.of( + APIv3.respondJson(ctx, ImmutableMap.of( "success", true - ); + )); } catch (Exception ex) { ex.printStackTrace(); - return ErrorUtils.error("Failed to send notification"); + ErrorUtils.respondGeneric(ctx, "Failed to send notification"); } } diff --git a/src/main/java/net/frozenorb/apiv3/routes/users/POSTUserRegister.java b/src/main/java/net/frozenorb/apiv3/routes/users/POSTUserRegister.java index 7b80338..3e3aad3 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/users/POSTUserRegister.java +++ b/src/main/java/net/frozenorb/apiv3/routes/users/POSTUserRegister.java @@ -1,6 +1,8 @@ package net.frozenorb.apiv3.routes.users; import com.google.common.collect.ImmutableMap; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.NotificationTemplate; import net.frozenorb.apiv3.models.User; @@ -22,30 +24,34 @@ public final class POSTUserRegister implements Handler { ); public void handle(RoutingContext ctx) { - User user = User.byId(ctx.request().getParam("id")); + User user = User.findById(ctx.request().getParam("id")); if (user == null) { - return ErrorUtils.respondNotFound("User", ctx.request().getParam("id")); + ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id")); + return; } if (user.getEmail() != null) { - return ErrorUtils.respondInvalidInput("User provided already has email set."); + ErrorUtils.respondInvalidInput(ctx, "User provided already has email set."); + return; } String email = ctx.request().getParam("email"); if (!VALID_EMAIL_PATTERN.matcher(email).matches()) { - return ErrorUtils.error(email + " is not a valid email."); + ErrorUtils.respondGeneric(ctx, email + " is not a valid email."); + return; } if (user.getEmailToken() != null && (System.currentTimeMillis() - user.getEmailTokenSetAt().getTime()) < TimeUnit.DAYS.toMillis(2)) { - return ErrorUtils.error("We just recently sent you a confirmation email. Please wait before trying to register again."); + ErrorUtils.respondGeneric(ctx, "We just recently sent you a confirmation email. Please wait before trying to register again."); + return; } user.setEmail(email); user.setEmailToken(new BigInteger(130, new Random()).toString(32)); user.setEmailTokenSetAt(new Date()); - APIv3.getDatastore().save(user); + user.save(); Map replacements = ImmutableMap.of( "username", user.getLastUsername(), @@ -53,16 +59,16 @@ public final class POSTUserRegister implements Handler { "emailToken", user.getEmailToken() ); - Notification notification = new Notification(NotificationTemplate.byId("email-confirmation"), replacements, replacements); + Notification notification = new Notification(NotificationTemplate.findById("email-confirmation"), replacements, replacements); try { notification.sendAsEmail(user.getEmail()); - return ImmutableMap.of( + APIv3.respondJson(ctx, ImmutableMap.of( "success", true - ); + )); } catch (Exception ex) { ex.printStackTrace(); - return ErrorUtils.error("Failed to send confirmation email. Please contact a MineHQ staff member."); + ErrorUtils.respondGeneric(ctx, "Failed to send confirmation email. Please contact a MineHQ staff member."); } } diff --git a/src/main/java/net/frozenorb/apiv3/routes/users/POSTUserSetupTOTP.java b/src/main/java/net/frozenorb/apiv3/routes/users/POSTUserSetupTOTP.java index 5a4e9c6..9b9f2bc 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/users/POSTUserSetupTOTP.java +++ b/src/main/java/net/frozenorb/apiv3/routes/users/POSTUserSetupTOTP.java @@ -2,6 +2,8 @@ package net.frozenorb.apiv3.routes.users; import com.google.common.collect.ImmutableMap; import com.warrenstrange.googleauth.GoogleAuthenticatorKey; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.User; import net.frozenorb.apiv3.utils.ErrorUtils; @@ -10,24 +12,26 @@ import net.frozenorb.apiv3.utils.TOTPUtils; public final class POSTUserSetupTOTP implements Handler { public void handle(RoutingContext ctx) { - User user = User.byId(ctx.request().getParam("id")); + User user = User.findById(ctx.request().getParam("id")); if (user == null) { - return ErrorUtils.respondNotFound("User", ctx.request().getParam("id")); + ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id")); + return; } if (user.getTotpSecret() != null) { - return ErrorUtils.respondInvalidInput("User provided already has TOTP code set."); + ErrorUtils.respondInvalidInput(ctx, "User provided already has TOTP code set."); + return; } GoogleAuthenticatorKey generated = TOTPUtils.generateTOTPKey(); user.setTotpSecret(generated.getKey()); - APIv3.getDatastore().save(user); + user.save(); - return ImmutableMap.of( + APIv3.respondJson(ctx, ImmutableMap.of( "qrCode", TOTPUtils.getQRCodeURL(user, generated) - ); + )); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/routes/users/POSTUserVerifyTOTP.java b/src/main/java/net/frozenorb/apiv3/routes/users/POSTUserVerifyTOTP.java index 2deb032..bc27b48 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/users/POSTUserVerifyTOTP.java +++ b/src/main/java/net/frozenorb/apiv3/routes/users/POSTUserVerifyTOTP.java @@ -1,6 +1,9 @@ package net.frozenorb.apiv3.routes.users; import com.google.common.collect.ImmutableMap; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.User; import net.frozenorb.apiv3.utils.ErrorUtils; import net.frozenorb.apiv3.utils.IPUtils; @@ -11,29 +14,33 @@ import java.util.concurrent.TimeUnit; public final class POSTUserVerifyTOTP implements Handler { public void handle(RoutingContext ctx) { - User user = User.byId(ctx.request().getParam("id")); + User user = User.findById(ctx.request().getParam("id")); if (user == null) { - return ErrorUtils.respondNotFound("User", ctx.request().getParam("id")); + ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id")); + return; } if (user.getTotpSecret() == null) { - return ErrorUtils.respondInvalidInput("User provided does not have TOTP code set."); + ErrorUtils.respondInvalidInput(ctx, "User provided does not have TOTP code set."); + return; } String userIp = ctx.request().getParam("userIp"); if (!IPUtils.isValidIP(userIp)) { - return ErrorUtils.respondInvalidInput("IP address \"" + userIp + "\" is not valid."); + ErrorUtils.respondInvalidInput(ctx, "IP address \"" + userIp + "\" is not valid."); + return; } int providedCode = Integer.parseInt(ctx.request().getParam("code")); if (TOTPUtils.wasRecentlyUsed(user, providedCode)) { - return ImmutableMap.of( + APIv3.respondJson(ctx, ImmutableMap.of( "authorized", false, "message", "TOTP code was recently used." - ); + )); + return; } boolean authorized = TOTPUtils.authorizeUser(user, providedCode); @@ -42,15 +49,15 @@ public final class POSTUserVerifyTOTP implements Handler { TOTPUtils.markPreAuthorized(user, userIp, 3, TimeUnit.DAYS); TOTPUtils.markRecentlyUsed(user, providedCode); - return ImmutableMap.of( + APIv3.respondJson(ctx, ImmutableMap.of( "authorized", true, "message", "Valid TOTP code provided." - ); + )); } else { - return ImmutableMap.of( + APIv3.respondJson(ctx, ImmutableMap.of( "authorized", false, "message", "TOTP code was not valid." - ); + )); } } diff --git a/src/main/java/net/frozenorb/apiv3/routes/users/PUTUserMeta.java b/src/main/java/net/frozenorb/apiv3/routes/users/PUTUserMeta.java index 0ff4eca..3fa80a8 100644 --- a/src/main/java/net/frozenorb/apiv3/routes/users/PUTUserMeta.java +++ b/src/main/java/net/frozenorb/apiv3/routes/users/PUTUserMeta.java @@ -1,5 +1,8 @@ package net.frozenorb.apiv3.routes.users; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.models.ServerGroup; import net.frozenorb.apiv3.models.User; import net.frozenorb.apiv3.utils.ErrorUtils; @@ -8,22 +11,24 @@ import org.bson.Document; public final class PUTUserMeta implements Handler { public void handle(RoutingContext ctx) { - User user = User.byId(ctx.request().getParam("id")); + User user = User.findById(ctx.request().getParam("id")); if (user == null) { - return ErrorUtils.respondNotFound("User", ctx.request().getParam("id")); + ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id")); + return; } - ServerGroup serverGroup = ServerGroup.byId(ctx.request().getParam("serverGroup")); + ServerGroup serverGroup = ServerGroup.findById(ctx.request().getParam("serverGroup")); if (serverGroup == null) { - return ErrorUtils.respondNotFound("Server group", ctx.request().getParam("serverGroup")); + ErrorUtils.respondNotFound(ctx, "Server group", ctx.request().getParam("serverGroup")); + return; } - Document data = Document.parse(req.body()); + Document data = Document.parse(ctx.getBodyAsString()); user.saveMeta(serverGroup, data); - return data; + APIv3.respondJson(ctx, data); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/unsorted/BlockingCallback.java b/src/main/java/net/frozenorb/apiv3/unsorted/BlockingCallback.java new file mode 100644 index 0000000..939de9c --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/unsorted/BlockingCallback.java @@ -0,0 +1,29 @@ +package net.frozenorb.apiv3.unsorted; + +import com.google.common.util.concurrent.SettableFuture; +import com.mongodb.async.SingleResultCallback; + +import java.util.concurrent.ExecutionException; + +public final class BlockingCallback implements SingleResultCallback { + + private final SettableFuture future = SettableFuture.create(); + + public void onResult(T val, Throwable error) { + if (error != null) { + future.setException(error); + } else { + future.set(val); + } + } + + public T get() { + try { + return future.get(); + } catch (InterruptedException | ExecutionException ex) { + // No matter what we get we'll just rethrow. + throw new RuntimeException(ex); + } + } + +} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/unsorted/LoggingExceptionHandler.java b/src/main/java/net/frozenorb/apiv3/unsorted/LoggingExceptionHandler.java deleted file mode 100644 index 193fab4..0000000 --- a/src/main/java/net/frozenorb/apiv3/unsorted/LoggingExceptionHandler.java +++ /dev/null @@ -1,27 +0,0 @@ -package net.frozenorb.apiv3.unsorted; - -import lombok.extern.slf4j.Slf4j; -import net.frozenorb.apiv3.APIv3; -import net.frozenorb.apiv3.utils.ErrorUtils; -import org.bson.types.ObjectId; -import spark.ExceptionHandler; -import spark.Request; -import spark.Response; - -@Slf4j -public final class LoggingExceptionHandler implements ExceptionHandler { - - public void handle(Exception ex, Request req, Response res) { - long started = req.attribute("requestStarted"); - APIv3.getStatsD().recordExecutionTime("apiv3.http.executionTime", System.currentTimeMillis() - started); - APIv3.getStatsD().incrementCounter("apiv3.http.requests"); - - APIv3.getStatsD().incrementCounter("apiv3.http.errors"); - - String code = new ObjectId().toHexString(); - - log.error(code + ":", ex); - res.body(APIv3.getGson().toJson(ErrorUtils.error("An unknown error has occurred. Please contact an API developer with the code \"" + code + "\"."))); - } - -} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/utils/ErrorUtils.java b/src/main/java/net/frozenorb/apiv3/utils/ErrorUtils.java index 9e25530..decc5b5 100644 --- a/src/main/java/net/frozenorb/apiv3/utils/ErrorUtils.java +++ b/src/main/java/net/frozenorb/apiv3/utils/ErrorUtils.java @@ -9,23 +9,24 @@ import net.frozenorb.apiv3.APIv3; public class ErrorUtils { public static void respondServerOnly(RoutingContext ctx) { - error(ctx, "This action can only be performed when requested by a server."); + respondGeneric(ctx, "This action can only be performed when requested by a server."); } public static void respondNotFound(RoutingContext ctx, String itemType, String id) { - error(ctx, "Not found: " + itemType + " with id " + id + " cannot be found."); + respondGeneric(ctx, "Not found: " + itemType + " with id " + id + " cannot be found."); } public static void respondInvalidInput(RoutingContext ctx, String message) { - error(ctx, "Invalid input: " + message + "."); + respondGeneric(ctx, "Invalid input: " + message + "."); } public static void respondRequiredInput(RoutingContext ctx, String field) { - error(ctx, "Field \"" + field + "\" is required."); + respondGeneric(ctx, "Field \"" + field + "\" is required."); } - public static void error(RoutingContext ctx, String message) { - APIv3.respond(ctx, ImmutableMap.of( + public static void respondGeneric(RoutingContext ctx, String message) { + // TODO: Proper status codes + APIv3.respondJson(ctx, 400, ImmutableMap.of( "success", false, "message", message )); diff --git a/src/main/java/net/frozenorb/apiv3/utils/MojangUtils.java b/src/main/java/net/frozenorb/apiv3/utils/MojangUtils.java index fc5626b..fd25359 100644 --- a/src/main/java/net/frozenorb/apiv3/utils/MojangUtils.java +++ b/src/main/java/net/frozenorb/apiv3/utils/MojangUtils.java @@ -1,10 +1,9 @@ package net.frozenorb.apiv3.utils; +import com.mongodb.async.SingleResultCallback; import lombok.experimental.UtilityClass; import net.frozenorb.apiv3.APIv3; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; +import net.frozenorb.apiv3.unsorted.BlockingCallback; import org.bson.Document; import java.util.UUID; @@ -12,30 +11,32 @@ import java.util.UUID; @UtilityClass public class MojangUtils { - private static OkHttpClient okHttpClient = new OkHttpClient.Builder().retryOnConnectionFailure(false).build(); - public static String getName(UUID id) { - Request.Builder builder = new Request.Builder(); + BlockingCallback callback = new BlockingCallback<>(); + getName(id, callback); + return callback.get(); + } - builder.get(); - builder.url("https://sessionserver.mojang.com/session/minecraft/profile/" + id.toString().replace("-", "")); + public static void getName(UUID id, SingleResultCallback callback) { + APIv3.getHttpClient().get("sessionserver.mojang.com", "session/minecraft/profile/" + id.toString().replace("-", ""), (response) -> { + response.bodyHandler((body) -> { + Document resJson = Document.parse(body.toString()); + String name = resJson.getString("name"); - try { - Response response = okHttpClient.newCall(builder.build()).execute(); - Document resJson = Document.parse(response.body().string()); + if (name == null) { + APIv3.getStatsD().incrementCounter("apiv3.mojang.sessionServer.rateLimited"); + callback.onResult(null, new RuntimeException("Hit Mojang API rate limit: " + resJson.toJson())); + } else { + APIv3.getStatsD().incrementCounter("apiv3.mojang.sessionServer.success"); + callback.onResult(name, null); + } + }); - String name = resJson.getString("name"); - - if (name == null) { - throw new RuntimeException("Hit Mojang API rate limit: " + resJson.toJson()); - } - - APIv3.getStatsD().incrementCounter("apiv3.mojang.sessionServer.success"); - return name; - } catch (Exception ex) { - APIv3.getStatsD().incrementCounter("apiv3.mojang.sessionServer.failure"); - throw new RuntimeException(ex); - } + response.exceptionHandler((error) -> { + APIv3.getStatsD().incrementCounter("apiv3.mojang.sessionServer.failure"); + callback.onResult(null, error); + }); + }); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/utils/PermissionUtils.java b/src/main/java/net/frozenorb/apiv3/utils/PermissionUtils.java index e896299..4081811 100644 --- a/src/main/java/net/frozenorb/apiv3/utils/PermissionUtils.java +++ b/src/main/java/net/frozenorb/apiv3/utils/PermissionUtils.java @@ -25,7 +25,7 @@ public class PermissionUtils { public static Map mergeUpTo(Map> unmerged, Rank upTo) { Map result = new HashMap<>(); - for (Rank rank : Rank.values()) { + for (Rank rank : Rank.findAll()) { Map rankPermissions = convertToMap(unmerged.get(rank.getId())); // If there's no permissions defined for this rank just skip it. diff --git a/src/main/java/net/frozenorb/apiv3/utils/SyncUtils.java b/src/main/java/net/frozenorb/apiv3/utils/SyncUtils.java new file mode 100644 index 0000000..12c982a --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/utils/SyncUtils.java @@ -0,0 +1,27 @@ +package net.frozenorb.apiv3.utils; + +import com.mongodb.async.client.MongoIterable; +import lombok.experimental.UtilityClass; +import net.frozenorb.apiv3.unsorted.BlockingCallback; + +import java.util.ArrayList; +import java.util.List; + +@UtilityClass +public class SyncUtils { + + public static T blockOne(MongoIterable mongoIterable) { + BlockingCallback callback = new BlockingCallback<>(); + + mongoIterable.first(callback); + return callback.get(); + } + + public static List blockMulti(MongoIterable mongoIterable) { + BlockingCallback> callback = new BlockingCallback<>(); + + mongoIterable.into(new ArrayList<>(), callback); + return callback.get(); + } + +} \ No newline at end of file