Push a bunch of experimental code (this doesn't currently work)
This commit is contained in:
parent
60a622fc43
commit
7e462e1915
@ -1,6 +1,4 @@
|
||||
general.releaseStage=production
|
||||
logging.level=info
|
||||
logging.debug=true
|
||||
mongo.address=localhost
|
||||
mongo.port=27017
|
||||
mongo.database=MineHQ
|
||||
@ -13,6 +11,5 @@ twillio.accountSID=AC9e2f88c5690134d29a56f698de3cd740
|
||||
twillio.authToken=982592505a171d3be6b0722f5ecacc0e
|
||||
mandrill.apiKey=0OYtwymqJP6oqvszeJu0vQ
|
||||
bugsnag.apiKey=0e47fba8b825416b7cbc839066184509
|
||||
auth.permittedUserRanks=developer,owner
|
||||
auth.websiteApiKey=RVbp4hY6sCFVaf
|
||||
auth.bungeeCordApiKey=6d9cf76dc9f0d23
|
27
pom.xml
27
pom.xml
@ -55,6 +55,10 @@
|
||||
<id>minehq-repo</id>
|
||||
<url>http://maven.minehq.com:8081/artifactory/minehq-all/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>mongo-jackson-codec-repo</id>
|
||||
<url>https://dl.bintray.com/ylemoigne/maven</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
@ -62,12 +66,17 @@
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-core</artifactId>
|
||||
<version>LATEST</version>
|
||||
<version>3.2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-web</artifactId>
|
||||
<version>LATEST</version>
|
||||
<version>3.2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-redis-client</artifactId>
|
||||
<version>3.2.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Google Libs -->
|
||||
@ -89,16 +98,14 @@
|
||||
<version>3.0.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>eu.dozd</groupId>
|
||||
<artifactId>mongo-mapper</artifactId>
|
||||
<version>1.0.1</version>
|
||||
<groupId>fr.javatic.mongo</groupId>
|
||||
<artifactId>mongo-jackson-codec</artifactId>
|
||||
<version>3.2.0__0.4</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Redis -->
|
||||
<dependency>
|
||||
<groupId>redis.clients</groupId>
|
||||
<artifactId>jedis</artifactId>
|
||||
<version>2.8.1</version>
|
||||
<groupId>de.undercouch</groupId>
|
||||
<artifactId>bson4jackson</artifactId>
|
||||
<version>2.6.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Notifications -->
|
||||
|
@ -1,39 +1,50 @@
|
||||
package net.frozenorb.apiv3;
|
||||
|
||||
import com.bugsnag.Client;
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.mongodb.Block;
|
||||
import com.mongodb.ConnectionString;
|
||||
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.ClusterConnectionMode;
|
||||
import com.mongodb.connection.ClusterSettings;
|
||||
import com.timgroup.statsd.NonBlockingStatsDClient;
|
||||
import com.timgroup.statsd.StatsDClient;
|
||||
import eu.dozd.mongo.MongoMapper;
|
||||
import fr.javatic.mongo.jacksonCodec.JacksonCodecProvider;
|
||||
import fr.javatic.mongo.jacksonCodec.ObjectMapperFactory;
|
||||
import io.vertx.core.AbstractVerticle;
|
||||
import io.vertx.core.Handler;
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.core.http.HttpClient;
|
||||
import io.vertx.core.http.HttpServer;
|
||||
import io.vertx.ext.web.Router;
|
||||
import io.vertx.ext.web.RoutingContext;
|
||||
import io.vertx.ext.web.handler.BodyHandler;
|
||||
import io.vertx.ext.web.handler.LoggerHandler;
|
||||
import io.vertx.ext.web.impl.BlockingHandlerDecorator;
|
||||
import io.vertx.ext.web.impl.RouteImpl;
|
||||
import io.vertx.redis.RedisClient;
|
||||
import io.vertx.redis.RedisOptions;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.frozenorb.apiv3.actors.ActorType;
|
||||
import net.frozenorb.apiv3.filters.ActorAttributeFilter;
|
||||
import net.frozenorb.apiv3.filters.AuthorizationFilter;
|
||||
import net.frozenorb.apiv3.filters.MetricsHandler;
|
||||
import net.frozenorb.apiv3.models.Grant;
|
||||
import net.frozenorb.apiv3.models.IPLogEntry;
|
||||
import net.frozenorb.apiv3.models.Punishment;
|
||||
import net.frozenorb.apiv3.models.User;
|
||||
import net.frozenorb.apiv3.handlers.ActorAttributeHandler;
|
||||
import net.frozenorb.apiv3.handlers.AuthorizationHandler;
|
||||
import net.frozenorb.apiv3.handlers.MetricsHandler;
|
||||
import net.frozenorb.apiv3.models.*;
|
||||
import net.frozenorb.apiv3.routes.GETDump;
|
||||
import net.frozenorb.apiv3.routes.GETWhoAmI;
|
||||
import net.frozenorb.apiv3.routes.POSTMetrics;
|
||||
@ -57,19 +68,23 @@ import net.frozenorb.apiv3.routes.serverGroups.GETServerGroups;
|
||||
import net.frozenorb.apiv3.routes.serverGroups.POSTServerGroup;
|
||||
import net.frozenorb.apiv3.routes.servers.*;
|
||||
import net.frozenorb.apiv3.routes.users.*;
|
||||
import net.frozenorb.apiv3.serialization.DateTypeAdapter;
|
||||
import net.frozenorb.apiv3.serialization.FollowAnnotationExclusionStrategy;
|
||||
import net.frozenorb.apiv3.serialization.ObjectIdTypeAdapter;
|
||||
import net.frozenorb.apiv3.serialization.*;
|
||||
import net.frozenorb.apiv3.unsorted.BlockingCallback;
|
||||
import net.frozenorb.apiv3.unsorted.BugsnagSLF4JLogger;
|
||||
import net.frozenorb.apiv3.utils.IPUtils;
|
||||
import net.frozenorb.apiv3.utils.SyncUtils;
|
||||
import net.frozenorb.apiv3.utils.UUIDUtils;
|
||||
import org.bson.Document;
|
||||
import org.bson.codecs.BsonValueCodecProvider;
|
||||
import org.bson.codecs.DocumentCodecProvider;
|
||||
import org.bson.codecs.ValueCodecProvider;
|
||||
import org.bson.codecs.configuration.CodecProvider;
|
||||
import org.bson.codecs.configuration.CodecRegistries;
|
||||
import org.bson.types.ObjectId;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
@ -80,26 +95,27 @@ public final class APIv3 extends AbstractVerticle {
|
||||
@Getter private static HttpClient httpClient;
|
||||
@Getter private static MongoDatabase database;
|
||||
@Getter private static Properties config = new Properties();
|
||||
@Getter private static JedisPool redisPool;
|
||||
@Getter private static RedisClient redisClient;
|
||||
@Getter private static StatsDClient statsD;
|
||||
@Getter private static Vertx vertxInstance;
|
||||
@Getter private static final Gson gson = new GsonBuilder()
|
||||
.registerTypeAdapter(ObjectId.class, new ObjectIdTypeAdapter())
|
||||
.registerTypeAdapter(Date.class, new DateTypeAdapter())
|
||||
.setExclusionStrategies(new FollowAnnotationExclusionStrategy())
|
||||
.create();
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
setupConfig();
|
||||
System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", config.getProperty("logging.level"));
|
||||
vertxInstance = vertx;
|
||||
|
||||
setupConfig();
|
||||
setupDatabase();
|
||||
setupRedis();
|
||||
setupMetrics();
|
||||
setupBugsnag();
|
||||
setupHttpServer();
|
||||
//setupHttpServer();
|
||||
setupHttpClient();
|
||||
|
||||
//convertData("158.69.126.126", true);
|
||||
convertData("mongodb://158.69.126.126", true);
|
||||
}
|
||||
|
||||
private void setupConfig() {
|
||||
@ -125,18 +141,37 @@ public final class APIv3 extends AbstractVerticle {
|
||||
|
||||
ClusterSettings clusterSettings = ClusterSettings
|
||||
.builder()
|
||||
.hosts(ImmutableList.of(
|
||||
new ServerAddress(
|
||||
config.getProperty("mongo.address"),
|
||||
Integer.parseInt(config.getProperty("mongo.port"))
|
||||
)
|
||||
))
|
||||
.applyConnectionString(new ConnectionString("mongodb://" + config.getProperty("mongo.address") + ":" + config.getProperty("mongo.port")))
|
||||
.build();
|
||||
|
||||
List<CodecProvider> providers = new ArrayList<>();
|
||||
|
||||
// Our override codec
|
||||
providers.add(new MineHQCodecProvider());
|
||||
|
||||
// Normal providers
|
||||
providers.add(new ValueCodecProvider());
|
||||
providers.add(new DocumentCodecProvider());
|
||||
providers.add(new BsonValueCodecProvider());
|
||||
|
||||
ObjectMapper objectMapper = ObjectMapperFactory.createObjectMapper();
|
||||
SimpleModule simpleModule = new SimpleModule();
|
||||
|
||||
simpleModule.addSerializer(UUID.class, new UUIDJsonSerializer());
|
||||
simpleModule.addDeserializer(UUID.class, new UUIDJsonDeserializer());
|
||||
|
||||
objectMapper.registerModule(simpleModule);
|
||||
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
|
||||
objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
|
||||
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
|
||||
providers.add(new JacksonCodecProvider(objectMapper));
|
||||
|
||||
MongoClientSettings settings = MongoClientSettings
|
||||
.builder()
|
||||
.codecRegistry(CodecRegistries.fromProviders(MongoMapper.getProviders()))
|
||||
.codecRegistry(CodecRegistries.fromProviders(providers))
|
||||
.credentialList(credentials)
|
||||
.clusterSettings(clusterSettings).build();
|
||||
.clusterSettings(clusterSettings)
|
||||
.build();
|
||||
|
||||
MongoClient client = MongoClients.create(settings);
|
||||
database = client.getDatabase(config.getProperty("mongo.database"));
|
||||
@ -144,9 +179,11 @@ public final class APIv3 extends AbstractVerticle {
|
||||
}
|
||||
|
||||
private void setupRedis() {
|
||||
redisPool = new JedisPool(
|
||||
config.getProperty("redis.address"),
|
||||
Integer.parseInt(config.getProperty("redis.port"))
|
||||
redisClient = RedisClient.create(
|
||||
vertx,
|
||||
new RedisOptions()
|
||||
.setAddress(config.getProperty("redis.address"))
|
||||
.setPort(Integer.parseInt(config.getProperty("redis.port")))
|
||||
);
|
||||
}
|
||||
|
||||
@ -176,8 +213,8 @@ public final class APIv3 extends AbstractVerticle {
|
||||
Router mainRouter = Router.router(vertx);
|
||||
|
||||
mainRouter.route().handler(new MetricsHandler());
|
||||
mainRouter.route().handler(new ActorAttributeFilter());
|
||||
mainRouter.route().handler(new AuthorizationFilter());
|
||||
mainRouter.route().handler(new ActorAttributeHandler());
|
||||
mainRouter.route().handler(new AuthorizationHandler());
|
||||
mainRouter.route().handler(LoggerHandler.create());
|
||||
mainRouter.route().handler(BodyHandler.create());
|
||||
|
||||
@ -218,7 +255,7 @@ public final class APIv3 extends AbstractVerticle {
|
||||
|
||||
mainRouter.get("/server/:id").blockingHandler(new GETServer());
|
||||
mainRouter.get("/servers").blockingHandler(new GETServers());
|
||||
mainRouter.post("/server/heartbeat").blockingHandler(new POSTServerHeartbeat());
|
||||
mainRouter.post("/server/heartbeat").handler(new POSTServerHeartbeat());
|
||||
mainRouter.post("/server").blockingHandler(new POSTServer());
|
||||
//put("/server/:id").blockingHandler(new PUTServer());
|
||||
mainRouter.delete("/server/:id").blockingHandler(new DELETEServer());
|
||||
@ -246,7 +283,22 @@ public final class APIv3 extends AbstractVerticle {
|
||||
mainRouter.delete("/user/:id/punishment").blockingHandler(new DELETEUserPunishment());
|
||||
|
||||
mainRouter.getRoutes().forEach((route) -> {
|
||||
System.out.println(route.getClass() + "||" + route.getPath());
|
||||
try {
|
||||
RouteImpl impl = (RouteImpl) route;
|
||||
Field field = RouteImpl.class.getDeclaredField("contextHandler");
|
||||
field.setAccessible(true);
|
||||
Handler<RoutingContext> handler = (Handler<RoutingContext>) field.get(impl);
|
||||
|
||||
if (handler instanceof BlockingHandlerDecorator) {
|
||||
field = BlockingHandlerDecorator.class.getDeclaredField("decoratedHandler");
|
||||
field.setAccessible(true);
|
||||
handler = (Handler<RoutingContext>) field.get(handler);
|
||||
}
|
||||
|
||||
System.out.println(route.getPath() + " is handled by " + handler.getClass());
|
||||
} catch (Exception ex) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
int port = Integer.parseInt(config.getProperty("http.port"));
|
||||
@ -276,174 +328,156 @@ public final class APIv3 extends AbstractVerticle {
|
||||
AtomicInteger skippedGrants = new AtomicInteger();
|
||||
AtomicInteger skippedIpLogs = new AtomicInteger();
|
||||
|
||||
importFrom.getCollection("user").find().forEach(new Block<Document>() {
|
||||
SyncUtils.blockMulti(importFrom.getCollection("user").find()).forEach((user) -> {
|
||||
String uuidString = String.valueOf(user.get("uuid"));
|
||||
|
||||
@Override
|
||||
public void apply(Document user) {
|
||||
String uuidString = String.valueOf(user.get("uuid"));
|
||||
|
||||
if (uuidString == null || uuidString.length() != 32) {
|
||||
return;
|
||||
}
|
||||
|
||||
UUID uuid = UUID.fromString(uuidString.replaceFirst( "([0-9a-fA-F]{8})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]+)", "$1-$2-$3-$4-$5" ));
|
||||
|
||||
if (!UUIDUtils.isAcceptableUUID(uuid)) {
|
||||
skippedUsers.incrementAndGet();
|
||||
return;
|
||||
}
|
||||
|
||||
mongoIdToUUID.put(user.getObjectId("_id"), uuid);
|
||||
|
||||
User created = new User(
|
||||
uuid,
|
||||
String.valueOf(user.get("name")).toString(),
|
||||
ImmutableMap.of(),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
user.getString("email"),
|
||||
user.getString("phone"),
|
||||
"INVALID",
|
||||
user.getDate("joined"),
|
||||
user.getDate("joined"),
|
||||
false
|
||||
);
|
||||
|
||||
if (forReal) {
|
||||
created.insert();
|
||||
}
|
||||
|
||||
log.info("Created user " + created.getLastUsername() + " (" + created.getId() + ")");
|
||||
if (uuidString == null || uuidString.length() != 32) {
|
||||
return;
|
||||
}
|
||||
}, (a, b) -> {});
|
||||
|
||||
importFrom.getCollection("punishment").find().forEach(new Block<Document>() {
|
||||
UUID uuid = UUID.fromString(uuidString.replaceFirst("([0-9a-fA-F]{8})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]+)", "$1-$2-$3-$4-$5"));
|
||||
|
||||
@Override
|
||||
public void apply(Document punishment) {
|
||||
UUID target = mongoIdToUUID.get(((DBRef) punishment.get("user")).getId());
|
||||
|
||||
if (target == null) {
|
||||
skippedPunishments.incrementAndGet();
|
||||
return;
|
||||
}
|
||||
|
||||
// Old punishments have this value set to false to indicate they're not active anymore.
|
||||
if (punishment.containsKey("active") && !punishment.getBoolean("active")) {
|
||||
return;
|
||||
}
|
||||
|
||||
com.mongodb.
|
||||
|
||||
Punishment created = new Punishment(
|
||||
new ObjectId().toString(),
|
||||
target,
|
||||
punishment.getString("reason").toString(),
|
||||
Punishment.PunishmentType.valueOf(punishment.getString("type").toUpperCase()),
|
||||
punishment.getDate("expires"),
|
||||
punishment.containsKey("meta") ? (punishment.get("meta") instanceof List ? ImmutableMap.of() : (Document) punishment.get("meta")) : ImmutableMap.of(),
|
||||
punishment.containsKey("addedBy") ? mongoIdToUUID.get(((DBRef) punishment.get("addedBy")).getId()) : null,
|
||||
(Date) punishment.getDate("created").clone(),
|
||||
punishment.containsKey("createdOn") ? String.valueOf(((DBRef) punishment.get("createdOn")).getId()) : "Website",
|
||||
punishment.containsKey("createdOn") ? ActorType.SERVER : ActorType.WEBSITE,
|
||||
punishment.containsKey("removedBy") ? (((DBRef) punishment.get("removedBy")).getCollectionName().equals("user") ? mongoIdToUUID.get(((DBRef) punishment.get("removedBy")).getId()) : null) : null,
|
||||
punishment.getDate("created"),
|
||||
punishment.containsKey("removalReason") ? punishment.getString("removalReason").toString() : ""
|
||||
);
|
||||
|
||||
if (forReal) {
|
||||
created.insert();
|
||||
}
|
||||
|
||||
log.info("Created punishment " + created.getId() + " (" + created.getType() + ")");
|
||||
if (!UUIDUtils.isAcceptableUUID(uuid)) {
|
||||
skippedUsers.incrementAndGet();
|
||||
return;
|
||||
}
|
||||
}, (a, b) -> {});
|
||||
|
||||
importFrom.getCollection("grant").find().forEach(new Block<Document>() {
|
||||
mongoIdToUUID.put(user.getObjectId("_id"), uuid);
|
||||
|
||||
@Override
|
||||
public void apply(Document grant) {
|
||||
UUID target = mongoIdToUUID.get(((DBRef) grant.get("target")).getId());
|
||||
User created = new User(
|
||||
uuid,
|
||||
String.valueOf(user.get("name")).toString(),
|
||||
ImmutableMap.of(user.getString("name"), user.getDate("joined")),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
user.getString("email"),
|
||||
user.getString("phone"),
|
||||
"INVALID",
|
||||
user.getDate("joined"),
|
||||
user.getDate("joined"),
|
||||
false
|
||||
);
|
||||
|
||||
if (target == null) {
|
||||
skippedGrants.incrementAndGet();
|
||||
return;
|
||||
}
|
||||
|
||||
String rank = grant.getString("role");
|
||||
|
||||
if (rank.equalsIgnoreCase("unban") || rank.equalsIgnoreCase("pass") || rank.equalsIgnoreCase("pink") || rank.equalsIgnoreCase("jrdev")) {
|
||||
return;
|
||||
} else if (rank.equalsIgnoreCase("high_roller")) {
|
||||
rank = "high-roller";
|
||||
} else if (rank.equalsIgnoreCase("dev")) {
|
||||
rank = "developer";
|
||||
}
|
||||
|
||||
Grant created = new Grant(
|
||||
new ObjectId().toString(),
|
||||
target,
|
||||
grant.containsKey("comment") ? grant.getString("comment") : "",
|
||||
grant.containsKey("scope") ? ImmutableSet.copyOf((Collection<String>) grant.get("scope")) : ImmutableSet.of(),
|
||||
rank,
|
||||
grant.getDate("expires"),
|
||||
grant.containsKey("addedBy") ? mongoIdToUUID.get(((DBRef) grant.get("addedBy")).getId()) : null,
|
||||
grant.containsKey("created") ? grant.getDate("created") : new Date(),
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
if (forReal) {
|
||||
created.insert();
|
||||
}
|
||||
|
||||
log.info("Created grant " + created.getId() + " (" + created.getRank() + ")");
|
||||
if (forReal) {
|
||||
created.insert();
|
||||
}
|
||||
}, (a, b) -> {});
|
||||
|
||||
importFrom.getCollection("iplog").find().forEach(new Block<Document>() {
|
||||
log.info("Created user " + created.getLastUsername() + " (" + created.getId() + ")");
|
||||
});
|
||||
|
||||
@Override
|
||||
public void apply(Document ipLogEntry) {
|
||||
UUID user = mongoIdToUUID.get(((DBRef) ipLogEntry.get("user")).getId());
|
||||
SyncUtils.blockMulti(importFrom.getCollection("punishment").find()).forEach((punishment) -> {
|
||||
UUID target = mongoIdToUUID.get(((Map<String, Object>) punishment.get("user")).get("$id"));
|
||||
|
||||
if (user == null || ipLogEntry.getString("ip") == null) {
|
||||
skippedIpLogs.incrementAndGet();
|
||||
return;
|
||||
}
|
||||
|
||||
String ip = ipLogEntry.getString("ip").replace("/", "");
|
||||
|
||||
if (!IPUtils.isValidIP(ip)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Date lastSeen = ipLogEntry.getDate("lastSeen");
|
||||
|
||||
if (lastSeen == null) {
|
||||
lastSeen = new Date();
|
||||
}
|
||||
|
||||
IPLogEntry created = new IPLogEntry(
|
||||
new ObjectId().toString(),
|
||||
user,
|
||||
ip,
|
||||
lastSeen,
|
||||
lastSeen,
|
||||
((Number) ipLogEntry.get("uses")).intValue()
|
||||
|
||||
);
|
||||
|
||||
if (forReal) {
|
||||
created.insert();
|
||||
}
|
||||
|
||||
log.info("Created ip log entry " + created.getId() + " (" + created.getUser() + " - " + created.getUserIp() + ")");
|
||||
if (target == null) {
|
||||
skippedPunishments.incrementAndGet();
|
||||
return;
|
||||
}
|
||||
}, (a, b) -> {});
|
||||
|
||||
// Old punishments have this value set to false to indicate they're not active anymore.
|
||||
if (punishment.containsKey("active") && !punishment.getBoolean("active")) {
|
||||
return;
|
||||
}
|
||||
|
||||
Punishment created = new Punishment(
|
||||
new ObjectId().toString(),
|
||||
target,
|
||||
punishment.getString("reason").toString(),
|
||||
Punishment.PunishmentType.valueOf(punishment.getString("type").toUpperCase()),
|
||||
punishment.getDate("expires"),
|
||||
punishment.containsKey("meta") ? (punishment.get("meta") instanceof List ? ImmutableMap.of() : (Document) punishment.get("meta")) : ImmutableMap.of(),
|
||||
punishment.containsKey("addedBy") ? mongoIdToUUID.get(((Map<String, Object>) punishment.get("addedBy")).get("$id")) : null,
|
||||
(Date) punishment.getDate("created").clone(),
|
||||
punishment.containsKey("createdOn") ? String.valueOf(((Map<String, Object>) punishment.get("createdOn")).get("$id")) : "Website",
|
||||
punishment.containsKey("createdOn") ? ActorType.SERVER : ActorType.WEBSITE,
|
||||
punishment.containsKey("removedBy") ? (((Map<String, Object>) punishment.get("removedBy")).get("$ref").equals("user") ? mongoIdToUUID.get(((Map<String, Object>) punishment.get("removedBy")).get("$id")) : null) : null,
|
||||
punishment.getDate("created"),
|
||||
punishment.containsKey("removalReason") ? punishment.getString("removalReason").toString() : ""
|
||||
);
|
||||
|
||||
if (forReal) {
|
||||
created.insert();
|
||||
}
|
||||
|
||||
log.info("Created punishment " + created.getId() + " (" + created.getType() + ")");
|
||||
});
|
||||
|
||||
SyncUtils.blockMulti(importFrom.getCollection("grant").find()).forEach((grant) -> {
|
||||
UUID target = mongoIdToUUID.get(((Map<String, Object>) grant.get("target")).get("$id"));
|
||||
|
||||
if (target == null) {
|
||||
skippedGrants.incrementAndGet();
|
||||
return;
|
||||
}
|
||||
|
||||
String rank = grant.getString("role");
|
||||
|
||||
if (rank.equalsIgnoreCase("unban") || rank.equalsIgnoreCase("pass") || rank.equalsIgnoreCase("pink") || rank.equalsIgnoreCase("jrdev")) {
|
||||
return;
|
||||
} else if (rank.equalsIgnoreCase("high_roller")) {
|
||||
rank = "high-roller";
|
||||
} else if (rank.equalsIgnoreCase("dev")) {
|
||||
rank = "developer";
|
||||
}
|
||||
|
||||
Grant created = new Grant(
|
||||
new ObjectId().toString(),
|
||||
target,
|
||||
grant.containsKey("comment") ? grant.getString("comment") : "",
|
||||
grant.containsKey("scope") ? ImmutableSet.copyOf((Collection<String>) grant.get("scope")) : ImmutableSet.of(),
|
||||
rank,
|
||||
grant.getDate("expires"),
|
||||
grant.containsKey("addedBy") ? mongoIdToUUID.get(((Map<String, Object>) grant.get("addedBy")).get("$id")) : null,
|
||||
grant.containsKey("created") ? grant.getDate("created") : new Date(),
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
if (forReal) {
|
||||
created.insert();
|
||||
}
|
||||
|
||||
log.info("Created grant " + created.getId() + " (" + created.getRank() + ")");
|
||||
});
|
||||
|
||||
SyncUtils.blockMulti(importFrom.getCollection("iplog").find()).forEach((ipLogEntry) -> {
|
||||
UUID user = mongoIdToUUID.get(((Map<String, Object>) ipLogEntry.get("user")).get("$id"));
|
||||
|
||||
if (user == null || ipLogEntry.getString("ip") == null) {
|
||||
skippedIpLogs.incrementAndGet();
|
||||
return;
|
||||
}
|
||||
|
||||
String ip = ipLogEntry.getString("ip").replace("/", "");
|
||||
|
||||
if (!IPUtils.isValidIP(ip)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Date lastSeen = ipLogEntry.getDate("lastSeen");
|
||||
|
||||
if (lastSeen == null) {
|
||||
lastSeen = new Date();
|
||||
}
|
||||
|
||||
IPLogEntry created = new IPLogEntry(
|
||||
new ObjectId().toString(),
|
||||
user,
|
||||
ip,
|
||||
lastSeen,
|
||||
lastSeen,
|
||||
((Number) ipLogEntry.get("uses")).intValue()
|
||||
|
||||
);
|
||||
|
||||
if (forReal) {
|
||||
created.insert();
|
||||
}
|
||||
|
||||
log.info("Created ip log entry " + created.getId() + " (" + created.getUser() + " - " + created.getUserIp() + ")");
|
||||
});
|
||||
|
||||
log.info("Skipped " + skippedUsers.get() + " users, " + skippedPunishments.get() + " punishments, " + skippedGrants.get() + " grants, and " + skippedIpLogs.get() + " ip logs");
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ import io.vertx.core.Vertx;
|
||||
final class Main {
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.setProperty("vertx.logger-delegate-factory-class-name", "io.vertx.core.logging.SLF4JLogDelegateFactory");
|
||||
System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "info");
|
||||
Vertx.vertx().deployVerticle(new APIv3());
|
||||
}
|
||||
|
||||
|
@ -2,14 +2,17 @@ package net.frozenorb.apiv3.actors;
|
||||
|
||||
public final class BungeeCordActor implements Actor {
|
||||
|
||||
@Override
|
||||
public boolean isAuthorized() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "BungeeCord";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActorType getType() {
|
||||
return ActorType.BUNGEECORD;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.frozenorb.apiv3.actors;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import net.frozenorb.apiv3.models.Server;
|
||||
|
||||
@ -11,14 +12,17 @@ public final class ServerActor implements Actor {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAuthorized() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return server.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActorType getType() {
|
||||
return ActorType.SERVER;
|
||||
}
|
||||
|
@ -2,14 +2,17 @@ package net.frozenorb.apiv3.actors;
|
||||
|
||||
public final class UnknownActor implements Actor {
|
||||
|
||||
@Override
|
||||
public boolean isAuthorized() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActorType getType() {
|
||||
return ActorType.UNKNOWN;
|
||||
}
|
||||
|
@ -4,35 +4,40 @@ import com.google.common.collect.ImmutableSet;
|
||||
import lombok.Getter;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.models.User;
|
||||
import net.frozenorb.apiv3.unsorted.Permissions;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public final class UserActor implements Actor {
|
||||
|
||||
private static final Set<String> permittedUserRanks = ImmutableSet.copyOf(APIv3.getConfig().getProperty("auth.permittedUserRanks").toLowerCase().split(","));
|
||||
|
||||
@Getter private final User user;
|
||||
// We use Boolean here so we can have null = not calculated;
|
||||
// Currently having this cached isn't important as we only check
|
||||
// this once, but later on when we have non-logged in routes
|
||||
// this will be important.
|
||||
private Boolean cachedAuthorized = null;
|
||||
|
||||
public UserActor(User user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAuthorized() {
|
||||
if (cachedAuthorized != null) {
|
||||
return cachedAuthorized;
|
||||
} else {
|
||||
String highestRankId = user.getHighestRankAnywhere().getId();
|
||||
cachedAuthorized = permittedUserRanks.contains(highestRankId.toLowerCase());
|
||||
return cachedAuthorized;
|
||||
boolean authorized = user.hasPermissionAnywhere(Permissions.SIGN_API_REQUEST);
|
||||
cachedAuthorized = authorized;
|
||||
return authorized;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return user.getLastUsername();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActorType getType() {
|
||||
return ActorType.USER;
|
||||
}
|
||||
|
@ -2,14 +2,17 @@ package net.frozenorb.apiv3.actors;
|
||||
|
||||
public final class WebsiteActor implements Actor {
|
||||
|
||||
@Override
|
||||
public boolean isAuthorized() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Website";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActorType getType() {
|
||||
return ActorType.WEBSITE;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package net.frozenorb.apiv3.filters;
|
||||
package net.frozenorb.apiv3.handlers;
|
||||
|
||||
import io.vertx.core.Handler;
|
||||
import io.vertx.ext.web.RoutingContext;
|
||||
@ -10,41 +10,46 @@ import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
|
||||
import java.util.Base64;
|
||||
|
||||
public final class ActorAttributeFilter implements Handler<RoutingContext> {
|
||||
public final class ActorAttributeHandler implements Handler<RoutingContext> {
|
||||
|
||||
// TODO: MAKE THIS ASYNC
|
||||
@Override
|
||||
public void handle(RoutingContext ctx) {
|
||||
String authHeader = ctx.request().getHeader("Authorization");
|
||||
String mhqAuthHeader = ctx.request().getHeader("MHQ-Authorization");
|
||||
String authorizationHeader = ctx.request().getHeader("Authorization");
|
||||
String mhqAuthorizationHeader = ctx.request().getHeader("MHQ-Authorization");
|
||||
|
||||
if (authHeader != null) {
|
||||
processBasicAuthorization(authHeader, ctx);
|
||||
} else if (mhqAuthHeader != null) {
|
||||
processMHQAuthorization(mhqAuthHeader, ctx);
|
||||
if (authorizationHeader != null) {
|
||||
processBasicAuthorization(authorizationHeader, ctx);
|
||||
} else if (mhqAuthorizationHeader != null) {
|
||||
processMHQAuthorization(mhqAuthorizationHeader, ctx);
|
||||
} else {
|
||||
ctx.put("actor", new UnknownActor());
|
||||
ctx.next();
|
||||
processNoAuthorization(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation") // We purposely get the User by their last username.
|
||||
private void processBasicAuthorization(String authHeader, RoutingContext ctx) {
|
||||
String encodedHeader = authHeader.substring("Basic ".length());
|
||||
String[] credentials = new String(Base64.getDecoder().decode(encodedHeader.getBytes())).split(":");
|
||||
String decodedHeader = new String(Base64.getDecoder().decode(encodedHeader.getBytes()));
|
||||
String[] credentials = decodedHeader.split(":");
|
||||
|
||||
if (credentials.length == 2) {
|
||||
User user = User.findByLastUsername(credentials[0]);
|
||||
String password = credentials[1];
|
||||
User.findByLastUsername(credentials[0], (user, error) -> {
|
||||
if (error != null) {
|
||||
String password = credentials[1];
|
||||
|
||||
if (user != null && user.getPassword() != null && user.checkPassword(password)) {
|
||||
ctx.put("actor", new UserActor(user));
|
||||
ctx.next();
|
||||
return;
|
||||
}
|
||||
if (user != null && user.getPassword() != null && user.checkPassword(password)) {
|
||||
ctx.put("actor", new UserActor(user));
|
||||
ctx.next();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ctx.response().putHeader("WWW-Authenticate", "Basic realm=\"MineHQ\"");
|
||||
ErrorUtils.respondGeneric(ctx, "Failed to authorize as " + credentials[0] + ".");
|
||||
});
|
||||
} else {
|
||||
ctx.response().putHeader("WWW-Authenticate", "Basic realm=\"MineHQ\"");
|
||||
ErrorUtils.respondGeneric(ctx, "Failed to authorize as " + credentials[0] + ".");
|
||||
}
|
||||
|
||||
ctx.response().putHeader("WWW-Authenticate", "Basic realm=\"MineHQ\"");
|
||||
ErrorUtils.respondGeneric(ctx, "Failed to authorize as " + credentials[0] + ".");
|
||||
}
|
||||
|
||||
private void processMHQAuthorization(String authHeader, RoutingContext ctx) {
|
||||
@ -93,4 +98,9 @@ public final class ActorAttributeFilter implements Handler<RoutingContext> {
|
||||
ErrorUtils.respondGeneric(ctx, "Failed to authorize.");
|
||||
}
|
||||
|
||||
public void processNoAuthorization(RoutingContext ctx) {
|
||||
ctx.put("actor", new UnknownActor());
|
||||
ctx.next();
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package net.frozenorb.apiv3.filters;
|
||||
package net.frozenorb.apiv3.handlers;
|
||||
|
||||
import io.vertx.core.Handler;
|
||||
import io.vertx.ext.web.RoutingContext;
|
||||
@ -6,8 +6,9 @@ import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.actors.Actor;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
|
||||
public final class AuthorizationFilter implements Handler<RoutingContext> {
|
||||
public final class AuthorizationHandler implements Handler<RoutingContext> {
|
||||
|
||||
@Override
|
||||
public void handle(RoutingContext ctx) {
|
||||
Actor actor = ctx.get("actor");
|
||||
|
@ -1,4 +1,4 @@
|
||||
package net.frozenorb.apiv3.filters;
|
||||
package net.frozenorb.apiv3.handlers;
|
||||
|
||||
import io.vertx.core.Handler;
|
||||
import io.vertx.ext.web.RoutingContext;
|
||||
@ -6,6 +6,7 @@ import net.frozenorb.apiv3.APIv3;
|
||||
|
||||
public final class MetricsHandler implements Handler<RoutingContext> {
|
||||
|
||||
@Override
|
||||
public void handle(RoutingContext ctx) {
|
||||
APIv3.getStatsD().incrementCounter("apiv3.http.requests");
|
||||
ctx.next();
|
@ -1,9 +1,9 @@
|
||||
package net.frozenorb.apiv3.models;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.mongodb.async.SingleResultCallback;
|
||||
import com.mongodb.async.client.MongoCollection;
|
||||
import eu.dozd.mongo.annotation.Entity;
|
||||
import eu.dozd.mongo.annotation.Id;
|
||||
import fr.javatic.mongo.jacksonCodec.objectId.Id;
|
||||
import lombok.Getter;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.actors.Actor;
|
||||
@ -15,12 +15,8 @@ import net.frozenorb.apiv3.utils.SyncUtils;
|
||||
import org.bson.Document;
|
||||
import org.bson.types.ObjectId;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
|
||||
@Entity
|
||||
public final class AuditLogEntry {
|
||||
|
||||
private static final MongoCollection<AuditLogEntry> auditLogCollection = APIv3.getDatabase().getCollection("auditLog", AuditLogEntry.class);
|
||||
@ -34,22 +30,46 @@ public final class AuditLogEntry {
|
||||
@Getter private AuditLogActionType type;
|
||||
@Getter private Map<String, Object> metadata;
|
||||
|
||||
public static List<AuditLogEntry> findAll() {
|
||||
public static List<AuditLogEntry> findAllSync() {
|
||||
return SyncUtils.blockMulti(auditLogCollection.find());
|
||||
}
|
||||
|
||||
public static AuditLogEntry findById(String id) {
|
||||
public static List<AuditLogEntry> findAllPaginatedSync(int skip, int pageSize) {
|
||||
return SyncUtils.blockMulti(auditLogCollection.find().sort(new Document("performedAt", 1)).skip(skip).limit(pageSize));
|
||||
}
|
||||
|
||||
public static AuditLogEntry findByIdSync(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> findByUserSync(User user) {
|
||||
return findByUserSync(user.getId());
|
||||
}
|
||||
|
||||
public static List<AuditLogEntry> findByUser(UUID user) {
|
||||
public static List<AuditLogEntry> findByUserSync(UUID user) {
|
||||
return SyncUtils.blockMulti(auditLogCollection.find(new Document("user", user)));
|
||||
}
|
||||
|
||||
public static void findAll(SingleResultCallback<List<AuditLogEntry>> callback) {
|
||||
auditLogCollection.find().into(new ArrayList<>(), callback);
|
||||
}
|
||||
|
||||
public static void findAllPaginated(int skip, int pageSize, SingleResultCallback<List<AuditLogEntry>> callback) {
|
||||
auditLogCollection.find().sort(new Document("performedAt", 1)).skip(skip).limit(pageSize).into(new ArrayList<>(), callback);
|
||||
}
|
||||
|
||||
public static void findById(String id, SingleResultCallback<AuditLogEntry> callback) {
|
||||
auditLogCollection.find(new Document("_id", id)).first(callback);
|
||||
}
|
||||
|
||||
public static void findByUser(User user, SingleResultCallback<List<AuditLogEntry>> callback) {
|
||||
findByUser(user.getId(), callback);
|
||||
}
|
||||
|
||||
public static void findByUser(UUID user, SingleResultCallback<List<AuditLogEntry>> callback) {
|
||||
auditLogCollection.find(new Document("user", user)).into(new ArrayList<>(), callback);
|
||||
}
|
||||
|
||||
public AuditLogEntry() {} // For Morphia
|
||||
|
||||
public AuditLogEntry(User user, String userIp, Actor actor, AuditLogActionType type, Map<String, Object> metadata) {
|
||||
|
@ -1,11 +1,10 @@
|
||||
package net.frozenorb.apiv3.models;
|
||||
|
||||
import com.google.common.collect.Collections2;
|
||||
import com.mongodb.async.SingleResultCallback;
|
||||
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 fr.javatic.mongo.jacksonCodec.objectId.Id;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
@ -16,7 +15,6 @@ import org.bson.types.ObjectId;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Entity
|
||||
@AllArgsConstructor
|
||||
public final class Grant {
|
||||
|
||||
@ -36,26 +34,74 @@ public final class Grant {
|
||||
@Getter private Date removedAt;
|
||||
@Getter private String removalReason;
|
||||
|
||||
public static List<Grant> findAll() {
|
||||
public static List<Grant> findAllSync() {
|
||||
return SyncUtils.blockMulti(grantsCollection.find());
|
||||
}
|
||||
|
||||
public static List<Grant> findByRank(Iterable<Rank> ranks) {
|
||||
public static List<Grant> findAllPaginatedSync(int skip, int pageSize) {
|
||||
return SyncUtils.blockMulti(grantsCollection.find().sort(new Document("addedAt", 1)).skip(skip).limit(pageSize));
|
||||
}
|
||||
|
||||
public static List<Grant> findByRankSync(Iterable<Rank> ranks) {
|
||||
return SyncUtils.blockMulti(grantsCollection.find(new Document("rank", new Document("$in", ranks))));
|
||||
}
|
||||
|
||||
public static Grant findById(String id) {
|
||||
public static Grant findByIdSync(String id) {
|
||||
return SyncUtils.blockOne(grantsCollection.find(new Document("_id", id)));
|
||||
}
|
||||
|
||||
public static List<Grant> findByUser(User user) {
|
||||
return findByUser(user.getId());
|
||||
public static List<Grant> findByUserSync(User user) {
|
||||
return findByUserSync(user.getId());
|
||||
}
|
||||
|
||||
public static List<Grant> findByUser(UUID user) {
|
||||
public static List<Grant> findByUserSync(UUID user) {
|
||||
return SyncUtils.blockMulti(grantsCollection.find(new Document("user", user)));
|
||||
}
|
||||
|
||||
public static void findAll(SingleResultCallback<List<Grant>> callback) {
|
||||
grantsCollection.find().into(new ArrayList<>(), callback);
|
||||
}
|
||||
|
||||
public static void findAllPaginated(int skip, int pageSize, SingleResultCallback<List<Grant>> callback) {
|
||||
grantsCollection.find().sort(new Document("addedAt", 1)).skip(skip).limit(pageSize).into(new ArrayList<>(), callback);
|
||||
}
|
||||
|
||||
public static void findByRank(Iterable<Rank> ranks, SingleResultCallback<List<Grant>> callback) {
|
||||
grantsCollection.find(new Document("rank", new Document("$in", ranks))).into(new ArrayList<>(), callback);
|
||||
}
|
||||
|
||||
public static void findById(String id, SingleResultCallback<Grant> callback) {
|
||||
grantsCollection.find(new Document("_id", id)).first(callback);
|
||||
}
|
||||
|
||||
public static void findByUser(User user, SingleResultCallback<List<Grant>> callback) {
|
||||
findByUser(user.getId(), callback);
|
||||
}
|
||||
|
||||
public static void findByUser(UUID user, SingleResultCallback<List<Grant>> callback) {
|
||||
grantsCollection.find(new Document("user", user)).into(new ArrayList<>(), callback);
|
||||
}
|
||||
|
||||
public static void findByUserGrouped(Iterable<UUID> users, SingleResultCallback<Map<UUID, List<Grant>>> callback) {
|
||||
grantsCollection.find(new Document("user", new Document("$in", users))).into(new ArrayList<>(), (grants, error) -> {
|
||||
if (error != null) {
|
||||
callback.onResult(null, error);
|
||||
} else {
|
||||
Map<UUID, List<Grant>> result = new HashMap<>();
|
||||
|
||||
for (UUID user : users) {
|
||||
result.put(user, new ArrayList<>());
|
||||
}
|
||||
|
||||
for (Grant grant : grants) {
|
||||
result.get(grant.getUser()).add(grant);
|
||||
}
|
||||
|
||||
callback.onResult(result, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Grant() {} // For Morphia
|
||||
|
||||
public Grant(User user, String reason, Set<ServerGroup> scopes, Rank rank, Date expiresAt, User addedBy) {
|
||||
|
@ -1,8 +1,9 @@
|
||||
package net.frozenorb.apiv3.models;
|
||||
|
||||
import com.mongodb.async.SingleResultCallback;
|
||||
import com.mongodb.async.client.MongoCollection;
|
||||
import eu.dozd.mongo.annotation.Entity;
|
||||
import eu.dozd.mongo.annotation.Id;
|
||||
import com.mongodb.client.result.UpdateResult;
|
||||
import fr.javatic.mongo.jacksonCodec.objectId.Id;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
@ -11,11 +12,11 @@ import net.frozenorb.apiv3.utils.SyncUtils;
|
||||
import org.bson.Document;
|
||||
import org.bson.types.ObjectId;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
@AllArgsConstructor
|
||||
public final class IPLogEntry {
|
||||
|
||||
@ -28,30 +29,54 @@ public final class IPLogEntry {
|
||||
@Getter private Date lastSeenAt;
|
||||
@Getter private int uses;
|
||||
|
||||
public static List<IPLogEntry> findAll() {
|
||||
public static List<IPLogEntry> findAllSync() {
|
||||
return SyncUtils.blockMulti(ipLogCollection.find());
|
||||
}
|
||||
|
||||
public static IPLogEntry findById(String id) {
|
||||
public static IPLogEntry findByIdSync(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> findByUserSync(User user) {
|
||||
return findByUserSync(user.getId());
|
||||
}
|
||||
|
||||
public static List<IPLogEntry> findByUser(UUID user) {
|
||||
public static List<IPLogEntry> findByUserSync(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 findByUserAndIpSync(User user, String userIp) {
|
||||
return findByUserAndIpSync(user.getId(), userIp);
|
||||
}
|
||||
|
||||
public static IPLogEntry findByUserAndIp(UUID user, String userIp) {
|
||||
public static IPLogEntry findByUserAndIpSync(UUID user, String userIp) {
|
||||
return SyncUtils.blockOne(ipLogCollection.find(new Document("user", user).append("userIp", userIp)));
|
||||
}
|
||||
|
||||
public static void findAll(SingleResultCallback<List<IPLogEntry>> callback) {
|
||||
ipLogCollection.find().into(new ArrayList<>(), callback);
|
||||
}
|
||||
|
||||
public static void findById(String id, SingleResultCallback<IPLogEntry> callback) {
|
||||
ipLogCollection.find(new Document("_id", id)).first(callback);
|
||||
}
|
||||
|
||||
public static void findByUser(User user, SingleResultCallback<List<IPLogEntry>> callback) {
|
||||
findByUser(user.getId(), callback);
|
||||
}
|
||||
|
||||
public static void findByUser(UUID user, SingleResultCallback<List<IPLogEntry>> callback) {
|
||||
ipLogCollection.find(new Document("user", user)).into(new ArrayList<>(), callback);
|
||||
}
|
||||
|
||||
public static void findByUserAndIp(User user, String userIp, SingleResultCallback<IPLogEntry> callback) {
|
||||
findByUserAndIp(user.getId(), userIp, callback);
|
||||
}
|
||||
|
||||
public static void findByUserAndIp(UUID user, String userIp, SingleResultCallback<IPLogEntry> callback) {
|
||||
ipLogCollection.find(new Document("user", user).append("userIp", userIp)).first(callback);
|
||||
}
|
||||
|
||||
public IPLogEntry() {} // For Morphia
|
||||
|
||||
public IPLogEntry(User user, String userIp) {
|
||||
@ -74,4 +99,10 @@ public final class IPLogEntry {
|
||||
callback.get();
|
||||
}
|
||||
|
||||
public void save() {
|
||||
BlockingCallback<UpdateResult> callback = new BlockingCallback<>();
|
||||
ipLogCollection.replaceOne(new Document("_id", id), this, callback);
|
||||
callback.get();
|
||||
}
|
||||
|
||||
}
|
@ -1,21 +1,22 @@
|
||||
package net.frozenorb.apiv3.models;
|
||||
|
||||
import com.mongodb.async.SingleResultCallback;
|
||||
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 fr.javatic.mongo.jacksonCodec.objectId.Id;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.unsorted.BlockingCallback;
|
||||
import net.frozenorb.apiv3.unsorted.Notification;
|
||||
import net.frozenorb.apiv3.utils.SyncUtils;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Entity
|
||||
public final class NotificationTemplate {
|
||||
|
||||
private static final MongoCollection<NotificationTemplate> notificationTemplatesCollection = APIv3.getDatabase().getCollection("notificationTemplates", NotificationTemplate.class);
|
||||
@ -24,14 +25,22 @@ public final class NotificationTemplate {
|
||||
@Getter @Setter private String subject;
|
||||
@Getter @Setter private String body;
|
||||
|
||||
public static List<NotificationTemplate> findAll() {
|
||||
public static List<NotificationTemplate> findAllSync() {
|
||||
return SyncUtils.blockMulti(notificationTemplatesCollection.find());
|
||||
}
|
||||
|
||||
public static NotificationTemplate findById(String id) {
|
||||
public static NotificationTemplate findByIdSync(String id) {
|
||||
return SyncUtils.blockOne(notificationTemplatesCollection.find(new Document("_id", id)));
|
||||
}
|
||||
|
||||
public static void findAll(SingleResultCallback<List<NotificationTemplate>> callback) {
|
||||
notificationTemplatesCollection.find().into(new ArrayList<>(), callback);
|
||||
}
|
||||
|
||||
public static void findById(String id, SingleResultCallback<NotificationTemplate> callback) {
|
||||
notificationTemplatesCollection.find(new Document("_id", id)).first(callback);
|
||||
}
|
||||
|
||||
public NotificationTemplate() {} // For Morphia
|
||||
|
||||
public NotificationTemplate(String id, String subject, String body) {
|
||||
|
@ -1,9 +1,9 @@
|
||||
package net.frozenorb.apiv3.models;
|
||||
|
||||
import com.mongodb.async.SingleResultCallback;
|
||||
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 fr.javatic.mongo.jacksonCodec.objectId.Id;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
@ -17,7 +17,6 @@ import org.bson.types.ObjectId;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Entity
|
||||
@AllArgsConstructor
|
||||
public final class Punishment {
|
||||
|
||||
@ -39,34 +38,90 @@ public final class Punishment {
|
||||
@Getter private Date removedAt;
|
||||
@Getter private String removalReason;
|
||||
|
||||
public static List<Punishment> findAll() {
|
||||
public static List<Punishment> findAllSync() {
|
||||
return SyncUtils.blockMulti(punishmentsCollection.find());
|
||||
}
|
||||
|
||||
public static List<Punishment> findByType(Iterable<PunishmentType> types) {
|
||||
public static List<Punishment> findAllPaginatedSync(int skip, int pageSize) {
|
||||
return SyncUtils.blockMulti(punishmentsCollection.find().sort(new Document("addedAt", 1)).skip(skip).limit(pageSize));
|
||||
}
|
||||
|
||||
public static List<Punishment> findByTypeSync(Iterable<PunishmentType> types) {
|
||||
return SyncUtils.blockMulti(punishmentsCollection.find(new Document("type", new Document("$in", types))));
|
||||
}
|
||||
|
||||
public static Punishment findById(String id) {
|
||||
public static Punishment findByIdSync(String id) {
|
||||
return SyncUtils.blockOne(punishmentsCollection.find(new Document("_id", id)));
|
||||
}
|
||||
|
||||
public static List<Punishment> findByUser(User user) {
|
||||
return findByUser(user.getId());
|
||||
public static List<Punishment> findByUserSync(User user) {
|
||||
return findByUserSync(user.getId());
|
||||
}
|
||||
|
||||
public static List<Punishment> findByUser(UUID user) {
|
||||
public static List<Punishment> findByUserSync(UUID user) {
|
||||
return SyncUtils.blockMulti(punishmentsCollection.find(new Document("user", user)));
|
||||
}
|
||||
|
||||
public static List<Punishment> findByUserAndType(User user, Iterable<PunishmentType> types) {
|
||||
return findByUserAndType(user.getId(), types);
|
||||
public static List<Punishment> findByUserAndTypeSync(User user, Iterable<PunishmentType> types) {
|
||||
return findByUserAndTypeSync(user.getId(), types);
|
||||
}
|
||||
|
||||
public static List<Punishment> findByUserAndType(UUID user, Iterable<PunishmentType> types) {
|
||||
public static List<Punishment> findByUserAndTypeSync(UUID user, Iterable<PunishmentType> types) {
|
||||
return SyncUtils.blockMulti(punishmentsCollection.find(new Document("user", user).append("type", new Document("$in", types))));
|
||||
}
|
||||
|
||||
public static void findAll(SingleResultCallback<List<Punishment>> callback) {
|
||||
punishmentsCollection.find().into(new ArrayList<>(), callback);
|
||||
}
|
||||
|
||||
public static void findAllPaginated(int skip, int pageSize, SingleResultCallback<List<Punishment>> callback) {
|
||||
punishmentsCollection.find().sort(new Document("addedAt", 1)).skip(skip).limit(pageSize).into(new ArrayList<>(), callback);
|
||||
}
|
||||
|
||||
public static void findByType(Iterable<PunishmentType> types, SingleResultCallback<List<Punishment>> callback) {
|
||||
punishmentsCollection.find(new Document("type", new Document("$in", types))).into(new ArrayList<>(), callback);
|
||||
}
|
||||
|
||||
public static void findById(String id, SingleResultCallback<Punishment> callback) {
|
||||
punishmentsCollection.find(new Document("_id", id)).first(callback);
|
||||
}
|
||||
|
||||
public static void findByUser(User user, SingleResultCallback<List<Punishment>> callback) {
|
||||
findByUser(user.getId(), callback);
|
||||
}
|
||||
|
||||
public static void findByUser(UUID user, SingleResultCallback<List<Punishment>> callback) {
|
||||
punishmentsCollection.find(new Document("user", user)).into(new ArrayList<>(), callback);
|
||||
}
|
||||
|
||||
public static void findByUserGrouped(Iterable<UUID> users, SingleResultCallback<Map<UUID, List<Punishment>>> callback) {
|
||||
punishmentsCollection.find(new Document("user", new Document("$in", users))).into(new ArrayList<>(), (punishments, error) -> {
|
||||
if (error != null) {
|
||||
callback.onResult(null, error);
|
||||
} else {
|
||||
Map<UUID, List<Punishment>> result = new HashMap<>();
|
||||
|
||||
for (UUID user : users) {
|
||||
result.put(user, new ArrayList<>());
|
||||
}
|
||||
|
||||
for (Punishment punishment : punishments) {
|
||||
result.get(punishment.getUser()).add(punishment);
|
||||
}
|
||||
|
||||
callback.onResult(result, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void findByUserAndType(User user, Iterable<PunishmentType> types, SingleResultCallback<List<Punishment>> callback) {
|
||||
findByUserAndType(user.getId(), types, callback);
|
||||
}
|
||||
|
||||
public static void findByUserAndType(UUID user, Iterable<PunishmentType> types, SingleResultCallback<List<Punishment>> callback) {
|
||||
punishmentsCollection.find(new Document("user", user).append("type", new Document("$in", types))).into(new ArrayList<>(), callback);
|
||||
}
|
||||
|
||||
public Punishment() {} // For Morphia
|
||||
|
||||
public Punishment(User user, String reason, PunishmentType type, Date expiresAt, User addedBy, Actor actor, Map<String, Object> metadata) {
|
||||
|
@ -5,8 +5,7 @@ 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 fr.javatic.mongo.jacksonCodec.objectId.Id;
|
||||
import lombok.Getter;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.unsorted.BlockingCallback;
|
||||
@ -19,7 +18,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Entity
|
||||
public final class Rank {
|
||||
|
||||
private static final MongoCollection<Rank> ranksCollection = APIv3.getDatabase().getCollection("ranks", Rank.class);
|
||||
|
@ -4,8 +4,7 @@ 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 fr.javatic.mongo.jacksonCodec.objectId.Id;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
@ -17,7 +16,6 @@ import org.bson.Document;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Entity
|
||||
public final class Server {
|
||||
|
||||
private static final MongoCollection<Server> serversCollection = APIv3.getDatabase().getCollection("servers", Server.class);
|
||||
|
@ -4,8 +4,7 @@ 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 fr.javatic.mongo.jacksonCodec.objectId.Id;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
@ -18,7 +17,6 @@ import org.bson.Document;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Entity
|
||||
public final class ServerGroup {
|
||||
|
||||
private static final MongoCollection<ServerGroup> serverGroupsCollection = APIv3.getDatabase().getCollection("serverGroups", ServerGroup.class);
|
||||
@ -29,8 +27,6 @@ public final class ServerGroup {
|
||||
|
||||
@Getter @Id private String id;
|
||||
@Getter private String image;
|
||||
// We rename this to public (only to gson), we just can't name it that because it's a Java identifier.
|
||||
@Getter @SerializedName("public") private boolean isPublic;
|
||||
// We define these HashSets up here because, in the event they're
|
||||
// empty, Morphia will load them as null, not empty sets.
|
||||
@Getter @Setter @ExcludeFromReplies private Set<String> announcements = new HashSet<>();
|
||||
@ -48,10 +44,9 @@ public final class ServerGroup {
|
||||
|
||||
public ServerGroup() {} // For Morphia
|
||||
|
||||
public ServerGroup(String id, String image, boolean isPublic) {
|
||||
public ServerGroup(String id, String image) {
|
||||
this.id = id;
|
||||
this.image = image;
|
||||
this.isPublic = isPublic;
|
||||
}
|
||||
|
||||
public Map<String, Boolean> calculatePermissions(Rank userRank) {
|
||||
|
@ -1,18 +1,22 @@
|
||||
package net.frozenorb.apiv3.models;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.hash.Hashing;
|
||||
import com.mongodb.async.SingleResultCallback;
|
||||
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 fr.javatic.mongo.jacksonCodec.objectId.Id;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.serialization.ExcludeFromReplies;
|
||||
import net.frozenorb.apiv3.serialization.UUIDJsonDeserializer;
|
||||
import net.frozenorb.apiv3.serialization.UUIDJsonSerializer;
|
||||
import net.frozenorb.apiv3.unsorted.BlockingCallback;
|
||||
import net.frozenorb.apiv3.utils.MojangUtils;
|
||||
import net.frozenorb.apiv3.utils.PermissionUtils;
|
||||
@ -22,13 +26,12 @@ import org.bson.Document;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Entity
|
||||
@AllArgsConstructor
|
||||
public final class User {
|
||||
|
||||
private static final MongoCollection<User> usersCollection = APIv3.getDatabase().getCollection("users", User.class);
|
||||
|
||||
@Getter @Id private UUID id;
|
||||
@Getter @Id @JsonSerialize(using=UUIDJsonSerializer.class) @JsonDeserialize(using=UUIDJsonDeserializer.class) private UUID id;
|
||||
@Getter private String lastUsername;
|
||||
@Getter @ExcludeFromReplies private Map<String, Date> aliases = new HashMap<>();
|
||||
@Getter @ExcludeFromReplies @Setter private String totpSecret;
|
||||
@ -42,11 +45,11 @@ public final class User {
|
||||
@Getter private Date firstSeenAt;
|
||||
@Getter private boolean online;
|
||||
|
||||
public static List<User> findAll() {
|
||||
public static List<User> findAllSync() {
|
||||
return SyncUtils.blockMulti(usersCollection.find());
|
||||
}
|
||||
|
||||
public static User findById(String id) {
|
||||
public static User findByIdSync(String id) {
|
||||
UUID uuid;
|
||||
|
||||
try {
|
||||
@ -55,10 +58,10 @@ public final class User {
|
||||
return null;
|
||||
}
|
||||
|
||||
return findById(uuid);
|
||||
return findByIdSync(uuid);
|
||||
}
|
||||
|
||||
public static User findById(UUID id) {
|
||||
public static User findByIdSync(UUID id) {
|
||||
if (UUIDUtils.isAcceptableUUID(id)) {
|
||||
return SyncUtils.blockOne(usersCollection.find(new Document("_id", id)));
|
||||
} else {
|
||||
@ -66,14 +69,63 @@ public final class User {
|
||||
}
|
||||
}
|
||||
|
||||
public static User findByEmailToken(String emailToken) {
|
||||
public static User findByEmailTokenSync(String emailToken) {
|
||||
return SyncUtils.blockOne(usersCollection.find(new Document("emailToken", emailToken)));
|
||||
}
|
||||
|
||||
public static User findByLastUsername(String lastUsername) {
|
||||
public static User findByLastUsernameSync(String lastUsername) {
|
||||
return SyncUtils.blockOne(usersCollection.find(new Document("lastUsername", lastUsername)));
|
||||
}
|
||||
|
||||
public static void findAll(SingleResultCallback<List<User>> callback) {
|
||||
usersCollection.find().into(new ArrayList<>(), callback);
|
||||
}
|
||||
|
||||
public static void findById(String id, SingleResultCallback<User> callback) {
|
||||
try {
|
||||
UUID uuid = UUID.fromString(id);
|
||||
findById(uuid, callback);
|
||||
} catch (IllegalArgumentException ex) { // from UUID parsing
|
||||
callback.onResult(null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static void findById(UUID id, SingleResultCallback<User> callback) {
|
||||
if (UUIDUtils.isAcceptableUUID(id)) {
|
||||
usersCollection.find(new Document("_id", id)).first(callback);
|
||||
} else {
|
||||
callback.onResult(null, null);
|
||||
}
|
||||
}
|
||||
|
||||
public static void findByIdGrouped(Iterable<UUID> search, SingleResultCallback<Map<UUID, User>> callback) {
|
||||
usersCollection.find(new Document("_id", new Document("$in", search))).into(new ArrayList<>(), (users, error) -> {
|
||||
if (error != null) {
|
||||
callback.onResult(null, error);
|
||||
} else {
|
||||
Map<UUID, User> result = new HashMap<>();
|
||||
|
||||
for (UUID user : search) {
|
||||
result.put(user, null);
|
||||
}
|
||||
|
||||
for (User user : users) {
|
||||
result.put(user.getId(), user);
|
||||
}
|
||||
|
||||
callback.onResult(result, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void findByEmailToken(String emailToken, SingleResultCallback<User> callback) {
|
||||
usersCollection.find(new Document("emailToken", emailToken)).first(callback);
|
||||
}
|
||||
|
||||
public static void findByLastUsername(String lastUsername, SingleResultCallback<User> callback) {
|
||||
usersCollection.find(new Document("lastUsername", lastUsername)).first(callback);
|
||||
}
|
||||
|
||||
public User() {} // For Morphia
|
||||
|
||||
public User(UUID id, String lastUsername) {
|
||||
@ -134,8 +186,10 @@ public final class User {
|
||||
|
||||
User withNewUsername;
|
||||
|
||||
while ((withNewUsername = User.findByLastUsername(username)) != null) {
|
||||
String newUsername = MojangUtils.getName(withNewUsername.getId());
|
||||
while ((withNewUsername = User.findByLastUsernameSync(username)) != null) {
|
||||
BlockingCallback<String> callback = new BlockingCallback<>();
|
||||
MojangUtils.getName(withNewUsername.getId(), callback);
|
||||
String newUsername = callback.get();
|
||||
withNewUsername.updateUsername(newUsername);
|
||||
}
|
||||
}
|
||||
@ -164,7 +218,7 @@ public final class User {
|
||||
}
|
||||
|
||||
public Rank getHighestRankScoped(ServerGroup serverGroup) {
|
||||
return getHighestRankScoped(serverGroup, Grant.findByUser(this));
|
||||
return getHighestRankScoped(serverGroup, Grant.findByUserSync(this));
|
||||
}
|
||||
|
||||
// TODO: Clean
|
||||
@ -195,7 +249,7 @@ public final class User {
|
||||
public Map<ServerGroup, Rank> getHighestRanks() {
|
||||
Map<ServerGroup, Rank> highestRanks = new HashMap<>();
|
||||
Rank defaultRank = Rank.findById("default");
|
||||
List<Grant> userGrants = Grant.findByUser(this);
|
||||
List<Grant> userGrants = Grant.findByUserSync(this);
|
||||
|
||||
for (ServerGroup serverGroup : ServerGroup.findAll()) {
|
||||
Rank highest = defaultRank;
|
||||
@ -221,12 +275,12 @@ public final class User {
|
||||
public Map<String, Object> getLoginInfo(Server server) {
|
||||
return createLoginInfo(
|
||||
server,
|
||||
Punishment.findByUserAndType(this, ImmutableSet.of(
|
||||
Punishment.findByUserAndTypeSync(this, ImmutableSet.of(
|
||||
Punishment.PunishmentType.BLACKLIST,
|
||||
Punishment.PunishmentType.BAN,
|
||||
Punishment.PunishmentType.MUTE
|
||||
)),
|
||||
Grant.findByUser(this)
|
||||
Grant.findByUserSync(this)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
package net.frozenorb.apiv3.models;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.mongodb.async.SingleResultCallback;
|
||||
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 fr.javatic.mongo.jacksonCodec.objectId.Id;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
@ -14,11 +14,11 @@ import net.frozenorb.apiv3.utils.SyncUtils;
|
||||
import org.bson.Document;
|
||||
import org.bson.types.ObjectId;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
public final class UserMetaEntry {
|
||||
|
||||
private static final MongoCollection<UserMetaEntry> userMetaCollection = APIv3.getDatabase().getCollection("userMeta", UserMetaEntry.class);
|
||||
@ -28,22 +28,38 @@ public final class UserMetaEntry {
|
||||
@Getter private String serverGroup;
|
||||
@Getter @Setter private Map<String, Object> data;
|
||||
|
||||
public static List<UserMetaEntry> findAll() {
|
||||
public static List<UserMetaEntry> findAllSync() {
|
||||
return SyncUtils.blockMulti(userMetaCollection.find());
|
||||
}
|
||||
|
||||
public static UserMetaEntry findById(String id) {
|
||||
public static UserMetaEntry findByIdSync(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 findByUserAndGroupSync(User user, ServerGroup serverGroup) {
|
||||
return findByUserAndGroupSync(user.getId(), serverGroup);
|
||||
}
|
||||
|
||||
public static UserMetaEntry findByUserAndGroup(UUID user, ServerGroup serverGroup) {
|
||||
public static UserMetaEntry findByUserAndGroupSync(UUID user, ServerGroup serverGroup) {
|
||||
return SyncUtils.blockOne(userMetaCollection.find(new Document("user", user).append("serverGroup", serverGroup.getId())));
|
||||
}
|
||||
|
||||
public static void findAll(SingleResultCallback<List<UserMetaEntry>> callback) {
|
||||
userMetaCollection.find().into(new ArrayList<>(), callback);
|
||||
}
|
||||
|
||||
public static void findById(String id, SingleResultCallback<UserMetaEntry> callback) {
|
||||
userMetaCollection.find(new Document("_id", id)).first(callback);
|
||||
}
|
||||
|
||||
public static void findByUserAndGroup(User user, ServerGroup serverGroup, SingleResultCallback<UserMetaEntry> callback) {
|
||||
findByUserAndGroup(user.getId(), serverGroup, callback);
|
||||
}
|
||||
|
||||
public static void findByUserAndGroup(UUID user, ServerGroup serverGroup, SingleResultCallback<UserMetaEntry> callback) {
|
||||
userMetaCollection.find(new Document("user", user).append("serverGroup", serverGroup.getId())).first(callback);
|
||||
}
|
||||
|
||||
public UserMetaEntry() {} // For Morphia
|
||||
|
||||
public UserMetaEntry(User user, ServerGroup serverGroup, Map<String, Object> data) {
|
||||
|
@ -29,8 +29,7 @@ public final class GETDump implements Handler<RoutingContext> {
|
||||
List<UUID> banCache = new ArrayList<>();
|
||||
List<UUID> blacklistCache = new ArrayList<>();
|
||||
|
||||
Punishment.findByType
|
||||
(ImmutableSet.of(
|
||||
Punishment.findByTypeSync(ImmutableSet.of(
|
||||
Punishment.PunishmentType.BAN,
|
||||
Punishment.PunishmentType.BLACKLIST
|
||||
)).forEach((punishment) -> {
|
||||
@ -52,7 +51,7 @@ public final class GETDump implements Handler<RoutingContext> {
|
||||
if (tick == 0 || tick % 2 == 0) {
|
||||
Map<String, List<UUID>> grantCache = new HashMap<>();
|
||||
|
||||
Grant.findAll().forEach((grant) -> {
|
||||
Grant.findAllSync().forEach((grant) -> {
|
||||
if (grant.isActive()) {
|
||||
List<UUID> users = grantCache.get(grant.getRank());
|
||||
|
||||
|
@ -10,12 +10,12 @@ public final class GETAuditLog implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
try {
|
||||
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 skip = ctx.request().getParam("skip") == null ? 0 : Integer.parseInt(ctx.request().getParam("skip"));
|
||||
int pageSize = ctx.request().getParam("pageSize") == null ? 100 : Integer.parseInt(ctx.request().getParam("pageSize"));
|
||||
|
||||
APIv3.respondJson(ctx, APIv3.getDatastore().createQuery(AuditLogEntry.class).order("performedAt").limit(limit).offset(offset).asList());
|
||||
APIv3.respondJson(ctx, AuditLogEntry.findAllPaginatedSync(skip, pageSize));
|
||||
} catch (NumberFormatException ex) {
|
||||
ErrorUtils.respondInvalidInput(ctx, "limit/offset must be numerical inputs.");
|
||||
ErrorUtils.respondInvalidInput(ctx, "skip and pageSize must be numerical inputs.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
public final class DELETEGrant implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
Grant grant = Grant.findById(ctx.request().getParam("id"));
|
||||
Grant grant = Grant.findByIdSync(ctx.request().getParam("id"));
|
||||
|
||||
if (grant == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "Grant", ctx.request().getParam("id"));
|
||||
@ -23,7 +23,7 @@ public final class DELETEGrant implements Handler<RoutingContext> {
|
||||
return;
|
||||
}
|
||||
|
||||
User removedBy = User.findById(ctx.request().getParam("removedBy"));
|
||||
User removedBy = User.findByIdSync(ctx.request().getParam("removedBy"));
|
||||
|
||||
if (removedBy == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("removedBy"));
|
||||
|
@ -8,7 +8,7 @@ import net.frozenorb.apiv3.models.Grant;
|
||||
public final class GETGrant implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
APIv3.respondJson(ctx, Grant.findById(ctx.request().getParam("id")));
|
||||
APIv3.respondJson(ctx, Grant.findByIdSync(ctx.request().getParam("id")));
|
||||
}
|
||||
|
||||
}
|
@ -10,12 +10,12 @@ public final class GETGrants implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
try {
|
||||
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 skip = ctx.request().getParam("skip") == null ? 0 : Integer.parseInt(ctx.request().getParam("skip"));
|
||||
int pageSize = ctx.request().getParam("pageSize") == null ? 100 : Integer.parseInt(ctx.request().getParam("pageSize"));
|
||||
|
||||
APIv3.respondJson(ctx, APIv3.getDatastore().createQuery(Grant.class).order("addedAt").limit(limit).offset(offset).asList());
|
||||
APIv3.respondJson(ctx, Grant.findAllPaginatedSync(skip, pageSize));
|
||||
} catch (NumberFormatException ex) {
|
||||
ErrorUtils.respondInvalidInput(ctx, "limit and offset must be numerical inputs.");
|
||||
ErrorUtils.respondInvalidInput(ctx, "skip and pageSize must be numerical inputs.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,14 +10,14 @@ import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
public final class GETUserGrants implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
User target = User.findById(ctx.request().getParam("id"));
|
||||
User target = User.findByIdSync(ctx.request().getParam("id"));
|
||||
|
||||
if (target == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
||||
return;
|
||||
}
|
||||
|
||||
APIv3.respondJson(ctx, Grant.findByUser(target));
|
||||
APIv3.respondJson(ctx, Grant.findByUserSync(target));
|
||||
}
|
||||
|
||||
}
|
@ -16,7 +16,7 @@ import java.util.Set;
|
||||
public final class POSTUserGrant implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
User target = User.findById(ctx.request().getParam("id"));
|
||||
User target = User.findByIdSync(ctx.request().getParam("id"));
|
||||
|
||||
if (target == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
||||
@ -67,7 +67,7 @@ public final class POSTUserGrant implements Handler<RoutingContext> {
|
||||
}
|
||||
|
||||
// We purposely don't do a null check, grants don't have to have a source.
|
||||
User addedBy = User.findById(ctx.request().getParam("addedBy"));
|
||||
User addedBy = User.findByIdSync(ctx.request().getParam("addedBy"));
|
||||
|
||||
Grant grant = new Grant(target, reason, scopes, rank, expiresAt, addedBy);
|
||||
grant.insert();
|
||||
|
@ -10,14 +10,14 @@ import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
public final class GETUserIPLog implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
User target = User.findById(ctx.request().getParam("id"));
|
||||
User target = User.findByIdSync(ctx.request().getParam("id"));
|
||||
|
||||
if (target == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
||||
return;
|
||||
}
|
||||
|
||||
APIv3.respondJson(ctx, IPLogEntry.findByUser(target));
|
||||
APIv3.respondJson(ctx, IPLogEntry.findByUserSync(target));
|
||||
}
|
||||
|
||||
}
|
@ -9,7 +9,7 @@ import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
public final class DELETENotificationTemplate implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
NotificationTemplate notificationTemplate = NotificationTemplate.findById(ctx.request().getParam("id"));
|
||||
NotificationTemplate notificationTemplate = NotificationTemplate.findByIdSync(ctx.request().getParam("id"));
|
||||
|
||||
if (notificationTemplate == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "Notification template", ctx.request().getParam("id"));
|
||||
|
@ -8,7 +8,7 @@ import net.frozenorb.apiv3.models.NotificationTemplate;
|
||||
public final class GETNotificationTemplate implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
APIv3.respondJson(ctx, NotificationTemplate.findById(ctx.request().getParam("id")));
|
||||
APIv3.respondJson(ctx, NotificationTemplate.findByIdSync(ctx.request().getParam("id")));
|
||||
}
|
||||
|
||||
}
|
@ -8,7 +8,7 @@ import net.frozenorb.apiv3.models.NotificationTemplate;
|
||||
public final class GETNotificationTemplates implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
APIv3.respondJson(ctx, NotificationTemplate.findAll());
|
||||
APIv3.respondJson(ctx, NotificationTemplate.findAllSync());
|
||||
}
|
||||
|
||||
}
|
@ -13,7 +13,7 @@ import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
public final class DELETEPunishment implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
Punishment punishment = Punishment.findById(ctx.request().getParam("id"));
|
||||
Punishment punishment = Punishment.findByIdSync(ctx.request().getParam("id"));
|
||||
|
||||
if (punishment == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "Punishment", ctx.request().getParam("id"));
|
||||
@ -23,7 +23,7 @@ public final class DELETEPunishment implements Handler<RoutingContext> {
|
||||
return;
|
||||
}
|
||||
|
||||
User removedBy = User.findById(ctx.request().getParam("removedBy"));
|
||||
User removedBy = User.findByIdSync(ctx.request().getParam("removedBy"));
|
||||
|
||||
if (removedBy == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("removedBy"));
|
||||
|
@ -8,7 +8,7 @@ import net.frozenorb.apiv3.models.Punishment;
|
||||
public final class GETPunishment implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
APIv3.respondJson(ctx, Punishment.findById(ctx.request().getParam("id")));
|
||||
APIv3.respondJson(ctx, Punishment.findByIdSync(ctx.request().getParam("id")));
|
||||
}
|
||||
|
||||
}
|
@ -10,12 +10,12 @@ public final class GETPunishments implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
try {
|
||||
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 skip = ctx.request().getParam("skip") == null ? 0 : Integer.parseInt(ctx.request().getParam("skip"));
|
||||
int pageSize = ctx.request().getParam("pageSize") == null ? 100 : Integer.parseInt(ctx.request().getParam("pageSize"));
|
||||
|
||||
APIv3.respondJson(ctx, APIv3.getDatastore().createQuery(Punishment.class).order("addedAt").limit(limit).offset(offset).asList());
|
||||
APIv3.respondJson(ctx, Punishment.findAllPaginatedSync(skip, pageSize));
|
||||
} catch (NumberFormatException ex) {
|
||||
ErrorUtils.respondInvalidInput(ctx, "limit and offset must be numerical inputs.");
|
||||
ErrorUtils.respondInvalidInput(ctx, "skip and pageSize must be numerical inputs.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,14 +10,14 @@ import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
public final class GETUserPunishments implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
User target = User.findById(ctx.request().getParam("id"));
|
||||
User target = User.findByIdSync(ctx.request().getParam("id"));
|
||||
|
||||
if (target == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
||||
return;
|
||||
}
|
||||
|
||||
APIv3.respondJson(ctx, Punishment.findByUser(target));
|
||||
APIv3.respondJson(ctx, Punishment.findByUserSync(target));
|
||||
}
|
||||
|
||||
}
|
@ -17,7 +17,7 @@ import java.util.Map;
|
||||
public final class POSTUserPunish implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
User target = User.findById(ctx.request().getParam("id"));
|
||||
User target = User.findByIdSync(ctx.request().getParam("id"));
|
||||
|
||||
if (target == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
||||
@ -34,9 +34,9 @@ public final class POSTUserPunish implements Handler<RoutingContext> {
|
||||
Punishment.PunishmentType type = Punishment.PunishmentType.valueOf(ctx.request().getParam("type"));
|
||||
|
||||
if (type != Punishment.PunishmentType.WARN) {
|
||||
for (Punishment punishment : Punishment.findByUserAndType(target, ImmutableSet.of(type))) {
|
||||
for (Punishment punishment : Punishment.findByUserAndTypeSync(target, ImmutableSet.of(type))) {
|
||||
if (punishment.isActive()) {
|
||||
ErrorUtils.respondGeneric(ctx, "A punishment by " + User.findById(punishment.getAddedBy()).getLastUsername() + " already covers this user.");
|
||||
ErrorUtils.respondGeneric(ctx, "A punishment by " + User.findByIdSync(punishment.getAddedBy()).getLastUsername() + " already covers this user.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -63,7 +63,7 @@ public final class POSTUserPunish implements Handler<RoutingContext> {
|
||||
}
|
||||
|
||||
// We purposely don't do a null check, grants don't have to have a source.
|
||||
User addedBy = User.findById(ctx.request().getParam("addedBy"));
|
||||
User addedBy = User.findByIdSync(ctx.request().getParam("addedBy"));
|
||||
|
||||
if (target.hasPermissionAnywhere(Permissions.PROTECTED_PUNISHMENT)) {
|
||||
ErrorUtils.respondGeneric(ctx, target.getLastSeenOn() + " is protected from punishments.");
|
||||
|
@ -10,9 +10,8 @@ public final class POSTServerGroup implements Handler<RoutingContext> {
|
||||
public void handle(RoutingContext ctx) {
|
||||
String id = ctx.request().getParam("id");
|
||||
String image = ctx.request().getParam("image");
|
||||
boolean isPublic = Boolean.valueOf(ctx.request().getParam("public"));
|
||||
|
||||
ServerGroup serverGroup = new ServerGroup(id, image, isPublic);
|
||||
ServerGroup serverGroup = new ServerGroup(id, image);
|
||||
serverGroup.insert();
|
||||
APIv3.respondJson(ctx, serverGroup);
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
package net.frozenorb.apiv3.routes.servers;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import io.vertx.core.CompositeFuture;
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.core.Handler;
|
||||
import io.vertx.ext.web.RoutingContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -18,7 +21,6 @@ import java.util.*;
|
||||
@Slf4j
|
||||
public final class POSTServerHeartbeat implements Handler<RoutingContext> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void handle(RoutingContext ctx) {
|
||||
Actor actor = ctx.get("actor");
|
||||
|
||||
@ -27,57 +29,132 @@ public final class POSTServerHeartbeat implements Handler<RoutingContext> {
|
||||
return;
|
||||
}
|
||||
|
||||
Server actorServer = Server.byId(actor.getName());
|
||||
ServerGroup actorServerGroup = ServerGroup.byId(actorServer.getServerGroup());
|
||||
Server actorServer = Server.findById(actor.getName());
|
||||
ServerGroup actorServerGroup = ServerGroup.findById(actorServer.getServerGroup());
|
||||
Document reqJson = Document.parse(ctx.getBodyAsString());
|
||||
Map<UUID, String> onlinePlayersNames = new HashMap<>();
|
||||
Map<UUID, User> onlinePlayersUsers;
|
||||
Map<UUID, List<Grant>> onlinePlayersGrants;
|
||||
Map<UUID, List<Punishment>> onlinePlayersPunishments;
|
||||
Map<String, Object> playersResponse = new HashMap<>();
|
||||
Map<UUID, String> playerNames = extractPlayerNames(reqJson);
|
||||
|
||||
// This code is messy, but we have to do db ops in parallel to avoid
|
||||
// spamming Mongo with queries, so we do this.
|
||||
for (Object player : (List<Object>) reqJson.get("players")) {
|
||||
Document playerJson = (Document) player;
|
||||
UUID uuid = UUID.fromString(playerJson.getString("uuid"));
|
||||
String username = playerJson.getString("username");
|
||||
|
||||
if (UUIDUtils.isAcceptableUUID(uuid)) {
|
||||
onlinePlayersNames.put(uuid, username);
|
||||
CompositeFuture.all(
|
||||
createInfoResponse(actorServer, reqJson.getDouble("tps"), playerNames),
|
||||
createPlayerResponse(actorServer, playerNames),
|
||||
createPermissionsResponse(actorServerGroup),
|
||||
createEventsResponse((List<Object>) reqJson.get("events"))
|
||||
).setHandler((result) -> {
|
||||
if (result.succeeded()) {
|
||||
APIv3.respondJson(ctx, ImmutableMap.of(
|
||||
"info", result.result().result(0),
|
||||
"players", result.result().result(1),
|
||||
"permissions", result.result().result(2),
|
||||
"events", result.result().result(3)
|
||||
));
|
||||
} else {
|
||||
ErrorUtils.respondGeneric(ctx, result.cause().getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Future<Map<String, Object>> createInfoResponse(Server server, double tps, Map<UUID, String> playerNames) {
|
||||
Future<Map<String, Object>> callback = Future.future();
|
||||
|
||||
server.setPlayers(playerNames.keySet());
|
||||
server.setLastTps(tps);
|
||||
server.setLastUpdatedAt(new Date());
|
||||
server.save();
|
||||
|
||||
return callback;
|
||||
}
|
||||
|
||||
public Future<Map<String, Object>> createPlayerResponse(Server server, Map<UUID, String> playerNames) {
|
||||
Future<Map<String, Object>> callback = Future.future();
|
||||
|
||||
Future<Map<UUID, User>> userLookupCallback = Future.future();
|
||||
Future<Map<UUID, List<Grant>>> grantLookupCallback = Future.future();
|
||||
Future<Map<UUID, List<Punishment>>> punishmentLookupCallback = Future.future();
|
||||
|
||||
User.findByIdGrouped(playerNames.keySet(), (users, error) -> {
|
||||
if (error != null) {
|
||||
userLookupCallback.fail(error);
|
||||
} else {
|
||||
userLookupCallback.complete(users);
|
||||
}
|
||||
});
|
||||
|
||||
Grant.findByUserGrouped(playerNames.keySet(), (grants, error) -> {
|
||||
if (error != null) {
|
||||
grantLookupCallback.fail(error);
|
||||
} else {
|
||||
grantLookupCallback.complete(grants);
|
||||
}
|
||||
});
|
||||
|
||||
Punishment.findByUserGrouped(playerNames.keySet(), (punishments, error) -> {
|
||||
if (error != null) {
|
||||
punishmentLookupCallback.fail(error);
|
||||
} else {
|
||||
punishmentLookupCallback.complete(punishments);
|
||||
}
|
||||
});
|
||||
|
||||
CompositeFuture.all(
|
||||
userLookupCallback,
|
||||
grantLookupCallback,
|
||||
punishmentLookupCallback
|
||||
).setHandler((result) -> {
|
||||
if (result.failed()) {
|
||||
callback.fail(result.cause());
|
||||
} else {
|
||||
Map<UUID, User> users = result.result().result(0);
|
||||
Map<UUID, List<Grant>> grants = result.result().result(1);
|
||||
Map<UUID, List<Punishment>> punishments = result.result().result(2);
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
|
||||
for (Map.Entry<UUID, User> userEntry : users.entrySet()) {
|
||||
UUID uuid = userEntry.getKey();
|
||||
User user = userEntry.getValue();
|
||||
|
||||
if (user == null) {
|
||||
String username = playerNames.get(uuid);
|
||||
user = new User(uuid, username);
|
||||
user.insert();
|
||||
users.put(uuid, user);
|
||||
}
|
||||
|
||||
// Only save if needed
|
||||
if (user.seenOnServer(server)) {
|
||||
user.save();
|
||||
}
|
||||
|
||||
response.put(uuid.toString(), user.createLoginInfo(server, punishments.get(uuid), grants.get(uuid)));
|
||||
}
|
||||
|
||||
callback.complete(response);
|
||||
}
|
||||
});
|
||||
|
||||
return callback;
|
||||
}
|
||||
|
||||
public Future<Map<String, Object>> createPermissionsResponse(ServerGroup serverGroup) {
|
||||
Future<Map<String, Object>> callback = Future.future();
|
||||
Map<String, Object> permissionsResponse = new HashMap<>();
|
||||
|
||||
for (Rank rank : Rank.findAll()) {
|
||||
Map<String, Boolean> scopedPermissions = PermissionUtils.mergePermissions(
|
||||
PermissionUtils.getDefaultPermissions(rank),
|
||||
serverGroup.calculatePermissions(rank)
|
||||
);
|
||||
|
||||
permissionsResponse.put(rank.getId(), scopedPermissions);
|
||||
}
|
||||
|
||||
onlinePlayersUsers = User.byIdGrouped(onlinePlayersNames.keySet());
|
||||
callback.complete(permissionsResponse);
|
||||
return callback;
|
||||
}
|
||||
|
||||
for (Map.Entry<UUID, User> entry : new HashMap<>(onlinePlayersUsers).entrySet()) {
|
||||
UUID uuid = entry.getKey();
|
||||
User user = entry.getValue();
|
||||
public Future<Map<String, Object>> createEventsResponse(List<Object> eventsData) {
|
||||
Future<Map<String, Object>> callback = Future.future();
|
||||
|
||||
if (user == null) {
|
||||
// Will be saved in the User constructor
|
||||
String username = onlinePlayersNames.get(uuid);
|
||||
user = new User(uuid, username);
|
||||
onlinePlayersUsers.put(uuid, user);
|
||||
}
|
||||
|
||||
// Only save if needed
|
||||
if (user.seenOnServer(actorServer)) {
|
||||
APIv3.getDatastore().save(user);
|
||||
}
|
||||
}
|
||||
|
||||
onlinePlayersGrants = Grant.byUserGrouped(onlinePlayersUsers.keySet());
|
||||
onlinePlayersPunishments = Punishment.byUserGrouped(onlinePlayersUsers.keySet());
|
||||
|
||||
for (Map.Entry<UUID, User> entry : onlinePlayersUsers.entrySet()) {
|
||||
UUID uuid = entry.getKey();
|
||||
User user = entry.getValue();
|
||||
|
||||
playersResponse.put(uuid.toString(), user.prepareLoginInfo(actorServer, onlinePlayersPunishments.get(uuid), onlinePlayersGrants.get(uuid)));
|
||||
}
|
||||
|
||||
for (Object event : (List<Object>) reqJson.get("events")) {
|
||||
for (Object event : eventsData) {
|
||||
Document eventJson = (Document) event;
|
||||
String type = eventJson.getString("type");
|
||||
|
||||
@ -93,26 +170,24 @@ public final class POSTServerHeartbeat implements Handler<RoutingContext> {
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Map<String, Boolean>> permissionsResponse = new HashMap<>();
|
||||
callback.complete(ImmutableMap.of());
|
||||
return callback;
|
||||
}
|
||||
|
||||
for (Rank rank : Rank.findAll()) {
|
||||
Map<String, Boolean> scopedPermissions = PermissionUtils.mergePermissions(
|
||||
PermissionUtils.getDefaultPermissions(rank),
|
||||
actorServerGroup.calculatePermissions(rank)
|
||||
);
|
||||
public Map<UUID, String> extractPlayerNames(Document reqJson) {
|
||||
Map<UUID, String> result = new HashMap<>();
|
||||
|
||||
permissionsResponse.put(rank.getId(), scopedPermissions);
|
||||
for (Object player : (List<Object>) reqJson.get("players")) {
|
||||
Document playerJson = (Document) player;
|
||||
UUID uuid = UUID.fromString(playerJson.getString("uuid"));
|
||||
String username = playerJson.getString("username");
|
||||
|
||||
if (UUIDUtils.isAcceptableUUID(uuid)) {
|
||||
result.put(uuid, username);
|
||||
}
|
||||
}
|
||||
|
||||
actorServer.setPlayers(onlinePlayersNames.keySet());
|
||||
actorServer.setLastTps(reqJson.getDouble("lastTps"));
|
||||
actorServer.setLastUpdatedAt(new Date());
|
||||
actorServer.save();
|
||||
|
||||
APIv3.respondJson(ctx, ImmutableMap.of(
|
||||
"players", playersResponse,
|
||||
"permissions", permissionsResponse
|
||||
));
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -12,7 +12,7 @@ import org.bson.Document;
|
||||
public final class DELETEUserMeta implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
User user = User.findById(ctx.request().getParam("id"));
|
||||
User user = User.findByIdSync(ctx.request().getParam("id"));
|
||||
|
||||
if (user == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
||||
@ -26,7 +26,7 @@ public final class DELETEUserMeta implements Handler<RoutingContext> {
|
||||
return;
|
||||
}
|
||||
|
||||
UserMetaEntry userMetaEntry = UserMetaEntry.findByUserAndGroup(user, serverGroup);
|
||||
UserMetaEntry userMetaEntry = UserMetaEntry.findByUserAndGroupSync(user, serverGroup);
|
||||
|
||||
if (userMetaEntry != null) {
|
||||
userMetaEntry.delete();
|
||||
|
@ -14,7 +14,7 @@ import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
public final class DELETEUserPunishment implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
User target = User.findById(ctx.request().getParam("id"));
|
||||
User target = User.findByIdSync(ctx.request().getParam("id"));
|
||||
|
||||
if (target == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
||||
@ -22,7 +22,7 @@ public final class DELETEUserPunishment implements Handler<RoutingContext> {
|
||||
}
|
||||
|
||||
Punishment.PunishmentType type = Punishment.PunishmentType.valueOf(ctx.request().getParam("type").toUpperCase());
|
||||
User removedBy = User.findById(ctx.request().getParam("removedBy"));
|
||||
User removedBy = User.findByIdSync(ctx.request().getParam("removedBy"));
|
||||
|
||||
if (removedBy == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("removedBy"));
|
||||
@ -36,7 +36,7 @@ public final class DELETEUserPunishment implements Handler<RoutingContext> {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Punishment punishment : target.getPunishments(ImmutableSet.of(type))) {
|
||||
for (Punishment punishment : Punishment.findByUserAndTypeSync(target, ImmutableSet.of(type))) {
|
||||
if (punishment.isActive()) {
|
||||
punishment.delete(removedBy, reason);
|
||||
AuditLog.log(removedBy, "", ctx.get("actor"), AuditLogActionType.DELETE_PUNISHMENT, ImmutableMap.of());
|
||||
|
@ -27,9 +27,9 @@ public final class GETStaff implements Handler<RoutingContext> {
|
||||
return Integer.compare(firstRank.getWeight(), secondRank.getWeight());
|
||||
});
|
||||
|
||||
Grant.findByRank(staffRanks.values()).forEach(grant -> {
|
||||
Grant.findByRankSync(staffRanks.values()).forEach(grant -> {
|
||||
if (grant.isActive()) {
|
||||
User user = User.findById(grant.getUser());
|
||||
User user = User.findByIdSync(grant.getUser());
|
||||
Rank rank = staffRanks.get(grant.getRank());
|
||||
|
||||
if (!result.containsKey(rank.getId())) {
|
||||
|
@ -8,7 +8,7 @@ import net.frozenorb.apiv3.models.User;
|
||||
public final class GETUser implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
APIv3.respondJson(ctx, User.findById(ctx.request().getParam("id")));
|
||||
APIv3.respondJson(ctx, User.findByIdSync(ctx.request().getParam("id")));
|
||||
}
|
||||
|
||||
}
|
@ -13,7 +13,7 @@ import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
public final class GETUserDetails implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
User user = User.findById(ctx.request().getParam("id"));
|
||||
User user = User.findByIdSync(ctx.request().getParam("id"));
|
||||
|
||||
if (user == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
||||
@ -23,9 +23,9 @@ public final class GETUserDetails implements Handler<RoutingContext> {
|
||||
// Too many fields to use .of()
|
||||
APIv3.respondJson(ctx, ImmutableMap.builder()
|
||||
.put("user", user)
|
||||
.put("grants", Grant.findByUser(user))
|
||||
.put("ipLog", IPLogEntry.findByUser(user))
|
||||
.put("punishments", Punishment.findByUser(user))
|
||||
.put("grants", Grant.findByUserSync(user))
|
||||
.put("ipLog", IPLogEntry.findByUserSync(user))
|
||||
.put("punishments", Punishment.findByUserSync(user))
|
||||
.put("aliases", user.getAliases())
|
||||
.put("totpSetup", user.getTotpSecret() != null)
|
||||
.build()
|
||||
|
@ -11,7 +11,7 @@ import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
public final class GETUserMeta implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
User user = User.findById(ctx.request().getParam("id"));
|
||||
User user = User.findByIdSync(ctx.request().getParam("id"));
|
||||
|
||||
if (user == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
||||
@ -25,7 +25,7 @@ public final class GETUserMeta implements Handler<RoutingContext> {
|
||||
return;
|
||||
}
|
||||
|
||||
UserMetaEntry userMetaEntry = UserMetaEntry.findByUserAndGroup(user, serverGroup);
|
||||
UserMetaEntry userMetaEntry = UserMetaEntry.findByUserAndGroupSync(user, serverGroup);
|
||||
APIv3.respondJson(ctx, userMetaEntry.getData());
|
||||
}
|
||||
|
||||
|
@ -2,9 +2,11 @@ package net.frozenorb.apiv3.routes.users;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import io.vertx.core.Handler;
|
||||
import io.vertx.core.cli.converters.BooleanConverter;
|
||||
import io.vertx.ext.web.RoutingContext;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.models.User;
|
||||
import net.frozenorb.apiv3.unsorted.BlockingCallback;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import net.frozenorb.apiv3.utils.IPUtils;
|
||||
import net.frozenorb.apiv3.utils.TOTPUtils;
|
||||
@ -12,7 +14,7 @@ import net.frozenorb.apiv3.utils.TOTPUtils;
|
||||
public final class GETUserRequiresTOTP implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
User user = User.findById(ctx.request().getParam("id"));
|
||||
User user = User.findByIdSync(ctx.request().getParam("id"));
|
||||
|
||||
if (user == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
||||
@ -34,7 +36,10 @@ public final class GETUserRequiresTOTP implements Handler<RoutingContext> {
|
||||
return;
|
||||
}
|
||||
|
||||
if (TOTPUtils.isPreAuthorized(user, userIp)) {
|
||||
BlockingCallback<Boolean> preAuthorizedCallback = new BlockingCallback<>();
|
||||
TOTPUtils.isPreAuthorized(user, userIp, preAuthorizedCallback);
|
||||
|
||||
if (preAuthorizedCallback.get()) {
|
||||
APIv3.respondJson(ctx, ImmutableMap.of(
|
||||
"required", false,
|
||||
"message", "User's IP has already been validated"
|
||||
|
@ -10,7 +10,7 @@ import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
public final class GETUserVerifyPassword implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
User user = User.findById(ctx.request().getParam("id"));
|
||||
User user = User.findByIdSync(ctx.request().getParam("id"));
|
||||
|
||||
if (user == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
||||
|
@ -22,7 +22,7 @@ public final class POSTUserConfirmRegister implements Handler<RoutingContext> {
|
||||
"nicole chelsea biteme matthew access yankees 987654321 dallas austin thunder taylor matrix").split(" "));
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
User user = User.findByEmailToken(ctx.request().getParam("emailToken"));
|
||||
User user = User.findByEmailTokenSync(ctx.request().getParam("emailToken"));
|
||||
|
||||
if (user == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "Email token", ctx.request().getParam("emailToken"));
|
||||
|
@ -10,7 +10,7 @@ public class POSTUserLeave implements Handler<RoutingContext> {
|
||||
|
||||
@Override
|
||||
public void handle(RoutingContext ctx) {
|
||||
User user = User.findById(ctx.request().getParam("id"));
|
||||
User user = User.findByIdSync(ctx.request().getParam("id"));
|
||||
|
||||
if (user == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
||||
|
@ -5,6 +5,7 @@ import io.vertx.ext.web.RoutingContext;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.actors.Actor;
|
||||
import net.frozenorb.apiv3.actors.ActorType;
|
||||
import net.frozenorb.apiv3.models.IPLogEntry;
|
||||
import net.frozenorb.apiv3.models.Server;
|
||||
import net.frozenorb.apiv3.models.User;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
@ -23,7 +24,7 @@ public final class POSTUserLogin implements Handler<RoutingContext> {
|
||||
return;
|
||||
}
|
||||
|
||||
User user = User.findById(uuid);
|
||||
User user = User.findByIdSync(uuid);
|
||||
String username = ctx.request().getParam("username");
|
||||
String userIp = ctx.request().getParam("userIp");
|
||||
Actor actor = ctx.get("actor");
|
||||
@ -45,7 +46,19 @@ public final class POSTUserLogin implements Handler<RoutingContext> {
|
||||
|
||||
Server actorServer = Server.findById(actor.getName());
|
||||
|
||||
user.getIPLogEntry(userIp).used();
|
||||
IPLogEntry ipLogEntry = IPLogEntry.findByUserAndIpSync(user, userIp);
|
||||
|
||||
// We use a little bit more verbose code here to save on the
|
||||
// overhead of a .insert() immediately followed by a .save()
|
||||
if (ipLogEntry == null) {
|
||||
ipLogEntry = new IPLogEntry(user, userIp);
|
||||
ipLogEntry.used();
|
||||
ipLogEntry.insert();
|
||||
} else {
|
||||
ipLogEntry.used();
|
||||
ipLogEntry.save();
|
||||
}
|
||||
|
||||
user.updateUsername(username);
|
||||
APIv3.respondJson(ctx, user.getLoginInfo(actorServer));
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import io.vertx.ext.web.RoutingContext;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.models.NotificationTemplate;
|
||||
import net.frozenorb.apiv3.models.User;
|
||||
import net.frozenorb.apiv3.unsorted.BlockingCallback;
|
||||
import net.frozenorb.apiv3.unsorted.Notification;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
|
||||
@ -15,7 +16,7 @@ import java.util.Map;
|
||||
public final class POSTUserNotify implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
User user = User.findById(ctx.request().getParam("id"));
|
||||
User user = User.findByIdSync(ctx.request().getParam("id"));
|
||||
|
||||
if (user == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
||||
@ -27,7 +28,7 @@ public final class POSTUserNotify implements Handler<RoutingContext> {
|
||||
return;
|
||||
}
|
||||
|
||||
NotificationTemplate template = NotificationTemplate.findById(ctx.request().getParam("template"));
|
||||
NotificationTemplate template = NotificationTemplate.findByIdSync(ctx.request().getParam("template"));
|
||||
|
||||
if (template == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "Notification template", ctx.request().getParam("template"));
|
||||
@ -49,7 +50,10 @@ public final class POSTUserNotify implements Handler<RoutingContext> {
|
||||
try {
|
||||
Notification notification = new Notification(template, subjectReplacements, bodyReplacements);
|
||||
|
||||
notification.sendAsEmail(user.getEmail());
|
||||
BlockingCallback<Void> callback = new BlockingCallback<>();
|
||||
notification.sendAsEmail(user.getEmail(), callback);
|
||||
callback.get();
|
||||
|
||||
APIv3.respondJson(ctx, ImmutableMap.of(
|
||||
"success", true
|
||||
));
|
||||
|
@ -6,6 +6,7 @@ import io.vertx.ext.web.RoutingContext;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.models.NotificationTemplate;
|
||||
import net.frozenorb.apiv3.models.User;
|
||||
import net.frozenorb.apiv3.unsorted.BlockingCallback;
|
||||
import net.frozenorb.apiv3.unsorted.Notification;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
|
||||
@ -24,7 +25,7 @@ public final class POSTUserRegister implements Handler<RoutingContext> {
|
||||
);
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
User user = User.findById(ctx.request().getParam("id"));
|
||||
User user = User.findByIdSync(ctx.request().getParam("id"));
|
||||
|
||||
if (user == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
||||
@ -59,10 +60,12 @@ public final class POSTUserRegister implements Handler<RoutingContext> {
|
||||
"emailToken", user.getEmailToken()
|
||||
);
|
||||
|
||||
Notification notification = new Notification(NotificationTemplate.findById("email-confirmation"), replacements, replacements);
|
||||
Notification notification = new Notification(NotificationTemplate.findByIdSync("email-confirmation"), replacements, replacements);
|
||||
|
||||
try {
|
||||
notification.sendAsEmail(user.getEmail());
|
||||
BlockingCallback<Void> callback = new BlockingCallback<>();
|
||||
notification.sendAsEmail(user.getEmail(), callback);
|
||||
callback.get();
|
||||
APIv3.respondJson(ctx, ImmutableMap.of(
|
||||
"success", true
|
||||
));
|
||||
|
@ -12,7 +12,7 @@ import net.frozenorb.apiv3.utils.TOTPUtils;
|
||||
public final class POSTUserSetupTOTP implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
User user = User.findById(ctx.request().getParam("id"));
|
||||
User user = User.findByIdSync(ctx.request().getParam("id"));
|
||||
|
||||
if (user == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
||||
|
@ -2,9 +2,12 @@ package net.frozenorb.apiv3.routes.users;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import io.vertx.core.Handler;
|
||||
import io.vertx.core.cli.converters.BooleanConverter;
|
||||
import io.vertx.ext.web.RoutingContext;
|
||||
import io.vertx.ext.web.handler.BodyHandler;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.models.User;
|
||||
import net.frozenorb.apiv3.unsorted.BlockingCallback;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import net.frozenorb.apiv3.utils.IPUtils;
|
||||
import net.frozenorb.apiv3.utils.TOTPUtils;
|
||||
@ -14,7 +17,7 @@ import java.util.concurrent.TimeUnit;
|
||||
public final class POSTUserVerifyTOTP implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
User user = User.findById(ctx.request().getParam("id"));
|
||||
User user = User.findByIdSync(ctx.request().getParam("id"));
|
||||
|
||||
if (user == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
||||
@ -34,8 +37,10 @@ public final class POSTUserVerifyTOTP implements Handler<RoutingContext> {
|
||||
}
|
||||
|
||||
int providedCode = Integer.parseInt(ctx.request().getParam("code"));
|
||||
BlockingCallback<Boolean> recentlyUsedCallback = new BlockingCallback<>();
|
||||
TOTPUtils.wasRecentlyUsed(user, providedCode, recentlyUsedCallback);
|
||||
|
||||
if (TOTPUtils.wasRecentlyUsed(user, providedCode)) {
|
||||
if (recentlyUsedCallback.get()) {
|
||||
APIv3.respondJson(ctx, ImmutableMap.of(
|
||||
"authorized", false,
|
||||
"message", "TOTP code was recently used."
|
||||
@ -46,8 +51,13 @@ public final class POSTUserVerifyTOTP implements Handler<RoutingContext> {
|
||||
boolean authorized = TOTPUtils.authorizeUser(user, providedCode);
|
||||
|
||||
if (authorized) {
|
||||
TOTPUtils.markPreAuthorized(user, userIp, 3, TimeUnit.DAYS);
|
||||
TOTPUtils.markRecentlyUsed(user, providedCode);
|
||||
BlockingCallback<Void> markPreAuthorizedCallback = new BlockingCallback<>();
|
||||
TOTPUtils.markPreAuthorized(user, userIp, 3, TimeUnit.DAYS, markPreAuthorizedCallback);
|
||||
markPreAuthorizedCallback.get();
|
||||
|
||||
BlockingCallback<Void> markRecentlyUsedCallback = new BlockingCallback<>();
|
||||
TOTPUtils.markRecentlyUsed(user, providedCode, markRecentlyUsedCallback);
|
||||
markRecentlyUsedCallback.get();
|
||||
|
||||
APIv3.respondJson(ctx, ImmutableMap.of(
|
||||
"authorized", true,
|
||||
|
@ -5,13 +5,14 @@ import io.vertx.ext.web.RoutingContext;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.models.ServerGroup;
|
||||
import net.frozenorb.apiv3.models.User;
|
||||
import net.frozenorb.apiv3.models.UserMetaEntry;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import org.bson.Document;
|
||||
|
||||
public final class PUTUserMeta implements Handler<RoutingContext> {
|
||||
|
||||
public void handle(RoutingContext ctx) {
|
||||
User user = User.findById(ctx.request().getParam("id"));
|
||||
User user = User.findByIdSync(ctx.request().getParam("id"));
|
||||
|
||||
if (user == null) {
|
||||
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
||||
@ -26,8 +27,16 @@ public final class PUTUserMeta implements Handler<RoutingContext> {
|
||||
}
|
||||
|
||||
Document data = Document.parse(ctx.getBodyAsString());
|
||||
UserMetaEntry metaEntry = UserMetaEntry.findByUserAndGroupSync(user, serverGroup);
|
||||
|
||||
if (metaEntry == null) {
|
||||
metaEntry = new UserMetaEntry(user, serverGroup, data);
|
||||
metaEntry.insert();
|
||||
} else {
|
||||
metaEntry.setData(data);
|
||||
metaEntry.save();
|
||||
}
|
||||
|
||||
user.saveMeta(serverGroup, data);
|
||||
APIv3.respondJson(ctx, data);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,40 @@
|
||||
package net.frozenorb.apiv3.serialization;
|
||||
|
||||
import org.bson.BsonReader;
|
||||
import org.bson.BsonWriter;
|
||||
import org.bson.codecs.Codec;
|
||||
import org.bson.codecs.DecoderContext;
|
||||
import org.bson.codecs.EncoderContext;
|
||||
import org.bson.codecs.configuration.CodecProvider;
|
||||
import org.bson.codecs.configuration.CodecRegistry;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public final class MineHQCodecProvider implements CodecProvider {
|
||||
|
||||
public <T> Codec<T> get(Class<T> clazz, CodecRegistry codecRegistry) {
|
||||
if (clazz == UUID.class) {
|
||||
return (Codec<T>) new Codec<UUID>() {
|
||||
|
||||
@Override
|
||||
public UUID decode(BsonReader bsonReader, DecoderContext decoderContext) {
|
||||
return UUID.fromString(bsonReader.readString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(BsonWriter bsonWriter, UUID uuid, EncoderContext encoderContext) {
|
||||
bsonWriter.writeString(uuid == null ? null : uuid.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<UUID> getEncoderClass() {
|
||||
return UUID.class;
|
||||
}
|
||||
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
package net.frozenorb.apiv3.serialization;
|
||||
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import org.bson.types.ObjectId;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public final class ObjectIdTypeAdapter extends TypeAdapter<ObjectId> {
|
||||
|
||||
public void write(JsonWriter writer, ObjectId write) throws IOException {
|
||||
writer.value(write.toString());
|
||||
}
|
||||
|
||||
// This is used with Gson, which is only used
|
||||
// to serialize outgoing responses, thus we
|
||||
// don't need to have a read method.
|
||||
public ObjectId read(JsonReader reader) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package net.frozenorb.apiv3.serialization;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
|
||||
public class UUIDJsonDeserializer extends JsonDeserializer<UUID> {
|
||||
|
||||
@Override
|
||||
public UUID deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
|
||||
return UUID.fromString(jsonParser.getValueAsString());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package net.frozenorb.apiv3.serialization;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
|
||||
public final class UUIDJsonSerializer extends JsonSerializer<UUID> {
|
||||
|
||||
@Override
|
||||
public void serialize(UUID uuid, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
|
||||
jsonGenerator.writeString(uuid.toString());
|
||||
}
|
||||
|
||||
}
|
@ -9,6 +9,7 @@ public final class BlockingCallback<T> implements SingleResultCallback<T> {
|
||||
|
||||
private final SettableFuture<T> future = SettableFuture.create();
|
||||
|
||||
@Override
|
||||
public void onResult(T val, Throwable error) {
|
||||
if (error != null) {
|
||||
future.setException(error);
|
||||
|
@ -5,6 +5,7 @@ import com.cribbstechnologies.clients.mandrill.model.MandrillHtmlMessage;
|
||||
import com.cribbstechnologies.clients.mandrill.model.MandrillMessageRequest;
|
||||
import com.cribbstechnologies.clients.mandrill.model.MandrillRecipient;
|
||||
import com.cribbstechnologies.clients.mandrill.request.MandrillMessagesRequest;
|
||||
import com.mongodb.async.SingleResultCallback;
|
||||
import com.twilio.sdk.TwilioRestException;
|
||||
import com.twilio.sdk.resource.factory.MessageFactory;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
@ -32,7 +33,7 @@ public final class Notification {
|
||||
this.body = template.fillBody(bodyReplacements);
|
||||
}
|
||||
|
||||
public void sendAsEmail(String email) throws IOException {
|
||||
public void sendAsEmail(String email, SingleResultCallback<Void> callback) throws IOException {
|
||||
MandrillHtmlMessage message = new MandrillHtmlMessage();
|
||||
|
||||
message.setFrom_email("no-reply@minehq.com");
|
||||
@ -43,31 +44,49 @@ public final class Notification {
|
||||
new MandrillRecipient(null, email)
|
||||
});
|
||||
|
||||
try {
|
||||
MandrillMessageRequest request = new MandrillMessageRequest();
|
||||
request.setMessage(message);
|
||||
mandrillMessagesRequest.sendMessage(request);
|
||||
APIv3.getStatsD().incrementCounter("apiv3.notification.email.success");
|
||||
} catch (RequestFailedException ex) {
|
||||
APIv3.getStatsD().incrementCounter("apiv3.notification.email.failure");
|
||||
throw new IOException("Failed to send notification to user", ex);
|
||||
}
|
||||
APIv3.getVertxInstance().executeBlocking((future) -> {
|
||||
try {
|
||||
MandrillMessageRequest request = new MandrillMessageRequest();
|
||||
request.setMessage(message);
|
||||
mandrillMessagesRequest.sendMessage(request);
|
||||
APIv3.getStatsD().incrementCounter("apiv3.notification.email.success");
|
||||
future.succeeded();
|
||||
} catch (RequestFailedException ex) {
|
||||
APIv3.getStatsD().incrementCounter("apiv3.notification.email.failure");
|
||||
future.fail(new IOException("Failed to send notification to user", ex));
|
||||
}
|
||||
}, (result) -> {
|
||||
if (result.succeeded()) {
|
||||
callback.onResult(null, null);
|
||||
} else {
|
||||
callback.onResult(null, result.cause());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void sendAsText(String phoneNumber) throws IOException {
|
||||
public void sendAsText(String phoneNumber, SingleResultCallback<Void> callback) throws IOException {
|
||||
List<NameValuePair> params = new ArrayList<>();
|
||||
|
||||
params.add(new BasicNameValuePair("To", phoneNumber));
|
||||
params.add(new BasicNameValuePair("From", "+13108795180"));
|
||||
params.add(new BasicNameValuePair("Body", body));
|
||||
|
||||
try {
|
||||
twillioMessageFactory.create(params);
|
||||
APIv3.getStatsD().incrementCounter("apiv3.notification.text.success");
|
||||
} catch (TwilioRestException ex) {
|
||||
APIv3.getStatsD().incrementCounter("apiv3.notification.text.failure");
|
||||
throw new IOException("Failed to send notification to user", ex);
|
||||
}
|
||||
APIv3.getVertxInstance().executeBlocking((future) -> {
|
||||
try {
|
||||
twillioMessageFactory.create(params);
|
||||
APIv3.getStatsD().incrementCounter("apiv3.notification.text.success");
|
||||
future.succeeded();
|
||||
} catch (TwilioRestException ex) {
|
||||
APIv3.getStatsD().incrementCounter("apiv3.notification.text.failure");
|
||||
future.fail(new IOException("Failed to send notification to user", ex));
|
||||
}
|
||||
}, (result) -> {
|
||||
if (result.succeeded()) {
|
||||
callback.onResult(null, null);
|
||||
} else {
|
||||
callback.onResult(null, result.cause());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -6,5 +6,6 @@ import lombok.experimental.UtilityClass;
|
||||
public class Permissions {
|
||||
|
||||
public static final String PROTECTED_PUNISHMENT = "minehq.punishment.protected";
|
||||
public static final String SIGN_API_REQUEST = "apiv3.signRequest";
|
||||
|
||||
}
|
@ -11,12 +11,6 @@ import java.util.UUID;
|
||||
@UtilityClass
|
||||
public class MojangUtils {
|
||||
|
||||
public static String getName(UUID id) {
|
||||
BlockingCallback<String> callback = new BlockingCallback<>();
|
||||
getName(id, callback);
|
||||
return callback.get();
|
||||
}
|
||||
|
||||
public static void getName(UUID id, SingleResultCallback<String> callback) {
|
||||
APIv3.getHttpClient().get("sessionserver.mojang.com", "session/minecraft/profile/" + id.toString().replace("-", ""), (response) -> {
|
||||
response.bodyHandler((body) -> {
|
||||
|
@ -1,15 +1,18 @@
|
||||
package net.frozenorb.apiv3.utils;
|
||||
|
||||
import com.mongodb.async.SingleResultCallback;
|
||||
import com.warrenstrange.googleauth.GoogleAuthenticator;
|
||||
import com.warrenstrange.googleauth.GoogleAuthenticatorConfig;
|
||||
import com.warrenstrange.googleauth.GoogleAuthenticatorKey;
|
||||
import com.warrenstrange.googleauth.GoogleAuthenticatorQRGenerator;
|
||||
import io.vertx.redis.RedisClient;
|
||||
import io.vertx.redis.RedisOptions;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.models.User;
|
||||
import redis.clients.jedis.Jedis;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
@UtilityClass
|
||||
public class TOTPUtils {
|
||||
@ -38,34 +41,60 @@ public class TOTPUtils {
|
||||
);
|
||||
}
|
||||
|
||||
public static boolean isPreAuthorized(User user, String ip) {
|
||||
try (Jedis redis = APIv3.getRedisPool().getResource()) {
|
||||
return redis.exists(user.getId() + ":preAuthorizedIP:" + ip.toLowerCase());
|
||||
}
|
||||
public static void isPreAuthorized(User user, String ip, SingleResultCallback<Boolean> callback) {
|
||||
APIv3.getRedisClient().exists(user.getId() + ":preAuthorizedIP:" + ip.toLowerCase(), (result) -> {
|
||||
if (result.succeeded()) {
|
||||
callback.onResult(result.result() == 1 , null);
|
||||
} else {
|
||||
callback.onResult(null, result.cause());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void markPreAuthorized(User user, String ip, long duration, TimeUnit unit) {
|
||||
try (Jedis redis = APIv3.getRedisPool().getResource()) {
|
||||
String key = user.getId() + ":preAuthorizedIP:" + ip.toLowerCase();
|
||||
public static void markPreAuthorized(User user, String ip, long duration, TimeUnit unit, SingleResultCallback<Void> callback) {
|
||||
String key = user.getId() + ":preAuthorizedIP:" + ip.toLowerCase();
|
||||
|
||||
redis.set(key, "");
|
||||
redis.expire(key, (int) unit.toSeconds(duration));
|
||||
}
|
||||
APIv3.getRedisClient().set(key, "", (result) -> {
|
||||
if (result.succeeded()) {
|
||||
APIv3.getRedisClient().expire(key, (int) unit.toSeconds(duration), (result2) -> {
|
||||
if (result2.succeeded()) {
|
||||
callback.onResult(null, null);
|
||||
} else {
|
||||
callback.onResult(null, result.cause());
|
||||
}
|
||||
});
|
||||
} else {
|
||||
callback.onResult(null, result.cause());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static boolean wasRecentlyUsed(User user, int code) {
|
||||
try (Jedis redis = APIv3.getRedisPool().getResource()) {
|
||||
return redis.exists(user.getId() + ":recentTOTPCodes:" + code);
|
||||
}
|
||||
public static void wasRecentlyUsed(User user, int code, SingleResultCallback<Boolean> callback) {
|
||||
APIv3.getRedisClient().exists(user.getId() + ":recentTOTPCodes:" + code, (result) -> {
|
||||
if (result.succeeded()) {
|
||||
callback.onResult(result.result() == 1 , null);
|
||||
} else {
|
||||
callback.onResult(null, result.cause());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void markRecentlyUsed(User user, int code) {
|
||||
try (Jedis redis = APIv3.getRedisPool().getResource()) {
|
||||
String key = user.getId() + ":recentTOTPCodes:" + code;
|
||||
public static void markRecentlyUsed(User user, int code, SingleResultCallback<Void> callback) {
|
||||
String key = user.getId() + ":recentTOTPCodes:" + code;
|
||||
|
||||
redis.set(key, "");
|
||||
redis.expire(key, (int) TimeUnit.MINUTES.toSeconds(5));
|
||||
}
|
||||
APIv3.getRedisClient().set(key, "", (result) -> {
|
||||
if (result.succeeded()) {
|
||||
APIv3.getRedisClient().expire(key, (int) TimeUnit.MINUTES.toSeconds(5), (result2) -> {
|
||||
if (result2.succeeded()) {
|
||||
callback.onResult(null, null);
|
||||
} else {
|
||||
callback.onResult(null, result.cause());
|
||||
}
|
||||
});
|
||||
} else {
|
||||
callback.onResult(null, result.cause());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user