Large commit to convert all models to be full async

This commit is contained in:
Colin McDonald 2016-06-24 03:00:37 -04:00
parent e9da784953
commit 4a727f3d04
50 changed files with 810 additions and 725 deletions

View File

@ -85,6 +85,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@ -107,6 +108,13 @@ public final class APIv3 extends AbstractVerticle {
setupDatabase();
setupHttpServer();
/*try {
ObjectMapper mapper = new ObjectMapper();
log.info(gson.toJson(mapper.readValue("email=test@google.com", Map.class)));
} catch (Exception ex) {
ex.printStackTrace();
}*/
/*V2Importer converter = new V2Importer("mongodb://158.69.126.126", "minehq");
converter.startImport((ignored, error) -> {
@ -218,12 +226,12 @@ public final class APIv3 extends AbstractVerticle {
http.route().handler(LoggerHandler.create(LoggerFormat.TINY));
http.route().handler(TimeoutHandler.create(TimeUnit.SECONDS.toMillis(5)));
http.route().method(HttpMethod.PUT).method(HttpMethod.POST).handler(BodyHandler.create());
http.route().method(HttpMethod.PUT).method(HttpMethod.POST).method(HttpMethod.DELETE).handler(BodyHandler.create());
http.route().handler(new ActorAttributeHandler());
http.route().handler(new AuthorizationHandler());
http.exceptionHandler(Throwable::printStackTrace);
// TODO: The commented out routes
// TODO: RENAME THESE ROUTES TO BE RIGHT
http.get("/auditLog").handler(new GETAuditLog());
http.post("/auditLog").handler(new POSTAuditLog());
@ -281,7 +289,7 @@ public final class APIv3 extends AbstractVerticle {
http.get("/staff").blockingHandler(new GETStaff(), false);
http.get("/users/:id").handler(new GETUser());
http.get("/users/:id/details").blockingHandler(new GETUserDetails(), false);
http.get("/users/:id/permissions").blockingHandler(new GETUserPermissions(), false);
http.get("/users/:id/permissions").handler(new GETUserPermissions());
http.get("/users/:id/requiresTotp").handler(new GETUserRequiresTotp());
http.get("/users/:id/verifyPassword").blockingHandler(new GETUserVerifyPassword(), false);
http.post("/users/:id/changePassword").blockingHandler(new POSTUserChangePassword(), false);
@ -299,6 +307,8 @@ public final class APIv3 extends AbstractVerticle {
webServer.requestHandler(http::accept).listen(port);
}
// TODO: TEST IF OUR MODEL CONSTRUCTORS CAN BE PRIVATE
public static void respondJson(RoutingContext ctx, Object response) {
respondJson(ctx, 200, response);
}
@ -306,6 +316,11 @@ public final class APIv3 extends AbstractVerticle {
public static void respondJson(RoutingContext ctx, int code, Object response) {
ctx.response().putHeader(HttpHeaders.CONTENT_TYPE, MediaType.JSON_UTF_8.toString());
ctx.response().setStatusCode(code);
if (!ctx.request().path().contains("dumps")) {
log.info(gson.toJson(response));
}
ctx.response().end(gson.toJson(response));
}

View File

@ -10,6 +10,7 @@ import net.frozenorb.apiv3.dataImport.converters.GrantConverter;
import net.frozenorb.apiv3.dataImport.converters.IpLogConverter;
import net.frozenorb.apiv3.dataImport.converters.PunishmentConverter;
import net.frozenorb.apiv3.dataImport.converters.UserConverter;
import net.frozenorb.apiv3.unsorted.FutureCompatibilityCallback;
import org.bson.types.ObjectId;
import java.util.HashMap;
@ -52,22 +53,4 @@ public final class V2Importer {
});
}
private static class FutureCompatibilityCallback<T> implements SingleResultCallback<T> {
private final Future<T> future;
private FutureCompatibilityCallback(Future<T> future) {
this.future = future;
}
public void onResult(T val, Throwable error) {
if (error != null) {
future.fail(error);
} else {
future.complete(val);
}
}
}
}

View File

@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableSet;
import com.mongodb.Block;
import lombok.extern.slf4j.Slf4j;
import net.frozenorb.apiv3.model.Grant;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import org.bson.Document;
import org.bson.types.ObjectId;
@ -56,7 +57,9 @@ public final class GrantConverter implements Block<Document> {
null
);
created.insert();
BlockingCallback<Void> callback = new BlockingCallback<>();
created.insert(callback);
callback.get();
log.info("Created grant " + created.getId() + " (" + created.getRank() + ")");
}

View File

@ -3,6 +3,7 @@ package net.frozenorb.apiv3.dataImport.converters;
import com.mongodb.Block;
import lombok.extern.slf4j.Slf4j;
import net.frozenorb.apiv3.model.IpLogEntry;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.util.IpUtils;
import org.bson.Document;
import org.bson.types.ObjectId;
@ -50,7 +51,9 @@ public final class IpLogConverter implements Block<Document> {
((Number) ipLogEntry.get("uses")).intValue()
);
created.insert();
BlockingCallback<Void> callback = new BlockingCallback<>();
created.insert(callback);
callback.get();
log.info("Created ip log entry " + created.getId() + " (" + created.getUser() + " - " + created.getUserIp() + ")");
}

View File

@ -5,6 +5,7 @@ import com.mongodb.Block;
import lombok.extern.slf4j.Slf4j;
import net.frozenorb.apiv3.actor.ActorType;
import net.frozenorb.apiv3.model.Punishment;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import org.bson.Document;
import org.bson.types.ObjectId;
@ -52,7 +53,9 @@ public final class PunishmentConverter implements Block<Document> {
punishment.containsKey("removedBy") ? punishment.getString("removalReason").toString() : null
);
created.insert();
BlockingCallback<Void> callback = new BlockingCallback<>();
created.insert(callback);
callback.get();
log.info("Created punishment " + created.getId() + " (" + created.getType() + ")");
}

View File

@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableMap;
import com.mongodb.Block;
import lombok.extern.slf4j.Slf4j;
import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.util.UuidUtils;
import org.bson.Document;
import org.bson.types.ObjectId;
@ -55,7 +56,9 @@ public final class UserConverter implements Block<Document> {
false
);
created.insert();
BlockingCallback<Void> callback = new BlockingCallback<>();
created.insert(callback);
callback.get();
log.info("Created user " + created.getLastUsername() + " (" + created.getId() + ")");
}

View File

@ -48,8 +48,14 @@ public final class ActorAttributeHandler implements Handler<RoutingContext> {
}
if (user != null && user.checkPassword(password)) {
ctx.put("actor", new UserActor(user, user.hasPermissionAnywhere(Permissions.SIGN_API_REQUEST))); // TODO: BLOCKING
ctx.next();
user.hasPermissionAnywhere(Permissions.SIGN_API_REQUEST, (hasPermission, error2) -> {
if (error2 != null) {
ErrorUtils.respondInternalError(ctx, error2);
} else {
ctx.put("actor", new UserActor(user, hasPermission));
ctx.next();
}
});
} else {
ErrorUtils.respondGeneric(ctx, 401, "Failed to authorize as " + username + ".");
}

View File

@ -9,8 +9,6 @@ import fr.javatic.mongo.jacksonCodec.objectId.Id;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.util.SyncUtils;
import org.bson.Document;
import org.bson.types.ObjectId;
@ -42,21 +40,9 @@ public final class Grant {
grantsCollection.find().sort(new Document("addedAt", -1)).into(new LinkedList<>(), callback);
}
public static List<Grant> findByRankSync(Collection<Rank> ranks) {
public static void findByRank(Collection<Rank> ranks, SingleResultCallback<List<Grant>> callback) {
Collection<String> convertedRanks = ranks.stream().map(Rank::getId).collect(Collectors.toList());
return SyncUtils.blockMulti(grantsCollection.find(new Document("rank", new Document("$in", convertedRanks))));
}
public static Grant findByIdSync(String id) {
return SyncUtils.blockOne(grantsCollection.find(new Document("_id", id)));
}
public static List<Grant> findByUserSync(User user) {
return findByUserSync(user.getId());
}
public static List<Grant> findByUserSync(UUID user) {
return SyncUtils.blockMulti(grantsCollection.find(new Document("user", user)));
grantsCollection.find(new Document("rank", new Document("$in", convertedRanks))).into(new LinkedList<>(), callback);
}
public static void findPaginated(Document query, int skip, int pageSize, SingleResultCallback<List<Grant>> callback) {
@ -128,20 +114,16 @@ public final class Grant {
return scopes.isEmpty();
}
public void insert() {
BlockingCallback<Void> callback = new BlockingCallback<>();
public void insert(SingleResultCallback<Void> callback) {
grantsCollection.insertOne(this, callback);
callback.get();
}
public void delete(User removedBy, String reason) {
public void delete(User removedBy, String reason, SingleResultCallback<UpdateResult> callback) {
this.removedBy = removedBy.getId();
this.removedAt = Instant.now();
this.removalReason = reason;
BlockingCallback<UpdateResult> callback = new BlockingCallback<>();
grantsCollection.replaceOne(new Document("_id", id), this, callback);
callback.get();
}
}

View File

@ -10,8 +10,6 @@ import lombok.Getter;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.actor.Actor;
import net.frozenorb.apiv3.actor.ActorType;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.util.SyncUtils;
import net.frozenorb.apiv3.util.TimeUtils;
import org.bson.Document;
import org.bson.types.ObjectId;
@ -39,10 +37,6 @@ public final class IpBan {
@Getter private Instant removedAt;
@Getter private String removalReason;
public static IpBan findByIdSync(String id) {
return SyncUtils.blockOne(ipBansCollection.find(new Document("_id", id)));
}
public static void findPaginated(Document query, int skip, int pageSize, SingleResultCallback<List<IpBan>> callback) {
ipBansCollection.find(query).sort(new Document("addedAt", -1)).skip(skip).limit(pageSize).into(new LinkedList<>(), callback);
}
@ -111,7 +105,6 @@ public final class IpBan {
return removedBy != null;
}
// TODO: CLEANUP
public void getAccessDenialReason(SingleResultCallback<String> callback) {
Punishment.findByLinkedIpBanId(id, (punishment, error) -> {
if (error != null) {
@ -123,53 +116,44 @@ public final class IpBan {
User.findById(punishment.getUser(), (user, error2) -> {
if (error2 != null) {
callback.onResult(null, error2);
return;
}
String accessDenialReason;
if (user != null) {
accessDenialReason = "Your IP address has been suspended from the MineHQ Network for a punishment related to " + user.getLastUsername() + ". \n\n";
} else {
accessDenialReason = "Your IP address has been suspended from the MineHQ Network. \n\n";
callback.onResult(buildDenialReason(user), null);
}
if (getExpiresAt() != null) {
accessDenialReason += "Expires in " + TimeUtils.formatIntoDetailedString(TimeUtils.getSecondsBetween(getExpiresAt(), Instant.now()));
} else {
accessDenialReason += "Appeal at MineHQ.com/appeal";
}
callback.onResult(accessDenialReason, null);
});
} else {
String accessDenialReason = "Your IP address has been suspended from the MineHQ Network. \n\n";
if (getExpiresAt() != null) {
accessDenialReason += "Expires in " + TimeUtils.formatIntoDetailedString(TimeUtils.getSecondsBetween(getExpiresAt(), Instant.now()));
} else {
accessDenialReason += "Appeal at MineHQ.com/appeal";
}
callback.onResult(accessDenialReason, null);
callback.onResult(buildDenialReason(null), null);
}
});
}
public void insert() {
BlockingCallback<Void> callback = new BlockingCallback<>();
ipBansCollection.insertOne(this, callback);
callback.get();
private String buildDenialReason(User linkedIpBanUser) {
String accessDenialReason;
if (linkedIpBanUser != null) {
accessDenialReason = "Your IP address has been suspended from the MineHQ Network for a punishment related to " + linkedIpBanUser.getLastUsername() + ". \n\n";
} else {
accessDenialReason = "Your IP address has been suspended from the MineHQ Network. \n\n";
}
if (getExpiresAt() != null) {
accessDenialReason += "Expires in " + TimeUtils.formatIntoDetailedString(TimeUtils.getSecondsBetween(getExpiresAt(), Instant.now()));
} else {
accessDenialReason += "Appeal at MineHQ.com/appeal";
}
return accessDenialReason;
}
public void delete(User removedBy, String reason) {
public void insert(SingleResultCallback<Void> callback) {
ipBansCollection.insertOne(this, callback);
}
public void delete(User removedBy, String reason, SingleResultCallback<UpdateResult> callback) {
this.removedBy = removedBy.getId();
this.removedAt = Instant.now();
this.removalReason = reason;
BlockingCallback<UpdateResult> callback = new BlockingCallback<>();
ipBansCollection.replaceOne(new Document("_id", id), this, callback);
callback.get();
}
}

View File

@ -46,7 +46,7 @@ public final class IpIntel {
} else {
IpIntel newIpIntel = new IpIntel(id, maxMindResult);
newIpIntel.insert((ignored, error3) -> {
ipIntelCollection.insertOne(newIpIntel, (ignored, error3) -> {
if (error3 != null) {
callback.onResult(null, error3);
} else {
@ -61,14 +61,10 @@ public final class IpIntel {
public IpIntel() {} // For Jackson
public IpIntel(String ip, MaxMindResult result) {
private IpIntel(String ip, MaxMindResult result) {
this.id = ip;
this.lastUpdatedAt = Instant.now();
this.result = result;
}
public void insert(SingleResultCallback<Void> callback) {
ipIntelCollection.insertOne(this, callback);
}
}

View File

@ -8,8 +8,6 @@ import fr.javatic.mongo.jacksonCodec.objectId.Id;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.util.SyncUtils;
import org.bson.Document;
import org.bson.types.ObjectId;
@ -31,30 +29,6 @@ public final class IpLogEntry {
@Getter private Instant lastSeenAt;
@Getter private int uses;
public static List<IpLogEntry> findAllSync() {
return SyncUtils.blockMulti(ipLogCollection.find().sort(new Document("lastSeenAt", -1)));
}
public static IpLogEntry findByIdSync(String id) {
return SyncUtils.blockOne(ipLogCollection.find(new Document("_id", id)));
}
public static List<IpLogEntry> findByUserSync(User user) {
return findByUserSync(user.getId());
}
public static List<IpLogEntry> findByUserSync(UUID user) {
return SyncUtils.blockMulti(ipLogCollection.find(new Document("user", user)).sort(new Document("lastSeenAt", -1)));
}
public static IpLogEntry findByUserAndIpSync(User user, String userIp) {
return findByUserAndIpSync(user.getId(), 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().sort(new Document("lastSeenAt", -1)).into(new LinkedList<>(), callback);
}
@ -95,16 +69,12 @@ public final class IpLogEntry {
this.uses++;
}
public void insert() {
BlockingCallback<Void> callback = new BlockingCallback<>();
public void insert(SingleResultCallback<Void> callback) {
ipLogCollection.insertOne(this, callback);
callback.get();
}
public void save() {
BlockingCallback<UpdateResult> callback = new BlockingCallback<>();
public void save(SingleResultCallback<UpdateResult> callback) {
ipLogCollection.replaceOne(new Document("_id", id), this, callback);
callback.get();
}
}

View File

@ -8,8 +8,6 @@ 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.util.SyncUtils;
import org.bson.Document;
import java.util.LinkedList;
@ -25,10 +23,6 @@ public final class NotificationTemplate {
@Getter @Setter private String subject;
@Getter @Setter private String body;
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 LinkedList<>(), callback);
}
@ -64,16 +58,12 @@ public final class NotificationTemplate {
return working;
}
public void insert() {
BlockingCallback<Void> callback = new BlockingCallback<>();
public void insert(SingleResultCallback<Void> callback) {
notificationTemplatesCollection.insertOne(this, callback);
callback.get();
}
public void delete() {
BlockingCallback<DeleteResult> callback = new BlockingCallback<>();
public void delete(SingleResultCallback<DeleteResult> callback) {
notificationTemplatesCollection.deleteOne(new Document("_id", id), callback);
callback.get();
}
}

View File

@ -10,8 +10,6 @@ import lombok.Getter;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.actor.Actor;
import net.frozenorb.apiv3.actor.ActorType;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.util.SyncUtils;
import net.frozenorb.apiv3.util.TimeUtils;
import org.bson.Document;
import org.bson.types.ObjectId;
@ -48,27 +46,6 @@ public final class Punishment {
punishmentsCollection.find(new Document("type", new Document("$in", convertedTypes))).into(new LinkedList<>(), callback);
}
public static Punishment findByIdSync(String id) {
return SyncUtils.blockOne(punishmentsCollection.find(new Document("_id", id)));
}
public static List<Punishment> findByUserSync(User user) {
return findByUserSync(user.getId());
}
public static List<Punishment> findByUserSync(UUID user) {
return SyncUtils.blockMulti(punishmentsCollection.find(new Document("user", user)));
}
public static List<Punishment> findByUserAndTypeSync(User user, Collection<PunishmentType> types) {
return findByUserAndTypeSync(user.getId(), types);
}
public static List<Punishment> findByUserAndTypeSync(UUID user, Collection<PunishmentType> types) {
Collection<String> convertedTypes = types.stream().map(PunishmentType::name).collect(Collectors.toList());
return SyncUtils.blockMulti(punishmentsCollection.find(new Document("user", user).append("type", new Document("$in", convertedTypes))));
}
public static void findPaginated(Document query, int skip, int pageSize, SingleResultCallback<List<Punishment>> callback) {
punishmentsCollection.find(query).sort(new Document("addedAt", -1)).skip(skip).limit(pageSize).into(new LinkedList<>(), callback);
}
@ -168,28 +145,38 @@ public final class Punishment {
this.linkedIpBanId = ipBan.getId();
}
public void insert() {
BlockingCallback<Void> callback = new BlockingCallback<>();
public void insert(SingleResultCallback<Void> callback) {
punishmentsCollection.insertOne(this, callback);
callback.get();
}
public void delete(User removedBy, String reason) {
public void delete(User removedBy, String reason, SingleResultCallback<UpdateResult> callback) {
this.removedBy = removedBy.getId();
this.removedAt = Instant.now();
this.removalReason = reason;
if (linkedIpBanId != null) {
IpBan ipBan = IpBan.findByIdSync(linkedIpBanId);
if (ipBan != null && ipBan.isActive()) {
ipBan.delete(removedBy, "Linked punishment removed: " + reason);
}
if (linkedIpBanId == null) {
punishmentsCollection.replaceOne(new Document("_id", id), this, callback);
return;
}
BlockingCallback<UpdateResult> callback = new BlockingCallback<>();
punishmentsCollection.replaceOne(new Document("_id", id), this, callback);
callback.get();
IpBan.findById(linkedIpBanId, (ipBan, error) -> {
if (error != null) {
callback.onResult(null, error);
return;
}
if (ipBan != null && ipBan.isActive()) {
ipBan.delete(removedBy, "Linked punishment removed: " + reason, (ignored, error2) -> {
if (error2 != null) {
callback.onResult(null, error2);
} else {
punishmentsCollection.replaceOne(new Document("_id", id), this, callback);
}
});
} else {
punishmentsCollection.replaceOne(new Document("_id", id), this, callback);
}
});
}
public enum PunishmentType {

View File

@ -1,15 +1,14 @@
package net.frozenorb.apiv3.model;
import com.google.common.collect.ImmutableList;
import com.google.common.primitives.Ints;
import com.google.common.collect.ImmutableMap;
import com.mongodb.async.SingleResultCallback;
import com.mongodb.async.client.MongoCollection;
import com.mongodb.client.result.DeleteResult;
import fr.javatic.mongo.jacksonCodec.Entity;
import fr.javatic.mongo.jacksonCodec.objectId.Id;
import lombok.Getter;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.util.SyncUtils;
import org.bson.Document;
import java.util.HashMap;
@ -23,9 +22,8 @@ public final class Rank {
private static final MongoCollection<Rank> ranksCollection = APIv3.getDatabase().getCollection("ranks", Rank.class);
private static Map<String, Rank> rankCache = null;
private static List<Rank> rankAltCache = null;
private static long rankCacheUpdated = 0;
private static Map<String, Rank> rankIdCache = null;
private static List<Rank> rankCache = null;
@Getter @Id private String id;
@Getter private int weight;
@ -35,13 +33,37 @@ public final class Rank {
@Getter private boolean staffRank;
public static List<Rank> findAll() {
updateCacheIfNeeded();
return ImmutableList.copyOf(rankAltCache);
return rankCache;
}
public static Rank findById(String id) {
updateCacheIfNeeded();
return rankCache.get(id);
return rankIdCache.get(id);
}
static {
updateCache();
APIv3.getVertxInstance().setPeriodic(TimeUnit.MINUTES.toMillis(1), (id) -> {
updateCache();
});
}
private static void updateCache() {
ranksCollection.find().into(new LinkedList<>(), (ranks, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Map<String, Rank> working = new HashMap<>();
for (Rank rank : ranks) {
working.put(rank.getId(), rank);
}
rankIdCache = ImmutableMap.copyOf(working);
rankCache = ImmutableList.copyOf(ranks);
});
}
public Rank() {} // For Jackson
@ -55,34 +77,12 @@ public final class Rank {
this.staffRank = staffRank;
}
private static void updateCacheIfNeeded() {
if (rankCache == null || (System.currentTimeMillis() - rankCacheUpdated) > TimeUnit.MINUTES.toMillis(1)) {
Map<String, Rank> working = new HashMap<>();
List<Rank> workingAlt = new LinkedList<>();
List<Rank> allRanks = SyncUtils.blockMulti(ranksCollection.find());
allRanks.sort((a, b) -> Ints.compare(a.getWeight(), b.getWeight()));
for (Rank rank : allRanks) {
working.put(rank.getId(), rank);
workingAlt.add(rank);
}
rankCache = working;
rankAltCache = workingAlt;
rankCacheUpdated = System.currentTimeMillis();
}
}
public void insert() {
BlockingCallback<Void> callback = new BlockingCallback<>();
public void insert(SingleResultCallback<Void> callback) {
ranksCollection.insertOne(this, callback);
callback.get();
}
public void delete() {
BlockingCallback<DeleteResult> callback = new BlockingCallback<>();
public void delete(SingleResultCallback<DeleteResult> callback) {
ranksCollection.deleteOne(new Document("_id", id), callback);
callback.get();
}
}

View File

@ -1,6 +1,9 @@
package net.frozenorb.apiv3.model;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.mongodb.async.SingleResultCallback;
import com.mongodb.async.client.MongoCollection;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
@ -9,8 +12,6 @@ import fr.javatic.mongo.jacksonCodec.objectId.Id;
import lombok.Getter;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.serialization.gson.ExcludeFromReplies;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.util.SyncUtils;
import org.bson.Document;
import java.time.Instant;
@ -22,9 +23,8 @@ public final class Server {
private static final MongoCollection<Server> serversCollection = APIv3.getDatabase().getCollection("servers", Server.class);
private static Map<String, Server> serverCache = null;
private static List<Server> serverCacheAlt = null;
private static long serverCacheUpdated = 0;
private static Map<String, Server> serverIdCache = null;
private static List<Server> serverCache = null;
@Getter @Id private String id;
@Getter private String displayName;
@ -36,13 +36,37 @@ public final class Server {
@Getter @ExcludeFromReplies private Set<UUID> players;
public static List<Server> findAll() {
updateCacheIfNeeded();
return serverCacheAlt;
return serverCache;
}
public static Server findById(String id) {
updateCacheIfNeeded();
return serverCache.get(id);
return serverIdCache.get(id);
}
static {
updateCache();
APIv3.getVertxInstance().setPeriodic(TimeUnit.MINUTES.toMillis(1), (id) -> {
updateCache();
});
}
private static void updateCache() {
serversCollection.find().into(new LinkedList<>(), (servers, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Map<String, Server> working = new HashMap<>();
for (Server server : servers) {
working.put(server.getId(), server);
}
serverIdCache = ImmutableMap.copyOf(working);
serverCache = ImmutableList.copyOf(servers);
});
}
public Server() {} // For Jackson
@ -58,44 +82,22 @@ public final class Server {
this.players = new HashSet<>();
}
private static void updateCacheIfNeeded() {
if (serverCache == null || (System.currentTimeMillis() - serverCacheUpdated) > TimeUnit.MINUTES.toMillis(1)) {
Map<String, Server> working = new HashMap<>();
List<Server> workingAlt = new LinkedList<>();
for (Server server : SyncUtils.blockMulti(serversCollection.find())) {
working.put(server.getId(), server);
workingAlt.add(server);
}
serverCache = working;
serverCacheAlt = workingAlt;
serverCacheUpdated = System.currentTimeMillis();
}
}
public void receivedHeartbeat(double tps, Iterable<UUID> players) {
this.lastUpdatedAt = Instant.now();
this.lastTps = tps;
this.players = ImmutableSet.copyOf(players);
}
public void insert() {
BlockingCallback<Void> callback = new BlockingCallback<>();
public void insert(SingleResultCallback<Void> callback) {
serversCollection.insertOne(this, callback);
callback.get();
}
public void save() {
BlockingCallback<UpdateResult> callback = new BlockingCallback<>();
public void save(SingleResultCallback<UpdateResult> callback) {
serversCollection.replaceOne(new Document("_id", id), this, callback);
callback.get();
}
public void delete() {
BlockingCallback<DeleteResult> callback = new BlockingCallback<>();
public void delete(SingleResultCallback<DeleteResult> callback) {
serversCollection.deleteOne(new Document("_id", id), callback);
callback.get();
}
}

View File

@ -1,5 +1,7 @@
package net.frozenorb.apiv3.model;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.mongodb.async.SingleResultCallback;
import com.mongodb.async.client.MongoCollection;
import com.mongodb.client.result.DeleteResult;
@ -10,9 +12,7 @@ import lombok.Getter;
import lombok.Setter;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.serialization.gson.ExcludeFromReplies;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.util.PermissionUtils;
import net.frozenorb.apiv3.util.SyncUtils;
import org.bson.Document;
import java.util.*;
@ -23,24 +23,46 @@ public final class ServerGroup {
private static final MongoCollection<ServerGroup> serverGroupsCollection = APIv3.getDatabase().getCollection("serverGroups", ServerGroup.class);
private static Map<String, ServerGroup> serverGroupCache = null;
private static List<ServerGroup> serverGroupAltCache = null;
private static long serverGroupCacheUpdated = 0;
private static Map<String, ServerGroup> serverGroupIdCache = null;
private static List<ServerGroup> serverGroupCache = null;
@Getter @Id private String id;
@Getter private String image;
@Getter @Setter private Set<String> announcements;
@Getter @Setter @ExcludeFromReplies private Map<String, List<String>> permissions;
// make this and other stuff async
public static List<ServerGroup> findAll() {
updateCacheIfNeeded();
return serverGroupAltCache;
return serverGroupCache;
}
public static ServerGroup findById(String id) {
updateCacheIfNeeded();
return serverGroupCache.get(id);
return serverGroupIdCache.get(id);
}
static {
updateCache();
APIv3.getVertxInstance().setPeriodic(TimeUnit.MINUTES.toMillis(1), (id) -> {
updateCache();
});
}
private static void updateCache() {
serverGroupsCollection.find().into(new LinkedList<>(), (serverGroups, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Map<String, ServerGroup> working = new HashMap<>();
for (ServerGroup serverGroup : serverGroups) {
working.put(serverGroup.getId(), serverGroup);
}
serverGroupIdCache = ImmutableMap.copyOf(working);
serverGroupCache = ImmutableList.copyOf(serverGroups);
});
}
public ServerGroup() {} // For Jackson
@ -54,36 +76,16 @@ public final class ServerGroup {
return PermissionUtils.mergeUpTo(permissions, userRank);
}
private static void updateCacheIfNeeded() {
if (serverGroupCache == null || (System.currentTimeMillis() - serverGroupCacheUpdated) > TimeUnit.MINUTES.toMillis(1)) {
Map<String, ServerGroup> working = new HashMap<>();
List<ServerGroup> workingAlt = new LinkedList<>();
for (ServerGroup serverGroup : SyncUtils.blockMulti(serverGroupsCollection.find())) {
working.put(serverGroup.getId(), serverGroup);
workingAlt.add(serverGroup);
}
serverGroupCache = working;
serverGroupAltCache = workingAlt;
serverGroupCacheUpdated = System.currentTimeMillis();
}
}
public void insert() {
BlockingCallback<Void> callback = new BlockingCallback<>();
public void insert(SingleResultCallback<Void> callback) {
serverGroupsCollection.insertOne(this, callback);
callback.get();
}
public void save(SingleResultCallback<UpdateResult> callback) {
serverGroupsCollection.replaceOne(new Document("_id", id), this, callback);
}
public void delete() {
BlockingCallback<DeleteResult> callback = new BlockingCallback<>();
public void delete(SingleResultCallback<DeleteResult> callback) {
serverGroupsCollection.deleteOne(new Document("_id", id), callback);
callback.get();
}
}

View File

@ -23,8 +23,9 @@ import net.frozenorb.apiv3.maxmind.MaxMindUserType;
import net.frozenorb.apiv3.serialization.gson.ExcludeFromReplies;
import net.frozenorb.apiv3.serialization.jackson.UuidJsonDeserializer;
import net.frozenorb.apiv3.serialization.jackson.UuidJsonSerializer;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.unsorted.FutureCompatibilityCallback;
import net.frozenorb.apiv3.unsorted.Permissions;
import net.frozenorb.apiv3.unsorted.RequiresTotpResult;
import net.frozenorb.apiv3.util.*;
import org.bson.Document;
@ -53,44 +54,12 @@ public final class User {
@Getter private Instant firstSeenAt;
@Getter private boolean online;
public static User findByIdSync(String id) {
UUID uuid;
try {
uuid = UUID.fromString(id);
} catch (NullPointerException | IllegalArgumentException ex) {
return null;
}
return findByIdSync(uuid);
}
public static User findByIdSync(UUID id) {
if (UuidUtils.isAcceptableUuid(id)) {
return SyncUtils.blockOne(usersCollection.find(new Document("_id", id)));
} else {
return null;
}
}
public static User findByEmailSync(String email) {
return SyncUtils.blockOne(usersCollection.find(new Document("email", email)));
}
public static User findByEmailTokenSync(String emailToken) {
return SyncUtils.blockOne(usersCollection.find(new Document("emailToken", emailToken)));
}
public static User findByLastUsernameSync(String lastUsername) {
return SyncUtils.blockOne(usersCollection.find(new Document("lastUsername", lastUsername)));
}
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);
} catch (IllegalArgumentException ignored) { // from UUID parsing
callback.onResult(null, null); // We don't pass in the exception, we just pretend we couldn't find them.
}
}
@ -102,6 +71,18 @@ public final class User {
}
}
public static void findByEmail(String email, SingleResultCallback<User> callback) {
usersCollection.find(new Document("email", email)).first(callback);
}
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 static void findByIdGrouped(Iterable<UUID> search, SingleResultCallback<Map<UUID, User>> callback) {
usersCollection.find(new Document("_id", new Document("$in", search))).into(new LinkedList<>(), (users, error) -> {
if (error != null) {
@ -122,62 +103,211 @@ public final class User {
});
}
public static void findByEmailTokenSync(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 Jackson
// TODO: THIS IS CURRENTLY BLOCKING. MAYBE FOR THE HEARTBEAT WE CAN DO SOMETHING
// TO MAKE IT NOT SO BLOCKING
public User(UUID id, String lastUsername) {
this.id = id;
this.lastUsername = ""; // Intentional, so updateUsername actually does something.
this.lastUsername = lastUsername;
this.aliases = new HashMap<>();
this.lastSeenAt = Instant.now();
this.firstSeenAt = Instant.now();
updateUsername(lastUsername);
this.aliases.put(lastUsername, Instant.now());
}
public boolean hasPermissionAnywhere(String permission) {
Map<String, Boolean> globalPermissions = getGlobalPermissions();
return globalPermissions.containsKey(permission) && globalPermissions.get(permission);
public void updateUsername(String newUsername) {
this.aliases.put(newUsername, Instant.now());
this.lastUsername = newUsername;
}
// TODO: ASYNC
public Map<String, Boolean> getGlobalPermissions() {
Map<String, Boolean> globalPermissions = PermissionUtils.getDefaultPermissions(getHighestRankAnywhere());
public void checkNameCollisions(SingleResultCallback<Void> callback) {
User.findByLastUsername(lastUsername, (collision, error) -> {
if (error != null) {
callback.onResult(null, error);
return;
}
for (Map.Entry<ServerGroup, Rank> serverGroupEntry : getHighestRanks().entrySet()) {
ServerGroup serverGroup = serverGroupEntry.getKey();
Rank rank = serverGroupEntry.getValue();
if (collision == null) {
callback.onResult(null, null);
return;
}
globalPermissions = PermissionUtils.mergePermissions(
globalPermissions,
serverGroup.calculatePermissions(rank)
);
MojangUtils.getName(collision.getId(), (collisionNewUsername, error2) -> {
if (error2 != null) {
callback.onResult(null, error2);
return;
}
collision.updateUsername(collisionNewUsername);
collision.checkNameCollisions((ignored, error3) -> {
if (error3 != null) {
callback.onResult(null, error3);
return;
}
collision.save((ignored2, error4) -> {
if (error4 != null) {
callback.onResult(null, error4);
} else {
callback.onResult(null, null);
}
});
});
});
});
}
public void getLoginInfo(Server server, String userIp, SingleResultCallback<Map<String, Object>> callback) {
Future<List<Punishment>> punishmentsFuture = Future.future();
Future<IpIntel> ipIntelFuture = Future.future();
Future<List<IpBan>> ipBansFuture = Future.future();
Future<List<Grant>> grantsFuture = Future.future();
Punishment.findByUserAndType(this, ImmutableSet.of(
Punishment.PunishmentType.BLACKLIST,
Punishment.PunishmentType.BAN,
Punishment.PunishmentType.MUTE
), new FutureCompatibilityCallback<>(punishmentsFuture));
if (userIp != null) {
IpIntel.findByIdOrInsert(userIp, new FutureCompatibilityCallback<>(ipIntelFuture));
IpBan.findByIp(userIp, new FutureCompatibilityCallback<>(ipBansFuture));
} else {
ipIntelFuture.complete(null);
ipBansFuture.complete(ImmutableList.of());
}
return ImmutableMap.copyOf(globalPermissions);
Grant.findByUser(this, new FutureCompatibilityCallback<>(grantsFuture));
CompositeFuture.all(punishmentsFuture, ipIntelFuture, ipBansFuture, grantsFuture).setHandler((result) -> {
if (result.succeeded()) {
Iterable<Punishment> punishments = result.result().result(0);
IpIntel ipIntel = result.result().result(1);
Iterable<IpBan> ipBans = result.result().result(2);
Iterable<Grant> grants = result.result().result(3);
getLoginInfo(server, ipIntel, punishments, ipBans, grants, (loginInfo, error) -> {
if (error != null) {
callback.onResult(null, error);
} else {
callback.onResult(loginInfo, null);
}
});
} else {
callback.onResult(null, result.cause());
}
});
}
// This is only used to help batch requests to mongo
public void getLoginInfo(Server server, IpIntel ipIntel, Iterable<Punishment> punishments, Iterable<IpBan> ipBans, Iterable<Grant> grants, SingleResultCallback<Map<String, Object>> callback) {
getAccessInfo(ipIntel, punishments, ipBans, (accessInfo, error) -> {
ServerGroup serverGroup = ServerGroup.findById(server.getServerGroup());
Punishment activeMute = null;
for (Punishment punishment : punishments) {
if (punishment.isActive() && punishment.getType() == Punishment.PunishmentType.MUTE) {
activeMute = punishment;
break;
}
}
Map<String, Object> result = new HashMap<>();
result.put("user", this);
result.put("access", accessInfo);
result.put("rank", getHighestRankScoped(serverGroup, grants).getId());
result.put("totpSetup", getTotpSecret() != null);
if (activeMute != null) {
result.put("mute", activeMute);
}
callback.onResult(result, null);
});
}
private void getAccessInfo(IpIntel ipIntel, Iterable<Punishment> punishments, Iterable<IpBan> ipBans, SingleResultCallback<Map<String, Object>> callback) {
Punishment activeBan = null;
IpBan activeIpBan = null;
for (Punishment punishment : punishments) {
if (punishment.isActive() && (punishment.getType() == Punishment.PunishmentType.BAN || punishment.getType() == Punishment.PunishmentType.BLACKLIST)) {
activeBan = punishment;
break;
}
}
for (IpBan ipBan : ipBans) {
if (ipBan.isActive()) {
activeIpBan = ipBan;
break;
}
}
Map<String, Object> accessAllowed = ImmutableMap.of(
"allowed", true,
"message", ""
);
if (activeBan != null) {
callback.onResult(ImmutableMap.of(
"allowed", false,
"message", activeBan.getAccessDenialReason()
), null);
} else if (activeIpBan != null) {
activeIpBan.getAccessDenialReason((denialReason, error) -> {
if (error != null) {
callback.onResult(null, error);
} else {
callback.onResult(ImmutableMap.of(
"allowed", false,
"message", denialReason
), null);
}
});
} else if (ipIntel != null) {
MaxMindResult maxMindResult = ipIntel.getResult();
MaxMindUserType userType = maxMindResult.getTraits().getUserType();
Map<String, Object> proposedAccess = null;
if (!userType.isAllowed()) {
proposedAccess = ImmutableMap.of(
"allowed", false,
"message", "You cannot join MineHQ from a VPN."
);
} else if (ImmutableList.of().contains(maxMindResult.getTraits().getAsn())) {
proposedAccess = ImmutableMap.of(
"allowed", false,
"message", "You cannot join MineHQ from this ISP."
);
}
Map<String, Object> finalProposedAccess = proposedAccess;
if (proposedAccess != null) {
hasPermissionAnywhere(Permissions.BYPASS_VPN_CHECK, (bypass, error) -> {
if (error != null) {
callback.onResult(null, error);
} else {
callback.onResult(bypass ? accessAllowed : finalProposedAccess, null);
}
});
} else {
callback.onResult(accessAllowed, null);
}
} else {
callback.onResult(accessAllowed, null);
}
}
// TODO: Clean
public boolean seenOnServer(Server server) {
if (online && server.getId().equals(this.lastSeenOn)) {
if (online && server.getId().equals(lastSeenOn)) {
return false;
}
this.lastSeenOn = server.getId();
if (!online) {
this.lastSeenAt = Instant.now();
}
this.lastSeenAt = Instant.now();
this.online = true;
return true;
}
@ -187,23 +317,6 @@ public final class User {
this.online = false;
}
public void updateUsername(String newUsername) {
if (!newUsername.equals(lastUsername)) {
this.lastUsername = newUsername;
User withNewUsername;
while ((withNewUsername = User.findByLastUsernameSync(newUsername)) != null) {
BlockingCallback<String> callback = new BlockingCallback<>();
MojangUtils.getName(withNewUsername.getId(), callback);
withNewUsername.updateUsername(callback.get());
withNewUsername.save();
}
}
this.aliases.put(newUsername, Instant.now());
}
public void setPassword(String input) {
this.password = Hashing
.sha256()
@ -242,15 +355,6 @@ public final class User {
});
}
// TODO: CLEAN
public enum RequiresTotpResult {
NOT_REQUIRED_NOT_SET,
NOT_REQUIRED_IP_PRE_AUTHORIZED,
REQUIRED_NO_EXEMPTIONS
}
public void completeRegistration(String email) {
this.email = email;
this.registeredAt = Instant.now();
@ -265,12 +369,50 @@ public final class User {
this.pendingEmailTokenSetAt = Instant.now();
}
public Rank getHighestRankAnywhere() {
return getHighestRankScoped(null, Grant.findByUserSync(this));
public void hasPermissionAnywhere(String permission, SingleResultCallback<Boolean> callback) {
getGlobalPermissions((permissions, error) -> {
if (error != null) {
callback.onResult(null, error);
} else {
boolean hasPermission = permissions.containsKey(permission) && permissions.get(permission);
callback.onResult(hasPermission, null);
}
});
}
// This is only used to help batch requests to mongo
public Rank getHighestRankScoped(ServerGroup serverGroup, Iterable<Grant> grants) {
public void getGlobalPermissions(SingleResultCallback<Map<String, Boolean>> callback) {
Grant.findByUser(this, (grants, error) -> {
if (error != null) {
callback.onResult(null, error);
} else {
Map<String, Boolean> globalPermissions = PermissionUtils.getDefaultPermissions(getHighestRankScoped(null, grants));
for (Map.Entry<ServerGroup, Rank> serverGroupEntry : getHighestRanks(grants).entrySet()) {
ServerGroup serverGroup = serverGroupEntry.getKey();
Rank rank = serverGroupEntry.getValue();
globalPermissions = PermissionUtils.mergePermissions(
globalPermissions,
serverGroup.calculatePermissions(rank)
);
}
callback.onResult(ImmutableMap.copyOf(globalPermissions), null);
}
});
}
private Map<ServerGroup, Rank> getHighestRanks(List<Grant> grants) {
Map<ServerGroup, Rank> highestRanks = new HashMap<>();
for (ServerGroup serverGroup : ServerGroup.findAll()) {
highestRanks.put(serverGroup, getHighestRankScoped(serverGroup, grants));
}
return highestRanks;
}
private Rank getHighestRankScoped(ServerGroup serverGroup, Iterable<Grant> grants) {
Rank highest = null;
for (Grant grant : grants) {
@ -292,187 +434,8 @@ public final class User {
}
}
public Map<ServerGroup, Rank> getHighestRanks() {
Map<ServerGroup, Rank> highestRanks = new HashMap<>();
Rank defaultRank = Rank.findById("default");
List<Grant> userGrants = Grant.findByUserSync(this);
for (ServerGroup serverGroup : ServerGroup.findAll()) {
Rank highest = defaultRank;
for (Grant grant : userGrants) {
if (!grant.isActive() || !grant.appliesOn(serverGroup)) {
continue;
}
Rank rank = Rank.findById(grant.getRank());
if (highest == null || rank.getWeight() > highest.getWeight()) {
highest = rank;
}
}
highestRanks.put(serverGroup, highest);
}
return highestRanks;
}
public void getLoginInfo(Server server, String userIp, SingleResultCallback<Map<String, Object>> callback) {
Future<Iterable<Punishment>> punishmentsFuture = Future.future();
Future<IpIntel> ipIntelFuture = Future.future();
Future<Iterable<IpBan>> ipBansFuture = Future.future();
Future<Iterable<Grant>> grantsFuture = Future.future();
Punishment.findByUserAndType(this, ImmutableSet.of(
Punishment.PunishmentType.BLACKLIST,
Punishment.PunishmentType.BAN,
Punishment.PunishmentType.MUTE
), (punishments, error) -> {
if (error != null) {
punishmentsFuture.fail(error);
} else {
punishmentsFuture.complete(punishments);
}
});
if (userIp != null) {
IpIntel.findByIdOrInsert(userIp, (ipIntel, error) -> {
if (error != null) {
ipIntelFuture.fail(error);
} else {
ipIntelFuture.complete(ipIntel);
}
});
IpBan.findByIp(userIp, (ipBans, error) -> {
if (error != null) {
ipBansFuture.fail(error);
} else {
ipBansFuture.complete(ipBans);
}
});
} else {
ipIntelFuture.complete(null);
ipBansFuture.complete(ImmutableSet.of());
}
Grant.findByUser(this, (grants, error) -> {
if (error != null) {
grantsFuture.fail(error);
} else {
grantsFuture.complete(grants);
}
});
CompositeFuture.all(punishmentsFuture, ipIntelFuture, ipBansFuture, grantsFuture).setHandler((result) -> {
if (result.succeeded()) {
Iterable<Punishment> punishments = result.result().result(0);
IpIntel ipIntel = result.result().result(1);
Iterable<IpBan> ipBans = result.result().result(2);
Iterable<Grant> grants = result.result().result(3);
callback.onResult(createLoginInfo(server, ipIntel, punishments, ipBans, grants), null);
} else {
callback.onResult(null, result.cause());
}
});
}
// This is only used to help batch requests to mongo
public Map<String, Object> createLoginInfo(Server server, IpIntel ipIntel, Iterable<Punishment> punishments, Iterable<IpBan> ipBans, Iterable<Grant> grants) {
Punishment activeMute = null;
Punishment activeBan = null;
IpBan activeIpBan = null;
for (Punishment punishment : punishments) {
if (!punishment.isActive()) {
continue;
}
if (punishment.getType() == Punishment.PunishmentType.MUTE) {
activeMute = punishment;
} else if (punishment.getType() == Punishment.PunishmentType.BAN || punishment.getType() == Punishment.PunishmentType.BLACKLIST) {
activeBan = punishment;
}
}
for (IpBan ipBan : ipBans) {
if (ipBan.isActive()) {
activeIpBan = ipBan;
break;
}
}
Rank highestRank = getHighestRankScoped(ServerGroup.findById(server.getServerGroup()), grants);
Map<String, Object> access = ImmutableMap.of(
"allowed", true,
"message", ""
);
if (activeBan != null) {
access = ImmutableMap.of(
"allowed", false,
"message", activeBan.getAccessDenialReason(),
"activeBanId", activeBan.getId()
);
} else if (activeIpBan != null) {
// TODO: ASYNC
BlockingCallback<String> callback = new BlockingCallback<>();
activeIpBan.getAccessDenialReason(callback);
String reason = callback.get();
access = ImmutableMap.of(
"allowed", false,
"message", reason,
"activeIpBanId", activeIpBan.getId()
);
} else if (ipIntel != null) {
MaxMindResult maxMindResult = ipIntel.getResult();
MaxMindUserType userType = maxMindResult.getTraits().getUserType();
Map<String, Object> proposedAccess = null;
if (!userType.isAllowed()) {
proposedAccess = ImmutableMap.of(
"allowed", false,
"message", "You cannot join MineHQ from a VPN.",
"userType", userType.name()
);
} else if (ImmutableList.of().contains(maxMindResult.getTraits().getAsn())) {
// TODO: BANNED ASNS
}
// We do this to avoid making an expensive .hasPermissionAnywhere call unless we need to.
// TODO: THIS IS BLOCKING :(
if (proposedAccess != null && !hasPermissionAnywhere(Permissions.BYPASS_VPN_CHECK)) {
access = proposedAccess;
}
}
// Generics are weird, yes we have to do this.
ImmutableMap.Builder<String, Object> result = ImmutableMap.<String, Object>builder()
.put("user", this)
.put("access", access)
.put("rank", highestRank.getId())
.put("totpSetup", getTotpSecret() != null);
if (activeMute != null) {
result.put("mute", activeMute);
}
return result.build();
}
public void insert() {
BlockingCallback<Void> callback = new BlockingCallback<>();
public void insert(SingleResultCallback<Void> callback) {
usersCollection.insertOne(this, callback);
callback.get();
}
public void save() {
BlockingCallback<UpdateResult> callback = new BlockingCallback<>();
save(callback);
callback.get();
}
public void save(SingleResultCallback<UpdateResult> callback) {

View File

@ -13,13 +13,14 @@ import net.frozenorb.apiv3.util.IpUtils;
public final class POSTAuditLog implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {
User.findById(ctx.request().getParam("id"), (user, error) -> {
JsonObject requestBody = ctx.getBodyAsJson();
User.findById(requestBody.getString("user"), (user, error) -> {
if (error != null) {
ErrorUtils.respondInternalError(ctx, error);
} else if (user == null) {
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
ErrorUtils.respondNotFound(ctx, "User", requestBody.getString("user"));
} else {
JsonObject requestBody = ctx.getBodyAsJson();
String userIp = requestBody.getString("userIp");
if (!IpUtils.isValidIp(userIp)) {

View File

@ -9,7 +9,7 @@ import net.frozenorb.apiv3.util.ErrorUtils;
public final class GETEmailTokensOwner implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {
User.findByEmailTokenSync(ctx.request().getParam("id"), (user, error) -> {
User.findByEmailToken(ctx.request().getParam("id"), (user, error) -> {
if (error != null) {
ErrorUtils.respondInternalError(ctx, error);
} else {

View File

@ -1,11 +1,13 @@
package net.frozenorb.apiv3.route.emailToken;
import com.google.common.collect.ImmutableMap;
import com.mongodb.client.result.UpdateResult;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.util.ErrorUtils;
import java.util.concurrent.TimeUnit;
@ -13,7 +15,9 @@ import java.util.concurrent.TimeUnit;
public final class POSTEmailTokensConfirm implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {
User user = User.findByEmailTokenSync(ctx.request().getParam("emailToken"));
BlockingCallback<User> userCallback = new BlockingCallback<>();
User.findByEmailToken(ctx.request().getParam("emailToken"), userCallback);
User user = userCallback.get();
if (user == null) {
ErrorUtils.respondNotFound(ctx, "Email token", ctx.request().getParam("emailToken"));
@ -42,7 +46,9 @@ public final class POSTEmailTokensConfirm implements Handler<RoutingContext> {
user.completeRegistration(user.getPendingEmail());
user.setPassword(password);
user.save();
BlockingCallback<UpdateResult> callback = new BlockingCallback<>();
user.save(callback);
callback.get();
APIv3.respondJson(ctx, ImmutableMap.of(
"success", true

View File

@ -1,6 +1,7 @@
package net.frozenorb.apiv3.route.grants;
import com.google.common.collect.ImmutableMap;
import com.mongodb.client.result.UpdateResult;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
@ -16,7 +17,9 @@ import net.frozenorb.apiv3.util.ErrorUtils;
public final class DELETEGrantsId implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {
Grant grant = Grant.findByIdSync(ctx.request().getParam("id"));
BlockingCallback<Grant> grantCallback = new BlockingCallback<>();
Grant.findById(ctx.request().getParam("id"), grantCallback);
Grant grant = grantCallback.get();
if (grant == null) {
ErrorUtils.respondNotFound(ctx, "Grant", ctx.request().getParam("id"));
@ -27,7 +30,9 @@ public final class DELETEGrantsId implements Handler<RoutingContext> {
}
JsonObject requestBody = ctx.getBodyAsJson();
User removedBy = User.findByIdSync(requestBody.getString("removedBy"));
BlockingCallback<User> userCallback = new BlockingCallback<>();
User.findById(requestBody.getString("removedBy"), userCallback);
User removedBy = userCallback.get();
if (removedBy == null) {
ErrorUtils.respondNotFound(ctx, "User", requestBody.getString("removedBy"));
@ -41,7 +46,9 @@ public final class DELETEGrantsId implements Handler<RoutingContext> {
return;
}
grant.delete(removedBy, reason);
BlockingCallback<UpdateResult> callback = new BlockingCallback<>();
grant.delete(removedBy, reason, callback);
callback.get();
BlockingCallback<AuditLogEntry> blockingCallback = new BlockingCallback<>();
AuditLog.log(removedBy, "", ctx.get("actor"), AuditLogActionType.DELETE_GRANT, ImmutableMap.of(), blockingCallback);
blockingCallback.get();

View File

@ -8,6 +8,7 @@ import net.frozenorb.apiv3.model.Grant;
import net.frozenorb.apiv3.model.Rank;
import net.frozenorb.apiv3.model.ServerGroup;
import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.util.ErrorUtils;
import java.time.Instant;
@ -19,7 +20,9 @@ public final class POSTGrants implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {
JsonObject requestBody = ctx.getBodyAsJson();
User target = User.findByIdSync(requestBody.getString("user"));
BlockingCallback<User> userCallback = new BlockingCallback<>();
User.findById(requestBody.getString("user"), userCallback);
User target = userCallback.get();
if (target == null) {
ErrorUtils.respondNotFound(ctx, "User", requestBody.getString("user"));
@ -68,10 +71,14 @@ public final class POSTGrants implements Handler<RoutingContext> {
}
// We purposely don't do a null check, grants don't have to have a source.
User addedBy = User.findByIdSync(requestBody.getString("addedBy"));
BlockingCallback<User> addedByCallback = new BlockingCallback<>();
User.findById(requestBody.getString("addedBt"), addedByCallback);
User addedBy = addedByCallback.get();
Grant grant = new Grant(target, reason, scopes, rank, expiresAt, addedBy);
grant.insert();
BlockingCallback<Void> callback = new BlockingCallback<>();
grant.insert(callback);
callback.get();
APIv3.respondJson(ctx, grant);
}

View File

@ -1,6 +1,7 @@
package net.frozenorb.apiv3.route.ipBans;
import com.google.common.collect.ImmutableMap;
import com.mongodb.client.result.UpdateResult;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
@ -16,7 +17,9 @@ import net.frozenorb.apiv3.util.ErrorUtils;
public final class DELETEIpBan implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {
IpBan ipBan = IpBan.findByIdSync(ctx.request().getParam("id"));
BlockingCallback<IpBan> ipBanCallback = new BlockingCallback<>();
IpBan.findById(ctx.request().getParam("id"), ipBanCallback);
IpBan ipBan = ipBanCallback.get();
if (ipBan == null) {
ErrorUtils.respondNotFound(ctx, "IpBan", ctx.request().getParam("id"));
@ -27,7 +30,9 @@ public final class DELETEIpBan implements Handler<RoutingContext> {
}
JsonObject requestBody = ctx.getBodyAsJson();
User removedBy = User.findByIdSync(requestBody.getString("removedBy"));
BlockingCallback<User> userCallback = new BlockingCallback<>();
User.findById(requestBody.getString("removedBy"), userCallback);
User removedBy = userCallback.get();
if (removedBy == null) {
ErrorUtils.respondNotFound(ctx, "User", requestBody.getString("removedBy"));
@ -41,7 +46,9 @@ public final class DELETEIpBan implements Handler<RoutingContext> {
return;
}
ipBan.delete(removedBy, reason);
BlockingCallback<UpdateResult> callback = new BlockingCallback<>();
ipBan.delete(removedBy, reason, callback);
callback.get();
BlockingCallback<AuditLogEntry> blockingCallback = new BlockingCallback<>();
AuditLog.log(removedBy, "", ctx.get("actor"), AuditLogActionType.DELETE_PUNISHMENT, ImmutableMap.of(), blockingCallback);
blockingCallback.get();

View File

@ -6,6 +6,7 @@ import io.vertx.ext.web.RoutingContext;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.IpBan;
import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.IpUtils;
@ -41,10 +42,14 @@ public final class POSTIpBans implements Handler<RoutingContext> {
}
// We purposely don't do a null check, ip bans don't have to have a source.
User addedBy = User.findByIdSync(requestBody.getString("addedBy"));
BlockingCallback<User> userCallback = new BlockingCallback<>();
User.findById(requestBody.getString("addedBy"), userCallback);
User addedBy = userCallback.get();
IpBan ipBan = new IpBan(userIp, reason, expiresAt, addedBy, ctx.get("actor"));
ipBan.insert();
BlockingCallback<Void> callback = new BlockingCallback<>();
ipBan.insert(callback);
callback.get();
APIv3.respondJson(ctx, ipBan);
}

View File

@ -1,22 +1,28 @@
package net.frozenorb.apiv3.route.notificationTemplates;
import com.mongodb.client.result.DeleteResult;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.NotificationTemplate;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.util.ErrorUtils;
public final class DELETENotificationTemplatesId implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {
NotificationTemplate notificationTemplate = NotificationTemplate.findByIdSync(ctx.request().getParam("id"));
BlockingCallback<NotificationTemplate> notificationTemplateCallback = new BlockingCallback<>();
NotificationTemplate.findById(ctx.request().getParam("id"), notificationTemplateCallback);
NotificationTemplate notificationTemplate = notificationTemplateCallback.get();
if (notificationTemplate == null) {
ErrorUtils.respondNotFound(ctx, "Notification template", ctx.request().getParam("id"));
return;
}
notificationTemplate.delete();
BlockingCallback<DeleteResult> callback = new BlockingCallback<>();
notificationTemplate.delete(callback);
callback.get();
APIv3.respondJson(ctx, notificationTemplate);
}

View File

@ -5,6 +5,7 @@ import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.NotificationTemplate;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
public final class POSTNotificationTemplates implements Handler<RoutingContext> {
@ -15,7 +16,9 @@ public final class POSTNotificationTemplates implements Handler<RoutingContext>
String body = requestBody.getString("body");
NotificationTemplate notificationTemplate = new NotificationTemplate(id, subject, body);
notificationTemplate.insert();
BlockingCallback<Void> callback = new BlockingCallback<>();
notificationTemplate.insert(callback);
callback.get();
APIv3.respondJson(ctx, notificationTemplate);
}

View File

@ -1,6 +1,7 @@
package net.frozenorb.apiv3.route.punishments;
import com.google.common.collect.ImmutableMap;
import com.mongodb.client.result.UpdateResult;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
@ -16,7 +17,9 @@ import net.frozenorb.apiv3.util.ErrorUtils;
public final class DELETEPunishments implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {
Punishment punishment = Punishment.findByIdSync(ctx.request().getParam("id"));
BlockingCallback<Punishment> punishmentCallback = new BlockingCallback<>();
Punishment.findById(ctx.request().getParam("id"), punishmentCallback);
Punishment punishment = punishmentCallback.get();
if (punishment == null) {
ErrorUtils.respondNotFound(ctx, "Punishment", ctx.request().getParam("id"));
@ -27,7 +30,9 @@ public final class DELETEPunishments implements Handler<RoutingContext> {
}
JsonObject requestBody = ctx.getBodyAsJson();
User removedBy = User.findByIdSync(requestBody.getString("removedBy"));
BlockingCallback<User> removedByCallback = new BlockingCallback<>();
User.findById(requestBody.getString("removedBy"), removedByCallback);
User removedBy = removedByCallback.get();
if (removedBy == null) {
ErrorUtils.respondNotFound(ctx, "User", requestBody.getString("removedBy"));
@ -41,7 +46,9 @@ public final class DELETEPunishments implements Handler<RoutingContext> {
return;
}
punishment.delete(removedBy, reason);
BlockingCallback<UpdateResult> removeCallback = new BlockingCallback<>();
punishment.delete(removedBy, reason, removeCallback);
removeCallback.get();
BlockingCallback<AuditLogEntry> blockingCallback = new BlockingCallback<>();
AuditLog.log(removedBy, "", ctx.get("actor"), AuditLogActionType.DELETE_PUNISHMENT, ImmutableMap.of(), blockingCallback);
blockingCallback.get();

View File

@ -2,6 +2,7 @@ package net.frozenorb.apiv3.route.punishments;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.mongodb.client.result.UpdateResult;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
@ -14,10 +15,14 @@ import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.util.ErrorUtils;
import java.util.List;
public final class DELETEUserActivePunishment implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {
User target = User.findByIdSync(ctx.request().getParam("id"));
BlockingCallback<User> userCallback = new BlockingCallback<>();
User.findById(ctx.request().getParam("id"), userCallback);
User target = userCallback.get();
if (target == null) {
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
@ -26,7 +31,10 @@ public final class DELETEUserActivePunishment implements Handler<RoutingContext>
JsonObject requestBody = ctx.getBodyAsJson();
Punishment.PunishmentType type = Punishment.PunishmentType.valueOf(requestBody.getString("type").toUpperCase());
User removedBy = User.findByIdSync(requestBody.getString("removedBy"));
BlockingCallback<User> removedByCallback = new BlockingCallback<>();
User.findById(requestBody.getString("removedBy"), removedByCallback);
User removedBy = removedByCallback.get();
if (removedBy == null) {
ErrorUtils.respondNotFound(ctx, "User", requestBody.getString("removedBy"));
@ -40,9 +48,14 @@ public final class DELETEUserActivePunishment implements Handler<RoutingContext>
return;
}
for (Punishment punishment : Punishment.findByUserAndTypeSync(target, ImmutableSet.of(type))) {
BlockingCallback<List<Punishment>> callback = new BlockingCallback<>();
Punishment.findByUserAndType(target, ImmutableSet.of(type), callback);
for (Punishment punishment : callback.get()) {
if (punishment.isActive()) {
punishment.delete(removedBy, reason);
BlockingCallback<UpdateResult> punishmentCallback = new BlockingCallback<>();
punishment.delete(removedBy, reason, punishmentCallback);
punishmentCallback.get();
BlockingCallback<AuditLogEntry> blockingCallback = new BlockingCallback<>();
AuditLog.log(removedBy, "", ctx.get("actor"), AuditLogActionType.DELETE_PUNISHMENT, ImmutableMap.of(), blockingCallback);
blockingCallback.get();

View File

@ -9,17 +9,21 @@ import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.IpBan;
import net.frozenorb.apiv3.model.Punishment;
import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.unsorted.Permissions;
import net.frozenorb.apiv3.util.ErrorUtils;
import java.time.Instant;
import java.util.List;
import java.util.Map;
public final class POSTPunishments implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {
JsonObject requestBody = ctx.getBodyAsJson();
User target = User.findByIdSync(requestBody.getString("user"));
BlockingCallback<User> userCallback = new BlockingCallback<>();
User.findById(requestBody.getString("user"), userCallback);
User target = userCallback.get();
if (target == null) {
ErrorUtils.respondNotFound(ctx, "User", requestBody.getString("user"));
@ -36,9 +40,14 @@ public final class POSTPunishments implements Handler<RoutingContext> {
Punishment.PunishmentType type = Punishment.PunishmentType.valueOf(requestBody.getString("type"));
if (type != Punishment.PunishmentType.WARN) {
for (Punishment punishment : Punishment.findByUserAndTypeSync(target, ImmutableSet.of(type))) {
BlockingCallback<List<Punishment>> punishmentsCallback = new BlockingCallback<>();
Punishment.findByUserAndType(target, ImmutableSet.of(type), punishmentsCallback);
for (Punishment punishment : punishmentsCallback.get()) {
if (punishment.isActive()) {
ErrorUtils.respondGeneric(ctx, 200, "A punishment by " + User.findByIdSync(punishment.getAddedBy()).getLastUsername() + " already covers this user.");
BlockingCallback<User> addedByCallback = new BlockingCallback<>();
User.findById(punishment.getAddedBy(), addedByCallback);
ErrorUtils.respondGeneric(ctx, 200, "A punishment by " + addedByCallback.get().getLastUsername() + " already covers this user.");
return;
}
}
@ -63,9 +72,14 @@ public final class POSTPunishments implements Handler<RoutingContext> {
}
// We purposely don't do a null check, punishments don't have to have a source.
User addedBy = User.findByIdSync(requestBody.getString("addedBy"));
BlockingCallback<User> addedByCallback = new BlockingCallback<>();
User.findById(requestBody.getString("addedBy"), addedByCallback);
User addedBy = addedByCallback.get();
if (target.hasPermissionAnywhere(Permissions.PROTECTED_PUNISHMENT)) {
BlockingCallback<Boolean> permissionsCallback = new BlockingCallback<>();
target.hasPermissionAnywhere(Permissions.PROTECTED_PUNISHMENT, permissionsCallback);
if (permissionsCallback.get()) {
ErrorUtils.respondGeneric(ctx, 200, target.getLastSeenOn() + " is protected from punishments.");
return;
}
@ -76,12 +90,16 @@ public final class POSTPunishments implements Handler<RoutingContext> {
if ((type == Punishment.PunishmentType.BAN || type == Punishment.PunishmentType.BLACKLIST) && userIp != null) {
IpBan ipBan = new IpBan(userIp, punishment);
ipBan.insert();
BlockingCallback<Void> ipBanCallback = new BlockingCallback<>();
ipBan.insert(ipBanCallback);
ipBanCallback.get();
punishment.linkIpBan(ipBan);
}
punishment.insert();
BlockingCallback<Void> callback = new BlockingCallback<>();
punishment.insert(callback);
callback.get();
APIv3.respondJson(ctx, ImmutableMap.of(
"punishment", punishment,

View File

@ -1,9 +1,11 @@
package net.frozenorb.apiv3.route.ranks;
import com.mongodb.client.result.DeleteResult;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.Rank;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.util.ErrorUtils;
public final class DELETERanksId implements Handler<RoutingContext> {
@ -16,7 +18,9 @@ public final class DELETERanksId implements Handler<RoutingContext> {
return;
}
rank.delete();
BlockingCallback<DeleteResult> callback = new BlockingCallback<>();
rank.delete(callback);
callback.get();
APIv3.respondJson(ctx, rank);
}

View File

@ -5,6 +5,7 @@ import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.Rank;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
public final class POSTRanks implements Handler<RoutingContext> {
@ -18,7 +19,9 @@ public final class POSTRanks implements Handler<RoutingContext> {
boolean staffRank = requestBody.getBoolean("staffRank");
Rank rank = new Rank(id, weight, displayName, gameColor, websiteColor, staffRank);
rank.insert();
BlockingCallback<Void> callback = new BlockingCallback<>();
rank.insert(callback);
callback.get();
APIv3.respondJson(ctx, rank);
}

View File

@ -1,9 +1,11 @@
package net.frozenorb.apiv3.route.serverGroups;
import com.mongodb.client.result.DeleteResult;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.ServerGroup;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.util.ErrorUtils;
public final class DELETEServerGroupsId implements Handler<RoutingContext> {
@ -16,7 +18,9 @@ public final class DELETEServerGroupsId implements Handler<RoutingContext> {
return;
}
serverGroup.delete();
BlockingCallback<DeleteResult> callback = new BlockingCallback<>();
serverGroup.delete(callback);
callback.get();
APIv3.respondJson(ctx, serverGroup);
}

View File

@ -5,6 +5,7 @@ import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.ServerGroup;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
public final class POSTServerGroups implements Handler<RoutingContext> {
@ -14,7 +15,9 @@ public final class POSTServerGroups implements Handler<RoutingContext> {
String image = requestBody.getString("image");
ServerGroup serverGroup = new ServerGroup(id, image);
serverGroup.insert();
BlockingCallback<Void> callback = new BlockingCallback<>();
serverGroup.insert(callback);
callback.get();
APIv3.respondJson(ctx, serverGroup);
}

View File

@ -1,9 +1,11 @@
package net.frozenorb.apiv3.route.servers;
import com.mongodb.client.result.DeleteResult;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.Server;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.util.ErrorUtils;
public final class DELETEServersId implements Handler<RoutingContext> {
@ -16,7 +18,9 @@ public final class DELETEServersId implements Handler<RoutingContext> {
return;
}
server.delete();
BlockingCallback<DeleteResult> callback = new BlockingCallback<>();
server.delete(callback);
callback.get();
APIv3.respondJson(ctx, server);
}

View File

@ -6,6 +6,7 @@ import io.vertx.ext.web.RoutingContext;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.Server;
import net.frozenorb.apiv3.model.ServerGroup;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.IpUtils;
@ -32,7 +33,9 @@ public final class POSTServers implements Handler<RoutingContext> {
String generatedApiKey = UUID.randomUUID().toString();
Server server = new Server(id, displayName, generatedApiKey, group, ip);
server.insert();
BlockingCallback<Void> callback = new BlockingCallback<>();
server.insert(callback);
callback.get();
APIv3.respondJson(ctx, server);
}

View File

@ -2,6 +2,7 @@ package net.frozenorb.apiv3.route.servers;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.mongodb.client.result.UpdateResult;
import io.vertx.core.CompositeFuture;
import io.vertx.core.Future;
import io.vertx.core.Handler;
@ -13,14 +14,13 @@ import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.actor.Actor;
import net.frozenorb.apiv3.actor.ActorType;
import net.frozenorb.apiv3.model.*;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.unsorted.FutureCompatibilityCallback;
import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.PermissionUtils;
import net.frozenorb.apiv3.util.UuidUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.*;
@Slf4j
public final class POSTServersHeartbeat implements Handler<RoutingContext> {
@ -58,14 +58,18 @@ public final class POSTServersHeartbeat implements Handler<RoutingContext> {
});
}
// TODO: ASYNC (MAKE ALL SAVES/INSERTS/ETC USED HERE ASYNC
private Future<Void> createInfoResponse(Server server, double tps, Map<UUID, String> playerNames) {
Future<Void> callback = Future.future();
server.receivedHeartbeat(tps, playerNames.keySet());
server.save();
server.save((ignored, error) -> {
if (error != null) {
callback.fail(error);
} else {
callback.complete();
}
});
callback.complete();
return callback;
}
@ -76,29 +80,9 @@ public final class POSTServersHeartbeat implements Handler<RoutingContext> {
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);
}
});
User.findByIdGrouped(playerNames.keySet(), new FutureCompatibilityCallback<>(userLookupCallback));
Grant.findByUserGrouped(playerNames.keySet(), new FutureCompatibilityCallback<>(grantLookupCallback));
Punishment.findByUserGrouped(playerNames.keySet(), new FutureCompatibilityCallback<>(punishmentLookupCallback));
CompositeFuture.all(
userLookupCallback,
@ -107,38 +91,58 @@ public final class POSTServersHeartbeat implements Handler<RoutingContext> {
).setHandler((result) -> {
if (result.failed()) {
callback.fail(result.cause());
} else {
try {
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();
}
// TODO: Provide IPs for ip ban lookup (and ip intel)
response.put(uuid.toString(), user.createLoginInfo(server,null, punishments.get(uuid), ImmutableList.of(), grants.get(uuid)));
}
callback.complete(response);
} catch (Exception ex) {
callback.fail(ex);
}
return;
}
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<>();
List<Future> loginInfoFutures = new LinkedList<>();
for (Map.Entry<UUID, User> userEntry : users.entrySet()) {
Future<Map<String, Object>> loginInfoFuture = Future.future();
Map<String, Object> res2 = new HashMap<>();
UUID uuid = userEntry.getKey();
User user = userEntry.getValue();
if (user == null) {
String username = playerNames.get(uuid);
user = new User(uuid, username);
BlockingCallback<Void> nameCollisionCallback = new BlockingCallback<>();
user.checkNameCollisions(nameCollisionCallback);
nameCollisionCallback.get();
BlockingCallback<Void> insertCallback = new BlockingCallback<>();
user.insert(insertCallback);
insertCallback.get();
users.put(uuid, user);
}
// Only save if needed
if (user.seenOnServer(server)) {
BlockingCallback<UpdateResult> saveCallback = new BlockingCallback<>();
user.save(saveCallback);
saveCallback.get();
}
// TODO: Provide IPs for ip ban lookup (and ip intel)
BlockingCallback<Map<String, Object>> loginInfo = new BlockingCallback<>();
user.getLoginInfo(server, null, punishments.get(uuid), ImmutableList.of(), grants.get(uuid), loginInfo);
res2.put(uuid.toString(), loginInfo.get());
loginInfoFuture.complete(res2);
loginInfoFutures.add(loginInfoFuture);
}
CompositeFuture.all(loginInfoFutures).setHandler((allLoginInfo) -> {
for (int i = 0; i < allLoginInfo.result().size(); i++) {
response.putAll(allLoginInfo.result().result(i));
}
callback.complete(response);
});
});
return callback;

View File

@ -6,6 +6,7 @@ import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.Grant;
import net.frozenorb.apiv3.model.Rank;
import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import java.util.*;
@ -27,9 +28,14 @@ public final class GETStaff implements Handler<RoutingContext> {
return Integer.compare(firstRank.getWeight(), secondRank.getWeight());
});
Grant.findByRankSync(staffRanks.values()).forEach(grant -> {
BlockingCallback<List<Grant>> grantsCallback = new BlockingCallback<>();
Grant.findByRank(staffRanks.values(), grantsCallback);
grantsCallback.get().forEach(grant -> {
if (grant.isActive()) {
User user = User.findByIdSync(grant.getUser());
BlockingCallback<User> userCallback = new BlockingCallback<>();
User.findById(grant.getUser(), userCallback);
User user = userCallback.get();
Rank rank = staffRanks.get(grant.getRank());
if (!result.containsKey(rank.getId())) {

View File

@ -1,6 +1,5 @@
package net.frozenorb.apiv3.route.users;
import com.google.common.collect.ImmutableMap;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
import net.frozenorb.apiv3.APIv3;
@ -8,28 +7,43 @@ import net.frozenorb.apiv3.model.Grant;
import net.frozenorb.apiv3.model.IpLogEntry;
import net.frozenorb.apiv3.model.Punishment;
import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.util.ErrorUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public final class GETUserDetails implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {
User user = User.findByIdSync(ctx.request().getParam("id"));
BlockingCallback<User> userCallback = new BlockingCallback<>();
User.findById(ctx.request().getParam("id"), userCallback);
User user = userCallback.get();
if (user == null) {
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
return;
}
// Too many fields to use .of()
APIv3.respondJson(ctx, ImmutableMap.builder()
.put("user", 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()
);
BlockingCallback<List<Grant>> grantsCallback = new BlockingCallback<>();
BlockingCallback<List<IpLogEntry>> ipLogCallback = new BlockingCallback<>();
BlockingCallback<List<Punishment>> punishmentsCallback = new BlockingCallback<>();
Grant.findByUser(user, grantsCallback);
IpLogEntry.findByUser(user, ipLogCallback);
Punishment.findByUser(user, punishmentsCallback);
Map<String, Object> result = new HashMap<>();
result.put("user", user);
result.put("grants", grantsCallback.get());
result.put("ipLog", ipLogCallback.get());
result.put("punishments", punishmentsCallback.get());
result.put("aliases", user.getAliases());
result.put("totpSetup", user.getTotpSecret() != null);
APIv3.respondJson(ctx, result);
}
}

View File

@ -9,14 +9,21 @@ import net.frozenorb.apiv3.util.ErrorUtils;
public final class GETUserPermissions implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {
User target = User.findByIdSync(ctx.request().getParam("id"));
if (target == null) {
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
return;
}
APIv3.respondJson(ctx, target.getGlobalPermissions());
User.findById(ctx.request().getParam("id"), (user, error) -> {
if (error != null) {
ErrorUtils.respondInternalError(ctx, error);
} else if (user == null) {
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
} else {
user.getGlobalPermissions((permissions, error2) -> {
if (error2 != null) {
ErrorUtils.respondInternalError(ctx, error2);
} else {
APIv3.respondJson(ctx, permissions);
}
});
}
});
}
}

View File

@ -5,6 +5,7 @@ import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.unsorted.RequiresTotpResult;
import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.IpUtils;
@ -29,7 +30,7 @@ public final class GETUserRequiresTotp implements Handler<RoutingContext> {
ErrorUtils.respondInternalError(ctx, error2);
} else {
APIv3.respondJson(ctx, ImmutableMap.of(
"required", (requiresTotpResult == User.RequiresTotpResult.REQUIRED_NO_EXEMPTIONS),
"required", (requiresTotpResult == RequiresTotpResult.REQUIRED_NO_EXEMPTIONS),
"message", requiresTotpResult.name()
));
}

View File

@ -5,19 +5,26 @@ import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.util.ErrorUtils;
public final class GETUserVerifyPassword implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {
User user = User.findByIdSync(ctx.request().getParam("id"));
BlockingCallback<User> callback = new BlockingCallback<>();
User.findById(ctx.request().getParam("id"), callback);
User user = callback.get();
if (user == null) {
user = User.findByLastUsernameSync(ctx.request().getParam("id"));
callback = new BlockingCallback<>();
User.findByLastUsername(ctx.request().getParam("id"), callback);
user = callback.get();
}
if (user == null) {
user = User.findByEmailSync(ctx.request().getParam("id"));
callback = new BlockingCallback<>();
User.findByEmail(ctx.request().getParam("id"), callback);
user = callback.get();
}
if (user == null) {

View File

@ -1,18 +1,22 @@
package net.frozenorb.apiv3.route.users;
import com.google.common.collect.ImmutableMap;
import com.mongodb.client.result.UpdateResult;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.unsorted.RequiresTotpResult;
import net.frozenorb.apiv3.util.ErrorUtils;
public final class POSTUserChangePassword implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {
User user = User.findByIdSync(ctx.request().getParam("id"));
BlockingCallback<User> userCallback = new BlockingCallback<>();
User.findById(ctx.request().getParam("id"), userCallback);
User user = userCallback.get();
if (user == null) {
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
@ -33,11 +37,11 @@ public final class POSTUserChangePassword implements Handler<RoutingContext> {
return;
}
BlockingCallback<User.RequiresTotpResult> totpRequiredCallback = new BlockingCallback<>();
BlockingCallback<RequiresTotpResult> totpRequiredCallback = new BlockingCallback<>();
user.requiresTotpAuthorization(null, totpRequiredCallback);
User.RequiresTotpResult requiresTotp = totpRequiredCallback.get();
RequiresTotpResult requiresTotp = totpRequiredCallback.get();
if (requiresTotp == User.RequiresTotpResult.REQUIRED_NO_EXEMPTIONS) {
if (requiresTotp == RequiresTotpResult.REQUIRED_NO_EXEMPTIONS) {
// TODO
}
@ -49,7 +53,9 @@ public final class POSTUserChangePassword implements Handler<RoutingContext> {
}
user.setPassword(newPassword);
user.save();
BlockingCallback<UpdateResult> saveCallback = new BlockingCallback<>();
user.save(saveCallback);
saveCallback.get();
APIv3.respondJson(ctx, ImmutableMap.of(
"success", true

View File

@ -1,5 +1,6 @@
package net.frozenorb.apiv3.route.users;
import com.mongodb.client.result.UpdateResult;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
@ -9,6 +10,7 @@ import net.frozenorb.apiv3.actor.ActorType;
import net.frozenorb.apiv3.model.IpLogEntry;
import net.frozenorb.apiv3.model.Server;
import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.IpUtils;
import net.frozenorb.apiv3.util.UuidUtils;
@ -26,7 +28,9 @@ public final class POSTUserLogin implements Handler<RoutingContext> {
}
JsonObject requestBody = ctx.getBodyAsJson();
User user = User.findByIdSync(uuid);
BlockingCallback<User> userCallback = new BlockingCallback<>();
User.findById(uuid, userCallback);
User user = userCallback.get();
String username = requestBody.getString("username");
String userIp = requestBody.getString("userIp");
Actor actor = ctx.get("actor");
@ -44,24 +48,42 @@ public final class POSTUserLogin implements Handler<RoutingContext> {
}
if (user == null) {
// Will be saved in the User constructor
user = new User(uuid, username);
BlockingCallback<Void> nameCollisionCallback = new BlockingCallback<>();
user.checkNameCollisions(nameCollisionCallback);
nameCollisionCallback.get();
BlockingCallback<Void> insertCallback = new BlockingCallback<>();
user.checkNameCollisions(insertCallback);
insertCallback.get();
}
IpLogEntry ipLogEntry = IpLogEntry.findByUserAndIpSync(user, userIp);
BlockingCallback<IpLogEntry> ipLogEntryCallback = new BlockingCallback<>();
IpLogEntry.findByUserAndIp(user, userIp, ipLogEntryCallback);
IpLogEntry ipLogEntry = ipLogEntryCallback.get();
// 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();
BlockingCallback<Void> callback = new BlockingCallback<>();
ipLogEntry.insert(callback);
callback.get();
} else {
ipLogEntry.used();
ipLogEntry.save();
BlockingCallback<UpdateResult> callback = new BlockingCallback<>();
ipLogEntry.save(callback);
callback.get();
}
if (!username.equals(user.getLastUsername())) {
BlockingCallback<Void> callback = new BlockingCallback<>();
user.checkNameCollisions(callback);
callback.get();
}
user.updateUsername(username);
user.getLoginInfo(server, userIp, (loginInfo, error) -> {
if (error != null) {
ErrorUtils.respondInternalError(ctx, error);

View File

@ -7,6 +7,7 @@ import io.vertx.ext.web.RoutingContext;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.NotificationTemplate;
import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.unsorted.Notification;
import net.frozenorb.apiv3.util.ErrorUtils;
@ -15,7 +16,9 @@ import java.util.Map;
public final class POSTUserNotify implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {
User user = User.findByIdSync(ctx.request().getParam("id"));
BlockingCallback<User> userCallback = new BlockingCallback<>();
User.findById(ctx.request().getParam("id"), userCallback);
User user = userCallback.get();
if (user == null) {
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
@ -28,7 +31,9 @@ public final class POSTUserNotify implements Handler<RoutingContext> {
}
JsonObject requestBody = ctx.getBodyAsJson();
NotificationTemplate template = NotificationTemplate.findByIdSync(requestBody.getString("template"));
BlockingCallback<NotificationTemplate> notificationTemplateCallback = new BlockingCallback<>();
NotificationTemplate.findById(requestBody.getString("template"), notificationTemplateCallback);
NotificationTemplate template = notificationTemplateCallback.get();
if (template == null) {
ErrorUtils.respondNotFound(ctx, "Notification template", requestBody.getString("template"));

View File

@ -1,12 +1,14 @@
package net.frozenorb.apiv3.route.users;
import com.google.common.collect.ImmutableMap;
import com.mongodb.client.result.UpdateResult;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.NotificationTemplate;
import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.unsorted.Notification;
import net.frozenorb.apiv3.util.ErrorUtils;
@ -22,7 +24,9 @@ public final class POSTUserRegister implements Handler<RoutingContext> {
);
public void handle(RoutingContext ctx) {
User user = User.findByIdSync(ctx.request().getParam("id"));
BlockingCallback<User> userCallback = new BlockingCallback<>();
User.findById(ctx.request().getParam("id"), userCallback);
User user = userCallback.get();
if (user == null) {
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
@ -48,15 +52,19 @@ public final class POSTUserRegister implements Handler<RoutingContext> {
}
user.startRegistration(email);
user.save();
BlockingCallback<UpdateResult> callback = new BlockingCallback<>();
user.save(callback);
callback.get();
Map<String, Object> replacements = ImmutableMap.of(
"username", user.getLastUsername(),
"email", user.getEmail(),
"email", user.getPendingEmail(),
"emailToken", user.getPendingEmailToken()
);
Notification notification = new Notification(NotificationTemplate.findByIdSync("email-confirmation"), replacements, replacements);
BlockingCallback<NotificationTemplate> notificationTemplateCallback = new BlockingCallback<>();
NotificationTemplate.findById("email-confirmation", notificationTemplateCallback);
Notification notification = new Notification(notificationTemplateCallback.get(), replacements, replacements);
notification.sendAsEmail(user.getEmail(), (ignored, error) -> {
if (error != null) {

View File

@ -1,18 +1,22 @@
package net.frozenorb.apiv3.route.users;
import com.google.common.collect.ImmutableMap;
import com.mongodb.client.result.UpdateResult;
import com.warrenstrange.googleauth.GoogleAuthenticatorKey;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.TotpUtils;
public final class POSTUserSetupTotp implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {
User user = User.findByIdSync(ctx.request().getParam("id"));
BlockingCallback<User> userCallback = new BlockingCallback<>();
User.findById(ctx.request().getParam("id"), userCallback);
User user = userCallback.get();
if (user == null) {
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
@ -27,7 +31,9 @@ public final class POSTUserSetupTotp implements Handler<RoutingContext> {
GoogleAuthenticatorKey generated = TotpUtils.generateTotpSecret();
user.setTotpSecret(generated.getKey());
user.save();
BlockingCallback<UpdateResult> callback = new BlockingCallback<>();
user.save(callback);
callback.get();
APIv3.respondJson(ctx, ImmutableMap.of(
"qrCode", TotpUtils.getQrCodeUrl(user, generated)

View File

@ -16,7 +16,9 @@ import java.util.concurrent.TimeUnit;
public final class POSTUserVerifyTotp implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {
User user = User.findByIdSync(ctx.request().getParam("id"));
BlockingCallback<User> userCallback = new BlockingCallback<>();
User.findById(ctx.request().getParam("id"), userCallback);
User user = userCallback.get();
if (user == null) {
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));

View File

@ -0,0 +1,22 @@
package net.frozenorb.apiv3.unsorted;
import com.mongodb.async.SingleResultCallback;
import io.vertx.core.Future;
public class FutureCompatibilityCallback<T> implements SingleResultCallback<T> {
private final Future<T> future;
public FutureCompatibilityCallback(Future<T> future) {
this.future = future;
}
public void onResult(T val, Throwable error) {
if (error != null) {
future.fail(error);
} else {
future.complete(val);
}
}
}

View File

@ -0,0 +1,9 @@
package net.frozenorb.apiv3.unsorted;
public enum RequiresTotpResult {
NOT_REQUIRED_NOT_SET,
NOT_REQUIRED_IP_PRE_AUTHORIZED,
REQUIRED_NO_EXEMPTIONS
}

View File

@ -1,27 +0,0 @@
package net.frozenorb.apiv3.util;
import com.mongodb.async.client.MongoIterable;
import lombok.experimental.UtilityClass;
import net.frozenorb.apiv3.unsorted.BlockingCallback;
import java.util.LinkedList;
import java.util.List;
@UtilityClass
public class SyncUtils {
public static <T> T blockOne(MongoIterable<T> mongoIterable) {
BlockingCallback<T> callback = new BlockingCallback<>();
mongoIterable.first(callback);
return callback.get();
}
public static <T> List<T> blockMulti(MongoIterable<T> mongoIterable) {
BlockingCallback<List<T>> callback = new BlockingCallback<>();
mongoIterable.into(new LinkedList<>(), callback);
return callback.get();
}
}