Push a bunch of experimental code (this doesn't currently work/compile)
This commit is contained in:
parent
7d626afa20
commit
60a622fc43
@ -8,9 +8,7 @@ mongo.username=
|
|||||||
mongo.password=
|
mongo.password=
|
||||||
redis.address=localhost
|
redis.address=localhost
|
||||||
redis.port=6379
|
redis.port=6379
|
||||||
http.address=0.0.0.0
|
|
||||||
http.port=80
|
http.port=80
|
||||||
http.workerThreads=
|
|
||||||
twillio.accountSID=AC9e2f88c5690134d29a56f698de3cd740
|
twillio.accountSID=AC9e2f88c5690134d29a56f698de3cd740
|
||||||
twillio.authToken=982592505a171d3be6b0722f5ecacc0e
|
twillio.authToken=982592505a171d3be6b0722f5ecacc0e
|
||||||
mandrill.apiKey=0OYtwymqJP6oqvszeJu0vQ
|
mandrill.apiKey=0OYtwymqJP6oqvszeJu0vQ
|
||||||
|
88
pom.xml
88
pom.xml
@ -58,6 +58,7 @@
|
|||||||
</repositories>
|
</repositories>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<!-- Vert.x -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.vertx</groupId>
|
<groupId>io.vertx</groupId>
|
||||||
<artifactId>vertx-core</artifactId>
|
<artifactId>vertx-core</artifactId>
|
||||||
@ -68,36 +69,39 @@
|
|||||||
<artifactId>vertx-web</artifactId>
|
<artifactId>vertx-web</artifactId>
|
||||||
<version>LATEST</version>
|
<version>LATEST</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Google Libs -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.guava</groupId>
|
<groupId>com.google.guava</groupId>
|
||||||
<artifactId>guava</artifactId>
|
<artifactId>guava</artifactId>
|
||||||
<version>19.0</version>
|
<version>19.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>redis.clients</groupId>
|
|
||||||
<artifactId>jedis</artifactId>
|
|
||||||
<version>2.8.1</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.code.gson</groupId>
|
<groupId>com.google.code.gson</groupId>
|
||||||
<artifactId>gson</artifactId>
|
<artifactId>gson</artifactId>
|
||||||
<version>2.6.2</version>
|
<version>2.6.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>com.indeed</groupId>
|
<!-- Mongo -->
|
||||||
<artifactId>java-dogstatsd-client</artifactId>
|
|
||||||
<version>2.0.12</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.bugsnag</groupId>
|
|
||||||
<artifactId>bugsnag</artifactId>
|
|
||||||
<version>2.0.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mongodb</groupId>
|
<groupId>org.mongodb</groupId>
|
||||||
<artifactId>mongo-java-driver</artifactId>
|
<artifactId>mongodb-driver-async</artifactId>
|
||||||
<version>3.2.2</version>
|
<version>3.0.4</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>eu.dozd</groupId>
|
||||||
|
<artifactId>mongo-mapper</artifactId>
|
||||||
|
<version>1.0.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Redis -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>redis.clients</groupId>
|
||||||
|
<artifactId>jedis</artifactId>
|
||||||
|
<version>2.8.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Notifications -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.cribbstechnologies.clients</groupId>
|
<groupId>com.cribbstechnologies.clients</groupId>
|
||||||
<artifactId>mandrillClient</artifactId>
|
<artifactId>mandrillClient</artifactId>
|
||||||
@ -108,46 +112,34 @@
|
|||||||
<artifactId>twilio-java-sdk</artifactId>
|
<artifactId>twilio-java-sdk</artifactId>
|
||||||
<version>6.3.0</version>
|
<version>6.3.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.mindrot</groupId>
|
<!-- TOTP -->
|
||||||
<artifactId>jbcrypt</artifactId>
|
|
||||||
<version>0.3m</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.mongodb.morphia</groupId>
|
|
||||||
<artifactId>morphia</artifactId>
|
|
||||||
<version>1.1.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.mongodb.morphia</groupId>
|
|
||||||
<artifactId>morphia-logging-slf4j</artifactId>
|
|
||||||
<version>1.1.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>slf4j-simple</artifactId>
|
|
||||||
<version>1.6.4</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.httpcomponents</groupId>
|
|
||||||
<artifactId>httpcore</artifactId>
|
|
||||||
<version>4.4</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.warrenstrange</groupId>
|
<groupId>com.warrenstrange</groupId>
|
||||||
<artifactId>googleauth</artifactId>
|
<artifactId>googleauth</artifactId>
|
||||||
<version>0.5.0</version>
|
<version>0.5.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Monitoring -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.squareup.okhttp3</groupId>
|
<groupId>com.indeed</groupId>
|
||||||
<artifactId>okhttp</artifactId>
|
<artifactId>java-dogstatsd-client</artifactId>
|
||||||
<version>3.2.0</version>
|
<version>2.0.12</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.squareup.okio</groupId>
|
<groupId>com.bugsnag</groupId>
|
||||||
<artifactId>okio</artifactId>
|
<artifactId>bugsnag</artifactId>
|
||||||
<version>1.8.0</version>
|
<version>2.0.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Logging -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-simple</artifactId>
|
||||||
|
<version>1.6.4</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Lombok -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
|
@ -6,23 +6,36 @@ import com.google.common.collect.ImmutableMap;
|
|||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import com.mongodb.*;
|
import com.mongodb.Block;
|
||||||
import com.mongodb.client.MongoDatabase;
|
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.NonBlockingStatsDClient;
|
||||||
import com.timgroup.statsd.StatsDClient;
|
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.Router;
|
||||||
import io.vertx.ext.web.RoutingContext;
|
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.Getter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.frozenorb.apiv3.actors.ActorType;
|
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.Grant;
|
||||||
import net.frozenorb.apiv3.models.IPLogEntry;
|
import net.frozenorb.apiv3.models.IPLogEntry;
|
||||||
import net.frozenorb.apiv3.models.Punishment;
|
import net.frozenorb.apiv3.models.Punishment;
|
||||||
import net.frozenorb.apiv3.models.User;
|
import net.frozenorb.apiv3.models.User;
|
||||||
import net.frozenorb.apiv3.routes.GETDump;
|
import net.frozenorb.apiv3.routes.GETDump;
|
||||||
import net.frozenorb.apiv3.routes.GETWhoAmI;
|
import net.frozenorb.apiv3.routes.GETWhoAmI;
|
||||||
import net.frozenorb.apiv3.routes.NotFound;
|
|
||||||
import net.frozenorb.apiv3.routes.POSTMetrics;
|
import net.frozenorb.apiv3.routes.POSTMetrics;
|
||||||
import net.frozenorb.apiv3.routes.announcements.GETAnnouncements;
|
import net.frozenorb.apiv3.routes.announcements.GETAnnouncements;
|
||||||
import net.frozenorb.apiv3.routes.auditLog.GETAuditLog;
|
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.FollowAnnotationExclusionStrategy;
|
||||||
import net.frozenorb.apiv3.serialization.ObjectIdTypeAdapter;
|
import net.frozenorb.apiv3.serialization.ObjectIdTypeAdapter;
|
||||||
import net.frozenorb.apiv3.unsorted.BugsnagSLF4JLogger;
|
import net.frozenorb.apiv3.unsorted.BugsnagSLF4JLogger;
|
||||||
import net.frozenorb.apiv3.unsorted.LoggingExceptionHandler;
|
|
||||||
import net.frozenorb.apiv3.utils.IPUtils;
|
import net.frozenorb.apiv3.utils.IPUtils;
|
||||||
import net.frozenorb.apiv3.utils.UUIDUtils;
|
import net.frozenorb.apiv3.utils.UUIDUtils;
|
||||||
import org.bson.Document;
|
import org.bson.Document;
|
||||||
|
import org.bson.codecs.configuration.CodecRegistries;
|
||||||
import org.bson.types.ObjectId;
|
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 redis.clients.jedis.JedisPool;
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
@ -66,13 +74,11 @@ import java.util.*;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import static spark.Spark.*;
|
|
||||||
import static spark.route.RouteOverview.enableRouteOverview;
|
|
||||||
|
|
||||||
@Slf4j
|
@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 Properties config = new Properties();
|
||||||
@Getter private static JedisPool redisPool;
|
@Getter private static JedisPool redisPool;
|
||||||
@Getter private static StatsDClient statsD;
|
@Getter private static StatsDClient statsD;
|
||||||
@ -82,7 +88,8 @@ public final class APIv3 {
|
|||||||
.setExclusionStrategies(new FollowAnnotationExclusionStrategy())
|
.setExclusionStrategies(new FollowAnnotationExclusionStrategy())
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
APIv3() {
|
@Override
|
||||||
|
public void start() {
|
||||||
setupConfig();
|
setupConfig();
|
||||||
System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", config.getProperty("logging.level"));
|
System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", config.getProperty("logging.level"));
|
||||||
|
|
||||||
@ -90,10 +97,9 @@ public final class APIv3 {
|
|||||||
setupRedis();
|
setupRedis();
|
||||||
setupMetrics();
|
setupMetrics();
|
||||||
setupBugsnag();
|
setupBugsnag();
|
||||||
setupHttp();
|
setupHttpServer();
|
||||||
|
|
||||||
//convertData("158.69.126.126", true);
|
//convertData("158.69.126.126", true);
|
||||||
LoggingFilter.setDebug(Boolean.valueOf(config.getProperty("logging.debug")));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupConfig() {
|
private void setupConfig() {
|
||||||
@ -108,28 +114,33 @@ public final class APIv3 {
|
|||||||
ImmutableList<MongoCredential> credentials = ImmutableList.of();
|
ImmutableList<MongoCredential> credentials = ImmutableList.of();
|
||||||
|
|
||||||
if (!config.getProperty("mongo.username").isEmpty()) {
|
if (!config.getProperty("mongo.username").isEmpty()) {
|
||||||
credentials = ImmutableList.of(MongoCredential.createCredential(
|
credentials = ImmutableList.of(
|
||||||
config.getProperty("mongo.username"),
|
MongoCredential.createCredential(
|
||||||
config.getProperty("mongo.database"),
|
config.getProperty("mongo.username"),
|
||||||
config.getProperty("mongo.password").toCharArray()
|
config.getProperty("mongo.database"),
|
||||||
));
|
config.getProperty("mongo.password").toCharArray()
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
MongoClient mongoClient = new MongoClient(new ServerAddress(
|
ClusterSettings clusterSettings = ClusterSettings
|
||||||
config.getProperty("mongo.address"),
|
.builder()
|
||||||
Integer.parseInt(config.getProperty("mongo.port"))),
|
.hosts(ImmutableList.of(
|
||||||
credentials
|
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();
|
MongoClient client = MongoClients.create(settings);
|
||||||
MorphiaLoggerFactory.registerLogger(SLF4JLoggerImplFactory.class);
|
database = client.getDatabase(config.getProperty("mongo.database"));
|
||||||
|
// TODO: Indexes
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupRedis() {
|
private void setupRedis() {
|
||||||
@ -160,103 +171,105 @@ public final class APIv3 {
|
|||||||
bugsnag.setLogger(new BugsnagSLF4JLogger());
|
bugsnag.setLogger(new BugsnagSLF4JLogger());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupHttp() {
|
private void setupHttpServer() {
|
||||||
Router.router()
|
HttpServer webServer = vertx.createHttpServer();
|
||||||
ipAddress(config.getProperty("http.address"));
|
Router mainRouter = Router.router(vertx);
|
||||||
port(Integer.parseInt(config.getProperty("http.port")));
|
|
||||||
String workerThreads = config.getProperty("http.workerThreads");
|
|
||||||
|
|
||||||
if (!workerThreads.isEmpty()) {
|
mainRouter.route().handler(new MetricsHandler());
|
||||||
threadPool(Integer.parseInt(workerThreads));
|
mainRouter.route().handler(new ActorAttributeFilter());
|
||||||
}
|
mainRouter.route().handler(new AuthorizationFilter());
|
||||||
|
mainRouter.route().handler(LoggerHandler.create());
|
||||||
before(new MetricsBeforeFilter());
|
mainRouter.route().handler(BodyHandler.create());
|
||||||
before(new ContentTypeFilter());
|
|
||||||
before(new ActorAttributeFilter());
|
|
||||||
before(new AuthorizationFilter());
|
|
||||||
after(new MetricsAfterFilter());
|
|
||||||
after(new LoggingFilter());
|
|
||||||
exception(Exception.class, new LoggingExceptionHandler());
|
|
||||||
|
|
||||||
// TODO: The commented out routes
|
// TODO: The commented out routes
|
||||||
|
|
||||||
post("/metrics", new POSTMetrics(), gson::toJson);
|
mainRouter.post("/metrics").blockingHandler(new POSTMetrics());
|
||||||
get("/announcements", new GETAnnouncements(), gson::toJson);
|
mainRouter.get("/announcements").blockingHandler(new GETAnnouncements());
|
||||||
get("/auditLog", new GETAuditLog(), gson::toJson);
|
mainRouter.get("/auditLog").blockingHandler(new GETAuditLog());
|
||||||
get("/chatFilterList", new GETChatFilterList(), gson::toJson);
|
mainRouter.get("/chatFilterList").blockingHandler(new GETChatFilterList());
|
||||||
get("/dump/:type", new GETDump(), gson::toJson);
|
mainRouter.get("/dump/:type").blockingHandler(new GETDump());
|
||||||
get("/whoami", new GETWhoAmI(), gson::toJson);
|
mainRouter.get("/whoami").blockingHandler(new GETWhoAmI());
|
||||||
enableRouteOverview("/routes");
|
|
||||||
|
|
||||||
get("/grant/:id", new GETGrant(), gson::toJson);
|
mainRouter.get("/grant/:id").blockingHandler(new GETGrant());
|
||||||
get("/grants", new GETGrants(), gson::toJson);
|
mainRouter.get("/grants").blockingHandler(new GETGrants());
|
||||||
delete("/grant/:id", new DELETEGrant(), gson::toJson);
|
mainRouter.delete("/grant/:id").blockingHandler(new DELETEGrant());
|
||||||
|
|
||||||
get("/notificationTemplate/:id", new GETNotificationTemplate(), gson::toJson);
|
mainRouter.get("/notificationTemplate/:id").blockingHandler(new GETNotificationTemplate());
|
||||||
get("/notificationTemplates", new GETNotificationTemplates(), gson::toJson);
|
mainRouter.get("/notificationTemplates").blockingHandler(new GETNotificationTemplates());
|
||||||
post("/notificationTemplate", new POSTNotificationTemplate(), gson::toJson);
|
mainRouter.post("/notificationTemplate").blockingHandler(new POSTNotificationTemplate());
|
||||||
//put("/notificationTemplate/:id", new PUTNotificationTemplate(), gson::toJson);
|
//mainRouter.put("/notificationTemplate/:id").blockingHandler(new PUTNotificationTemplate());
|
||||||
delete("/notificationTemplate/:id", new DELETENotificationTemplate(), gson::toJson);
|
mainRouter.delete("/notificationTemplate/:id").blockingHandler(new DELETENotificationTemplate());
|
||||||
|
|
||||||
get("/punishment/:id", new GETPunishment(), gson::toJson);
|
mainRouter.get("/punishment/:id").blockingHandler(new GETPunishment());
|
||||||
get("/punishments", new GETPunishments(), gson::toJson);
|
mainRouter.get("/punishments").blockingHandler(new GETPunishments());
|
||||||
delete("/punishment/:id", new DELETEPunishment(), gson::toJson);
|
mainRouter.delete("/punishment/:id").blockingHandler(new DELETEPunishment());
|
||||||
|
|
||||||
get("/rank/:id", new GETRank(), gson::toJson);
|
mainRouter.get("/rank/:id").blockingHandler(new GETRank());
|
||||||
get("/ranks", new GETRanks(), gson::toJson);
|
mainRouter.get("/ranks").blockingHandler(new GETRanks());
|
||||||
post("/rank", new POSTRank(), gson::toJson);
|
mainRouter.post("/rank").blockingHandler(new POSTRank());
|
||||||
//put("/rank/:id", new PUTRank(), gson::toJson);
|
//put("/rank/:id").blockingHandler(new PUTRank());
|
||||||
delete("/rank/:id", new DELETERank(), gson::toJson);
|
mainRouter.delete("/rank/:id").blockingHandler(new DELETERank());
|
||||||
|
|
||||||
get("/serverGroup/:id", new GETServerGroup(), gson::toJson);
|
mainRouter.get("/serverGroup/:id").blockingHandler(new GETServerGroup());
|
||||||
get("/serverGroups", new GETServerGroups(), gson::toJson);
|
mainRouter.get("/serverGroups").blockingHandler(new GETServerGroups());
|
||||||
post("/serverGroup", new POSTServerGroup(), gson::toJson);
|
mainRouter.post("/serverGroup").blockingHandler(new POSTServerGroup());
|
||||||
//put("/serverGroup/:id", new PUTServerGroup(), gson::toJson);
|
//put("/serverGroup/:id").blockingHandler(new PUTServerGroup());
|
||||||
delete("/serverGroup/:id", new DELETEServerGroup(), gson::toJson);
|
mainRouter.delete("/serverGroup/:id").blockingHandler(new DELETEServerGroup());
|
||||||
|
|
||||||
get("/server/:id", new GETServer(), gson::toJson);
|
mainRouter.get("/server/:id").blockingHandler(new GETServer());
|
||||||
get("/servers", new GETServers(), gson::toJson);
|
mainRouter.get("/servers").blockingHandler(new GETServers());
|
||||||
post("/server/heartbeat", new POSTServerHeartbeat(), gson::toJson);
|
mainRouter.post("/server/heartbeat").blockingHandler(new POSTServerHeartbeat());
|
||||||
post("/server", new POSTServer(), gson::toJson);
|
mainRouter.post("/server").blockingHandler(new POSTServer());
|
||||||
//put("/server/:id", new PUTServer(), gson::toJson);
|
//put("/server/:id").blockingHandler(new PUTServer());
|
||||||
delete("/server/:id", new DELETEServer(), gson::toJson);
|
mainRouter.delete("/server/:id").blockingHandler(new DELETEServer());
|
||||||
|
|
||||||
get("/staff", new GETStaff(), gson::toJson);
|
mainRouter.get("/staff").blockingHandler(new GETStaff());
|
||||||
get("/user/:id/details", new GETUserDetails(), gson::toJson);
|
mainRouter.get("/user/:id/details").blockingHandler(new GETUserDetails());
|
||||||
get("/user/:id/meta/:serverGroup", new GETUserMeta(), gson::toJson);
|
mainRouter.get("/user/:id/meta/:serverGroup").blockingHandler(new GETUserMeta());
|
||||||
get("/user/:id/grants", new GETUserGrants(), gson::toJson);
|
mainRouter.get("/user/:id/grants").blockingHandler(new GETUserGrants());
|
||||||
get("/user/:id/punishments", new GETUserPunishments(), gson::toJson);
|
mainRouter.get("/user/:id/punishments").blockingHandler(new GETUserPunishments());
|
||||||
get("/user/:id/ipLog", new GETUserIPLog(), gson::toJson);
|
mainRouter.get("/user/:id/ipLog").blockingHandler(new GETUserIPLog());
|
||||||
get("/user/:id/requiresTOTP", new GETUserRequiresTOTP(), gson::toJson);
|
mainRouter.get("/user/:id/requiresTOTP").blockingHandler(new GETUserRequiresTOTP());
|
||||||
get("/user/:id/verifyPassword", new GETUserVerifyPassword(), gson::toJson);
|
mainRouter.get("/user/:id/verifyPassword").blockingHandler(new GETUserVerifyPassword());
|
||||||
get("/user/:id", new GETUser(), gson::toJson);
|
mainRouter.get("/user/:id").blockingHandler(new GETUser());
|
||||||
post("/user/:id/verifyTOTP", new POSTUserVerifyTOTP(), gson::toJson);
|
mainRouter.post("/user/:id/verifyTOTP").blockingHandler(new POSTUserVerifyTOTP());
|
||||||
post("/user/:id/grant", new POSTUserGrant(), gson::toJson);
|
mainRouter.post("/user/:id/grant").blockingHandler(new POSTUserGrant());
|
||||||
post("/user/:id/punish", new POSTUserPunish(), gson::toJson);
|
mainRouter.post("/user/:id/punish").blockingHandler(new POSTUserPunish());
|
||||||
post("/user/:id/login", new POSTUserLogin(), gson::toJson);
|
mainRouter.post("/user/:id/login").blockingHandler(new POSTUserLogin());
|
||||||
post("/user/:id/leave", new POSTUserLeave(), gson::toJson);
|
mainRouter.post("/user/:id/leave").blockingHandler(new POSTUserLeave());
|
||||||
post("/user/:id/notify", new POSTUserNotify(), gson::toJson);
|
mainRouter.post("/user/:id/notify").blockingHandler(new POSTUserNotify());
|
||||||
post("/user/:id/register", new POSTUserRegister(), gson::toJson);
|
mainRouter.post("/user/:id/register").blockingHandler(new POSTUserRegister());
|
||||||
post("/user/:id/setupTOTP", new POSTUserSetupTOTP(), gson::toJson);
|
mainRouter.post("/user/:id/setupTOTP").blockingHandler(new POSTUserSetupTOTP());
|
||||||
post("/user/confirmRegister/:emailToken", new POSTUserConfirmRegister(), gson::toJson);
|
mainRouter.post("/user/confirmRegister/:emailToken").blockingHandler(new POSTUserConfirmRegister());
|
||||||
put("/user/:id/meta/:serverGroup", new PUTUserMeta(), gson::toJson);
|
mainRouter.put("/user/:id/meta/:serverGroup").blockingHandler(new PUTUserMeta());
|
||||||
delete("/user/:id/meta/:serverGroup", new DELETEUserMeta(), gson::toJson);
|
mainRouter.delete("/user/:id/meta/:serverGroup").blockingHandler(new DELETEUserMeta());
|
||||||
delete("/user/:id/punishment", new DELETEUserPunishment(), gson::toJson);
|
mainRouter.delete("/user/:id/punishment").blockingHandler(new DELETEUserPunishment());
|
||||||
|
|
||||||
// There's no way to do a JSON 404 page w/o doing this :(
|
mainRouter.getRoutes().forEach((route) -> {
|
||||||
get("/*", new NotFound(), gson::toJson);
|
System.out.println(route.getClass() + "||" + route.getPath());
|
||||||
post("/*", new NotFound(), gson::toJson);
|
});
|
||||||
put("/*", new NotFound(), gson::toJson);
|
|
||||||
delete("/*", new NotFound(), gson::toJson);
|
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));
|
ctx.response().end(gson.toJson(response));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void convertData(String oldIp, boolean forReal) {
|
private void convertData(String oldIp, boolean forReal) {
|
||||||
// A lot of unneeded .toString()'s and cloning objects is our ghetto null validation.
|
// 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<ObjectId, UUID> mongoIdToUUID = new HashMap<>();
|
Map<ObjectId, UUID> mongoIdToUUID = new HashMap<>();
|
||||||
AtomicInteger skippedUsers = new AtomicInteger();
|
AtomicInteger skippedUsers = new AtomicInteger();
|
||||||
AtomicInteger skippedPunishments = new AtomicInteger();
|
AtomicInteger skippedPunishments = new AtomicInteger();
|
||||||
@ -299,12 +312,12 @@ public final class APIv3 {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (forReal) {
|
if (forReal) {
|
||||||
APIv3.getDatastore().save(created);
|
created.insert();
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("Created user " + created.getLastUsername() + " (" + created.getId() + ")");
|
log.info("Created user " + created.getLastUsername() + " (" + created.getId() + ")");
|
||||||
}
|
}
|
||||||
});
|
}, (a, b) -> {});
|
||||||
|
|
||||||
importFrom.getCollection("punishment").find().forEach(new Block<Document>() {
|
importFrom.getCollection("punishment").find().forEach(new Block<Document>() {
|
||||||
|
|
||||||
@ -322,6 +335,8 @@ public final class APIv3 {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
com.mongodb.
|
||||||
|
|
||||||
Punishment created = new Punishment(
|
Punishment created = new Punishment(
|
||||||
new ObjectId().toString(),
|
new ObjectId().toString(),
|
||||||
target,
|
target,
|
||||||
@ -339,12 +354,12 @@ public final class APIv3 {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (forReal) {
|
if (forReal) {
|
||||||
APIv3.getDatastore().save(created);
|
created.insert();
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("Created punishment " + created.getId() + " (" + created.getType() + ")");
|
log.info("Created punishment " + created.getId() + " (" + created.getType() + ")");
|
||||||
}
|
}
|
||||||
});
|
}, (a, b) -> {});
|
||||||
|
|
||||||
importFrom.getCollection("grant").find().forEach(new Block<Document>() {
|
importFrom.getCollection("grant").find().forEach(new Block<Document>() {
|
||||||
|
|
||||||
@ -382,12 +397,12 @@ public final class APIv3 {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (forReal) {
|
if (forReal) {
|
||||||
APIv3.getDatastore().save(created);
|
created.insert();
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("Created grant " + created.getId() + " (" + created.getRank() + ")");
|
log.info("Created grant " + created.getId() + " (" + created.getRank() + ")");
|
||||||
}
|
}
|
||||||
});
|
}, (a, b) -> {});
|
||||||
|
|
||||||
importFrom.getCollection("iplog").find().forEach(new Block<Document>() {
|
importFrom.getCollection("iplog").find().forEach(new Block<Document>() {
|
||||||
|
|
||||||
@ -423,12 +438,12 @@ public final class APIv3 {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (forReal) {
|
if (forReal) {
|
||||||
APIv3.getDatastore().save(created);
|
created.insert();
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("Created ip log entry " + created.getId() + " (" + created.getUser() + " - " + created.getUserIp() + ")");
|
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");
|
log.info("Skipped " + skippedUsers.get() + " users, " + skippedPunishments.get() + " punishments, " + skippedGrants.get() + " grants, and " + skippedIpLogs.get() + " ip logs");
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
package net.frozenorb.apiv3;
|
package net.frozenorb.apiv3;
|
||||||
|
|
||||||
|
import io.vertx.core.Vertx;
|
||||||
|
|
||||||
final class Main {
|
final class Main {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
new APIv3();
|
Vertx.vertx().deployVerticle(new APIv3());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -23,7 +23,7 @@ public final class UserActor implements Actor {
|
|||||||
if (cachedAuthorized != null) {
|
if (cachedAuthorized != null) {
|
||||||
return cachedAuthorized;
|
return cachedAuthorized;
|
||||||
} else {
|
} else {
|
||||||
String highestRankId = user.getHighestRank().getId();
|
String highestRankId = user.getHighestRankAnywhere().getId();
|
||||||
cachedAuthorized = permittedUserRanks.contains(highestRankId.toLowerCase());
|
cachedAuthorized = permittedUserRanks.contains(highestRankId.toLowerCase());
|
||||||
return cachedAuthorized;
|
return cachedAuthorized;
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,9 @@ public class AuditLog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void log(User performedBy, String performedByIp, Actor actor, AuditLogActionType actionType, Map<String, Object> actionData) {
|
public static void log(User performedBy, String performedByIp, Actor actor, AuditLogActionType actionType, Map<String, Object> actionData) {
|
||||||
|
AuditLogEntry entry = new AuditLogEntry(performedBy, performedByIp, actor, actionType, actionData);
|
||||||
|
entry.insert();
|
||||||
APIv3.getStatsD().incrementCounter("apiv3.auditLog.insertions");
|
APIv3.getStatsD().incrementCounter("apiv3.auditLog.insertions");
|
||||||
APIv3.getDatastore().save(new AuditLogEntry(performedBy, performedByIp, actor, actionType, actionData));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,52 +1,53 @@
|
|||||||
package net.frozenorb.apiv3.filters;
|
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.APIv3;
|
||||||
import net.frozenorb.apiv3.actors.*;
|
import net.frozenorb.apiv3.actors.*;
|
||||||
import net.frozenorb.apiv3.models.Server;
|
import net.frozenorb.apiv3.models.Server;
|
||||||
import net.frozenorb.apiv3.models.User;
|
import net.frozenorb.apiv3.models.User;
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
import spark.Filter;
|
|
||||||
import spark.Request;
|
|
||||||
import spark.Response;
|
|
||||||
import spark.Spark;
|
|
||||||
|
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
|
|
||||||
public final class ActorAttributeFilter implements Filter {
|
public final class ActorAttributeFilter implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(Request req, Response res) {
|
// TODO: MAKE THIS ASYNC
|
||||||
String authHeader = req.headers("Authorization");
|
public void handle(RoutingContext ctx) {
|
||||||
String mhqAuthHeader = req.headers("MHQ-Authorization");
|
String authHeader = ctx.request().getHeader("Authorization");
|
||||||
|
String mhqAuthHeader = ctx.request().getHeader("MHQ-Authorization");
|
||||||
|
|
||||||
if (authHeader != null) {
|
if (authHeader != null) {
|
||||||
req.attribute("actor", processBasicAuthorization(authHeader, res));
|
processBasicAuthorization(authHeader, ctx);
|
||||||
} else if (mhqAuthHeader != null) {
|
} else if (mhqAuthHeader != null) {
|
||||||
req.attribute("actor", processMHQAuthorization(mhqAuthHeader));
|
processMHQAuthorization(mhqAuthHeader, ctx);
|
||||||
} else {
|
} else {
|
||||||
req.attribute("actor", new UnknownActor());
|
ctx.put("actor", new UnknownActor());
|
||||||
|
ctx.next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation") // We purposely get the User by their last username.
|
@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 encodedHeader = authHeader.substring("Basic ".length());
|
||||||
String[] credentials = new String(Base64.getDecoder().decode(encodedHeader.getBytes())).split(":");
|
String[] credentials = new String(Base64.getDecoder().decode(encodedHeader.getBytes())).split(":");
|
||||||
|
|
||||||
if (credentials.length == 2) {
|
if (credentials.length == 2) {
|
||||||
User user = User.byLastUsername(credentials[0]);
|
User user = User.findByLastUsername(credentials[0]);
|
||||||
String password = credentials[1];
|
String password = credentials[1];
|
||||||
|
|
||||||
if (user != null && user.getPassword() != null && user.checkPassword(password)) {
|
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\"");
|
ctx.response().putHeader("WWW-Authenticate", "Basic realm=\"MineHQ\"");
|
||||||
Spark.halt(401, APIv3.getGson().toJson(ErrorUtils.error("Failed to authorize as " + credentials[0] + ".")));
|
ErrorUtils.respondGeneric(ctx, "Failed to authorize as " + credentials[0] + ".");
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Actor processMHQAuthorization(String authHeader) {
|
private void processMHQAuthorization(String authHeader, RoutingContext ctx) {
|
||||||
String[] split = authHeader.split(" ");
|
String[] split = authHeader.split(" ");
|
||||||
|
|
||||||
if (split.length >= 2) {
|
if (split.length >= 2) {
|
||||||
@ -57,33 +58,39 @@ public final class ActorAttributeFilter implements Filter {
|
|||||||
String properKey = APIv3.getConfig().getProperty("auth.websiteApiKey");
|
String properKey = APIv3.getConfig().getProperty("auth.websiteApiKey");
|
||||||
|
|
||||||
if (givenKey.equals(properKey)) {
|
if (givenKey.equals(properKey)) {
|
||||||
return new WebsiteActor();
|
ctx.put("actor", new WebsiteActor());
|
||||||
|
ctx.next();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} else if (type.equals("Server") && split.length == 3) {
|
} else if (type.equals("Server") && split.length == 3) {
|
||||||
Server server = Server.byId(split[1]);
|
Server server = Server.findById(split[1]);
|
||||||
|
|
||||||
if (server == null) {
|
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 givenKey = split[2];
|
||||||
String properKey = server.getApiKey();
|
String properKey = server.getApiKey();
|
||||||
|
|
||||||
if (givenKey.equals(properKey)) {
|
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) {
|
} else if (type.equals("BungeeCord") && split.length == 2) {
|
||||||
String givenKey = split[1];
|
String givenKey = split[1];
|
||||||
String properKey = APIv3.getConfig().getProperty("auth.bungeeCordApiKey");
|
String properKey = APIv3.getConfig().getProperty("auth.bungeeCordApiKey");
|
||||||
|
|
||||||
if (givenKey.equals(properKey)) {
|
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.")));
|
ErrorUtils.respondGeneric(ctx, "Failed to authorize.");
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,22 +1,22 @@
|
|||||||
package net.frozenorb.apiv3.filters;
|
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.APIv3;
|
||||||
import net.frozenorb.apiv3.actors.Actor;
|
import net.frozenorb.apiv3.actors.Actor;
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
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<RoutingContext> {
|
||||||
|
|
||||||
public void handle(Request req, Response res) {
|
public void handle(RoutingContext ctx) {
|
||||||
Actor actor = ctx.get("actor");
|
Actor actor = ctx.get("actor");
|
||||||
|
|
||||||
if (!actor.isAuthorized()) {
|
if (!actor.isAuthorized()) {
|
||||||
APIv3.getStatsD().incrementCounter("apiv3.http.unauthorized");
|
APIv3.getStatsD().incrementCounter("apiv3.http.unauthorized");
|
||||||
res.header("WWW-Authenticate", "Basic realm=\"MineHQ\"");
|
ctx.response().putHeader("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())));
|
ErrorUtils.respondGeneric(ctx, "Unauthorized access: Please authorize as an approved actor. You're currently authorized as " + actor.getName());
|
||||||
|
} else {
|
||||||
|
ctx.next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -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() : ""));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -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");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -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());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -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<RoutingContext> {
|
||||||
|
|
||||||
|
public void handle(RoutingContext ctx) {
|
||||||
|
APIv3.getStatsD().incrementCounter("apiv3.http.requests");
|
||||||
|
ctx.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,31 +1,55 @@
|
|||||||
package net.frozenorb.apiv3.models;
|
package net.frozenorb.apiv3.models;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
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 lombok.Getter;
|
||||||
|
import net.frozenorb.apiv3.APIv3;
|
||||||
import net.frozenorb.apiv3.actors.Actor;
|
import net.frozenorb.apiv3.actors.Actor;
|
||||||
import net.frozenorb.apiv3.actors.ActorType;
|
import net.frozenorb.apiv3.actors.ActorType;
|
||||||
|
import net.frozenorb.apiv3.auditLog.AuditLog;
|
||||||
import net.frozenorb.apiv3.auditLog.AuditLogActionType;
|
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.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.Date;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@Entity(value = "auditLog", noClassnameStored = true)
|
@Entity
|
||||||
public final class AuditLogEntry {
|
public final class AuditLogEntry {
|
||||||
|
|
||||||
|
private static final MongoCollection<AuditLogEntry> auditLogCollection = APIv3.getDatabase().getCollection("auditLog", AuditLogEntry.class);
|
||||||
|
|
||||||
@Getter @Id private String id;
|
@Getter @Id private String id;
|
||||||
@Getter @Indexed private UUID user;
|
@Getter private UUID user;
|
||||||
@Getter private String userIp;
|
@Getter private String userIp;
|
||||||
@Getter @Indexed private Date performedAt;
|
@Getter private Date performedAt;
|
||||||
@Getter private String actorName;
|
@Getter private String actorName;
|
||||||
@Getter private ActorType actorType;
|
@Getter private ActorType actorType;
|
||||||
@Getter private AuditLogActionType type;
|
@Getter private AuditLogActionType type;
|
||||||
@Getter private Map<String, Object> metadata;
|
@Getter private Map<String, Object> metadata;
|
||||||
|
|
||||||
|
public static List<AuditLogEntry> findAll() {
|
||||||
|
return SyncUtils.blockMulti(auditLogCollection.find());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AuditLogEntry findById(String id) {
|
||||||
|
return SyncUtils.blockOne(auditLogCollection.find(new Document("_id", id)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<AuditLogEntry> findByUser(User user) {
|
||||||
|
return findByUser(user.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<AuditLogEntry> findByUser(UUID user) {
|
||||||
|
return SyncUtils.blockMulti(auditLogCollection.find(new Document("user", user)));
|
||||||
|
}
|
||||||
|
|
||||||
public AuditLogEntry() {} // For Morphia
|
public AuditLogEntry() {} // For Morphia
|
||||||
|
|
||||||
public AuditLogEntry(User user, String userIp, Actor actor, AuditLogActionType type, Map<String, Object> metadata) {
|
public AuditLogEntry(User user, String userIp, Actor actor, AuditLogActionType type, Map<String, Object> metadata) {
|
||||||
@ -39,4 +63,10 @@ public final class AuditLogEntry {
|
|||||||
this.metadata = ImmutableMap.copyOf(metadata);
|
this.metadata = ImmutableMap.copyOf(metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void insert() {
|
||||||
|
BlockingCallback<Void> callback = new BlockingCallback<>();
|
||||||
|
auditLogCollection.insertOne(this, callback);
|
||||||
|
callback.get();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,56 +1,59 @@
|
|||||||
package net.frozenorb.apiv3.models;
|
package net.frozenorb.apiv3.models;
|
||||||
|
|
||||||
import com.google.common.collect.Collections2;
|
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.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import net.frozenorb.apiv3.APIv3;
|
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.bson.types.ObjectId;
|
||||||
import org.mongodb.morphia.annotations.Entity;
|
|
||||||
import org.mongodb.morphia.annotations.Id;
|
|
||||||
import org.mongodb.morphia.annotations.Indexed;
|
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@Entity(value = "grants", noClassnameStored = true)
|
@Entity
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public final class Grant {
|
public final class Grant {
|
||||||
|
|
||||||
|
private static final MongoCollection<Grant> grantsCollection = APIv3.getDatabase().getCollection("grants", Grant.class);
|
||||||
|
|
||||||
@Getter @Id private String id;
|
@Getter @Id private String id;
|
||||||
@Getter @Indexed private UUID user;
|
@Getter private UUID user;
|
||||||
@Getter private String reason;
|
@Getter private String reason;
|
||||||
@Getter private Set<String> scopes = new HashSet<>(); // So on things w/o scopes we still load properly (Morphia drops empty sets)
|
@Getter private Set<String> 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 Date expiresAt;
|
||||||
|
|
||||||
@Getter private UUID addedBy;
|
@Getter private UUID addedBy;
|
||||||
@Getter @Indexed private Date addedAt;
|
@Getter private Date addedAt;
|
||||||
|
|
||||||
@Getter private UUID removedBy;
|
@Getter private UUID removedBy;
|
||||||
@Getter private Date removedAt;
|
@Getter private Date removedAt;
|
||||||
@Getter private String removalReason;
|
@Getter private String removalReason;
|
||||||
|
|
||||||
public static Grant byId(String id) {
|
public static List<Grant> findAll() {
|
||||||
return APIv3.getDatastore().createQuery(Grant.class).field("id").equal(id).get();
|
return SyncUtils.blockMulti(grantsCollection.find());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Map<UUID, List<Grant>> byUserGrouped(Iterable<UUID> ids) {
|
public static List<Grant> findByRank(Iterable<Rank> ranks) {
|
||||||
Map<UUID, List<Grant>> result = new HashMap<>();
|
return SyncUtils.blockMulti(grantsCollection.find(new Document("rank", new Document("$in", ranks))));
|
||||||
Set<UUID> uuidsToSearch = new HashSet<>();
|
}
|
||||||
|
|
||||||
for (UUID id : ids) {
|
public static Grant findById(String id) {
|
||||||
result.put(id, new ArrayList<>());
|
return SyncUtils.blockOne(grantsCollection.find(new Document("_id", id)));
|
||||||
|
}
|
||||||
|
|
||||||
if (UUIDUtils.isAcceptableUUID(id)) {
|
public static List<Grant> findByUser(User user) {
|
||||||
uuidsToSearch.add(id);
|
return findByUser(user.getId());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
APIv3.getDatastore().createQuery(Grant.class).field("user").in(uuidsToSearch).forEach((grant) -> {
|
public static List<Grant> findByUser(UUID user) {
|
||||||
result.get(grant.getUser()).add(grant);
|
return SyncUtils.blockMulti(grantsCollection.find(new Document("user", user)));
|
||||||
});
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Grant() {} // For Morphia
|
public Grant() {} // For Morphia
|
||||||
@ -66,14 +69,6 @@ public final class Grant {
|
|||||||
this.addedAt = new Date();
|
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() {
|
public boolean isActive() {
|
||||||
return !(isExpired() || isRemoved());
|
return !(isExpired() || isRemoved());
|
||||||
}
|
}
|
||||||
@ -98,4 +93,20 @@ public final class Grant {
|
|||||||
return scopes.isEmpty();
|
return scopes.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void insert() {
|
||||||
|
BlockingCallback<Void> 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<DeleteResult> callback = new BlockingCallback<>();
|
||||||
|
grantsCollection.deleteOne(new Document("_id", id), callback);
|
||||||
|
callback.get();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,31 +1,57 @@
|
|||||||
package net.frozenorb.apiv3.models;
|
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.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import net.frozenorb.apiv3.APIv3;
|
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.bson.types.ObjectId;
|
||||||
import org.mongodb.morphia.annotations.*;
|
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@Entity(value = "ipLog", noClassnameStored = true)
|
@Entity
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@Indexes(
|
|
||||||
@Index(fields = {
|
|
||||||
@Field("user"),
|
|
||||||
@Field("userIp")
|
|
||||||
})
|
|
||||||
)
|
|
||||||
public final class IPLogEntry {
|
public final class IPLogEntry {
|
||||||
|
|
||||||
|
private static final MongoCollection<IPLogEntry> ipLogCollection = APIv3.getDatabase().getCollection("ipLog", IPLogEntry.class);
|
||||||
|
|
||||||
@Getter @Id private String id;
|
@Getter @Id private String id;
|
||||||
@Getter @Indexed private UUID user;
|
@Getter private UUID user;
|
||||||
@Getter @Indexed private String userIp;
|
@Getter private String userIp;
|
||||||
@Getter private Date firstSeenAt;
|
@Getter private Date firstSeenAt;
|
||||||
@Getter private Date lastSeenAt;
|
@Getter private Date lastSeenAt;
|
||||||
@Getter private int uses;
|
@Getter private int uses;
|
||||||
|
|
||||||
|
public static List<IPLogEntry> findAll() {
|
||||||
|
return SyncUtils.blockMulti(ipLogCollection.find());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IPLogEntry findById(String id) {
|
||||||
|
return SyncUtils.blockOne(ipLogCollection.find(new Document("_id", id)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<IPLogEntry> findByUser(User user) {
|
||||||
|
return findByUser(user.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<IPLogEntry> 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() {} // For Morphia
|
||||||
|
|
||||||
public IPLogEntry(User user, String userIp) {
|
public IPLogEntry(User user, String userIp) {
|
||||||
@ -40,8 +66,12 @@ public final class IPLogEntry {
|
|||||||
public void used() {
|
public void used() {
|
||||||
this.lastSeenAt = new Date();
|
this.lastSeenAt = new Date();
|
||||||
this.uses++;
|
this.uses++;
|
||||||
|
}
|
||||||
|
|
||||||
APIv3.getDatastore().save(this);
|
public void insert() {
|
||||||
|
BlockingCallback<Void> callback = new BlockingCallback<>();
|
||||||
|
ipLogCollection.insertOne(this, callback);
|
||||||
|
callback.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,26 +1,35 @@
|
|||||||
package net.frozenorb.apiv3.models;
|
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.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
import net.frozenorb.apiv3.APIv3;
|
import net.frozenorb.apiv3.APIv3;
|
||||||
import org.mongodb.morphia.annotations.Entity;
|
import net.frozenorb.apiv3.unsorted.BlockingCallback;
|
||||||
import org.mongodb.morphia.annotations.Id;
|
import net.frozenorb.apiv3.utils.SyncUtils;
|
||||||
|
import org.bson.Document;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@Entity(value = "notificationTemplates", noClassnameStored = true)
|
@Entity
|
||||||
public final class NotificationTemplate {
|
public final class NotificationTemplate {
|
||||||
|
|
||||||
@Getter @Id private String id;
|
private static final MongoCollection<NotificationTemplate> notificationTemplatesCollection = APIv3.getDatabase().getCollection("notificationTemplates", NotificationTemplate.class);
|
||||||
@Getter private String subject;
|
|
||||||
@Getter private String body;
|
|
||||||
|
|
||||||
public static NotificationTemplate byId(String id) {
|
@Getter @Id private String id;
|
||||||
return APIv3.getDatastore().createQuery(NotificationTemplate.class).field("id").equal(id).get();
|
@Getter @Setter private String subject;
|
||||||
|
@Getter @Setter private String body;
|
||||||
|
|
||||||
|
public static List<NotificationTemplate> findAll() {
|
||||||
|
return SyncUtils.blockMulti(notificationTemplatesCollection.find());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<NotificationTemplate> values() {
|
public static NotificationTemplate findById(String id) {
|
||||||
return APIv3.getDatastore().createQuery(NotificationTemplate.class).asList();
|
return SyncUtils.blockOne(notificationTemplatesCollection.find(new Document("_id", id)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public NotificationTemplate() {} // For Morphia
|
public NotificationTemplate() {} // For Morphia
|
||||||
@ -31,17 +40,6 @@ public final class NotificationTemplate {
|
|||||||
this.body = body;
|
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<String, Object> replacements) {
|
public String fillSubject(Map<String, Object> replacements) {
|
||||||
return fill(subject, replacements);
|
return fill(subject, replacements);
|
||||||
}
|
}
|
||||||
@ -61,4 +59,22 @@ public final class NotificationTemplate {
|
|||||||
return working;
|
return working;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void insert() {
|
||||||
|
BlockingCallback<Void> callback = new BlockingCallback<>();
|
||||||
|
notificationTemplatesCollection.insertOne(this, callback);
|
||||||
|
callback.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save() {
|
||||||
|
BlockingCallback<UpdateResult> callback = new BlockingCallback<>();
|
||||||
|
notificationTemplatesCollection.replaceOne(new Document("_id", id), this, callback);
|
||||||
|
callback.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete() {
|
||||||
|
BlockingCallback<DeleteResult> callback = new BlockingCallback<>();
|
||||||
|
notificationTemplatesCollection.deleteOne(new Document("_id", id), callback);
|
||||||
|
callback.get();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,37 +1,37 @@
|
|||||||
package net.frozenorb.apiv3.models;
|
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.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import net.frozenorb.apiv3.APIv3;
|
import net.frozenorb.apiv3.APIv3;
|
||||||
import net.frozenorb.apiv3.actors.Actor;
|
import net.frozenorb.apiv3.actors.Actor;
|
||||||
import net.frozenorb.apiv3.actors.ActorType;
|
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.TimeUtils;
|
||||||
import net.frozenorb.apiv3.utils.UUIDUtils;
|
import org.bson.Document;
|
||||||
import org.bson.types.ObjectId;
|
import org.bson.types.ObjectId;
|
||||||
import org.mongodb.morphia.annotations.*;
|
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@Entity(value = "punishments", noClassnameStored = true)
|
@Entity
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@Indexes(
|
|
||||||
@Index(fields = {
|
|
||||||
@Field("user"),
|
|
||||||
@Field("type")
|
|
||||||
})
|
|
||||||
)
|
|
||||||
public final class Punishment {
|
public final class Punishment {
|
||||||
|
|
||||||
|
private static final MongoCollection<Punishment> punishmentsCollection = APIv3.getDatabase().getCollection("punishments", Punishment.class);
|
||||||
|
|
||||||
@Getter @Id private String id;
|
@Getter @Id private String id;
|
||||||
@Getter @Indexed private UUID user;
|
@Getter private UUID user;
|
||||||
@Getter private String reason;
|
@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 Date expiresAt;
|
||||||
@Getter private Map<String, Object> metadata;
|
@Getter private Map<String, Object> metadata;
|
||||||
|
|
||||||
@Getter private UUID addedBy;
|
@Getter private UUID addedBy;
|
||||||
@Getter @Indexed private Date addedAt;
|
@Getter private Date addedAt;
|
||||||
@Getter private String actorName;
|
@Getter private String actorName;
|
||||||
@Getter private ActorType actorType;
|
@Getter private ActorType actorType;
|
||||||
|
|
||||||
@ -39,31 +39,32 @@ public final class Punishment {
|
|||||||
@Getter private Date removedAt;
|
@Getter private Date removedAt;
|
||||||
@Getter private String removalReason;
|
@Getter private String removalReason;
|
||||||
|
|
||||||
public static Punishment byId(String id) {
|
public static List<Punishment> findAll() {
|
||||||
return APIv3.getDatastore().createQuery(Punishment.class).field("id").equal(id).get();
|
return SyncUtils.blockMulti(punishmentsCollection.find());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Map<UUID, List<Punishment>> byUserGrouped(Iterable<UUID> ids) {
|
public static List<Punishment> findByType(Iterable<PunishmentType> types) {
|
||||||
return byUserGrouped(ids, ImmutableSet.copyOf(PunishmentType.values()));
|
return SyncUtils.blockMulti(punishmentsCollection.find(new Document("type", new Document("$in", types))));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Map<UUID, List<Punishment>> byUserGrouped(Iterable<UUID> ids, Iterable<Punishment.PunishmentType> types) {
|
public static Punishment findById(String id) {
|
||||||
Map<UUID, List<Punishment>> result = new HashMap<>();
|
return SyncUtils.blockOne(punishmentsCollection.find(new Document("_id", id)));
|
||||||
Set<UUID> uuidsToSearch = new HashSet<>();
|
}
|
||||||
|
|
||||||
for (UUID id : ids) {
|
public static List<Punishment> findByUser(User user) {
|
||||||
result.put(id, new ArrayList<>());
|
return findByUser(user.getId());
|
||||||
|
}
|
||||||
|
|
||||||
if (UUIDUtils.isAcceptableUUID(id)) {
|
public static List<Punishment> findByUser(UUID user) {
|
||||||
uuidsToSearch.add(id);
|
return SyncUtils.blockMulti(punishmentsCollection.find(new Document("user", user)));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
APIv3.getDatastore().createQuery(Punishment.class).field("user").in(uuidsToSearch).field("type").in(types).forEach((punishment) -> {
|
public static List<Punishment> findByUserAndType(User user, Iterable<PunishmentType> types) {
|
||||||
result.get(punishment.getUser()).add(punishment);
|
return findByUserAndType(user.getId(), types);
|
||||||
});
|
}
|
||||||
|
|
||||||
return result;
|
public static List<Punishment> findByUserAndType(UUID user, Iterable<PunishmentType> types) {
|
||||||
|
return SyncUtils.blockMulti(punishmentsCollection.find(new Document("user", user).append("type", new Document("$in", types))));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Punishment() {} // For Morphia
|
public Punishment() {} // For Morphia
|
||||||
@ -81,14 +82,6 @@ public final class Punishment {
|
|||||||
this.metadata = metadata;
|
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() {
|
public boolean isActive() {
|
||||||
return !(isExpired() || isRemoved());
|
return !(isExpired() || isRemoved());
|
||||||
}
|
}
|
||||||
@ -124,6 +117,22 @@ public final class Punishment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void insert() {
|
||||||
|
BlockingCallback<Void> 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<DeleteResult> callback = new BlockingCallback<>();
|
||||||
|
punishmentsCollection.deleteOne(new Document("_id", id), callback);
|
||||||
|
callback.get();
|
||||||
|
}
|
||||||
|
|
||||||
public enum PunishmentType {
|
public enum PunishmentType {
|
||||||
|
|
||||||
BLACKLIST, BAN, MUTE, WARN
|
BLACKLIST, BAN, MUTE, WARN
|
||||||
|
@ -1,11 +1,17 @@
|
|||||||
package net.frozenorb.apiv3.models;
|
package net.frozenorb.apiv3.models;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
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 lombok.Getter;
|
||||||
import net.frozenorb.apiv3.APIv3;
|
import net.frozenorb.apiv3.APIv3;
|
||||||
import org.mongodb.morphia.annotations.Entity;
|
import net.frozenorb.apiv3.unsorted.BlockingCallback;
|
||||||
import org.mongodb.morphia.annotations.Id;
|
import net.frozenorb.apiv3.utils.SyncUtils;
|
||||||
import org.mongodb.morphia.annotations.Indexed;
|
import org.bson.Document;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -13,9 +19,11 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@Entity(value = "ranks", noClassnameStored = true)
|
@Entity
|
||||||
public final class Rank {
|
public final class Rank {
|
||||||
|
|
||||||
|
private static final MongoCollection<Rank> ranksCollection = APIv3.getDatabase().getCollection("ranks", Rank.class);
|
||||||
|
|
||||||
private static Map<String, Rank> rankCache = null;
|
private static Map<String, Rank> rankCache = null;
|
||||||
private static List<Rank> rankAltCache = null;
|
private static List<Rank> rankAltCache = null;
|
||||||
private static long rankCacheUpdated = 0;
|
private static long rankCacheUpdated = 0;
|
||||||
@ -25,18 +33,18 @@ public final class Rank {
|
|||||||
@Getter private String displayName;
|
@Getter private String displayName;
|
||||||
@Getter private String gameColor;
|
@Getter private String gameColor;
|
||||||
@Getter private String websiteColor;
|
@Getter private String websiteColor;
|
||||||
@Getter @Indexed private boolean staffRank;
|
@Getter private boolean staffRank;
|
||||||
|
|
||||||
public static Rank byId(String id) {
|
public static List<Rank> findAll() {
|
||||||
updateCacheIfNeeded();
|
|
||||||
return rankCache.get(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<Rank> values() {
|
|
||||||
updateCacheIfNeeded();
|
updateCacheIfNeeded();
|
||||||
return ImmutableList.copyOf(rankAltCache);
|
return ImmutableList.copyOf(rankAltCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Rank findById(String id) {
|
||||||
|
updateCacheIfNeeded();
|
||||||
|
return rankCache.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
public Rank() {} // For Morphia
|
public Rank() {} // For Morphia
|
||||||
|
|
||||||
public Rank(String id, int weight, String displayName, String gameColor, String websiteColor, boolean staffRank) {
|
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;
|
this.staffRank = staffRank;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void delete() {
|
|
||||||
APIv3.getDatastore().delete(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void updateCacheIfNeeded() {
|
private static void updateCacheIfNeeded() {
|
||||||
if (rankCache == null || (System.currentTimeMillis() - rankCacheUpdated) > TimeUnit.MINUTES.toMillis(1)) {
|
if (rankCache == null || (System.currentTimeMillis() - rankCacheUpdated) > TimeUnit.MINUTES.toMillis(1)) {
|
||||||
Map<String, Rank> working = new HashMap<>();
|
Map<String, Rank> working = new HashMap<>();
|
||||||
List<Rank> workingAlt = new ArrayList<>();
|
List<Rank> workingAlt = new ArrayList<>();
|
||||||
|
List<Rank> 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);
|
working.put(rank.getId(), rank);
|
||||||
workingAlt.add(rank);
|
workingAlt.add(rank);
|
||||||
}
|
}
|
||||||
@ -68,4 +74,22 @@ public final class Rank {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void insert() {
|
||||||
|
BlockingCallback<Void> callback = new BlockingCallback<>();
|
||||||
|
ranksCollection.insertOne(this, callback);
|
||||||
|
callback.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save() {
|
||||||
|
BlockingCallback<UpdateResult> callback = new BlockingCallback<>();
|
||||||
|
ranksCollection.replaceOne(new Document("_id", id), this, callback);
|
||||||
|
callback.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete() {
|
||||||
|
BlockingCallback<DeleteResult> callback = new BlockingCallback<>();
|
||||||
|
ranksCollection.deleteOne(new Document("_id", id), callback);
|
||||||
|
callback.get();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,19 +1,27 @@
|
|||||||
package net.frozenorb.apiv3.models;
|
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.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import net.frozenorb.apiv3.APIv3;
|
import net.frozenorb.apiv3.APIv3;
|
||||||
import net.frozenorb.apiv3.serialization.ExcludeFromReplies;
|
import net.frozenorb.apiv3.serialization.ExcludeFromReplies;
|
||||||
import org.mongodb.morphia.annotations.Entity;
|
import net.frozenorb.apiv3.unsorted.BlockingCallback;
|
||||||
import org.mongodb.morphia.annotations.Id;
|
import net.frozenorb.apiv3.utils.SyncUtils;
|
||||||
import org.mongodb.morphia.annotations.Indexed;
|
import org.bson.Document;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@Entity(value = "servers", noClassnameStored = true)
|
@Entity
|
||||||
public final class Server {
|
public final class Server {
|
||||||
|
|
||||||
|
private static final MongoCollection<Server> serversCollection = APIv3.getDatabase().getCollection("servers", Server.class);
|
||||||
|
|
||||||
private static Map<String, Server> serverCache = null;
|
private static Map<String, Server> serverCache = null;
|
||||||
private static List<Server> serverCacheAlt = null;
|
private static List<Server> serverCacheAlt = null;
|
||||||
private static long serverCacheUpdated = 0;
|
private static long serverCacheUpdated = 0;
|
||||||
@ -21,22 +29,22 @@ public final class Server {
|
|||||||
@Getter @Id private String id;
|
@Getter @Id private String id;
|
||||||
@Getter private String displayName;
|
@Getter private String displayName;
|
||||||
@Getter @ExcludeFromReplies String apiKey;
|
@Getter @ExcludeFromReplies String apiKey;
|
||||||
@Getter @Indexed private String serverGroup;
|
@Getter private String serverGroup;
|
||||||
@Getter private String serverIp;
|
@Getter private String serverIp;
|
||||||
@Getter @Setter private Date lastUpdatedAt;
|
@Getter @Setter private Date lastUpdatedAt;
|
||||||
@Getter @Setter private double lastTps;
|
@Getter @Setter private double lastTps;
|
||||||
@Getter @Setter @ExcludeFromReplies private Set<UUID> players;
|
@Getter @Setter @ExcludeFromReplies private Set<UUID> players;
|
||||||
|
|
||||||
public static Server byId(String id) {
|
public static List<Server> findAll() {
|
||||||
updateCacheIfNeeded();
|
|
||||||
return serverCache.get(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<Server> values() {
|
|
||||||
updateCacheIfNeeded();
|
updateCacheIfNeeded();
|
||||||
return serverCacheAlt;
|
return serverCacheAlt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Server findById(String id) {
|
||||||
|
updateCacheIfNeeded();
|
||||||
|
return serverCache.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
public Server() {} // For Morphia
|
public Server() {} // For Morphia
|
||||||
|
|
||||||
public Server(String id, String displayName, String apiKey, ServerGroup serverGroup, String serverIp) {
|
public Server(String id, String displayName, String apiKey, ServerGroup serverGroup, String serverIp) {
|
||||||
@ -50,16 +58,12 @@ public final class Server {
|
|||||||
this.players = new HashSet<>();
|
this.players = new HashSet<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void delete() {
|
|
||||||
APIv3.getDatastore().delete(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void updateCacheIfNeeded() {
|
private static void updateCacheIfNeeded() {
|
||||||
if (serverCache == null || (System.currentTimeMillis() - serverCacheUpdated) > TimeUnit.MINUTES.toMillis(1)) {
|
if (serverCache == null || (System.currentTimeMillis() - serverCacheUpdated) > TimeUnit.MINUTES.toMillis(1)) {
|
||||||
Map<String, Server> working = new HashMap<>();
|
Map<String, Server> working = new HashMap<>();
|
||||||
List<Server> workingAlt = new ArrayList<>();
|
List<Server> workingAlt = new ArrayList<>();
|
||||||
|
|
||||||
for (Server server : APIv3.getDatastore().createQuery(Server.class).asList()) {
|
for (Server server : SyncUtils.blockMulti(serversCollection.find())) {
|
||||||
working.put(server.getId(), server);
|
working.put(server.getId(), server);
|
||||||
workingAlt.add(server);
|
workingAlt.add(server);
|
||||||
}
|
}
|
||||||
@ -70,4 +74,28 @@ public final class Server {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void receivedHeartbeat(double tps, Iterable<UUID> players) {
|
||||||
|
this.lastUpdatedAt = new Date();
|
||||||
|
this.lastTps = tps;
|
||||||
|
this.players = ImmutableSet.copyOf(players);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void insert() {
|
||||||
|
BlockingCallback<Void> callback = new BlockingCallback<>();
|
||||||
|
serversCollection.insertOne(this, callback);
|
||||||
|
callback.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save() {
|
||||||
|
BlockingCallback<UpdateResult> callback = new BlockingCallback<>();
|
||||||
|
serversCollection.replaceOne(new Document("_id", id), this, callback);
|
||||||
|
callback.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete() {
|
||||||
|
BlockingCallback<DeleteResult> callback = new BlockingCallback<>();
|
||||||
|
serversCollection.deleteOne(new Document("_id", id), callback);
|
||||||
|
callback.get();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,44 +1,51 @@
|
|||||||
package net.frozenorb.apiv3.models;
|
package net.frozenorb.apiv3.models;
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName;
|
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.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import net.frozenorb.apiv3.APIv3;
|
import net.frozenorb.apiv3.APIv3;
|
||||||
import net.frozenorb.apiv3.serialization.ExcludeFromReplies;
|
import net.frozenorb.apiv3.serialization.ExcludeFromReplies;
|
||||||
|
import net.frozenorb.apiv3.unsorted.BlockingCallback;
|
||||||
import net.frozenorb.apiv3.utils.PermissionUtils;
|
import net.frozenorb.apiv3.utils.PermissionUtils;
|
||||||
import org.mongodb.morphia.annotations.Entity;
|
import net.frozenorb.apiv3.utils.SyncUtils;
|
||||||
import org.mongodb.morphia.annotations.Id;
|
import org.bson.Document;
|
||||||
import org.mongodb.morphia.annotations.Property;
|
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@Entity(value = "serverGroups", noClassnameStored = true)
|
@Entity
|
||||||
public final class ServerGroup {
|
public final class ServerGroup {
|
||||||
|
|
||||||
|
private static final MongoCollection<ServerGroup> serverGroupsCollection = APIv3.getDatabase().getCollection("serverGroups", ServerGroup.class);
|
||||||
|
|
||||||
private static Map<String, ServerGroup> serverGroupCache = null;
|
private static Map<String, ServerGroup> serverGroupCache = null;
|
||||||
private static List<ServerGroup> serverGroupAltCache = null;
|
private static List<ServerGroup> serverGroupAltCache = null;
|
||||||
private static long serverGroupCacheUpdated = 0;
|
private static long serverGroupCacheUpdated = 0;
|
||||||
|
|
||||||
@Getter @Id private String id;
|
@Getter @Id private String id;
|
||||||
@Getter private String image;
|
@Getter private String image;
|
||||||
// We rename this to public, we just can't name it that because it's a Java identifier.
|
// We rename this to public (only to gson), we just can't name it that because it's a Java identifier.
|
||||||
@Getter @Property("public") @SerializedName("public") private boolean isPublic;
|
@Getter @SerializedName("public") private boolean isPublic;
|
||||||
// We define these HashSets up here because, in the event they're
|
// We define these HashSets up here because, in the event they're
|
||||||
// empty, Morphia will load them as null, not empty sets.
|
// empty, Morphia will load them as null, not empty sets.
|
||||||
@Getter @Setter @ExcludeFromReplies private Set<String> announcements = new HashSet<>();
|
@Getter @Setter @ExcludeFromReplies private Set<String> announcements = new HashSet<>();
|
||||||
@Getter @Setter @ExcludeFromReplies private Map<String, List<String>> permissions = new HashMap<>();
|
@Getter @Setter @ExcludeFromReplies private Map<String, List<String>> permissions = new HashMap<>();
|
||||||
|
|
||||||
public static ServerGroup byId(String id) {
|
public static List<ServerGroup> findAll() {
|
||||||
updateCacheIfNeeded();
|
|
||||||
return serverGroupCache.get(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<ServerGroup> values() {
|
|
||||||
updateCacheIfNeeded();
|
updateCacheIfNeeded();
|
||||||
return serverGroupAltCache;
|
return serverGroupAltCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ServerGroup findById(String id) {
|
||||||
|
updateCacheIfNeeded();
|
||||||
|
return serverGroupCache.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
public ServerGroup() {} // For Morphia
|
public ServerGroup() {} // For Morphia
|
||||||
|
|
||||||
public ServerGroup(String id, String image, boolean isPublic) {
|
public ServerGroup(String id, String image, boolean isPublic) {
|
||||||
@ -51,16 +58,12 @@ public final class ServerGroup {
|
|||||||
return PermissionUtils.mergeUpTo(permissions, userRank);
|
return PermissionUtils.mergeUpTo(permissions, userRank);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void delete() {
|
|
||||||
APIv3.getDatastore().delete(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void updateCacheIfNeeded() {
|
private static void updateCacheIfNeeded() {
|
||||||
if (serverGroupCache == null || (System.currentTimeMillis() - serverGroupCacheUpdated) > TimeUnit.MINUTES.toMillis(1)) {
|
if (serverGroupCache == null || (System.currentTimeMillis() - serverGroupCacheUpdated) > TimeUnit.MINUTES.toMillis(1)) {
|
||||||
Map<String, ServerGroup> working = new HashMap<>();
|
Map<String, ServerGroup> working = new HashMap<>();
|
||||||
List<ServerGroup> workingAlt = new ArrayList<>();
|
List<ServerGroup> workingAlt = new ArrayList<>();
|
||||||
|
|
||||||
for (ServerGroup serverGroup : APIv3.getDatastore().createQuery(ServerGroup.class).asList()) {
|
for (ServerGroup serverGroup : SyncUtils.blockMulti(serverGroupsCollection.find())) {
|
||||||
working.put(serverGroup.getId(), serverGroup);
|
working.put(serverGroup.getId(), serverGroup);
|
||||||
workingAlt.add(serverGroup);
|
workingAlt.add(serverGroup);
|
||||||
}
|
}
|
||||||
@ -71,4 +74,22 @@ public final class ServerGroup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void insert() {
|
||||||
|
BlockingCallback<Void> callback = new BlockingCallback<>();
|
||||||
|
serverGroupsCollection.insertOne(this, callback);
|
||||||
|
callback.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save() {
|
||||||
|
BlockingCallback<UpdateResult> callback = new BlockingCallback<>();
|
||||||
|
serverGroupsCollection.replaceOne(new Document("_id", id), this, callback);
|
||||||
|
callback.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete() {
|
||||||
|
BlockingCallback<DeleteResult> callback = new BlockingCallback<>();
|
||||||
|
serverGroupsCollection.deleteOne(new Document("_id", id), callback);
|
||||||
|
callback.get();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -4,30 +4,35 @@ import com.google.common.base.Charsets;
|
|||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.hash.Hashing;
|
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.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import net.frozenorb.apiv3.APIv3;
|
import net.frozenorb.apiv3.APIv3;
|
||||||
import net.frozenorb.apiv3.serialization.ExcludeFromReplies;
|
import net.frozenorb.apiv3.serialization.ExcludeFromReplies;
|
||||||
|
import net.frozenorb.apiv3.unsorted.BlockingCallback;
|
||||||
import net.frozenorb.apiv3.utils.MojangUtils;
|
import net.frozenorb.apiv3.utils.MojangUtils;
|
||||||
import net.frozenorb.apiv3.utils.PermissionUtils;
|
import net.frozenorb.apiv3.utils.PermissionUtils;
|
||||||
|
import net.frozenorb.apiv3.utils.SyncUtils;
|
||||||
import net.frozenorb.apiv3.utils.UUIDUtils;
|
import net.frozenorb.apiv3.utils.UUIDUtils;
|
||||||
import org.bson.Document;
|
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.*;
|
import java.util.*;
|
||||||
|
|
||||||
@Entity(value = "users", noClassnameStored = true)
|
@Entity
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public final class User {
|
public final class User {
|
||||||
|
|
||||||
|
private static final MongoCollection<User> usersCollection = APIv3.getDatabase().getCollection("users", User.class);
|
||||||
|
|
||||||
@Getter @Id private UUID id;
|
@Getter @Id private UUID id;
|
||||||
@Getter @Indexed private String lastUsername;
|
@Getter private String lastUsername;
|
||||||
@Getter @ExcludeFromReplies private Map<String, Date> aliases = new HashMap<>();
|
@Getter @ExcludeFromReplies private Map<String, Date> aliases = new HashMap<>();
|
||||||
@Getter @Setter @ExcludeFromReplies private String totpSecret;
|
@Getter @ExcludeFromReplies @Setter private String totpSecret;
|
||||||
@Getter @Indexed @ExcludeFromReplies @Setter private String emailToken;
|
@Getter @ExcludeFromReplies @Setter private String emailToken;
|
||||||
@Getter @ExcludeFromReplies @Setter private Date emailTokenSetAt;
|
@Getter @ExcludeFromReplies @Setter private Date emailTokenSetAt;
|
||||||
@Getter @ExcludeFromReplies private String password;
|
@Getter @ExcludeFromReplies private String password;
|
||||||
@Getter @Setter private String email;
|
@Getter @Setter private String email;
|
||||||
@ -37,48 +42,36 @@ public final class User {
|
|||||||
@Getter private Date firstSeenAt;
|
@Getter private Date firstSeenAt;
|
||||||
@Getter private boolean online;
|
@Getter private boolean online;
|
||||||
|
|
||||||
public static User byId(String id) {
|
public static List<User> findAll() {
|
||||||
try {
|
return SyncUtils.blockMulti(usersCollection.find());
|
||||||
return byId(UUID.fromString(id));
|
|
||||||
} catch (Exception ex) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)) {
|
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 {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Map<UUID, User> byIdGrouped(Iterable<UUID> ids) {
|
public static User findByEmailToken(String emailToken) {
|
||||||
Map<UUID, User> result = new HashMap<>();
|
return SyncUtils.blockOne(usersCollection.find(new Document("emailToken", emailToken)));
|
||||||
Set<UUID> 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 byEmailToken(String name) {
|
public static User findByLastUsername(String lastUsername) {
|
||||||
return APIv3.getDatastore().createQuery(User.class).field("emailToken").equal(name).get();
|
return SyncUtils.blockOne(usersCollection.find(new Document("lastUsername", lastUsername)));
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public static User byLastUsername(String lastUsername) {
|
|
||||||
return APIv3.getDatastore().createQuery(User.class).field("lastUsername").equal(lastUsername).get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public User() {} // For Morphia
|
public User() {} // For Morphia
|
||||||
@ -98,18 +91,8 @@ public final class User {
|
|||||||
updateUsername(lastUsername);
|
updateUsername(lastUsername);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasPermissionScoped(String permission, ServerGroup scope) {
|
|
||||||
Rank highestRank = getHighestRank(scope);
|
|
||||||
Map<String, Boolean> scopedPermissions = PermissionUtils.mergePermissions(
|
|
||||||
PermissionUtils.getDefaultPermissions(highestRank),
|
|
||||||
scope.calculatePermissions(highestRank)
|
|
||||||
);
|
|
||||||
|
|
||||||
return scopedPermissions.containsKey(permission) && scopedPermissions.get(permission);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasPermissionAnywhere(String permission) {
|
public boolean hasPermissionAnywhere(String permission) {
|
||||||
Map<String, Boolean> globalPermissions = PermissionUtils.getDefaultPermissions(getHighestRank());
|
Map<String, Boolean> globalPermissions = PermissionUtils.getDefaultPermissions(getHighestRankAnywhere());
|
||||||
|
|
||||||
for (Map.Entry<ServerGroup, Rank> serverGroupEntry : getHighestRanks().entrySet()) {
|
for (Map.Entry<ServerGroup, Rank> serverGroupEntry : getHighestRanks().entrySet()) {
|
||||||
ServerGroup serverGroup = serverGroupEntry.getKey();
|
ServerGroup serverGroup = serverGroupEntry.getKey();
|
||||||
@ -124,48 +107,7 @@ public final class User {
|
|||||||
return globalPermissions.containsKey(permission) && globalPermissions.get(permission);
|
return globalPermissions.containsKey(permission) && globalPermissions.get(permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Grant> getGrants() {
|
// TODO: Clean
|
||||||
return APIv3.getDatastore().createQuery(Grant.class).field("user").equal(id).asList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<IPLogEntry> 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<Punishment> getPunishments() {
|
|
||||||
return APIv3.getDatastore().createQuery(Punishment.class).field("user").equal(id).asList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Punishment> getPunishments(Iterable<Punishment.PunishmentType> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean seenOnServer(Server server) {
|
public boolean seenOnServer(Server server) {
|
||||||
if (online && server.getId().equals(this.lastSeenOn)) {
|
if (online && server.getId().equals(this.lastSeenOn)) {
|
||||||
return false;
|
return false;
|
||||||
@ -192,14 +134,13 @@ public final class User {
|
|||||||
|
|
||||||
User withNewUsername;
|
User withNewUsername;
|
||||||
|
|
||||||
while ((withNewUsername = User.byLastUsername(username)) != null) {
|
while ((withNewUsername = User.findByLastUsername(username)) != null) {
|
||||||
String newUsername = MojangUtils.getName(withNewUsername.getId());
|
String newUsername = MojangUtils.getName(withNewUsername.getId());
|
||||||
withNewUsername.updateUsername(newUsername);
|
withNewUsername.updateUsername(newUsername);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.aliases.put(username, new Date());
|
this.aliases.put(username, new Date());
|
||||||
APIv3.getDatastore().save(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPassword(String input) {
|
public void setPassword(String input) {
|
||||||
@ -218,16 +159,17 @@ public final class User {
|
|||||||
return hashed.equals(password);
|
return hashed.equals(password);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Rank getHighestRank() {
|
public Rank getHighestRankAnywhere() {
|
||||||
return getHighestRank(null);
|
return getHighestRankScoped(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Rank getHighestRank(ServerGroup serverGroup) {
|
public Rank getHighestRankScoped(ServerGroup serverGroup) {
|
||||||
return getHighestRank(serverGroup, getGrants());
|
return getHighestRankScoped(serverGroup, Grant.findByUser(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Clean
|
||||||
// This is only used to help batch requests to mongo
|
// This is only used to help batch requests to mongo
|
||||||
public Rank getHighestRank(ServerGroup serverGroup, Iterable<Grant> grants) {
|
public Rank getHighestRankScoped(ServerGroup serverGroup, Iterable<Grant> grants) {
|
||||||
Rank highest = null;
|
Rank highest = null;
|
||||||
|
|
||||||
for (Grant grant : grants) {
|
for (Grant grant : grants) {
|
||||||
@ -235,7 +177,7 @@ public final class User {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rank rank = Rank.byId(grant.getRank());
|
Rank rank = Rank.findById(grant.getRank());
|
||||||
|
|
||||||
if (highest == null || rank.getWeight() > highest.getWeight()) {
|
if (highest == null || rank.getWeight() > highest.getWeight()) {
|
||||||
highest = rank;
|
highest = rank;
|
||||||
@ -245,16 +187,17 @@ public final class User {
|
|||||||
if (highest != null) {
|
if (highest != null) {
|
||||||
return highest;
|
return highest;
|
||||||
} else {
|
} else {
|
||||||
return Rank.byId("default");
|
return Rank.findById("default");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Clean
|
||||||
public Map<ServerGroup, Rank> getHighestRanks() {
|
public Map<ServerGroup, Rank> getHighestRanks() {
|
||||||
Map<ServerGroup, Rank> highestRanks = new HashMap<>();
|
Map<ServerGroup, Rank> highestRanks = new HashMap<>();
|
||||||
Rank defaultRank = Rank.byId("default");
|
Rank defaultRank = Rank.findById("default");
|
||||||
List<Grant> userGrants = getGrants();
|
List<Grant> userGrants = Grant.findByUser(this);
|
||||||
|
|
||||||
for (ServerGroup serverGroup : ServerGroup.values()) {
|
for (ServerGroup serverGroup : ServerGroup.findAll()) {
|
||||||
Rank highest = defaultRank;
|
Rank highest = defaultRank;
|
||||||
|
|
||||||
for (Grant grant : userGrants) {
|
for (Grant grant : userGrants) {
|
||||||
@ -262,7 +205,7 @@ public final class User {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rank rank = Rank.byId(grant.getRank());
|
Rank rank = Rank.findById(grant.getRank());
|
||||||
|
|
||||||
if (highest == null || rank.getWeight() > highest.getWeight()) {
|
if (highest == null || rank.getWeight() > highest.getWeight()) {
|
||||||
highest = rank;
|
highest = rank;
|
||||||
@ -276,19 +219,19 @@ public final class User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Object> getLoginInfo(Server server) {
|
public Map<String, Object> getLoginInfo(Server server) {
|
||||||
return getLoginInfo(
|
return createLoginInfo(
|
||||||
server,
|
server,
|
||||||
getPunishments(ImmutableSet.of(
|
Punishment.findByUserAndType(this, ImmutableSet.of(
|
||||||
Punishment.PunishmentType.BLACKLIST,
|
Punishment.PunishmentType.BLACKLIST,
|
||||||
Punishment.PunishmentType.BAN,
|
Punishment.PunishmentType.BAN,
|
||||||
Punishment.PunishmentType.MUTE
|
Punishment.PunishmentType.MUTE
|
||||||
)),
|
)),
|
||||||
getGrants()
|
Grant.findByUser(this)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is only used to help batch requests to mongo
|
// This is only used to help batch requests to mongo
|
||||||
public Map<String, Object> getLoginInfo(Server server, Iterable<Punishment> punishments, Iterable<Grant> grants) {
|
public Map<String, Object> createLoginInfo(Server server, Iterable<Punishment> punishments, Iterable<Grant> grants) {
|
||||||
Punishment activeMute = null;
|
Punishment activeMute = null;
|
||||||
String accessDenialReason = 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.
|
// Generics are weird, yes we have to do this.
|
||||||
ImmutableMap.Builder<String, Object> result = ImmutableMap.<String, Object>builder()
|
ImmutableMap.Builder<String, Object> result = ImmutableMap.<String, Object>builder()
|
||||||
@ -323,4 +266,16 @@ public final class User {
|
|||||||
return result.build();
|
return result.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void insert() {
|
||||||
|
BlockingCallback<Void> callback = new BlockingCallback<>();
|
||||||
|
usersCollection.insertOne(this, callback);
|
||||||
|
callback.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save() {
|
||||||
|
BlockingCallback<UpdateResult> callback = new BlockingCallback<>();
|
||||||
|
usersCollection.replaceOne(new Document("_id", id), this, callback);
|
||||||
|
callback.get();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,25 +1,49 @@
|
|||||||
package net.frozenorb.apiv3.models;
|
package net.frozenorb.apiv3.models;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
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.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import net.frozenorb.apiv3.APIv3;
|
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.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.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@Entity(value = "userMeta", noClassnameStored = true)
|
@Entity
|
||||||
public final class UserMetaEntry {
|
public final class UserMetaEntry {
|
||||||
|
|
||||||
|
private static final MongoCollection<UserMetaEntry> userMetaCollection = APIv3.getDatabase().getCollection("userMeta", UserMetaEntry.class);
|
||||||
|
|
||||||
@Getter @Id private String id;
|
@Getter @Id private String id;
|
||||||
@Getter @Indexed private UUID user;
|
@Getter private UUID user;
|
||||||
@Getter @Indexed private String serverGroup;
|
@Getter private String serverGroup;
|
||||||
@Getter @Setter private Map<String, Object> data;
|
@Getter @Setter private Map<String, Object> data;
|
||||||
|
|
||||||
|
public static List<UserMetaEntry> 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() {} // For Morphia
|
||||||
|
|
||||||
public UserMetaEntry(User user, ServerGroup serverGroup, Map<String, Object> data) {
|
public UserMetaEntry(User user, ServerGroup serverGroup, Map<String, Object> data) {
|
||||||
@ -29,8 +53,22 @@ public final class UserMetaEntry {
|
|||||||
this.data = ImmutableMap.copyOf(data);
|
this.data = ImmutableMap.copyOf(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void insert() {
|
||||||
|
BlockingCallback<Void> callback = new BlockingCallback<>();
|
||||||
|
userMetaCollection.insertOne(this, callback);
|
||||||
|
callback.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save() {
|
||||||
|
BlockingCallback<UpdateResult> callback = new BlockingCallback<>();
|
||||||
|
userMetaCollection.replaceOne(new Document("_id", id), this, callback);
|
||||||
|
callback.get();
|
||||||
|
}
|
||||||
|
|
||||||
public void delete() {
|
public void delete() {
|
||||||
APIv3.getDatastore().delete(this);
|
BlockingCallback<DeleteResult> callback = new BlockingCallback<>();
|
||||||
|
userMetaCollection.deleteOne(new Document("_id", id), callback);
|
||||||
|
callback.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package net.frozenorb.apiv3.routes;
|
package net.frozenorb.apiv3.routes;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import io.vertx.core.Handler;
|
||||||
import io.vertx.ext.web.RoutingContext;
|
import io.vertx.ext.web.RoutingContext;
|
||||||
import net.frozenorb.apiv3.APIv3;
|
import net.frozenorb.apiv3.APIv3;
|
||||||
import net.frozenorb.apiv3.models.Grant;
|
import net.frozenorb.apiv3.models.Grant;
|
||||||
@ -28,7 +29,8 @@ public final class GETDump implements Handler<RoutingContext> {
|
|||||||
List<UUID> banCache = new ArrayList<>();
|
List<UUID> banCache = new ArrayList<>();
|
||||||
List<UUID> blacklistCache = new ArrayList<>();
|
List<UUID> blacklistCache = new ArrayList<>();
|
||||||
|
|
||||||
APIv3.getDatastore().createQuery(Punishment.class).field("type").in(ImmutableSet.of(
|
Punishment.findByType
|
||||||
|
(ImmutableSet.of(
|
||||||
Punishment.PunishmentType.BAN,
|
Punishment.PunishmentType.BAN,
|
||||||
Punishment.PunishmentType.BLACKLIST
|
Punishment.PunishmentType.BLACKLIST
|
||||||
)).forEach((punishment) -> {
|
)).forEach((punishment) -> {
|
||||||
@ -50,7 +52,7 @@ public final class GETDump implements Handler<RoutingContext> {
|
|||||||
if (tick == 0 || tick % 2 == 0) {
|
if (tick == 0 || tick % 2 == 0) {
|
||||||
Map<String, List<UUID>> grantCache = new HashMap<>();
|
Map<String, List<UUID>> grantCache = new HashMap<>();
|
||||||
|
|
||||||
APIv3.getDatastore().createQuery(Grant.class).forEach((grant) -> {
|
Grant.findAll().forEach((grant) -> {
|
||||||
if (grant.isActive()) {
|
if (grant.isActive()) {
|
||||||
List<UUID> users = grantCache.get(grant.getRank());
|
List<UUID> users = grantCache.get(grant.getRank());
|
||||||
|
|
||||||
@ -88,21 +90,25 @@ public final class GETDump implements Handler<RoutingContext> {
|
|||||||
|
|
||||||
switch (type.toLowerCase()) {
|
switch (type.toLowerCase()) {
|
||||||
case "ban":
|
case "ban":
|
||||||
return banCache;
|
APIv3.respondJson(ctx, banCache);
|
||||||
|
return;
|
||||||
case "blacklist":
|
case "blacklist":
|
||||||
return blacklistCache;
|
APIv3.respondJson(ctx, blacklistCache);
|
||||||
|
return;
|
||||||
case "accessdeniable": // Lowercase d because we convert to lowercase above
|
case "accessdeniable": // Lowercase d because we convert to lowercase above
|
||||||
List<UUID> result = new ArrayList<>();
|
List<UUID> result = new ArrayList<>();
|
||||||
|
|
||||||
result.addAll(banCache);
|
result.addAll(banCache);
|
||||||
result.addAll(blacklistCache);
|
result.addAll(blacklistCache);
|
||||||
|
|
||||||
return result;
|
APIv3.respondJson(ctx, result);
|
||||||
|
return;
|
||||||
case "grant":
|
case "grant":
|
||||||
return grantCache;
|
APIv3.respondJson(ctx, grantCache);
|
||||||
|
return;
|
||||||
default:
|
default:
|
||||||
ErrorUtils.respondInvalidInput(ctx, "type", type + " is not a valid type. Not in [ban, blacklist, accessDeniable, grant]");
|
ErrorUtils.respondInvalidInput(ctx, type + " is not a valid type. Not in [ban, blacklist, accessDeniable, grant]");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package net.frozenorb.apiv3.routes;
|
package net.frozenorb.apiv3.routes;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
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;
|
import net.frozenorb.apiv3.actors.Actor;
|
||||||
|
|
||||||
public final class GETWhoAmI implements Handler<RoutingContext> {
|
public final class GETWhoAmI implements Handler<RoutingContext> {
|
||||||
@ -8,11 +11,11 @@ public final class GETWhoAmI implements Handler<RoutingContext> {
|
|||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
Actor actor = ctx.get("actor");
|
Actor actor = ctx.get("actor");
|
||||||
|
|
||||||
return ImmutableMap.of(
|
APIv3.respondJson(ctx, ImmutableMap.of(
|
||||||
"name", actor.getName(),
|
"name", actor.getName(),
|
||||||
"type", actor.getType(),
|
"type", actor.getType(),
|
||||||
"authorized", actor.isAuthorized()
|
"authorized", actor.isAuthorized()
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -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<RoutingContext> {
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,13 +1,14 @@
|
|||||||
package net.frozenorb.apiv3.routes;
|
package net.frozenorb.apiv3.routes;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
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<RoutingContext> {
|
public final class POSTMetrics implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
//LibratoBatch batch = new LibratoBatch();
|
APIv3.respondJson(ctx, ImmutableMap.of());
|
||||||
|
|
||||||
return ImmutableMap.of();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -21,9 +21,9 @@ public final class GETAnnouncements implements Handler<RoutingContext> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Server sender = ((ServerActor) actor).getServer();
|
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());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -13,7 +13,7 @@ public final class GETAuditLog implements Handler<RoutingContext> {
|
|||||||
int limit = ctx.request().getParam("limit") == null ? 100 : Integer.parseInt(ctx.request().getParam("limit"));
|
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"));
|
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) {
|
} catch (NumberFormatException ex) {
|
||||||
ErrorUtils.respondInvalidInput(ctx, "limit/offset must be numerical inputs.");
|
ErrorUtils.respondInvalidInput(ctx, "limit/offset must be numerical inputs.");
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package net.frozenorb.apiv3.routes.chatFilterList;
|
package net.frozenorb.apiv3.routes.chatFilterList;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.ImmutableSet;
|
|
||||||
import io.vertx.core.Handler;
|
import io.vertx.core.Handler;
|
||||||
import io.vertx.ext.web.RoutingContext;
|
import io.vertx.ext.web.RoutingContext;
|
||||||
import net.frozenorb.apiv3.APIv3;
|
import net.frozenorb.apiv3.APIv3;
|
||||||
@ -9,7 +8,7 @@ import net.frozenorb.apiv3.APIv3;
|
|||||||
public final class GETChatFilterList implements Handler<RoutingContext> {
|
public final class GETChatFilterList implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
APIv3.respond(ctx, ImmutableMap.of());
|
APIv3.respondJson(ctx, ImmutableMap.of());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -13,7 +13,7 @@ import net.frozenorb.apiv3.utils.ErrorUtils;
|
|||||||
public final class DELETEGrant implements Handler<RoutingContext> {
|
public final class DELETEGrant implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
Grant grant = Grant.byId(ctx.request().getParam("id"));
|
Grant grant = Grant.findById(ctx.request().getParam("id"));
|
||||||
|
|
||||||
if (grant == null) {
|
if (grant == null) {
|
||||||
ErrorUtils.respondNotFound(ctx, "Grant", ctx.request().getParam("id"));
|
ErrorUtils.respondNotFound(ctx, "Grant", ctx.request().getParam("id"));
|
||||||
@ -23,7 +23,7 @@ public final class DELETEGrant implements Handler<RoutingContext> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
User removedBy = User.byId(ctx.request().getParam("removedBy"));
|
User removedBy = User.findById(ctx.request().getParam("removedBy"));
|
||||||
|
|
||||||
if (removedBy == null) {
|
if (removedBy == null) {
|
||||||
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("removedBy"));
|
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("removedBy"));
|
||||||
@ -39,7 +39,7 @@ public final class DELETEGrant implements Handler<RoutingContext> {
|
|||||||
|
|
||||||
grant.delete(removedBy, reason);
|
grant.delete(removedBy, reason);
|
||||||
AuditLog.log(removedBy, "", ctx.get("actor"), AuditLogActionType.DELETE_GRANT, ImmutableMap.of());
|
AuditLog.log(removedBy, "", ctx.get("actor"), AuditLogActionType.DELETE_GRANT, ImmutableMap.of());
|
||||||
APIv3.respond(ctx, grant);
|
APIv3.respondJson(ctx, grant);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -8,7 +8,7 @@ import net.frozenorb.apiv3.models.Grant;
|
|||||||
public final class GETGrant implements Handler<RoutingContext> {
|
public final class GETGrant implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
APIv3.respond(ctx, Grant.byId(ctx.request().getParam("id")));
|
APIv3.respondJson(ctx, Grant.findById(ctx.request().getParam("id")));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -13,7 +13,7 @@ public final class GETGrants implements Handler<RoutingContext> {
|
|||||||
int limit = ctx.request().getParam("limit") == null ? 100 : Integer.parseInt(ctx.request().getParam("limit"));
|
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"));
|
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) {
|
} catch (NumberFormatException ex) {
|
||||||
ErrorUtils.respondInvalidInput(ctx, "limit and offset must be numerical inputs.");
|
ErrorUtils.respondInvalidInput(ctx, "limit and offset must be numerical inputs.");
|
||||||
}
|
}
|
||||||
|
@ -3,20 +3,21 @@ package net.frozenorb.apiv3.routes.grants;
|
|||||||
import io.vertx.core.Handler;
|
import io.vertx.core.Handler;
|
||||||
import io.vertx.ext.web.RoutingContext;
|
import io.vertx.ext.web.RoutingContext;
|
||||||
import net.frozenorb.apiv3.APIv3;
|
import net.frozenorb.apiv3.APIv3;
|
||||||
|
import net.frozenorb.apiv3.models.Grant;
|
||||||
import net.frozenorb.apiv3.models.User;
|
import net.frozenorb.apiv3.models.User;
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
|
|
||||||
public final class GETUserGrants implements Handler<RoutingContext> {
|
public final class GETUserGrants implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
User target = User.byId(ctx.request().getParam("id"));
|
User target = User.findById(ctx.request().getParam("id"));
|
||||||
|
|
||||||
if (target == null) {
|
if (target == null) {
|
||||||
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
APIv3.respond(ctx, target.getGrants());
|
APIv3.respondJson(ctx, Grant.findByUser(target));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,5 +1,7 @@
|
|||||||
package net.frozenorb.apiv3.routes.grants;
|
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.APIv3;
|
||||||
import net.frozenorb.apiv3.models.Grant;
|
import net.frozenorb.apiv3.models.Grant;
|
||||||
import net.frozenorb.apiv3.models.Rank;
|
import net.frozenorb.apiv3.models.Rank;
|
||||||
@ -14,16 +16,18 @@ import java.util.Set;
|
|||||||
public final class POSTUserGrant implements Handler<RoutingContext> {
|
public final class POSTUserGrant implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
User target = User.byId(ctx.request().getParam("id"));
|
User target = User.findById(ctx.request().getParam("id"));
|
||||||
|
|
||||||
if (target == null) {
|
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");
|
String reason = ctx.request().getParam("reason");
|
||||||
|
|
||||||
if (reason == null || reason.trim().isEmpty()) {
|
if (reason == null || reason.trim().isEmpty()) {
|
||||||
return ErrorUtils.respondRequiredInput("reason");
|
ErrorUtils.respondRequiredInput(ctx, "reason");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<ServerGroup> scopes = new HashSet<>();
|
Set<ServerGroup> scopes = new HashSet<>();
|
||||||
@ -31,20 +35,22 @@ public final class POSTUserGrant implements Handler<RoutingContext> {
|
|||||||
|
|
||||||
if (!scopesUnparsed.isEmpty()) {
|
if (!scopesUnparsed.isEmpty()) {
|
||||||
for (String serverGroupId : scopesUnparsed.split(",")) {
|
for (String serverGroupId : scopesUnparsed.split(",")) {
|
||||||
ServerGroup serverGroup = ServerGroup.byId(serverGroupId);
|
ServerGroup serverGroup = ServerGroup.findById(serverGroupId);
|
||||||
|
|
||||||
if (serverGroup == null) {
|
if (serverGroup == null) {
|
||||||
return ErrorUtils.respondNotFound("Server group", serverGroupId);
|
ErrorUtils.respondNotFound(ctx, "Server group", serverGroupId);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
scopes.add(serverGroup);
|
scopes.add(serverGroup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rank rank = Rank.byId(ctx.request().getParam("rank"));
|
Rank rank = Rank.findById(ctx.request().getParam("rank"));
|
||||||
|
|
||||||
if (rank == null) {
|
if (rank == null) {
|
||||||
return ErrorUtils.respondNotFound("Rank", ctx.request().getParam("rank"));
|
ErrorUtils.respondNotFound(ctx, "Rank", ctx.request().getParam("rank"));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Date expiresAt;
|
Date expiresAt;
|
||||||
@ -56,15 +62,16 @@ public final class POSTUserGrant implements Handler<RoutingContext> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (expiresAt != null && expiresAt.before(new Date())) {
|
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.
|
// 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);
|
Grant grant = new Grant(target, reason, scopes, rank, expiresAt, addedBy);
|
||||||
APIv3.getDatastore().save(grant);
|
grant.insert();
|
||||||
return grant;
|
APIv3.respondJson(ctx, grant);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -3,20 +3,21 @@ package net.frozenorb.apiv3.routes.ipLog;
|
|||||||
import io.vertx.core.Handler;
|
import io.vertx.core.Handler;
|
||||||
import io.vertx.ext.web.RoutingContext;
|
import io.vertx.ext.web.RoutingContext;
|
||||||
import net.frozenorb.apiv3.APIv3;
|
import net.frozenorb.apiv3.APIv3;
|
||||||
|
import net.frozenorb.apiv3.models.IPLogEntry;
|
||||||
import net.frozenorb.apiv3.models.User;
|
import net.frozenorb.apiv3.models.User;
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
|
|
||||||
public final class GETUserIPLog implements Handler<RoutingContext> {
|
public final class GETUserIPLog implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
User target = User.byId(ctx.request().getParam("id"));
|
User target = User.findById(ctx.request().getParam("id"));
|
||||||
|
|
||||||
if (target == null) {
|
if (target == null) {
|
||||||
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
APIv3.respond(ctx, target.getIPLog());
|
APIv3.respondJson(ctx, IPLogEntry.findByUser(target));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -9,7 +9,7 @@ import net.frozenorb.apiv3.utils.ErrorUtils;
|
|||||||
public final class DELETENotificationTemplate implements Handler<RoutingContext> {
|
public final class DELETENotificationTemplate implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
NotificationTemplate notificationTemplate = NotificationTemplate.byId(ctx.request().getParam("id"));
|
NotificationTemplate notificationTemplate = NotificationTemplate.findById(ctx.request().getParam("id"));
|
||||||
|
|
||||||
if (notificationTemplate == null) {
|
if (notificationTemplate == null) {
|
||||||
ErrorUtils.respondNotFound(ctx, "Notification template", ctx.request().getParam("id"));
|
ErrorUtils.respondNotFound(ctx, "Notification template", ctx.request().getParam("id"));
|
||||||
@ -17,7 +17,7 @@ public final class DELETENotificationTemplate implements Handler<RoutingContext>
|
|||||||
}
|
}
|
||||||
|
|
||||||
notificationTemplate.delete();
|
notificationTemplate.delete();
|
||||||
APIv3.respond(ctx, notificationTemplate);
|
APIv3.respondJson(ctx, notificationTemplate);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -8,7 +8,7 @@ import net.frozenorb.apiv3.models.NotificationTemplate;
|
|||||||
public final class GETNotificationTemplate implements Handler<RoutingContext> {
|
public final class GETNotificationTemplate implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
APIv3.respond(ctx, NotificationTemplate.byId(ctx.request().getParam("id")));
|
APIv3.respondJson(ctx, NotificationTemplate.findById(ctx.request().getParam("id")));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -8,7 +8,7 @@ import net.frozenorb.apiv3.models.NotificationTemplate;
|
|||||||
public final class GETNotificationTemplates implements Handler<RoutingContext> {
|
public final class GETNotificationTemplates implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
APIv3.respond(ctx, NotificationTemplate.values());
|
APIv3.respondJson(ctx, NotificationTemplate.findAll());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -13,8 +13,8 @@ public final class POSTNotificationTemplate implements Handler<RoutingContext> {
|
|||||||
String body = ctx.request().getParam("body");
|
String body = ctx.request().getParam("body");
|
||||||
|
|
||||||
NotificationTemplate notificationTemplate = new NotificationTemplate(id, subject, body);
|
NotificationTemplate notificationTemplate = new NotificationTemplate(id, subject, body);
|
||||||
APIv3.getDatastore().save(notificationTemplate);
|
notificationTemplate.insert();
|
||||||
APIv3.respond(ctx, notificationTemplate);
|
APIv3.respondJson(ctx, notificationTemplate);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,6 +1,9 @@
|
|||||||
package net.frozenorb.apiv3.routes.punishments;
|
package net.frozenorb.apiv3.routes.punishments;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
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.AuditLog;
|
||||||
import net.frozenorb.apiv3.auditLog.AuditLogActionType;
|
import net.frozenorb.apiv3.auditLog.AuditLogActionType;
|
||||||
import net.frozenorb.apiv3.models.Punishment;
|
import net.frozenorb.apiv3.models.Punishment;
|
||||||
@ -10,29 +13,33 @@ import net.frozenorb.apiv3.utils.ErrorUtils;
|
|||||||
public final class DELETEPunishment implements Handler<RoutingContext> {
|
public final class DELETEPunishment implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
Punishment punishment = Punishment.byId(ctx.request().getParam("id"));
|
Punishment punishment = Punishment.findById(ctx.request().getParam("id"));
|
||||||
|
|
||||||
if (punishment == null) {
|
if (punishment == null) {
|
||||||
return ErrorUtils.respondNotFound("Punishment", ctx.request().getParam("id"));
|
ErrorUtils.respondNotFound(ctx, "Punishment", ctx.request().getParam("id"));
|
||||||
|
return;
|
||||||
} else if (!punishment.isActive()) {
|
} 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) {
|
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");
|
String reason = ctx.request().getParam("reason");
|
||||||
|
|
||||||
if (reason == null || reason.trim().isEmpty()) {
|
if (reason == null || reason.trim().isEmpty()) {
|
||||||
return ErrorUtils.respondRequiredInput("reason");
|
ErrorUtils.respondRequiredInput(ctx, "reason");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
punishment.delete(removedBy, reason);
|
punishment.delete(removedBy, reason);
|
||||||
AuditLog.log(removedBy, "", ctx.get("actor"), AuditLogActionType.DELETE_PUNISHMENT, ImmutableMap.of());
|
AuditLog.log(removedBy, "", ctx.get("actor"), AuditLogActionType.DELETE_PUNISHMENT, ImmutableMap.of());
|
||||||
return punishment;
|
APIv3.respondJson(ctx, punishment);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,11 +1,14 @@
|
|||||||
package net.frozenorb.apiv3.routes.punishments;
|
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.Punishment;
|
||||||
|
|
||||||
public final class GETPunishment implements Handler<RoutingContext> {
|
public final class GETPunishment implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
return Punishment.byId(ctx.request().getParam("id"));
|
APIv3.respondJson(ctx, Punishment.findById(ctx.request().getParam("id")));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,5 +1,7 @@
|
|||||||
package net.frozenorb.apiv3.routes.punishments;
|
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.APIv3;
|
||||||
import net.frozenorb.apiv3.models.Punishment;
|
import net.frozenorb.apiv3.models.Punishment;
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
@ -11,9 +13,9 @@ public final class GETPunishments implements Handler<RoutingContext> {
|
|||||||
int limit = ctx.request().getParam("limit") == null ? 100 : Integer.parseInt(ctx.request().getParam("limit"));
|
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"));
|
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) {
|
} catch (NumberFormatException ex) {
|
||||||
return ErrorUtils.respondInvalidInput("limit and offset must be numerical inputs.");
|
ErrorUtils.respondInvalidInput(ctx, "limit and offset must be numerical inputs.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,18 +1,23 @@
|
|||||||
package net.frozenorb.apiv3.routes.punishments;
|
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.models.User;
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
|
|
||||||
public final class GETUserPunishments implements Handler<RoutingContext> {
|
public final class GETUserPunishments implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
User target = User.byId(ctx.request().getParam("id"));
|
User target = User.findById(ctx.request().getParam("id"));
|
||||||
|
|
||||||
if (target == null) {
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -2,6 +2,8 @@ package net.frozenorb.apiv3.routes.punishments;
|
|||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.ImmutableSet;
|
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.APIv3;
|
||||||
import net.frozenorb.apiv3.models.Punishment;
|
import net.frozenorb.apiv3.models.Punishment;
|
||||||
import net.frozenorb.apiv3.models.User;
|
import net.frozenorb.apiv3.models.User;
|
||||||
@ -15,24 +17,27 @@ import java.util.Map;
|
|||||||
public final class POSTUserPunish implements Handler<RoutingContext> {
|
public final class POSTUserPunish implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
User target = User.byId(ctx.request().getParam("id"));
|
User target = User.findById(ctx.request().getParam("id"));
|
||||||
|
|
||||||
if (target == null) {
|
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");
|
String reason = ctx.request().getParam("reason");
|
||||||
|
|
||||||
if (reason == null || reason.trim().isEmpty()) {
|
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"));
|
Punishment.PunishmentType type = Punishment.PunishmentType.valueOf(ctx.request().getParam("type"));
|
||||||
|
|
||||||
if (type != Punishment.PunishmentType.WARN) {
|
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()) {
|
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<RoutingContext> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (expiresAt != null && expiresAt.before(new Date())) {
|
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<String, Object> meta = Document.parse(req.body());
|
Map<String, Object> meta = Document.parse(ctx.getBodyAsString());
|
||||||
|
|
||||||
if (meta == null) {
|
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.
|
// 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)) {
|
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);
|
Punishment punishment = new Punishment(target, reason, type, expiresAt, addedBy, ctx.get("actor"), meta);
|
||||||
String accessDenialReason = punishment.getAccessDenialReason();
|
String accessDenialReason = punishment.getAccessDenialReason();
|
||||||
APIv3.getDatastore().save(punishment);
|
punishment.insert();
|
||||||
|
|
||||||
return ImmutableMap.of(
|
APIv3.respondJson(ctx, ImmutableMap.of(
|
||||||
"punishment", punishment,
|
"punishment", punishment,
|
||||||
"accessDenialReason", accessDenialReason == null ? "" : accessDenialReason
|
"accessDenialReason", accessDenialReason == null ? "" : accessDenialReason
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,19 +1,23 @@
|
|||||||
package net.frozenorb.apiv3.routes.ranks;
|
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.models.Rank;
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
|
|
||||||
public final class DELETERank implements Handler<RoutingContext> {
|
public final class DELETERank implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
Rank rank = Rank.byId(ctx.request().getParam("id"));
|
Rank rank = Rank.findById(ctx.request().getParam("id"));
|
||||||
|
|
||||||
if (rank == null) {
|
if (rank == null) {
|
||||||
return ErrorUtils.respondNotFound("Rank", ctx.request().getParam("id"));
|
ErrorUtils.respondNotFound(ctx, "Rank", ctx.request().getParam("id"));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
rank.delete();
|
rank.delete();
|
||||||
return rank;
|
APIv3.respondJson(ctx, rank);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,11 +1,14 @@
|
|||||||
package net.frozenorb.apiv3.routes.ranks;
|
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.models.Rank;
|
||||||
|
|
||||||
public final class GETRank implements Handler<RoutingContext> {
|
public final class GETRank implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
return Rank.byId(ctx.request().getParam("id"));
|
APIv3.respondJson(ctx, Rank.findById(ctx.request().getParam("id")));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,11 +1,14 @@
|
|||||||
package net.frozenorb.apiv3.routes.ranks;
|
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.models.Rank;
|
||||||
|
|
||||||
public final class GETRanks implements Handler<RoutingContext> {
|
public final class GETRanks implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
return Rank.values();
|
APIv3.respondJson(ctx, Rank.findAll());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,5 +1,7 @@
|
|||||||
package net.frozenorb.apiv3.routes.ranks;
|
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.APIv3;
|
||||||
import net.frozenorb.apiv3.models.Rank;
|
import net.frozenorb.apiv3.models.Rank;
|
||||||
|
|
||||||
@ -14,8 +16,8 @@ public final class POSTRank implements Handler<RoutingContext> {
|
|||||||
boolean staffRank = Boolean.parseBoolean(ctx.request().getParam("staffRank"));
|
boolean staffRank = Boolean.parseBoolean(ctx.request().getParam("staffRank"));
|
||||||
|
|
||||||
Rank rank = new Rank(id, weight, displayName, gameColor, websiteColor, staffRank);
|
Rank rank = new Rank(id, weight, displayName, gameColor, websiteColor, staffRank);
|
||||||
APIv3.getDatastore().save(rank);
|
rank.insert();
|
||||||
return rank;
|
APIv3.respondJson(ctx, rank);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,19 +1,23 @@
|
|||||||
package net.frozenorb.apiv3.routes.serverGroups;
|
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.models.ServerGroup;
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
|
|
||||||
public final class DELETEServerGroup implements Handler<RoutingContext> {
|
public final class DELETEServerGroup implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
ServerGroup serverGroup = ServerGroup.byId(ctx.request().getParam("id"));
|
ServerGroup serverGroup = ServerGroup.findById(ctx.request().getParam("id"));
|
||||||
|
|
||||||
if (serverGroup == null) {
|
if (serverGroup == null) {
|
||||||
return ErrorUtils.respondNotFound("Server group", ctx.request().getParam("id"));
|
ErrorUtils.respondNotFound(ctx, "Server group", ctx.request().getParam("id"));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
serverGroup.delete();
|
serverGroup.delete();
|
||||||
return serverGroup;
|
APIv3.respondJson(ctx, serverGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,11 +1,14 @@
|
|||||||
package net.frozenorb.apiv3.routes.serverGroups;
|
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.models.ServerGroup;
|
||||||
|
|
||||||
public final class GETServerGroup implements Handler<RoutingContext> {
|
public final class GETServerGroup implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
return ServerGroup.byId(ctx.request().getParam("id"));
|
APIv3.respondJson(ctx, ServerGroup.findById(ctx.request().getParam("id")));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,11 +1,14 @@
|
|||||||
package net.frozenorb.apiv3.routes.serverGroups;
|
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.models.ServerGroup;
|
||||||
|
|
||||||
public final class GETServerGroups implements Handler<RoutingContext> {
|
public final class GETServerGroups implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
return ServerGroup.values();
|
APIv3.respondJson(ctx, ServerGroup.findAll());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,5 +1,7 @@
|
|||||||
package net.frozenorb.apiv3.routes.serverGroups;
|
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.APIv3;
|
||||||
import net.frozenorb.apiv3.models.ServerGroup;
|
import net.frozenorb.apiv3.models.ServerGroup;
|
||||||
|
|
||||||
@ -11,8 +13,8 @@ public final class POSTServerGroup implements Handler<RoutingContext> {
|
|||||||
boolean isPublic = Boolean.valueOf(ctx.request().getParam("public"));
|
boolean isPublic = Boolean.valueOf(ctx.request().getParam("public"));
|
||||||
|
|
||||||
ServerGroup serverGroup = new ServerGroup(id, image, isPublic);
|
ServerGroup serverGroup = new ServerGroup(id, image, isPublic);
|
||||||
APIv3.getDatastore().save(serverGroup);
|
serverGroup.insert();
|
||||||
return serverGroup;
|
APIv3.respondJson(ctx, serverGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,19 +1,23 @@
|
|||||||
package net.frozenorb.apiv3.routes.servers;
|
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.Server;
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
|
|
||||||
public final class DELETEServer implements Handler<RoutingContext> {
|
public final class DELETEServer implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
Server server = Server.byId(ctx.request().getParam("id"));
|
Server server = Server.findById(ctx.request().getParam("id"));
|
||||||
|
|
||||||
if (server == null) {
|
if (server == null) {
|
||||||
return ErrorUtils.respondNotFound("Server", ctx.request().getParam("id"));
|
ErrorUtils.respondNotFound(ctx, "Server", ctx.request().getParam("id"));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
server.delete();
|
server.delete();
|
||||||
return server;
|
APIv3.respondJson(ctx, server);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,11 +1,14 @@
|
|||||||
package net.frozenorb.apiv3.routes.servers;
|
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.Server;
|
||||||
|
|
||||||
public final class GETServer implements Handler<RoutingContext> {
|
public final class GETServer implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
return Server.byId(ctx.request().getParam("id"));
|
APIv3.respondJson(ctx, Server.findById(ctx.request().getParam("id")));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,11 +1,14 @@
|
|||||||
package net.frozenorb.apiv3.routes.servers;
|
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.Server;
|
||||||
|
|
||||||
public final class GETServers implements Handler<RoutingContext> {
|
public final class GETServers implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
return Server.values();
|
APIv3.respondJson(ctx, Server.findAll());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,5 +1,7 @@
|
|||||||
package net.frozenorb.apiv3.routes.servers;
|
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.APIv3;
|
||||||
import net.frozenorb.apiv3.models.Server;
|
import net.frozenorb.apiv3.models.Server;
|
||||||
import net.frozenorb.apiv3.models.ServerGroup;
|
import net.frozenorb.apiv3.models.ServerGroup;
|
||||||
@ -12,20 +14,22 @@ public final class POSTServer implements Handler<RoutingContext> {
|
|||||||
String id = ctx.request().getParam("id");
|
String id = ctx.request().getParam("id");
|
||||||
String displayName = ctx.request().getParam("displayName");
|
String displayName = ctx.request().getParam("displayName");
|
||||||
String apiKey = ctx.request().getParam("apiKey");
|
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");
|
String ip = ctx.request().getParam("ip");
|
||||||
|
|
||||||
if (group == null) {
|
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)) {
|
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);
|
Server server = new Server(id, displayName, apiKey, group, ip);
|
||||||
APIv3.getDatastore().save(server);
|
server.insert();
|
||||||
return server;
|
APIv3.respondJson(ctx, server);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,6 +1,8 @@
|
|||||||
package net.frozenorb.apiv3.routes.servers;
|
package net.frozenorb.apiv3.routes.servers;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import io.vertx.core.Handler;
|
||||||
|
import io.vertx.ext.web.RoutingContext;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.frozenorb.apiv3.APIv3;
|
import net.frozenorb.apiv3.APIv3;
|
||||||
import net.frozenorb.apiv3.actors.Actor;
|
import net.frozenorb.apiv3.actors.Actor;
|
||||||
@ -21,16 +23,17 @@ public final class POSTServerHeartbeat implements Handler<RoutingContext> {
|
|||||||
Actor actor = ctx.get("actor");
|
Actor actor = ctx.get("actor");
|
||||||
|
|
||||||
if (actor.getType() != ActorType.SERVER) {
|
if (actor.getType() != ActorType.SERVER) {
|
||||||
return ErrorUtils.respondServerOnly();
|
ErrorUtils.respondServerOnly(ctx);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Server actorServer = Server.byId(actor.getName());
|
Server actorServer = Server.byId(actor.getName());
|
||||||
ServerGroup actorServerGroup = ServerGroup.byId(actorServer.getServerGroup());
|
ServerGroup actorServerGroup = ServerGroup.byId(actorServer.getServerGroup());
|
||||||
Document reqJson = Document.parse(req.body());
|
Document reqJson = Document.parse(ctx.getBodyAsString());
|
||||||
Map<UUID, String> onlinePlayersNames = new HashMap<>();
|
Map<UUID, String> onlinePlayersNames = new HashMap<>();
|
||||||
Map<UUID, User> onlinePlayersUsers = new HashMap<>();
|
Map<UUID, User> onlinePlayersUsers;
|
||||||
Map<UUID, List<Grant>> onlinePlayersGrants = new HashMap<>();
|
Map<UUID, List<Grant>> onlinePlayersGrants;
|
||||||
Map<UUID, List<Punishment>> onlinePlayersPunishments = new HashMap<>();
|
Map<UUID, List<Punishment>> onlinePlayersPunishments;
|
||||||
Map<String, Object> playersResponse = new HashMap<>();
|
Map<String, Object> playersResponse = new HashMap<>();
|
||||||
|
|
||||||
// This code is messy, but we have to do db ops in parallel to avoid
|
// 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<RoutingContext> {
|
|||||||
UUID uuid = entry.getKey();
|
UUID uuid = entry.getKey();
|
||||||
User user = entry.getValue();
|
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<Object>) reqJson.get("events")) {
|
for (Object event : (List<Object>) reqJson.get("events")) {
|
||||||
@ -92,7 +95,7 @@ public final class POSTServerHeartbeat implements Handler<RoutingContext> {
|
|||||||
|
|
||||||
Map<String, Map<String, Boolean>> permissionsResponse = new HashMap<>();
|
Map<String, Map<String, Boolean>> permissionsResponse = new HashMap<>();
|
||||||
|
|
||||||
for (Rank rank : Rank.values()) {
|
for (Rank rank : Rank.findAll()) {
|
||||||
Map<String, Boolean> scopedPermissions = PermissionUtils.mergePermissions(
|
Map<String, Boolean> scopedPermissions = PermissionUtils.mergePermissions(
|
||||||
PermissionUtils.getDefaultPermissions(rank),
|
PermissionUtils.getDefaultPermissions(rank),
|
||||||
actorServerGroup.calculatePermissions(rank)
|
actorServerGroup.calculatePermissions(rank)
|
||||||
@ -104,12 +107,12 @@ public final class POSTServerHeartbeat implements Handler<RoutingContext> {
|
|||||||
actorServer.setPlayers(onlinePlayersNames.keySet());
|
actorServer.setPlayers(onlinePlayersNames.keySet());
|
||||||
actorServer.setLastTps(reqJson.getDouble("lastTps"));
|
actorServer.setLastTps(reqJson.getDouble("lastTps"));
|
||||||
actorServer.setLastUpdatedAt(new Date());
|
actorServer.setLastUpdatedAt(new Date());
|
||||||
APIv3.getDatastore().save(actorServer);
|
actorServer.save();
|
||||||
|
|
||||||
return ImmutableMap.of(
|
APIv3.respondJson(ctx, ImmutableMap.of(
|
||||||
"players", playersResponse,
|
"players", playersResponse,
|
||||||
"permissions", permissionsResponse
|
"permissions", permissionsResponse
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,29 +1,39 @@
|
|||||||
package net.frozenorb.apiv3.routes.users;
|
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.ServerGroup;
|
||||||
import net.frozenorb.apiv3.models.User;
|
import net.frozenorb.apiv3.models.User;
|
||||||
import net.frozenorb.apiv3.models.UserMetaEntry;
|
import net.frozenorb.apiv3.models.UserMetaEntry;
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
|
import org.bson.Document;
|
||||||
|
|
||||||
public final class DELETEUserMeta implements Handler<RoutingContext> {
|
public final class DELETEUserMeta implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
User user = User.byId(ctx.request().getParam("id"));
|
User user = User.findById(ctx.request().getParam("id"));
|
||||||
|
|
||||||
if (user == null) {
|
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) {
|
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();
|
if (userMetaEntry != null) {
|
||||||
return userMetaEntry.getData();
|
userMetaEntry.delete();
|
||||||
|
APIv3.respondJson(ctx, userMetaEntry.getData());
|
||||||
|
} else {
|
||||||
|
APIv3.respondJson(ctx, new Document());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -2,6 +2,9 @@ package net.frozenorb.apiv3.routes.users;
|
|||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.ImmutableSet;
|
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.AuditLog;
|
||||||
import net.frozenorb.apiv3.auditLog.AuditLogActionType;
|
import net.frozenorb.apiv3.auditLog.AuditLogActionType;
|
||||||
import net.frozenorb.apiv3.models.Punishment;
|
import net.frozenorb.apiv3.models.Punishment;
|
||||||
@ -11,34 +14,38 @@ import net.frozenorb.apiv3.utils.ErrorUtils;
|
|||||||
public final class DELETEUserPunishment implements Handler<RoutingContext> {
|
public final class DELETEUserPunishment implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
User target = User.byId(ctx.request().getParam("id"));
|
User target = User.findById(ctx.request().getParam("id"));
|
||||||
|
|
||||||
if (target == null) {
|
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());
|
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) {
|
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");
|
String reason = ctx.request().getParam("reason");
|
||||||
|
|
||||||
if (reason == null || reason.trim().isEmpty()) {
|
if (reason == null || reason.trim().isEmpty()) {
|
||||||
return ErrorUtils.respondRequiredInput("reason");
|
ErrorUtils.respondRequiredInput(ctx, "reason");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Punishment punishment : target.getPunishments(ImmutableSet.of(type))) {
|
for (Punishment punishment : target.getPunishments(ImmutableSet.of(type))) {
|
||||||
if (punishment.isActive()) {
|
if (punishment.isActive()) {
|
||||||
punishment.delete(removedBy, reason);
|
punishment.delete(removedBy, reason);
|
||||||
AuditLog.log(removedBy, "", ctx.get("actor"), AuditLogActionType.DELETE_PUNISHMENT, ImmutableMap.of());
|
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,5 +1,7 @@
|
|||||||
package net.frozenorb.apiv3.routes.users;
|
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.APIv3;
|
||||||
import net.frozenorb.apiv3.models.Grant;
|
import net.frozenorb.apiv3.models.Grant;
|
||||||
import net.frozenorb.apiv3.models.Rank;
|
import net.frozenorb.apiv3.models.Rank;
|
||||||
@ -12,22 +14,22 @@ public final class GETStaff implements Handler<RoutingContext> {
|
|||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
Map<String, Rank> staffRanks = new HashMap<>();
|
Map<String, Rank> staffRanks = new HashMap<>();
|
||||||
|
|
||||||
Rank.values().forEach(rank -> {
|
Rank.findAll().forEach(rank -> {
|
||||||
if (rank.isStaffRank()) {
|
if (rank.isStaffRank()) {
|
||||||
staffRanks.put(rank.getId(), rank);
|
staffRanks.put(rank.getId(), rank);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Map<String, Set<User>> result = new TreeMap<>((first, second) -> {
|
Map<String, Set<User>> result = new TreeMap<>((first, second) -> {
|
||||||
Rank firstRank = Rank.byId(first);
|
Rank firstRank = staffRanks.get(first);
|
||||||
Rank secondRank = Rank.byId(second);
|
Rank secondRank = staffRanks.get(second);
|
||||||
|
|
||||||
return Integer.compare(firstRank.getWeight(), secondRank.getWeight());
|
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()) {
|
if (grant.isActive()) {
|
||||||
User user = User.byId(grant.getUser());
|
User user = User.findById(grant.getUser());
|
||||||
Rank rank = staffRanks.get(grant.getRank());
|
Rank rank = staffRanks.get(grant.getRank());
|
||||||
|
|
||||||
if (!result.containsKey(rank.getId())) {
|
if (!result.containsKey(rank.getId())) {
|
||||||
@ -38,7 +40,7 @@ public final class GETStaff implements Handler<RoutingContext> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return result;
|
APIv3.respondJson(ctx, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,11 +1,14 @@
|
|||||||
package net.frozenorb.apiv3.routes.users;
|
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.models.User;
|
||||||
|
|
||||||
public final class GETUser implements Handler<RoutingContext> {
|
public final class GETUser implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
return User.byId(ctx.request().getParam("id"));
|
APIv3.respondJson(ctx, User.findById(ctx.request().getParam("id")));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,27 +1,35 @@
|
|||||||
package net.frozenorb.apiv3.routes.users;
|
package net.frozenorb.apiv3.routes.users;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
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.models.User;
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
|
|
||||||
public final class GETUserDetails implements Handler<RoutingContext> {
|
public final class GETUserDetails implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
User user = User.byId(ctx.request().getParam("id"));
|
User user = User.findById(ctx.request().getParam("id"));
|
||||||
|
|
||||||
if (user == null) {
|
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()
|
// Too many fields to use .of()
|
||||||
return ImmutableMap.builder()
|
APIv3.respondJson(ctx, ImmutableMap.builder()
|
||||||
.put("user", user)
|
.put("user", user)
|
||||||
.put("grants", user.getGrants())
|
.put("grants", Grant.findByUser(user))
|
||||||
.put("ipLog", user.getIPLog())
|
.put("ipLog", IPLogEntry.findByUser(user))
|
||||||
.put("punishments", user.getPunishments())
|
.put("punishments", Punishment.findByUser(user))
|
||||||
.put("aliases", user.getAliases())
|
.put("aliases", user.getAliases())
|
||||||
.put("totpSetup", user.getTotpSecret() != null)
|
.put("totpSetup", user.getTotpSecret() != null)
|
||||||
.build();
|
.build()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,5 +1,8 @@
|
|||||||
package net.frozenorb.apiv3.routes.users;
|
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.ServerGroup;
|
||||||
import net.frozenorb.apiv3.models.User;
|
import net.frozenorb.apiv3.models.User;
|
||||||
import net.frozenorb.apiv3.models.UserMetaEntry;
|
import net.frozenorb.apiv3.models.UserMetaEntry;
|
||||||
@ -8,20 +11,22 @@ import net.frozenorb.apiv3.utils.ErrorUtils;
|
|||||||
public final class GETUserMeta implements Handler<RoutingContext> {
|
public final class GETUserMeta implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
User user = User.byId(ctx.request().getParam("id"));
|
User user = User.findById(ctx.request().getParam("id"));
|
||||||
|
|
||||||
if (user == null) {
|
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) {
|
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);
|
||||||
return userMetaEntry.getData();
|
APIv3.respondJson(ctx, userMetaEntry.getData());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,6 +1,9 @@
|
|||||||
package net.frozenorb.apiv3.routes.users;
|
package net.frozenorb.apiv3.routes.users;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
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.models.User;
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
import net.frozenorb.apiv3.utils.IPUtils;
|
import net.frozenorb.apiv3.utils.IPUtils;
|
||||||
@ -9,36 +12,39 @@ import net.frozenorb.apiv3.utils.TOTPUtils;
|
|||||||
public final class GETUserRequiresTOTP implements Handler<RoutingContext> {
|
public final class GETUserRequiresTOTP implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
User user = User.byId(ctx.request().getParam("id"));
|
User user = User.findById(ctx.request().getParam("id"));
|
||||||
|
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
return ErrorUtils.respondNotFound("User", ctx.request().getParam("id"));
|
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user.getTotpSecret() == null) {
|
if (user.getTotpSecret() == null) {
|
||||||
return ImmutableMap.of(
|
APIv3.respondJson(ctx, ImmutableMap.of(
|
||||||
"required", false,
|
"required", false,
|
||||||
"message", "User does not have TOTP setup."
|
"message", "User does not have TOTP setup."
|
||||||
);
|
));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String userIp = ctx.request().getParam("userIp");
|
String userIp = ctx.request().getParam("userIp");
|
||||||
|
|
||||||
if (!IPUtils.isValidIP(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)) {
|
if (TOTPUtils.isPreAuthorized(user, userIp)) {
|
||||||
return ImmutableMap.of(
|
APIv3.respondJson(ctx, ImmutableMap.of(
|
||||||
"required", false,
|
"required", false,
|
||||||
"message", "User's IP has already been validated"
|
"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."
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,27 +1,32 @@
|
|||||||
package net.frozenorb.apiv3.routes.users;
|
package net.frozenorb.apiv3.routes.users;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
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.models.User;
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
|
|
||||||
public final class GETUserVerifyPassword implements Handler<RoutingContext> {
|
public final class GETUserVerifyPassword implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
User user = User.byId(ctx.request().getParam("id"));
|
User user = User.findById(ctx.request().getParam("id"));
|
||||||
|
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
return ErrorUtils.respondNotFound("User", ctx.request().getParam("id"));
|
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user.getPassword() == null) {
|
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"));
|
boolean authorized = user.checkPassword(ctx.request().getParam("password"));
|
||||||
|
|
||||||
return ImmutableMap.of(
|
APIv3.respondJson(ctx, ImmutableMap.of(
|
||||||
"authorized", authorized
|
"authorized", authorized
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -2,6 +2,8 @@ package net.frozenorb.apiv3.routes.users;
|
|||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
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.APIv3;
|
||||||
import net.frozenorb.apiv3.models.User;
|
import net.frozenorb.apiv3.models.User;
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
@ -20,37 +22,42 @@ public final class POSTUserConfirmRegister implements Handler<RoutingContext> {
|
|||||||
"nicole chelsea biteme matthew access yankees 987654321 dallas austin thunder taylor matrix").split(" "));
|
"nicole chelsea biteme matthew access yankees 987654321 dallas austin thunder taylor matrix").split(" "));
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
User user = User.byEmailToken(ctx.request().getParam("emailToken"));
|
User user = User.findByEmailToken(ctx.request().getParam("emailToken"));
|
||||||
|
|
||||||
if (user == null) {
|
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
|
// We can't check email != null as that's set while we're pending
|
||||||
// confirmation, we have to check the token.
|
// confirmation, we have to check the token.
|
||||||
if (user.getEmailToken() == null) {
|
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)) {
|
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");
|
String password = ctx.request().getParam("password");
|
||||||
|
|
||||||
if (password.length() < 8) {
|
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)) {
|
} 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.setEmailToken(null);
|
||||||
user.setPassword(password);
|
user.setPassword(password);
|
||||||
APIv3.getDatastore().save(user);
|
user.save();
|
||||||
|
|
||||||
return ImmutableMap.of(
|
APIv3.respondJson(ctx, ImmutableMap.of(
|
||||||
"success", true
|
"success", true
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,24 +1,25 @@
|
|||||||
package net.frozenorb.apiv3.routes.users;
|
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.APIv3;
|
||||||
import net.frozenorb.apiv3.models.User;
|
import net.frozenorb.apiv3.models.User;
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
import spark.Request;
|
|
||||||
import spark.Response;
|
|
||||||
|
|
||||||
public class POSTUserLeave implements Handler<RoutingContext> {
|
public class POSTUserLeave implements Handler<RoutingContext> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object handle(Request req, Response res) throws Exception {
|
public void handle(RoutingContext ctx) {
|
||||||
User user = User.byId(ctx.request().getParam("id"));
|
User user = User.findById(ctx.request().getParam("id"));
|
||||||
|
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
return ErrorUtils.respondNotFound("User", ctx.request().getParam("id"));
|
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
user.leftServer();
|
user.leftServer();
|
||||||
APIv3.getDatastore().save(user);
|
user.save();
|
||||||
return user;
|
APIv3.respondJson(ctx, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,5 +1,8 @@
|
|||||||
package net.frozenorb.apiv3.routes.users;
|
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.Actor;
|
||||||
import net.frozenorb.apiv3.actors.ActorType;
|
import net.frozenorb.apiv3.actors.ActorType;
|
||||||
import net.frozenorb.apiv3.models.Server;
|
import net.frozenorb.apiv3.models.Server;
|
||||||
@ -16,20 +19,23 @@ public final class POSTUserLogin implements Handler<RoutingContext> {
|
|||||||
UUID uuid = UUID.fromString(ctx.request().getParam("id"));
|
UUID uuid = UUID.fromString(ctx.request().getParam("id"));
|
||||||
|
|
||||||
if (!UUIDUtils.isAcceptableUUID(uuid)) {
|
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 username = ctx.request().getParam("username");
|
||||||
String userIp = ctx.request().getParam("userIp");
|
String userIp = ctx.request().getParam("userIp");
|
||||||
Actor actor = ctx.get("actor");
|
Actor actor = ctx.get("actor");
|
||||||
|
|
||||||
if (actor.getType() != ActorType.SERVER) {
|
if (actor.getType() != ActorType.SERVER) {
|
||||||
return ErrorUtils.respondServerOnly();
|
ErrorUtils.respondServerOnly(ctx);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IPUtils.isValidIP(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 (user == null) {
|
if (user == null) {
|
||||||
@ -37,11 +43,11 @@ public final class POSTUserLogin implements Handler<RoutingContext> {
|
|||||||
user = new User(uuid, username);
|
user = new User(uuid, username);
|
||||||
}
|
}
|
||||||
|
|
||||||
Server actorServer = Server.byId(actor.getName());
|
Server actorServer = Server.findById(actor.getName());
|
||||||
|
|
||||||
user.getIPLogEntry(userIp).used();
|
user.getIPLogEntry(userIp).used();
|
||||||
user.updateUsername(username);
|
user.updateUsername(username);
|
||||||
return user.getLoginInfo(actorServer);
|
APIv3.respondJson(ctx, user.getLoginInfo(actorServer));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,6 +1,9 @@
|
|||||||
package net.frozenorb.apiv3.routes.users;
|
package net.frozenorb.apiv3.routes.users;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
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.NotificationTemplate;
|
||||||
import net.frozenorb.apiv3.models.User;
|
import net.frozenorb.apiv3.models.User;
|
||||||
import net.frozenorb.apiv3.unsorted.Notification;
|
import net.frozenorb.apiv3.unsorted.Notification;
|
||||||
@ -12,43 +15,47 @@ import java.util.Map;
|
|||||||
public final class POSTUserNotify implements Handler<RoutingContext> {
|
public final class POSTUserNotify implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
User user = User.byId(ctx.request().getParam("id"));
|
User user = User.findById(ctx.request().getParam("id"));
|
||||||
|
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
return ErrorUtils.respondNotFound("User", ctx.request().getParam("id"));
|
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user.getEmail() == null) {
|
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) {
|
if (template == null) {
|
||||||
return ErrorUtils.respondNotFound("Notification template", ctx.request().getParam("template"));
|
ErrorUtils.respondNotFound(ctx, "Notification template", ctx.request().getParam("template"));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, Object> subjectReplacements = new HashMap<>();
|
Map<String, Object> subjectReplacements = new HashMap<>();
|
||||||
Map<String, Object> bodyReplacements = new HashMap<>();
|
Map<String, Object> 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]);
|
subjectReplacements.put(key, values[0]);
|
||||||
});
|
});
|
||||||
|
|
||||||
req.queryMap("body").toMap().forEach((key, values) -> {
|
req.queryMap("body").toMap().forEach((key, values) -> {
|
||||||
bodyReplacements.put(key, values[0]);
|
bodyReplacements.put(key, values[0]);
|
||||||
});
|
});*/
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Notification notification = new Notification(template, subjectReplacements, bodyReplacements);
|
Notification notification = new Notification(template, subjectReplacements, bodyReplacements);
|
||||||
|
|
||||||
notification.sendAsEmail(user.getEmail());
|
notification.sendAsEmail(user.getEmail());
|
||||||
return ImmutableMap.of(
|
APIv3.respondJson(ctx, ImmutableMap.of(
|
||||||
"success", true
|
"success", true
|
||||||
);
|
));
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
return ErrorUtils.error("Failed to send notification");
|
ErrorUtils.respondGeneric(ctx, "Failed to send notification");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package net.frozenorb.apiv3.routes.users;
|
package net.frozenorb.apiv3.routes.users;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
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.APIv3;
|
||||||
import net.frozenorb.apiv3.models.NotificationTemplate;
|
import net.frozenorb.apiv3.models.NotificationTemplate;
|
||||||
import net.frozenorb.apiv3.models.User;
|
import net.frozenorb.apiv3.models.User;
|
||||||
@ -22,30 +24,34 @@ public final class POSTUserRegister implements Handler<RoutingContext> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
User user = User.byId(ctx.request().getParam("id"));
|
User user = User.findById(ctx.request().getParam("id"));
|
||||||
|
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
return ErrorUtils.respondNotFound("User", ctx.request().getParam("id"));
|
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user.getEmail() != null) {
|
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");
|
String email = ctx.request().getParam("email");
|
||||||
|
|
||||||
if (!VALID_EMAIL_PATTERN.matcher(email).matches()) {
|
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)) {
|
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.setEmail(email);
|
||||||
user.setEmailToken(new BigInteger(130, new Random()).toString(32));
|
user.setEmailToken(new BigInteger(130, new Random()).toString(32));
|
||||||
user.setEmailTokenSetAt(new Date());
|
user.setEmailTokenSetAt(new Date());
|
||||||
APIv3.getDatastore().save(user);
|
user.save();
|
||||||
|
|
||||||
Map<String, Object> replacements = ImmutableMap.of(
|
Map<String, Object> replacements = ImmutableMap.of(
|
||||||
"username", user.getLastUsername(),
|
"username", user.getLastUsername(),
|
||||||
@ -53,16 +59,16 @@ public final class POSTUserRegister implements Handler<RoutingContext> {
|
|||||||
"emailToken", user.getEmailToken()
|
"emailToken", user.getEmailToken()
|
||||||
);
|
);
|
||||||
|
|
||||||
Notification notification = new Notification(NotificationTemplate.byId("email-confirmation"), replacements, replacements);
|
Notification notification = new Notification(NotificationTemplate.findById("email-confirmation"), replacements, replacements);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
notification.sendAsEmail(user.getEmail());
|
notification.sendAsEmail(user.getEmail());
|
||||||
return ImmutableMap.of(
|
APIv3.respondJson(ctx, ImmutableMap.of(
|
||||||
"success", true
|
"success", true
|
||||||
);
|
));
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
ex.printStackTrace();
|
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.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,8 @@ package net.frozenorb.apiv3.routes.users;
|
|||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.warrenstrange.googleauth.GoogleAuthenticatorKey;
|
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.APIv3;
|
||||||
import net.frozenorb.apiv3.models.User;
|
import net.frozenorb.apiv3.models.User;
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
@ -10,24 +12,26 @@ import net.frozenorb.apiv3.utils.TOTPUtils;
|
|||||||
public final class POSTUserSetupTOTP implements Handler<RoutingContext> {
|
public final class POSTUserSetupTOTP implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
User user = User.byId(ctx.request().getParam("id"));
|
User user = User.findById(ctx.request().getParam("id"));
|
||||||
|
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
return ErrorUtils.respondNotFound("User", ctx.request().getParam("id"));
|
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user.getTotpSecret() != null) {
|
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();
|
GoogleAuthenticatorKey generated = TOTPUtils.generateTOTPKey();
|
||||||
|
|
||||||
user.setTotpSecret(generated.getKey());
|
user.setTotpSecret(generated.getKey());
|
||||||
APIv3.getDatastore().save(user);
|
user.save();
|
||||||
|
|
||||||
return ImmutableMap.of(
|
APIv3.respondJson(ctx, ImmutableMap.of(
|
||||||
"qrCode", TOTPUtils.getQRCodeURL(user, generated)
|
"qrCode", TOTPUtils.getQRCodeURL(user, generated)
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,6 +1,9 @@
|
|||||||
package net.frozenorb.apiv3.routes.users;
|
package net.frozenorb.apiv3.routes.users;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
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.models.User;
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
import net.frozenorb.apiv3.utils.IPUtils;
|
import net.frozenorb.apiv3.utils.IPUtils;
|
||||||
@ -11,29 +14,33 @@ import java.util.concurrent.TimeUnit;
|
|||||||
public final class POSTUserVerifyTOTP implements Handler<RoutingContext> {
|
public final class POSTUserVerifyTOTP implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
User user = User.byId(ctx.request().getParam("id"));
|
User user = User.findById(ctx.request().getParam("id"));
|
||||||
|
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
return ErrorUtils.respondNotFound("User", ctx.request().getParam("id"));
|
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user.getTotpSecret() == null) {
|
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");
|
String userIp = ctx.request().getParam("userIp");
|
||||||
|
|
||||||
if (!IPUtils.isValidIP(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"));
|
int providedCode = Integer.parseInt(ctx.request().getParam("code"));
|
||||||
|
|
||||||
if (TOTPUtils.wasRecentlyUsed(user, providedCode)) {
|
if (TOTPUtils.wasRecentlyUsed(user, providedCode)) {
|
||||||
return ImmutableMap.of(
|
APIv3.respondJson(ctx, ImmutableMap.of(
|
||||||
"authorized", false,
|
"authorized", false,
|
||||||
"message", "TOTP code was recently used."
|
"message", "TOTP code was recently used."
|
||||||
);
|
));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean authorized = TOTPUtils.authorizeUser(user, providedCode);
|
boolean authorized = TOTPUtils.authorizeUser(user, providedCode);
|
||||||
@ -42,15 +49,15 @@ public final class POSTUserVerifyTOTP implements Handler<RoutingContext> {
|
|||||||
TOTPUtils.markPreAuthorized(user, userIp, 3, TimeUnit.DAYS);
|
TOTPUtils.markPreAuthorized(user, userIp, 3, TimeUnit.DAYS);
|
||||||
TOTPUtils.markRecentlyUsed(user, providedCode);
|
TOTPUtils.markRecentlyUsed(user, providedCode);
|
||||||
|
|
||||||
return ImmutableMap.of(
|
APIv3.respondJson(ctx, ImmutableMap.of(
|
||||||
"authorized", true,
|
"authorized", true,
|
||||||
"message", "Valid TOTP code provided."
|
"message", "Valid TOTP code provided."
|
||||||
);
|
));
|
||||||
} else {
|
} else {
|
||||||
return ImmutableMap.of(
|
APIv3.respondJson(ctx, ImmutableMap.of(
|
||||||
"authorized", false,
|
"authorized", false,
|
||||||
"message", "TOTP code was not valid."
|
"message", "TOTP code was not valid."
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package net.frozenorb.apiv3.routes.users;
|
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.ServerGroup;
|
||||||
import net.frozenorb.apiv3.models.User;
|
import net.frozenorb.apiv3.models.User;
|
||||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
@ -8,22 +11,24 @@ import org.bson.Document;
|
|||||||
public final class PUTUserMeta implements Handler<RoutingContext> {
|
public final class PUTUserMeta implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
User user = User.byId(ctx.request().getParam("id"));
|
User user = User.findById(ctx.request().getParam("id"));
|
||||||
|
|
||||||
if (user == null) {
|
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) {
|
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);
|
user.saveMeta(serverGroup, data);
|
||||||
return data;
|
APIv3.respondJson(ctx, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -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<T> implements SingleResultCallback<T> {
|
||||||
|
|
||||||
|
private final SettableFuture<T> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 + "\".")));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -9,23 +9,24 @@ import net.frozenorb.apiv3.APIv3;
|
|||||||
public class ErrorUtils {
|
public class ErrorUtils {
|
||||||
|
|
||||||
public static void respondServerOnly(RoutingContext ctx) {
|
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) {
|
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) {
|
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) {
|
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) {
|
public static void respondGeneric(RoutingContext ctx, String message) {
|
||||||
APIv3.respond(ctx, ImmutableMap.of(
|
// TODO: Proper status codes
|
||||||
|
APIv3.respondJson(ctx, 400, ImmutableMap.of(
|
||||||
"success", false,
|
"success", false,
|
||||||
"message", message
|
"message", message
|
||||||
));
|
));
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
package net.frozenorb.apiv3.utils;
|
package net.frozenorb.apiv3.utils;
|
||||||
|
|
||||||
|
import com.mongodb.async.SingleResultCallback;
|
||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
import net.frozenorb.apiv3.APIv3;
|
import net.frozenorb.apiv3.APIv3;
|
||||||
import okhttp3.OkHttpClient;
|
import net.frozenorb.apiv3.unsorted.BlockingCallback;
|
||||||
import okhttp3.Request;
|
|
||||||
import okhttp3.Response;
|
|
||||||
import org.bson.Document;
|
import org.bson.Document;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@ -12,30 +11,32 @@ import java.util.UUID;
|
|||||||
@UtilityClass
|
@UtilityClass
|
||||||
public class MojangUtils {
|
public class MojangUtils {
|
||||||
|
|
||||||
private static OkHttpClient okHttpClient = new OkHttpClient.Builder().retryOnConnectionFailure(false).build();
|
|
||||||
|
|
||||||
public static String getName(UUID id) {
|
public static String getName(UUID id) {
|
||||||
Request.Builder builder = new Request.Builder();
|
BlockingCallback<String> callback = new BlockingCallback<>();
|
||||||
|
getName(id, callback);
|
||||||
|
return callback.get();
|
||||||
|
}
|
||||||
|
|
||||||
builder.get();
|
public static void getName(UUID id, SingleResultCallback<String> callback) {
|
||||||
builder.url("https://sessionserver.mojang.com/session/minecraft/profile/" + id.toString().replace("-", ""));
|
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 {
|
if (name == null) {
|
||||||
Response response = okHttpClient.newCall(builder.build()).execute();
|
APIv3.getStatsD().incrementCounter("apiv3.mojang.sessionServer.rateLimited");
|
||||||
Document resJson = Document.parse(response.body().string());
|
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");
|
response.exceptionHandler((error) -> {
|
||||||
|
APIv3.getStatsD().incrementCounter("apiv3.mojang.sessionServer.failure");
|
||||||
if (name == null) {
|
callback.onResult(null, error);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -25,7 +25,7 @@ public class PermissionUtils {
|
|||||||
public static Map<String, Boolean> mergeUpTo(Map<String, List<String>> unmerged, Rank upTo) {
|
public static Map<String, Boolean> mergeUpTo(Map<String, List<String>> unmerged, Rank upTo) {
|
||||||
Map<String, Boolean> result = new HashMap<>();
|
Map<String, Boolean> result = new HashMap<>();
|
||||||
|
|
||||||
for (Rank rank : Rank.values()) {
|
for (Rank rank : Rank.findAll()) {
|
||||||
Map<String, Boolean> rankPermissions = convertToMap(unmerged.get(rank.getId()));
|
Map<String, Boolean> rankPermissions = convertToMap(unmerged.get(rank.getId()));
|
||||||
|
|
||||||
// If there's no permissions defined for this rank just skip it.
|
// If there's no permissions defined for this rank just skip it.
|
||||||
|
27
src/main/java/net/frozenorb/apiv3/utils/SyncUtils.java
Normal file
27
src/main/java/net/frozenorb/apiv3/utils/SyncUtils.java
Normal file
@ -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> T blockOne(MongoIterable<T> mongoIterable) {
|
||||||
|
BlockingCallback<T> callback = new BlockingCallback<>();
|
||||||
|
|
||||||
|
mongoIterable.first(callback);
|
||||||
|
return callback.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> List<T> blockMulti(MongoIterable<T> mongoIterable) {
|
||||||
|
BlockingCallback<List<T>> callback = new BlockingCallback<>();
|
||||||
|
|
||||||
|
mongoIterable.into(new ArrayList<>(), callback);
|
||||||
|
return callback.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user