Merged spark-experimental into master
This commit is contained in:
commit
27d139f0f6
15
apiv3.properties
Normal file
15
apiv3.properties
Normal file
@ -0,0 +1,15 @@
|
||||
mongo.address=ds055505.mongolab.com
|
||||
mongo.port=55505
|
||||
mongo.database=minehqapi
|
||||
mongo.username=test
|
||||
mongo.password=test
|
||||
redis.address=localhost
|
||||
redis.port=6379
|
||||
http.address=
|
||||
http.port=80
|
||||
http.workerThreads=6
|
||||
twillio.accountSID=AC9e2f88c5690134d29a56f698de3cd740
|
||||
twillio.authToken=982592505a171d3be6b0722f5ecacc0e
|
||||
mandrill.apiKey=0OYtwymqJP6oqvszeJu0vQ
|
||||
auth.permittedUserRanks=developer,owner
|
||||
auth.websiteApiKey=RVbp4hY6sCFVaf
|
80
pom.xml
80
pom.xml
@ -48,24 +48,84 @@
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-core</artifactId>
|
||||
<version>3.2.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-web</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<groupId>com.sparkjava</groupId>
|
||||
<artifactId>spark-core</artifactId>
|
||||
<version>2.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>19.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>redis.clients</groupId>
|
||||
<artifactId>jedis</artifactId>
|
||||
<version>2.8.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.6.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.librato.metrics</groupId>
|
||||
<artifactId>metrics-librato</artifactId>
|
||||
<version>4.1.2.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dropwizard.metrics</groupId>
|
||||
<artifactId>metrics-core</artifactId>
|
||||
<version>3.1.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.bugsnag</groupId>
|
||||
<artifactId>bugsnag</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>mongodb-driver-async</artifactId>
|
||||
<version>3.0.4</version>
|
||||
<artifactId>mongo-java-driver</artifactId>
|
||||
<version>3.2.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.cribbstechnologies.clients</groupId>
|
||||
<artifactId>mandrillClient</artifactId>
|
||||
<version>1.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.twilio.sdk</groupId>
|
||||
<artifactId>twilio-java-sdk</artifactId>
|
||||
<version>6.3.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mindrot</groupId>
|
||||
<artifactId>jbcrypt</artifactId>
|
||||
<version>0.3m</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mongodb.morphia</groupId>
|
||||
<artifactId>morphia</artifactId>
|
||||
<version>1.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mongodb.morphia</groupId>
|
||||
<artifactId>morphia-logging-slf4j</artifactId>
|
||||
<version>1.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
<version>1.6.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpcore</artifactId>
|
||||
<version>4.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.warrenstrange</groupId>
|
||||
<artifactId>googleauth</artifactId>
|
||||
<version>0.5.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
|
@ -1,49 +1,190 @@
|
||||
package net.frozenorb.apiv3;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.mongodb.MongoClient;
|
||||
import com.mongodb.MongoCredential;
|
||||
import com.mongodb.ServerAddress;
|
||||
import com.mongodb.async.client.MongoDatabase;
|
||||
import io.vertx.core.AbstractVerticle;
|
||||
import io.vertx.ext.web.Router;
|
||||
import lombok.Getter;
|
||||
import net.frozenorb.apiv3.routes.*;
|
||||
import net.frozenorb.apiv3.util.MongoUtils;
|
||||
import net.frozenorb.apiv3.filters.ActorAttributeFilter;
|
||||
import net.frozenorb.apiv3.filters.AuthorizationFilter;
|
||||
import net.frozenorb.apiv3.filters.ContentTypeFilter;
|
||||
import net.frozenorb.apiv3.models.NotificationTemplate;
|
||||
import net.frozenorb.apiv3.routes.GETDump;
|
||||
import net.frozenorb.apiv3.routes.GETWhoAmI;
|
||||
import net.frozenorb.apiv3.routes.NotFound;
|
||||
import net.frozenorb.apiv3.routes.announcements.GETAnnouncements;
|
||||
import net.frozenorb.apiv3.routes.auditLog.GETAuditLog;
|
||||
import net.frozenorb.apiv3.routes.chatFilterList.GETChatFilterList;
|
||||
import net.frozenorb.apiv3.routes.grants.*;
|
||||
import net.frozenorb.apiv3.routes.ipLog.GETUserIPLog;
|
||||
import net.frozenorb.apiv3.routes.notificationTemplate.DELETENotificationTemplate;
|
||||
import net.frozenorb.apiv3.routes.notificationTemplate.GETNotificationTemplate;
|
||||
import net.frozenorb.apiv3.routes.notificationTemplate.GETNotificationTemplates;
|
||||
import net.frozenorb.apiv3.routes.notificationTemplate.POSTNotificationTemplate;
|
||||
import net.frozenorb.apiv3.routes.punishments.DELETEPunishment;
|
||||
import net.frozenorb.apiv3.routes.punishments.GETPunishment;
|
||||
import net.frozenorb.apiv3.routes.punishments.GETPunishments;
|
||||
import net.frozenorb.apiv3.routes.punishments.POSTUserPunish;
|
||||
import net.frozenorb.apiv3.routes.ranks.DELETERank;
|
||||
import net.frozenorb.apiv3.routes.ranks.GETRank;
|
||||
import net.frozenorb.apiv3.routes.ranks.GETRanks;
|
||||
import net.frozenorb.apiv3.routes.ranks.POSTRank;
|
||||
import net.frozenorb.apiv3.routes.serverGroups.DELETEServerGroup;
|
||||
import net.frozenorb.apiv3.routes.serverGroups.GETServerGroup;
|
||||
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.FollowAnnotationExclusionStrategy;
|
||||
import net.frozenorb.apiv3.serialization.ObjectIdTypeAdapter;
|
||||
import net.frozenorb.apiv3.unsorted.LoggingExceptionHandler;
|
||||
import net.frozenorb.apiv3.unsorted.Notification;
|
||||
import org.bson.types.ObjectId;
|
||||
import org.mongodb.morphia.Datastore;
|
||||
import org.mongodb.morphia.Morphia;
|
||||
import org.mongodb.morphia.logging.MorphiaLoggerFactory;
|
||||
import org.mongodb.morphia.logging.slf4j.SLF4JLoggerImplFactory;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
|
||||
public final class APIv3 extends AbstractVerticle {
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
|
||||
@Getter private static MongoDatabase mongo;
|
||||
import static spark.Spark.*;
|
||||
|
||||
// TODO: review the find* methods in models to make sure they're good (and sometimes not too broad, ex findAll on Users)
|
||||
// TODO: consistency -- sometimes we refer to a user as user or target.
|
||||
public final class APIv3 {
|
||||
|
||||
public void start() {
|
||||
@Getter private static Datastore datastore;
|
||||
@Getter private static Properties config = new Properties();
|
||||
@Getter private static JedisPool redisPool;
|
||||
@Getter private static final Gson gson = new GsonBuilder()
|
||||
.registerTypeAdapter(ObjectId.class, new ObjectIdTypeAdapter())
|
||||
.setExclusionStrategies(new FollowAnnotationExclusionStrategy())
|
||||
.create();
|
||||
|
||||
APIv3() {
|
||||
//System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "trace");
|
||||
|
||||
setupConfig();
|
||||
setupDatabase();
|
||||
setupRedis();
|
||||
setupHttp();
|
||||
}
|
||||
|
||||
public void setupDatabase() {
|
||||
mongo = MongoUtils.initializeConnection(ImmutableList.of(new ServerAddress("ds055505.mongolab.com", 55505)), "minehqapi", "test", "test".toCharArray());
|
||||
private void setupConfig() {
|
||||
try (InputStream in = new FileInputStream("apiv3.properties")) {
|
||||
config.load(in);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void setupHttp() {
|
||||
Router rootRouter = Router.router(vertx);
|
||||
private void setupDatabase() {
|
||||
MongoClient mongoClient = new MongoClient(new ServerAddress(
|
||||
config.getProperty("mongo.address"),
|
||||
Integer.parseInt(config.getProperty("mongo.port"))),
|
||||
ImmutableList.of(
|
||||
MongoCredential.createCredential(
|
||||
config.getProperty("mongo.username"),
|
||||
config.getProperty("mongo.database"),
|
||||
config.getProperty("mongo.password").toCharArray())
|
||||
));
|
||||
|
||||
// We always reply in JSON.
|
||||
rootRouter.route("/*").handler(ctx -> {
|
||||
ctx.response().putHeader("content-type", "application/json");
|
||||
ctx.next();
|
||||
});
|
||||
MorphiaLoggerFactory.reset();
|
||||
MorphiaLoggerFactory.registerLogger(SLF4JLoggerImplFactory.class);
|
||||
|
||||
rootRouter.mountSubRouter("/auditLog", AuditLogRouter.create(vertx));
|
||||
rootRouter.mountSubRouter("/grants", GrantsRouter.create(vertx));
|
||||
rootRouter.mountSubRouter("/ipLog", IPLogRouter.create(vertx));
|
||||
rootRouter.mountSubRouter("/notifications", NotificationsRouter.create(vertx));
|
||||
rootRouter.mountSubRouter("/punishments", PunishmentsRouter.create(vertx));
|
||||
rootRouter.mountSubRouter("/serverGroups", ServerGroupsRouter.create(vertx));
|
||||
rootRouter.mountSubRouter("/servers", ServersRouter.create(vertx));
|
||||
rootRouter.mountSubRouter("/users", UsersRouter.create(vertx));
|
||||
Morphia morphia = new Morphia();
|
||||
morphia.mapPackage("net.frozenorb.apiv3.accessor");
|
||||
|
||||
vertx.createHttpServer().requestHandler(rootRouter::accept).listen(8080);
|
||||
datastore = morphia.createDatastore(mongoClient, config.getProperty("mongo.database"));
|
||||
datastore.ensureIndexes();
|
||||
}
|
||||
|
||||
private void setupRedis() {
|
||||
redisPool = new JedisPool(
|
||||
config.getProperty("redis.address"),
|
||||
Integer.parseInt(config.getProperty("redis.port"))
|
||||
);
|
||||
}
|
||||
|
||||
private void setupHttp() {
|
||||
ipAddress(config.getProperty("http.address"));
|
||||
port(Integer.parseInt(config.getProperty("http.port")));
|
||||
threadPool(Integer.parseInt(config.getProperty("http.workerThreads")));
|
||||
before(new ContentTypeFilter());
|
||||
before(new ActorAttributeFilter());
|
||||
before(new AuthorizationFilter());
|
||||
exception(Exception.class, new LoggingExceptionHandler());
|
||||
|
||||
// TODO: The commented out routes
|
||||
|
||||
get("/announcements", new GETAnnouncements(), gson::toJson);
|
||||
get("/auditLog", new GETAuditLog(), gson::toJson);
|
||||
get("/chatFilterList", new GETChatFilterList(), gson::toJson);
|
||||
get("/dump/:type", new GETDump(), gson::toJson);
|
||||
get("/whoami", new GETWhoAmI(), gson::toJson);
|
||||
|
||||
get("/grant/:id", new GETGrant(), gson::toJson);
|
||||
get("/grants", new GETGrants(), gson::toJson);
|
||||
delete("/grant/:id", new DELETEGrant(), gson::toJson);
|
||||
|
||||
get("/notificationTemplate/:id", new GETNotificationTemplate(), gson::toJson);
|
||||
get("/notificationTemplates", new GETNotificationTemplates(), gson::toJson);
|
||||
post("/notificationTemplate", new POSTNotificationTemplate(), gson::toJson);
|
||||
//put("/notificationTemplate/:id", new PUTNotificationTemplate(), gson::toJson);
|
||||
delete("/notificationTemplate/:id", new DELETENotificationTemplate(), gson::toJson);
|
||||
|
||||
get("/punishment/:id", new GETPunishment(), gson::toJson);
|
||||
get("/punishments", new GETPunishments(), gson::toJson);
|
||||
delete("/punishment/:id", new DELETEPunishment(), gson::toJson);
|
||||
|
||||
get("/rank/:id", new GETRank(), gson::toJson);
|
||||
get("/ranks", new GETRanks(), gson::toJson);
|
||||
post("/rank", new POSTRank(), gson::toJson);
|
||||
//put("/rank/:id", new PUTRank(), gson::toJson);
|
||||
delete("/rank/:id", new DELETERank(), gson::toJson);
|
||||
|
||||
get("/serverGroup/:id", new GETServerGroup(), gson::toJson);
|
||||
get("/serverGroups", new GETServerGroups(), gson::toJson);
|
||||
post("/serverGroup", new POSTServerGroup(), gson::toJson);
|
||||
//put("/serverGroup/:id", new PUTServerGroup(), gson::toJson);
|
||||
delete("/serverGroup/:id", new DELETEServerGroup(), gson::toJson);
|
||||
|
||||
get("/server/:id", new GETServer(), gson::toJson);
|
||||
get("/servers", new GETServers(), gson::toJson);
|
||||
post("/server/heartbeat", new POSTServerHeartbeat(), gson::toJson);
|
||||
post("/server/metrics", new POSTServerMetrics(), gson::toJson);
|
||||
post("/server", new POSTServer(), gson::toJson);
|
||||
//put("/server/:id", new PUTServer(), gson::toJson);
|
||||
delete("/server/:id", new DELETEServer(), gson::toJson);
|
||||
|
||||
get("/staff", new GETStaff(), gson::toJson);
|
||||
get("/user/:id/details", new GETUserDetails(), gson::toJson);
|
||||
get("/user/:id/meta/:serverGroup", new GETUserMeta(), gson::toJson);
|
||||
get("/user/:id/grants", new GETUserGrants(), gson::toJson);
|
||||
get("/user/:id/ipLog", new GETUserIPLog(), gson::toJson);
|
||||
get("/user/:id/requiresTOTP", new GETUserRequiresTOTP(), gson::toJson);
|
||||
get("/user/:id/verifyPassword", new GETUserVerifyPassword(), gson::toJson);
|
||||
get("/user/:id", new GETUser(), gson::toJson);
|
||||
post("/user/:id/verifyTOTP", new POSTUserVerifyTOTP(), gson::toJson);
|
||||
post("/user/:id:/grant", new POSTUserGrant(), gson::toJson);
|
||||
post("/user/:id:/punish", new POSTUserPunish(), gson::toJson);
|
||||
post("/user/:id/login", new POSTUserLogin(), gson::toJson);
|
||||
post("/user/:id/notify", new POSTUserNotify(), gson::toJson);
|
||||
post("/user/:id/register", new POSTUserRegister(), gson::toJson);
|
||||
post("/user/:id/setupTOTP", new POSTUserSetupTOTP(), gson::toJson);
|
||||
post("/user/confirmRegister/:emailToken", new POSTUserConfirmRegister(), gson::toJson);
|
||||
put("/user/:id/meta/:serverGroup", new PUTUserMeta(), gson::toJson);
|
||||
delete("/user/:id/meta/:serverGroup", new DELETEUserMeta(), gson::toJson);
|
||||
|
||||
// There's no way to do a JSON 404 page w/o doing this :(
|
||||
get("/*", new NotFound(), gson::toJson);
|
||||
post("/*", new NotFound(), gson::toJson);
|
||||
put("/*", new NotFound(), gson::toJson);
|
||||
delete("/*", new NotFound(), gson::toJson);
|
||||
}
|
||||
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
package net.frozenorb.apiv3;
|
||||
|
||||
import org.bson.Document;
|
||||
|
||||
public interface LiteFullJson {
|
||||
|
||||
Document toLiteJson();
|
||||
default Document toFullJson() {
|
||||
return toLiteJson();
|
||||
}
|
||||
|
||||
}
|
@ -1,11 +1,9 @@
|
||||
package net.frozenorb.apiv3;
|
||||
|
||||
import io.vertx.core.Vertx;
|
||||
|
||||
public final class Main {
|
||||
final class Main {
|
||||
|
||||
public static void main(String[] args) {
|
||||
Vertx.vertx().deployVerticle(new APIv3());
|
||||
new APIv3();
|
||||
}
|
||||
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
package net.frozenorb.apiv3.accessor;
|
||||
|
||||
import com.mongodb.async.SingleResultCallback;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.model.AuditLogEntry;
|
||||
import net.frozenorb.apiv3.util.MongoUtils;
|
||||
import org.bson.Document;
|
||||
import org.bson.types.ObjectId;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
@UtilityClass
|
||||
public class AuditLog {
|
||||
|
||||
public static final String COLLECTION_NAME = "auditLog";
|
||||
private static final Document TIME_BASED_SORT = new Document("performedAt", -1);
|
||||
|
||||
public static void findAll(SingleResultCallback<Collection<AuditLogEntry>> callback) {
|
||||
MongoUtils.findAndTransform(COLLECTION_NAME, new Document(), TIME_BASED_SORT, AuditLogEntry::new, callback);
|
||||
}
|
||||
|
||||
public static void findByPerformer(UUID performer, SingleResultCallback<Collection<AuditLogEntry>> callback) {
|
||||
MongoUtils.findAndTransform(COLLECTION_NAME, new Document("performedBy", performer.toString()), TIME_BASED_SORT, AuditLogEntry::new, callback);
|
||||
}
|
||||
|
||||
public static void findByPerformerIp(String performerIp, SingleResultCallback<Collection<AuditLogEntry>> callback) {
|
||||
MongoUtils.findAndTransform(COLLECTION_NAME, new Document("performedFrom", performerIp), TIME_BASED_SORT, AuditLogEntry::new, callback);
|
||||
}
|
||||
|
||||
public static void findByActionType(String actionType, SingleResultCallback<Collection<AuditLogEntry>> callback) {
|
||||
MongoUtils.findAndTransform(COLLECTION_NAME, new Document("actionType", actionType), TIME_BASED_SORT, AuditLogEntry::new, callback);
|
||||
}
|
||||
|
||||
public static void log(UUID user, String userIp, String actionType, SingleResultCallback<Void> callback) {
|
||||
log(user, userIp, actionType, callback);
|
||||
}
|
||||
|
||||
public static void log(UUID user, String userIp, String actionType, Document data, SingleResultCallback<Void> callback) {
|
||||
Document insert = new Document();
|
||||
|
||||
insert.put("_id", new ObjectId().toString());
|
||||
insert.put("performedBy", user.toString());
|
||||
insert.put("performedAt", new Date());
|
||||
insert.put("performedFrom", userIp);
|
||||
insert.put("actionType", actionType);
|
||||
insert.put("actionData", data);
|
||||
|
||||
APIv3.getMongo().getCollection(COLLECTION_NAME).insertOne(insert, callback);
|
||||
}
|
||||
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
package net.frozenorb.apiv3.accessor;
|
||||
|
||||
import com.mongodb.async.SingleResultCallback;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.model.Grant;
|
||||
import net.frozenorb.apiv3.util.MongoUtils;
|
||||
import org.bson.Document;
|
||||
import org.bson.types.ObjectId;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
@UtilityClass
|
||||
public class Grants {
|
||||
|
||||
public static final String COLLECTION_NAME = "grant";
|
||||
private static final Document TIME_BASED_SORT = new Document("addedAt", -1);
|
||||
|
||||
public static void findById(String id, SingleResultCallback<Grant> callback) {
|
||||
MongoUtils.findOneAndTransform(COLLECTION_NAME, new Document("_id", id), Grant::new, callback);
|
||||
}
|
||||
|
||||
public static void findByTarget(UUID target, SingleResultCallback<Collection<Grant>> callback) {
|
||||
MongoUtils.findAndTransform(COLLECTION_NAME, new Document("target", target.toString()), TIME_BASED_SORT, Grant::new, callback);
|
||||
}
|
||||
|
||||
public static void findByAddedBy(UUID addedBy, SingleResultCallback<Collection<Grant>> callback) {
|
||||
MongoUtils.findAndTransform(COLLECTION_NAME, new Document("addedBy", addedBy.toString()), TIME_BASED_SORT, Grant::new, callback);
|
||||
}
|
||||
|
||||
public static void createGrant(UUID target, Set<String> scopes, String rank, Instant expiresAt, UUID addedBy, String reason, SingleResultCallback<Void> callback) {
|
||||
Document insert = new Document();
|
||||
|
||||
insert.put("_id", new ObjectId().toString());
|
||||
insert.put("target", target.toString());
|
||||
insert.put("reason", reason);
|
||||
insert.put("scopes", scopes);
|
||||
insert.put("rank", rank);
|
||||
insert.put("expiresAt", expiresAt);
|
||||
|
||||
insert.put("addedBy", addedBy.toString());
|
||||
insert.put("addedAt", Instant.now());
|
||||
|
||||
APIv3.getMongo().getCollection(COLLECTION_NAME).insertOne(insert, callback);
|
||||
}
|
||||
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package net.frozenorb.apiv3.accessor;
|
||||
|
||||
import com.mongodb.async.SingleResultCallback;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import net.frozenorb.apiv3.model.IPBan;
|
||||
import net.frozenorb.apiv3.util.MongoUtils;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@UtilityClass
|
||||
public class IPBans {
|
||||
|
||||
public static final String COLLECTION_NAME = "ipBan";
|
||||
|
||||
public static void findAll(SingleResultCallback<Collection<IPBan>> callback) {
|
||||
MongoUtils.findAndTransform(COLLECTION_NAME, new Document(), IPBan::new, callback);
|
||||
}
|
||||
|
||||
public static void findById(String id, SingleResultCallback<IPBan> callback) {
|
||||
MongoUtils.findOneAndTransform(COLLECTION_NAME, new Document("_id", id), IPBan::new, callback);
|
||||
}
|
||||
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
package net.frozenorb.apiv3.accessor;
|
||||
|
||||
import com.mongodb.async.SingleResultCallback;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.model.IPLogEntry;
|
||||
import net.frozenorb.apiv3.util.MongoUtils;
|
||||
import org.bson.Document;
|
||||
import org.bson.types.ObjectId;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
import java.util.UUID;
|
||||
|
||||
@UtilityClass
|
||||
public class IPLog {
|
||||
|
||||
public static final String COLLECTION_NAME = "ipLog";
|
||||
private static final Document TIME_BASED_SORT = new Document("lastSeen", -1);
|
||||
|
||||
public static void findByUser(UUID user, SingleResultCallback<Collection<IPLogEntry>> callback) {
|
||||
MongoUtils.findAndTransform(COLLECTION_NAME, new Document("user", user.toString()), TIME_BASED_SORT, IPLogEntry::new, callback);
|
||||
}
|
||||
|
||||
public static void findByIp(String ip, SingleResultCallback<Collection<IPLogEntry>> callback) {
|
||||
MongoUtils.findAndTransform(COLLECTION_NAME, new Document("ip", ip), TIME_BASED_SORT, IPLogEntry::new, callback);
|
||||
}
|
||||
|
||||
public static void log(UUID user, String ip , SingleResultCallback<Void> callback) {
|
||||
MongoUtils.findOneAndTransform(COLLECTION_NAME, new Document("user", user.toString()).append("ip", ip), IPLogEntry::new, (ipLogEntry, error) -> {
|
||||
if (error != null) {
|
||||
callback.onResult(null, error);
|
||||
} else if (ipLogEntry != null) {
|
||||
ipLogEntry.used(callback);
|
||||
} else {
|
||||
Document insert = new Document();
|
||||
|
||||
insert.put("_id", new ObjectId().toString());
|
||||
insert.put("user", user.toString());
|
||||
insert.put("ip", ip);
|
||||
insert.put("lastSeen", Instant.now());
|
||||
insert.put("firstSeen", Instant.now());
|
||||
insert.put("uses", 1);
|
||||
|
||||
APIv3.getMongo().getCollection(COLLECTION_NAME).insertOne(insert, (ignored, error2) -> {
|
||||
callback.onResult(null, error2);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
package net.frozenorb.apiv3.accessor;
|
||||
|
||||
import com.mongodb.async.SingleResultCallback;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.model.NotificationLogEntry;
|
||||
import net.frozenorb.apiv3.util.MongoUtils;
|
||||
import org.bson.Document;
|
||||
import org.bson.types.ObjectId;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
import java.util.UUID;
|
||||
|
||||
@UtilityClass
|
||||
public class NotificationLog {
|
||||
|
||||
public static final String COLLECTION_NAME = "notificationLog";
|
||||
|
||||
public static void findByTarget(UUID target, SingleResultCallback<Collection<NotificationLogEntry>> callback) {
|
||||
MongoUtils.findAndTransform(COLLECTION_NAME, new Document("target", target.toString()), NotificationLogEntry::new, callback);
|
||||
}
|
||||
|
||||
public static void logEmail(UUID user, String title, String body, SingleResultCallback<Void> callback) {
|
||||
log(user, NotificationLogEntry.NotificationType.EMAIL, title, body, callback);
|
||||
}
|
||||
|
||||
public static void logSMS(UUID user, String title, String body, SingleResultCallback<Void> callback) {
|
||||
log(user, NotificationLogEntry.NotificationType.SMS, title, body, callback);
|
||||
}
|
||||
|
||||
private static void log(UUID user, NotificationLogEntry.NotificationType type, String title, String body, SingleResultCallback<Void> callback) {
|
||||
Document insert = new Document();
|
||||
|
||||
insert.put("_id", new ObjectId().toString());
|
||||
insert.put("target", user.toString());
|
||||
insert.put("sentAt", Instant.now());
|
||||
insert.put("type", type.name());
|
||||
insert.put("title", title);
|
||||
insert.put("body", body);
|
||||
|
||||
APIv3.getMongo().getCollection(COLLECTION_NAME).insertOne(insert, callback);
|
||||
}
|
||||
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package net.frozenorb.apiv3.accessor;
|
||||
|
||||
import com.mongodb.async.SingleResultCallback;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.model.NotificationTemplate;
|
||||
import net.frozenorb.apiv3.util.MongoUtils;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
import java.util.UUID;
|
||||
|
||||
@UtilityClass
|
||||
public class NotificationTemplates {
|
||||
|
||||
public static final String COLLECTION_NAME = "notificationTemplate";
|
||||
|
||||
public static void findAll(SingleResultCallback<Collection<NotificationTemplate>> callback) {
|
||||
MongoUtils.findAndTransform(COLLECTION_NAME, new Document(), NotificationTemplate::new, callback);
|
||||
}
|
||||
|
||||
public static void findById(String id, SingleResultCallback<NotificationTemplate> callback) {
|
||||
MongoUtils.findOneAndTransform(COLLECTION_NAME, new Document("_id", id), NotificationTemplate::new, callback);
|
||||
}
|
||||
|
||||
public static void createNotificationTemplate(String id, String title, String body, UUID creator, SingleResultCallback<Void> callback) {
|
||||
Document insert = new Document();
|
||||
|
||||
insert.put("_id", id);
|
||||
insert.put("title", title);
|
||||
insert.put("body", body);
|
||||
insert.put("lastUpdatedAt", Instant.now());
|
||||
insert.put("lastUpdatedBy", creator.toString());
|
||||
|
||||
APIv3.getMongo().getCollection(COLLECTION_NAME).insertOne(insert, callback);
|
||||
}
|
||||
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
package net.frozenorb.apiv3.accessor;
|
||||
|
||||
import com.mongodb.async.SingleResultCallback;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.model.Grant;
|
||||
import net.frozenorb.apiv3.model.Punishment;
|
||||
import net.frozenorb.apiv3.util.MongoUtils;
|
||||
import org.bson.Document;
|
||||
import org.bson.types.ObjectId;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
import java.util.UUID;
|
||||
|
||||
@UtilityClass
|
||||
public class Punishments {
|
||||
|
||||
public static final String COLLECTION_NAME = "punishment";
|
||||
private static final Document TIME_BASED_SORT = new Document("addedAt", -1);
|
||||
|
||||
public static void findById(String id, SingleResultCallback<Punishment> callback) {
|
||||
MongoUtils.findOneAndTransform(COLLECTION_NAME, new Document("_id", id), Punishment::new, callback);
|
||||
}
|
||||
|
||||
public static void findByTarget(UUID target, SingleResultCallback<Collection<Punishment>> callback) {
|
||||
MongoUtils.findAndTransform(COLLECTION_NAME, new Document("target", target.toString()), TIME_BASED_SORT, Punishment::new, callback);
|
||||
}
|
||||
|
||||
public static void findByAddedBy(UUID addedBy, SingleResultCallback<Collection<Grant>> callback) {
|
||||
MongoUtils.findAndTransform(COLLECTION_NAME, new Document("addedBy", addedBy.toString()), TIME_BASED_SORT, Grant::new, callback);
|
||||
}
|
||||
|
||||
public static void createPunishment(UUID target, Punishment.PunishmentType type, Instant expiresAt, UUID addedBy, String addedOn, String reason, SingleResultCallback<Void> callback) {
|
||||
Document insert = new Document();
|
||||
|
||||
insert.put("_id", new ObjectId().toString());
|
||||
insert.put("target", target.toString());
|
||||
insert.put("reason", reason);
|
||||
insert.put("type", type.name());
|
||||
insert.put("expiresAt", expiresAt);
|
||||
|
||||
insert.put("addedBy", addedBy.toString());
|
||||
insert.put("addedAt", Instant.now());
|
||||
insert.put("addedOn", addedOn);
|
||||
|
||||
APIv3.getMongo().getCollection(COLLECTION_NAME).insertOne(insert, callback);
|
||||
}
|
||||
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package net.frozenorb.apiv3.accessor;
|
||||
|
||||
import com.mongodb.async.SingleResultCallback;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import net.frozenorb.apiv3.model.ServerGroup;
|
||||
import net.frozenorb.apiv3.util.MongoUtils;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@UtilityClass
|
||||
public class ServerGroups {
|
||||
|
||||
public static final String COLLECTION_NAME = "serverGroup";
|
||||
|
||||
public static void findAll(SingleResultCallback<Collection<ServerGroup>> callback) {
|
||||
MongoUtils.findAndTransform(COLLECTION_NAME, new Document(), ServerGroup::new, callback);
|
||||
}
|
||||
|
||||
public static void findById(String id, SingleResultCallback<ServerGroup> callback) {
|
||||
MongoUtils.findOneAndTransform(COLLECTION_NAME, new Document("_id", id), ServerGroup::new, callback);
|
||||
}
|
||||
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
package net.frozenorb.apiv3.accessor;
|
||||
|
||||
import com.mongodb.async.SingleResultCallback;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import net.frozenorb.apiv3.model.Server;
|
||||
import net.frozenorb.apiv3.util.MongoUtils;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@UtilityClass
|
||||
public class Servers {
|
||||
|
||||
public static final String COLLECTION_NAME = "server";
|
||||
|
||||
public static void findAll(SingleResultCallback<Collection<Server>> callback) {
|
||||
MongoUtils.findAndTransform(COLLECTION_NAME, new Document(), Server::new, callback);
|
||||
}
|
||||
|
||||
public static void findById(String id, SingleResultCallback<Server> callback) {
|
||||
MongoUtils.findOneAndTransform(COLLECTION_NAME, new Document("_id", id), Server::new, callback);
|
||||
}
|
||||
|
||||
public static void findByGroup(String groupId, SingleResultCallback<Collection<Server>> callback) {
|
||||
MongoUtils.findAndTransform(COLLECTION_NAME, new Document("group", groupId), Server::new, callback);
|
||||
}
|
||||
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package net.frozenorb.apiv3.accessor;
|
||||
|
||||
import com.mongodb.async.SingleResultCallback;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import net.frozenorb.apiv3.model.User;
|
||||
import net.frozenorb.apiv3.util.MongoUtils;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.UUID;
|
||||
|
||||
@UtilityClass
|
||||
public class Users {
|
||||
|
||||
public static final String COLLECTION_NAME = "user";
|
||||
|
||||
public static void findAll(SingleResultCallback<Collection<User>> callback) {
|
||||
MongoUtils.findAndTransform(COLLECTION_NAME, new Document(), User::new, callback);
|
||||
}
|
||||
|
||||
public static void findById(UUID id, SingleResultCallback<User> callback) {
|
||||
MongoUtils.findOneAndTransform(COLLECTION_NAME, new Document("_id", id.toString()), User::new, callback);
|
||||
}
|
||||
|
||||
}
|
9
src/main/java/net/frozenorb/apiv3/actors/Actor.java
Normal file
9
src/main/java/net/frozenorb/apiv3/actors/Actor.java
Normal file
@ -0,0 +1,9 @@
|
||||
package net.frozenorb.apiv3.actors;
|
||||
|
||||
public interface Actor {
|
||||
|
||||
boolean isAuthorized();
|
||||
String getName();
|
||||
ActorType getType();
|
||||
|
||||
}
|
7
src/main/java/net/frozenorb/apiv3/actors/ActorType.java
Normal file
7
src/main/java/net/frozenorb/apiv3/actors/ActorType.java
Normal file
@ -0,0 +1,7 @@
|
||||
package net.frozenorb.apiv3.actors;
|
||||
|
||||
public enum ActorType {
|
||||
|
||||
WEBSITE, SERVER, USER, UNKNOWN
|
||||
|
||||
}
|
25
src/main/java/net/frozenorb/apiv3/actors/ServerActor.java
Normal file
25
src/main/java/net/frozenorb/apiv3/actors/ServerActor.java
Normal file
@ -0,0 +1,25 @@
|
||||
package net.frozenorb.apiv3.actors;
|
||||
|
||||
import net.frozenorb.apiv3.models.Server;
|
||||
|
||||
public final class ServerActor implements Actor {
|
||||
|
||||
private final Server server;
|
||||
|
||||
public ServerActor(Server server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
public boolean isAuthorized() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return server.getId();
|
||||
}
|
||||
|
||||
public ActorType getType() {
|
||||
return ActorType.SERVER;
|
||||
}
|
||||
|
||||
}
|
17
src/main/java/net/frozenorb/apiv3/actors/UnknownActor.java
Normal file
17
src/main/java/net/frozenorb/apiv3/actors/UnknownActor.java
Normal file
@ -0,0 +1,17 @@
|
||||
package net.frozenorb.apiv3.actors;
|
||||
|
||||
public final class UnknownActor implements Actor {
|
||||
|
||||
public boolean isAuthorized() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
public ActorType getType() {
|
||||
return ActorType.UNKNOWN;
|
||||
}
|
||||
|
||||
}
|
39
src/main/java/net/frozenorb/apiv3/actors/UserActor.java
Normal file
39
src/main/java/net/frozenorb/apiv3/actors/UserActor.java
Normal file
@ -0,0 +1,39 @@
|
||||
package net.frozenorb.apiv3.actors;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.models.User;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public final class UserActor implements Actor {
|
||||
|
||||
private static final Set<String> authorizedUserGrants = ImmutableSet.copyOf(APIv3.getConfig().getProperty("auth.permittedUserRanks").split(","));
|
||||
|
||||
private final User user;
|
||||
// We use Boolean here so we can have null = not calculated;
|
||||
private Boolean cachedAuthorized = null;
|
||||
|
||||
public UserActor(User user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public boolean isAuthorized() {
|
||||
if (cachedAuthorized != null) {
|
||||
return cachedAuthorized;
|
||||
} else {
|
||||
String highestRankId = user.getHighestRank().getId();
|
||||
cachedAuthorized = authorizedUserGrants.contains(highestRankId);
|
||||
return cachedAuthorized;
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return user.getLastUsername();
|
||||
}
|
||||
|
||||
public ActorType getType() {
|
||||
return ActorType.USER;
|
||||
}
|
||||
|
||||
}
|
17
src/main/java/net/frozenorb/apiv3/actors/WebsiteActor.java
Normal file
17
src/main/java/net/frozenorb/apiv3/actors/WebsiteActor.java
Normal file
@ -0,0 +1,17 @@
|
||||
package net.frozenorb.apiv3.actors;
|
||||
|
||||
public final class WebsiteActor implements Actor {
|
||||
|
||||
public boolean isAuthorized() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return "Website";
|
||||
}
|
||||
|
||||
public ActorType getType() {
|
||||
return ActorType.WEBSITE;
|
||||
}
|
||||
|
||||
}
|
24
src/main/java/net/frozenorb/apiv3/auditLog/AuditLog.java
Normal file
24
src/main/java/net/frozenorb/apiv3/auditLog/AuditLog.java
Normal file
@ -0,0 +1,24 @@
|
||||
package net.frozenorb.apiv3.auditLog;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.actors.Actor;
|
||||
import net.frozenorb.apiv3.models.AuditLogEntry;
|
||||
import net.frozenorb.apiv3.models.User;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@UtilityClass
|
||||
public class AuditLog {
|
||||
|
||||
public static void log(User performedBy, String performedByIp, Actor actor, AuditLogActionType actionType) {
|
||||
log(performedBy, performedByIp, actor, actionType, ImmutableMap.of());
|
||||
}
|
||||
|
||||
public static void log(User performedBy, String performedByIp, Actor actor, AuditLogActionType actionType, Map<String, Object> actionData) {
|
||||
APIv3.getDatastore().save(new AuditLogEntry(performedBy, performedByIp, actor, actionType, actionData));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package net.frozenorb.apiv3.auditLog;
|
||||
|
||||
import net.frozenorb.apiv3.models.AuditLogEntry;
|
||||
|
||||
public enum AuditLogActionType {
|
||||
|
||||
DELETE_PUNISHMENT {
|
||||
|
||||
@Override
|
||||
public void revert(AuditLogEntry entry) {
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
DELETE_GRANT {
|
||||
|
||||
@Override
|
||||
public void revert(AuditLogEntry entry) {
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
public void revert(AuditLogEntry entry) {}
|
||||
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package net.frozenorb.apiv3.filters;
|
||||
|
||||
import com.sun.xml.internal.messaging.saaj.util.Base64;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.actors.*;
|
||||
import net.frozenorb.apiv3.models.Server;
|
||||
import net.frozenorb.apiv3.models.User;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import spark.Filter;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Spark;
|
||||
|
||||
public final class ActorAttributeFilter implements Filter {
|
||||
|
||||
public void handle(Request req, Response res) {
|
||||
String authHeader = req.headers("Authorization");
|
||||
String mhqAuthHeader = req.headers("MHQ-Authorization");
|
||||
|
||||
if (authHeader != null) {
|
||||
req.attribute("actor", processBasicAuthorization(authHeader));
|
||||
} else if (mhqAuthHeader != null) {
|
||||
req.attribute("actor", processMHQAuthorization(mhqAuthHeader));
|
||||
} else {
|
||||
req.attribute("actor", new UnknownActor());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation") // We purposely get the User by their last username.
|
||||
private Actor processBasicAuthorization(String authHeader) {
|
||||
String encodedHeader = authHeader.substring("Basic ".length());
|
||||
String[] credentials = Base64.base64Decode(encodedHeader).split(":");
|
||||
|
||||
if (credentials.length == 2) {
|
||||
User user = User.byLastUsername(credentials[0]);
|
||||
char[] password = credentials[1].toCharArray();
|
||||
|
||||
if (user != null && user.checkPassword(password)) {
|
||||
return new UserActor(user);
|
||||
}
|
||||
}
|
||||
|
||||
Spark.halt(401, APIv3.getGson().toJson(ErrorUtils.error("Failed to authorize.")));
|
||||
return null;
|
||||
}
|
||||
|
||||
private Actor processMHQAuthorization(String authHeader) {
|
||||
String[] split = authHeader.split(" ");
|
||||
|
||||
if (split.length >= 2) {
|
||||
String type = split[0];
|
||||
|
||||
if (type.equals("Website") && split.length == 2) {
|
||||
String givenKey = split[1];
|
||||
String properKey = APIv3.getConfig().getProperty("auth.websiteApiKey");
|
||||
|
||||
if (givenKey.equals(properKey)) {
|
||||
return new WebsiteActor();
|
||||
}
|
||||
} else if (type.equals("Server") && split.length == 3) {
|
||||
Server server = Server.byId(split[1]);
|
||||
|
||||
if (server == null) {
|
||||
Spark.halt(401, APIv3.getGson().toJson(ErrorUtils.notFound("Server", split[1])));
|
||||
}
|
||||
|
||||
String givenKey = split[2];
|
||||
String properKey = server.getApiKey();
|
||||
|
||||
if (givenKey.equals(properKey)) {
|
||||
return new ServerActor(server);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spark.halt(401, APIv3.getGson().toJson(ErrorUtils.error("Failed to authorize.")));
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package net.frozenorb.apiv3.filters;
|
||||
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.actors.Actor;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import spark.Filter;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Spark;
|
||||
|
||||
public final class AuthorizationFilter implements Filter {
|
||||
|
||||
public void handle(Request req, Response res) {
|
||||
Actor actor = req.attribute("actor");
|
||||
|
||||
if (!actor.isAuthorized()) {
|
||||
Spark.halt(APIv3.getGson().toJson(ErrorUtils.error("Unauthorized access: Please authenticate as either a server, the website, or an authorized user. You're currently authorized as " + actor.getName())));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package net.frozenorb.apiv3.filters;
|
||||
|
||||
import spark.Filter;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
|
||||
public final class ContentTypeFilter implements Filter {
|
||||
|
||||
public void handle(Request req, Response res) {
|
||||
res.header("content-type", "application/json");
|
||||
}
|
||||
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
package net.frozenorb.apiv3.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import net.frozenorb.apiv3.accessor.AuditLog;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.UUID;
|
||||
|
||||
@ToString
|
||||
public final class AuditLogEntry extends BaseModel {
|
||||
|
||||
@Getter private String id;
|
||||
@Getter private UUID performedBy;
|
||||
@Getter private Instant performedAt;
|
||||
@Getter private String performedFrom;
|
||||
@Getter private String actionType;
|
||||
@Getter private Document actionData;
|
||||
|
||||
public AuditLogEntry(Document json) {
|
||||
super(AuditLog.COLLECTION_NAME);
|
||||
|
||||
this.id = json.getString("_id");
|
||||
this.performedBy = UUID.fromString(json.getString("performedBy"));
|
||||
this.performedAt = (Instant) json.get("performedAt");
|
||||
this.performedFrom = json.getString("performedFrom");
|
||||
this.actionType = json.getString("actionType");
|
||||
this.actionData = (Document) json.get("actionData");
|
||||
|
||||
setId(id);
|
||||
}
|
||||
|
||||
public Document toLiteJson() {
|
||||
Document json = new Document();
|
||||
|
||||
json.put("id", id);
|
||||
json.put("performedBy", performedBy.toString());
|
||||
json.put("performedAt", performedAt.toString());
|
||||
json.put("performedFrom", performedFrom);
|
||||
json.put("actionType", actionType);
|
||||
json.put("actionData", actionData);
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
package net.frozenorb.apiv3.model;
|
||||
|
||||
import com.mongodb.async.SingleResultCallback;
|
||||
import lombok.Setter;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.LiteFullJson;
|
||||
import org.bson.Document;
|
||||
|
||||
public abstract class BaseModel implements LiteFullJson {
|
||||
|
||||
private final String collectionName;
|
||||
@Setter private String id;
|
||||
|
||||
public BaseModel(String collectionName) {
|
||||
this.collectionName = collectionName;
|
||||
}
|
||||
|
||||
protected void update(Document update, SingleResultCallback<Void> callback) {
|
||||
APIv3.getMongo().getCollection(collectionName).updateOne(new Document("_id", id), update, (updateResult, error) -> {
|
||||
callback.onResult(null, error);
|
||||
});
|
||||
}
|
||||
|
||||
protected void delete(SingleResultCallback<Void> callback) {
|
||||
APIv3.getMongo().getCollection(collectionName).deleteOne(new Document("_id", id), (deleteResult, error) -> {
|
||||
callback.onResult(null, error);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -1,114 +0,0 @@
|
||||
package net.frozenorb.apiv3.model;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.mongodb.async.SingleResultCallback;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import net.frozenorb.apiv3.accessor.Grants;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
@ToString
|
||||
public final class Grant extends BaseModel {
|
||||
|
||||
@Getter private String id;
|
||||
@Getter private UUID target;
|
||||
@Getter private String reason;
|
||||
@Getter private Set<String> scopes;
|
||||
@Getter private String rank;
|
||||
@Getter private Instant expiresAt;
|
||||
|
||||
@Getter private UUID addedBy;
|
||||
@Getter private Instant addedAt;
|
||||
|
||||
@Getter private UUID removedBy;
|
||||
@Getter private Instant removedAt;
|
||||
@Getter private String removalReason;
|
||||
|
||||
public Grant(Document json) {
|
||||
super(Grants.COLLECTION_NAME);
|
||||
|
||||
this.id = json.getString("_id");
|
||||
this.target = UUID.fromString(json.getString("target"));
|
||||
this.reason = json.getString("reason");
|
||||
this.scopes = ImmutableSet.copyOf((Collection) json.get("scopes")); // This is a safe cast, the collection's type is always String
|
||||
this.rank = json.getString("rank");
|
||||
this.expiresAt = (Instant) json.get("expiresAt");
|
||||
|
||||
this.addedBy = UUID.fromString(json.getString("addedBy"));
|
||||
this.addedAt = (Instant) json.get("addedAt");
|
||||
|
||||
if (json.containsKey("removedBy")) {
|
||||
this.removedBy = UUID.fromString(json.getString("removedBy"));
|
||||
this.removedAt = (Instant) json.get("removedAt");
|
||||
this.removalReason = json.getString("removalReason");
|
||||
}
|
||||
|
||||
setId(id);
|
||||
}
|
||||
|
||||
public void delete(UUID removedBy, String reason, SingleResultCallback<Void> callback) {
|
||||
this.removedBy = removedBy;
|
||||
this.removedAt = Instant.now();
|
||||
this.removalReason = reason;
|
||||
|
||||
Document set = new Document();
|
||||
|
||||
set.put("removedBy", removedBy.toString());
|
||||
set.put("removedAt", removedAt);
|
||||
set.put("removalReason", removalReason);
|
||||
|
||||
super.update(new Document("$set", set), callback);
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return !(isExpired() || isRemoved());
|
||||
}
|
||||
|
||||
public boolean isExpired() {
|
||||
if (expiresAt == null) {
|
||||
return false; // Never expires
|
||||
} else {
|
||||
return expiresAt.isAfter(Instant.now());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRemoved() {
|
||||
return removedBy != null;
|
||||
}
|
||||
|
||||
public Document toLiteJson() {
|
||||
Document json = new Document();
|
||||
|
||||
json.put("id", id);
|
||||
json.put("target", target.toString());
|
||||
json.put("reason", reason);
|
||||
json.put("scopes", scopes);
|
||||
json.put("rank", rank);
|
||||
json.put("expiresAt", expiresAt == null ? null : expiresAt.toString());
|
||||
|
||||
json.put("addedBy", addedBy.toString());
|
||||
json.put("addedAt", addedAt.toString());
|
||||
|
||||
Document statusJson = new Document();
|
||||
|
||||
statusJson.put("active", isActive());
|
||||
statusJson.put("expired", isExpired());
|
||||
statusJson.put("removed", isRemoved());
|
||||
|
||||
json.put("status", statusJson);
|
||||
|
||||
if (removedBy != null) {
|
||||
json.put("removedBy", removedBy.toString());
|
||||
json.put("removedAt", removedAt.toString());
|
||||
json.put("removalReason", removalReason);
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
package net.frozenorb.apiv3.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import net.frozenorb.apiv3.accessor.IPBans;
|
||||
import org.bson.Document;
|
||||
|
||||
@ToString
|
||||
public final class IPBan extends BaseModel {
|
||||
|
||||
@Getter private String id;
|
||||
|
||||
public IPBan(Document json) {
|
||||
super(IPBans.COLLECTION_NAME);
|
||||
|
||||
this.id = json.getString("_id");
|
||||
|
||||
setId(id);
|
||||
}
|
||||
|
||||
public Document toLiteJson() {
|
||||
Document json = new Document();
|
||||
|
||||
json.put("_id", id);
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
public Document toFullJson() {
|
||||
Document json = toLiteJson();
|
||||
|
||||
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
package net.frozenorb.apiv3.model;
|
||||
|
||||
import com.mongodb.async.SingleResultCallback;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import net.frozenorb.apiv3.accessor.IPLog;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.UUID;
|
||||
|
||||
@ToString
|
||||
public final class IPLogEntry extends BaseModel {
|
||||
|
||||
@Getter private String id;
|
||||
@Getter private UUID user;
|
||||
@Getter private String ip;
|
||||
@Getter private Instant firstSeen;
|
||||
@Getter private Instant lastSeen;
|
||||
@Getter private int uses;
|
||||
|
||||
public IPLogEntry(Document json) {
|
||||
super(IPLog.COLLECTION_NAME);
|
||||
|
||||
this.id = json.getString("_id");
|
||||
this.user = UUID.fromString(json.getString("user"));
|
||||
this.ip = json.getString("ip");
|
||||
this.lastSeen = (Instant) json.get("lastSeen");
|
||||
this.firstSeen = (Instant) json.get("firstSeen");
|
||||
this.uses = json.getInteger("uses");
|
||||
|
||||
setId(id);
|
||||
}
|
||||
|
||||
public void used(SingleResultCallback<Void> callback) {
|
||||
this.lastSeen = Instant.now();
|
||||
this.uses++;
|
||||
|
||||
Document set = new Document();
|
||||
|
||||
set.put("lastSeen", lastSeen);
|
||||
set.put("uses", uses);
|
||||
|
||||
super.update(new Document("$set", set), (updateResult, error) -> {
|
||||
callback.onResult(null, error);
|
||||
});
|
||||
}
|
||||
|
||||
public Document toLiteJson() {
|
||||
Document json = new Document();
|
||||
|
||||
json.put("id", id);
|
||||
json.put("user", user.toString());
|
||||
json.put("ip", ip);
|
||||
json.put("firstSeen", firstSeen.toString());
|
||||
json.put("lastSeen", lastSeen.toString());
|
||||
json.put("uses", uses);
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
package net.frozenorb.apiv3.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import net.frozenorb.apiv3.accessor.NotificationLog;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.UUID;
|
||||
|
||||
@ToString
|
||||
public final class NotificationLogEntry extends BaseModel {
|
||||
|
||||
@Getter private String id;
|
||||
@Getter private UUID target;
|
||||
@Getter private Instant sentAt;
|
||||
@Getter private NotificationType type;
|
||||
@Getter private String title;
|
||||
@Getter private String body;
|
||||
|
||||
public NotificationLogEntry(Document json) {
|
||||
super(NotificationLog.COLLECTION_NAME);
|
||||
|
||||
this.id = json.getString("_id");
|
||||
this.target = UUID.fromString(json.getString("target"));
|
||||
this.sentAt = (Instant) json.get("sentAt");
|
||||
this.type = NotificationType.valueOf(json.getString("type"));
|
||||
this.title = json.getString("title");
|
||||
this.body = json.getString("body");
|
||||
|
||||
setId(id);
|
||||
}
|
||||
|
||||
public Document toLiteJson() {
|
||||
Document json = new Document();
|
||||
|
||||
json.put("id", id);
|
||||
json.put("target", target.toString());
|
||||
json.put("sentAt", sentAt.toString());
|
||||
json.put("type", type.name());
|
||||
json.put("title", title);
|
||||
json.put("body", body);
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
public enum NotificationType {
|
||||
|
||||
EMAIL, SMS
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
package net.frozenorb.apiv3.model;
|
||||
|
||||
import com.mongodb.async.SingleResultCallback;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import net.frozenorb.apiv3.accessor.NotificationTemplates;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
@ToString
|
||||
public final class NotificationTemplate extends BaseModel {
|
||||
|
||||
@Getter private String id;
|
||||
@Getter private String title;
|
||||
@Getter private String body;
|
||||
@Getter private Instant lastUpdatedAt;
|
||||
@Getter private UUID lastUpdatedBy;
|
||||
|
||||
public NotificationTemplate(Document json) {
|
||||
super(NotificationTemplates.COLLECTION_NAME);
|
||||
|
||||
this.id = json.getString("_id");
|
||||
this.title = json.getString("title");
|
||||
this.body = json.getString("body");
|
||||
this.lastUpdatedAt = (Instant) json.get("lastUpdatedAt");
|
||||
this.lastUpdatedBy = UUID.fromString(json.getString("lastUpdatedBy"));
|
||||
|
||||
setId(id);
|
||||
}
|
||||
|
||||
public Document toLiteJson() {
|
||||
Document json = new Document();
|
||||
|
||||
json.put("id", id);
|
||||
json.put("title", title);
|
||||
json.put("body", body);
|
||||
json.put("lastUpdatedAt", lastUpdatedAt.toString());
|
||||
json.put("lastUpdatedBy", lastUpdatedBy.toString());
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
public void update(String title, String body, UUID updatedBy, SingleResultCallback<Void> callback) {
|
||||
this.title = title;
|
||||
this.body = body;
|
||||
this.lastUpdatedAt = Instant.now();
|
||||
this.lastUpdatedBy = updatedBy;
|
||||
|
||||
Document set = new Document();
|
||||
|
||||
set.put("title", title);
|
||||
set.put("body", body);
|
||||
set.put("lastUpdatedAt", lastUpdatedAt.toString());
|
||||
set.put("lastUpdatedBy", lastUpdatedBy.toString());
|
||||
|
||||
super.update(new Document("$set", set), (updateResult, error) -> {
|
||||
callback.onResult(null, error);
|
||||
});
|
||||
}
|
||||
|
||||
public void delete(SingleResultCallback<Void> callback) {
|
||||
super.delete(callback);
|
||||
}
|
||||
|
||||
public String fillTitle(Map<String, Object> replacements) {
|
||||
return fill(title, replacements);
|
||||
}
|
||||
|
||||
public String fillBody(Map<String, Object> replacements) {
|
||||
return fill(body, replacements);
|
||||
}
|
||||
|
||||
private String fill(String working, Map<String, Object> replacements) {
|
||||
for (Map.Entry<String, Object> replacement : replacements.entrySet()) {
|
||||
String key = replacement.getKey();
|
||||
String value = String.valueOf(replacement.getValue());
|
||||
|
||||
working = working.replace(key, value);
|
||||
}
|
||||
|
||||
return working;
|
||||
}
|
||||
|
||||
}
|
@ -1,116 +0,0 @@
|
||||
package net.frozenorb.apiv3.model;
|
||||
|
||||
import com.mongodb.async.SingleResultCallback;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import net.frozenorb.apiv3.accessor.Punishments;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.UUID;
|
||||
|
||||
@ToString
|
||||
public final class Punishment extends BaseModel {
|
||||
|
||||
@Getter private String id;
|
||||
@Getter private UUID target;
|
||||
@Getter private String reason;
|
||||
@Getter private PunishmentType type;
|
||||
@Getter private Instant expiresAt;
|
||||
|
||||
@Getter private UUID addedBy;
|
||||
@Getter private Instant addedAt;
|
||||
@Getter private String addedOn;
|
||||
|
||||
@Getter private UUID removedBy;
|
||||
@Getter private Instant removedAt;
|
||||
@Getter private String removalReason;
|
||||
|
||||
public Punishment(Document json) {
|
||||
super(Punishments.COLLECTION_NAME);
|
||||
|
||||
this.id = json.getString("_id");
|
||||
this.target = UUID.fromString(json.getString("target"));
|
||||
this.reason = json.getString("reason");
|
||||
this.type = PunishmentType.valueOf(json.getString("type"));
|
||||
this.expiresAt = (Instant) json.get("expiresAt");
|
||||
|
||||
this.addedBy = UUID.fromString(json.getString("addedBy"));
|
||||
this.addedAt = (Instant) json.get("addedAt");
|
||||
this.addedOn = json.getString("addedOn");
|
||||
|
||||
if (json.containsKey("removedBy")) {
|
||||
this.removedBy = UUID.fromString(json.getString("removedBy"));
|
||||
this.removedAt = (Instant) json.get("removedAt");
|
||||
this.removalReason = json.getString("removalReason");
|
||||
}
|
||||
|
||||
setId(id);
|
||||
}
|
||||
|
||||
public void delete(UUID removedBy, String reason, SingleResultCallback<Void> callback) {
|
||||
this.removedBy = removedBy;
|
||||
this.removedAt = Instant.now();
|
||||
this.removalReason = reason;
|
||||
|
||||
Document set = new Document();
|
||||
|
||||
set.put("removedBy", removedBy.toString());
|
||||
set.put("removedAt", removedAt);
|
||||
set.put("removalReason", removalReason);
|
||||
|
||||
super.update(new Document("$set", set), callback);
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return !(isExpired() || isRemoved());
|
||||
}
|
||||
|
||||
public boolean isExpired() {
|
||||
if (expiresAt == null) {
|
||||
return false; // Never expires
|
||||
} else {
|
||||
return expiresAt.isAfter(Instant.now());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRemoved() {
|
||||
return removedBy != null;
|
||||
}
|
||||
|
||||
public Document toLiteJson() {
|
||||
Document json = new Document();
|
||||
|
||||
json.put("id", id);
|
||||
json.put("target", target.toString());
|
||||
json.put("reason", reason);
|
||||
json.put("type", type.name());
|
||||
json.put("expiresAt", expiresAt == null ? null : expiresAt.toString());
|
||||
|
||||
json.put("addedBy", addedBy.toString());
|
||||
json.put("addedAt", addedAt.toString());
|
||||
|
||||
Document statusJson = new Document();
|
||||
|
||||
statusJson.put("active", isActive());
|
||||
statusJson.put("expired", isExpired());
|
||||
statusJson.put("removed", isRemoved());
|
||||
|
||||
json.put("status", statusJson);
|
||||
|
||||
if (removedBy != null) {
|
||||
json.put("removedBy", removedBy.toString());
|
||||
json.put("removedAt", removedAt.toString());
|
||||
json.put("removalReason", removalReason);
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
public enum PunishmentType {
|
||||
|
||||
BAN, MUTE, WARN
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
package net.frozenorb.apiv3.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import net.frozenorb.apiv3.accessor.Servers;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ToString
|
||||
public final class Server extends BaseModel {
|
||||
|
||||
@Getter private String id;
|
||||
@Getter private String bungeeId;
|
||||
@Getter private String displayName;
|
||||
@Getter private String secret;
|
||||
@Getter private String group;
|
||||
@Getter private String ip;
|
||||
@Getter private Instant lastUpdate;
|
||||
@Getter private double lastTps;
|
||||
@Getter private List<UUID> players;
|
||||
|
||||
public Server(Document json) {
|
||||
super(Servers.COLLECTION_NAME);
|
||||
|
||||
this.id = json.getString("_id");
|
||||
this.bungeeId = json.getString("bungeeId");
|
||||
this.displayName = json.getString("displayName");
|
||||
this.secret = json.getString("secret");
|
||||
this.group = json.getString("group");
|
||||
this.ip = json.getString("ip");
|
||||
this.lastUpdate = (Instant) json.get("lastUpdate");
|
||||
this.lastTps = ((Number) json.get("lastTps")).doubleValue();
|
||||
this.players = new ArrayList<>();
|
||||
|
||||
for (Object uuidString : (Collection) json.get("players")) {
|
||||
players.add(UUID.fromString((String) uuidString));
|
||||
}
|
||||
|
||||
setId(id);
|
||||
}
|
||||
|
||||
public Document toLiteJson() {
|
||||
Document json = new Document();
|
||||
|
||||
json.put("id", id);
|
||||
json.put("bungeeId", bungeeId);
|
||||
json.put("displayName", displayName);
|
||||
json.put("group", group);
|
||||
json.put("ip", ip);
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
public Document toFullJson() {
|
||||
Document json = toLiteJson();
|
||||
|
||||
json.put("lastUpdate", lastUpdate.toString());
|
||||
json.put("lastTps", lastTps);
|
||||
json.put("players", players.stream().map(UUID::toString).collect(Collectors.toList()));
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
package net.frozenorb.apiv3.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import net.frozenorb.apiv3.accessor.ServerGroups;
|
||||
import org.bson.Document;
|
||||
|
||||
@ToString
|
||||
public final class ServerGroup extends BaseModel {
|
||||
|
||||
@Getter private String id;
|
||||
|
||||
public ServerGroup(Document json) {
|
||||
super(ServerGroups.COLLECTION_NAME);
|
||||
|
||||
this.id = json.getString("_id");
|
||||
|
||||
setId(id);
|
||||
}
|
||||
|
||||
public Document toLiteJson() {
|
||||
Document json = new Document();
|
||||
|
||||
json.put("_id", id);
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
public Document toFullJson() {
|
||||
Document json = toLiteJson();
|
||||
|
||||
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
package net.frozenorb.apiv3.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import net.frozenorb.apiv3.accessor.Users;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
@ToString
|
||||
public final class User extends BaseModel {
|
||||
|
||||
@Getter private UUID id;
|
||||
@Getter private String lastName;
|
||||
@Getter private Map<String, Instant> aliases;
|
||||
@Getter private String otpCode;
|
||||
@Getter private String password;
|
||||
@Getter private String passwordSalt;
|
||||
@Getter private String email;
|
||||
@Getter private int phoneNumber;
|
||||
@Getter private String lastSeenOn;
|
||||
@Getter private Instant lastSeenAt;
|
||||
@Getter private Instant firstSeen;
|
||||
|
||||
public User(Document json) {
|
||||
super(Users.COLLECTION_NAME);
|
||||
|
||||
this.id = UUID.fromString(json.getString("_id"));
|
||||
this.lastName = json.getString("lastName");
|
||||
this.aliases = (Map<String, Instant>) json.get("aliases");
|
||||
this.otpCode = json.getString("otpCode");
|
||||
this.password = json.getString("password");
|
||||
this.passwordSalt = json.getString("passwordSalt");
|
||||
this.email = json.getString("email");
|
||||
this.phoneNumber = json.getInteger("phoneNumber");
|
||||
this.lastSeenOn = json.getString("lastSeenOn");
|
||||
this.lastSeenAt = (Instant) json.get("lastSeenAt");
|
||||
this.firstSeen = (Instant) json.get("firstSeen");
|
||||
|
||||
setId(id.toString());
|
||||
}
|
||||
|
||||
public Document toLiteJson() {
|
||||
Document json = new Document();
|
||||
|
||||
json.put("id", id.toString());
|
||||
json.put("lastName", lastName);
|
||||
json.put("email", email);
|
||||
json.put("phoneNumber", phoneNumber);
|
||||
json.put("lastSeenOn", lastSeenOn);
|
||||
json.put("lastSeenAt", lastSeenAt.toString());
|
||||
json.put("firstSeen", firstSeen.toString());
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
public Document toFullJson() {
|
||||
Document json = toLiteJson();
|
||||
|
||||
json.put("aliases", aliases);
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
}
|
42
src/main/java/net/frozenorb/apiv3/models/AuditLogEntry.java
Normal file
42
src/main/java/net/frozenorb/apiv3/models/AuditLogEntry.java
Normal file
@ -0,0 +1,42 @@
|
||||
package net.frozenorb.apiv3.models;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import lombok.Getter;
|
||||
import net.frozenorb.apiv3.actors.Actor;
|
||||
import net.frozenorb.apiv3.actors.ActorType;
|
||||
import net.frozenorb.apiv3.auditLog.AuditLogActionType;
|
||||
import org.bson.types.ObjectId;
|
||||
import org.mongodb.morphia.annotations.Entity;
|
||||
import org.mongodb.morphia.annotations.Id;
|
||||
import org.mongodb.morphia.annotations.Indexed;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity(value = "auditLog", noClassnameStored = true)
|
||||
public final class AuditLogEntry {
|
||||
|
||||
@Getter @Id private String id;
|
||||
@Getter @Indexed private UUID performedBy;
|
||||
@Getter private String performedByIp;
|
||||
@Getter @Indexed private Date performedAt;
|
||||
@Getter private String actorName;
|
||||
@Getter private ActorType actorType;
|
||||
@Getter private AuditLogActionType actionType;
|
||||
@Getter private Map<String, Object> actionData;
|
||||
|
||||
public AuditLogEntry() {} // For Morphia
|
||||
|
||||
public AuditLogEntry(User performedBy, String performedByIp, Actor actor, AuditLogActionType actionType, Map<String, Object> actionData) {
|
||||
this.id = new ObjectId().toString();
|
||||
this.performedBy = performedBy.getId();
|
||||
this.performedByIp = performedByIp;
|
||||
this.performedAt = new Date();
|
||||
this.actorName = actor.getName();
|
||||
this.actorType = actor.getType();
|
||||
this.actionType = actionType;
|
||||
this.actionData = ImmutableMap.copyOf(actionData);
|
||||
}
|
||||
|
||||
}
|
84
src/main/java/net/frozenorb/apiv3/models/Grant.java
Normal file
84
src/main/java/net/frozenorb/apiv3/models/Grant.java
Normal file
@ -0,0 +1,84 @@
|
||||
package net.frozenorb.apiv3.models;
|
||||
|
||||
import com.google.common.collect.Collections2;
|
||||
import lombok.Getter;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.actors.Actor;
|
||||
import net.frozenorb.apiv3.actors.ActorType;
|
||||
import org.bson.types.ObjectId;
|
||||
import org.mongodb.morphia.annotations.Entity;
|
||||
import org.mongodb.morphia.annotations.Id;
|
||||
import org.mongodb.morphia.annotations.Indexed;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity(value = "grants", noClassnameStored = true)
|
||||
public final class Grant {
|
||||
|
||||
@Getter @Id private String id;
|
||||
@Getter @Indexed private UUID target;
|
||||
@Getter private String reason;
|
||||
@Getter private Set<String> scopes;
|
||||
@Getter @Indexed private String rank;
|
||||
@Getter private Date expiresAt;
|
||||
|
||||
@Getter private UUID addedBy;
|
||||
@Getter @Indexed private Date addedAt;
|
||||
|
||||
@Getter private UUID removedBy;
|
||||
@Getter private Date removedAt;
|
||||
@Getter private String removalReason;
|
||||
|
||||
public static Grant byId(String id) {
|
||||
return APIv3.getDatastore().createQuery(Grant.class).field("id").equal(id).get();
|
||||
}
|
||||
|
||||
public Grant() {} // For Morphia
|
||||
|
||||
public Grant(User target, String reason, Set<ServerGroup> scopes, Rank rank, Date expiresAt, User addedBy) {
|
||||
this.id = new ObjectId().toString();
|
||||
this.target = target.getId();
|
||||
this.reason = reason;
|
||||
this.scopes = new HashSet<>(Collections2.transform(scopes, ServerGroup::getId));
|
||||
this.rank = rank.getId();
|
||||
this.expiresAt = (Date) expiresAt.clone();
|
||||
this.addedBy = addedBy.getId();
|
||||
this.addedAt = new Date();
|
||||
}
|
||||
|
||||
public void delete(User removedBy, String reason) {
|
||||
this.removedBy = removedBy.getId();
|
||||
this.removedAt = new Date();
|
||||
this.removalReason = reason;
|
||||
|
||||
APIv3.getDatastore().save(this);
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return !(isExpired() || isRemoved());
|
||||
}
|
||||
|
||||
public boolean isExpired() {
|
||||
if (expiresAt == null) {
|
||||
return false; // Never expires
|
||||
} else {
|
||||
return expiresAt.after(new Date());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRemoved() {
|
||||
return removedBy != null;
|
||||
}
|
||||
|
||||
public boolean appliesOn(ServerGroup serverGroup) {
|
||||
return isGlobal() || scopes.contains(serverGroup.getId());
|
||||
}
|
||||
|
||||
public boolean isGlobal() {
|
||||
return scopes.isEmpty();
|
||||
}
|
||||
|
||||
}
|
42
src/main/java/net/frozenorb/apiv3/models/IPLogEntry.java
Normal file
42
src/main/java/net/frozenorb/apiv3/models/IPLogEntry.java
Normal file
@ -0,0 +1,42 @@
|
||||
package net.frozenorb.apiv3.models;
|
||||
|
||||
import lombok.Getter;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.serialization.ExcludeFromReplies;
|
||||
import org.bson.types.ObjectId;
|
||||
import org.mongodb.morphia.annotations.Entity;
|
||||
import org.mongodb.morphia.annotations.Id;
|
||||
import org.mongodb.morphia.annotations.Indexed;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity(value = "ipLog", noClassnameStored = true)
|
||||
public final class IPLogEntry {
|
||||
|
||||
@Getter @Id private String id;
|
||||
@Getter @ExcludeFromReplies @Indexed private UUID user;
|
||||
@Getter @Indexed private String ip;
|
||||
@Getter private Date firstSeen;
|
||||
@Getter private Date lastSeen;
|
||||
@Getter private int uses;
|
||||
|
||||
public IPLogEntry() {} // For Morphia
|
||||
|
||||
public IPLogEntry(User user, String ip) {
|
||||
this.id = new ObjectId().toString();
|
||||
this.user = user.getId();
|
||||
this.ip = ip;
|
||||
this.firstSeen = new Date();
|
||||
this.lastSeen = new Date();
|
||||
this.uses = 0;
|
||||
}
|
||||
|
||||
public void used() {
|
||||
this.lastSeen = new Date();
|
||||
this.uses++;
|
||||
|
||||
APIv3.getDatastore().save(this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package net.frozenorb.apiv3.models;
|
||||
|
||||
import lombok.Getter;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import org.mongodb.morphia.annotations.Entity;
|
||||
import org.mongodb.morphia.annotations.Id;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Entity(value = "notificationTemplates", noClassnameStored = true)
|
||||
public final class NotificationTemplate {
|
||||
|
||||
@Getter @Id private String id;
|
||||
@Getter private String subject;
|
||||
@Getter private String body;
|
||||
|
||||
public static NotificationTemplate byId(String id) {
|
||||
return APIv3.getDatastore().createQuery(NotificationTemplate.class).field("id").equal(id).get();
|
||||
}
|
||||
|
||||
public static List<NotificationTemplate> values() {
|
||||
return APIv3.getDatastore().createQuery(NotificationTemplate.class).asList();
|
||||
}
|
||||
|
||||
public NotificationTemplate() {} // For Morphia
|
||||
|
||||
public NotificationTemplate(String id, String subject, String body) {
|
||||
this.id = id;
|
||||
this.subject = subject;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public void update(String subject, String body) {
|
||||
this.subject = subject;
|
||||
this.body = body;
|
||||
|
||||
APIv3.getDatastore().save(this);
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
APIv3.getDatastore().delete(this);
|
||||
}
|
||||
|
||||
public String fillSubject(Map<String, Object> replacements) {
|
||||
return fill(subject, replacements);
|
||||
}
|
||||
|
||||
public String fillBody(Map<String, Object> replacements) {
|
||||
return fill(body, replacements);
|
||||
}
|
||||
|
||||
private String fill(String working, Map<String, Object> replacements) {
|
||||
for (Map.Entry<String, Object> replacement : replacements.entrySet()) {
|
||||
String key = replacement.getKey();
|
||||
String value = String.valueOf(replacement.getValue());
|
||||
|
||||
working = working.replace("%" + key + "%", value);
|
||||
}
|
||||
|
||||
return working;
|
||||
}
|
||||
|
||||
}
|
81
src/main/java/net/frozenorb/apiv3/models/Punishment.java
Normal file
81
src/main/java/net/frozenorb/apiv3/models/Punishment.java
Normal file
@ -0,0 +1,81 @@
|
||||
package net.frozenorb.apiv3.models;
|
||||
|
||||
import lombok.Getter;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.actors.Actor;
|
||||
import net.frozenorb.apiv3.actors.ActorType;
|
||||
import org.bson.types.ObjectId;
|
||||
import org.mongodb.morphia.annotations.Entity;
|
||||
import org.mongodb.morphia.annotations.Id;
|
||||
import org.mongodb.morphia.annotations.Indexed;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity(value = "punishments", noClassnameStored = true)
|
||||
public final class Punishment {
|
||||
|
||||
@Getter @Id private String id;
|
||||
@Getter @Indexed private UUID target;
|
||||
@Getter private String reason;
|
||||
@Getter @Indexed private PunishmentType type; // Type is indexed for the rank dump
|
||||
@Getter private Date expiresAt;
|
||||
|
||||
@Getter private UUID addedBy;
|
||||
@Getter @Indexed private Date addedAt;
|
||||
@Getter private String actorName;
|
||||
@Getter private ActorType actorType;
|
||||
|
||||
@Getter private UUID removedBy;
|
||||
@Getter private Date removedAt;
|
||||
@Getter private String removalReason;
|
||||
|
||||
public static Punishment byId(String id) {
|
||||
return APIv3.getDatastore().createQuery(Punishment.class).field("id").equal(id).get();
|
||||
}
|
||||
|
||||
public Punishment() {} // For Morphia
|
||||
|
||||
public Punishment(User target, String reason, PunishmentType type, Date expiresAt, User addedBy, Actor actor) {
|
||||
this.id = new ObjectId().toString();
|
||||
this.target = target.getId();
|
||||
this.reason = reason;
|
||||
this.type = type;
|
||||
this.expiresAt = (Date) expiresAt.clone();
|
||||
this.addedBy = addedBy.getId();
|
||||
this.addedAt = new Date();
|
||||
this.actorName = actor.getName();
|
||||
this.actorType = actor.getType();
|
||||
}
|
||||
|
||||
public void delete(User removedBy, String reason) {
|
||||
this.removedBy = removedBy.getId();
|
||||
this.removedAt = new Date();
|
||||
this.removalReason = reason;
|
||||
|
||||
APIv3.getDatastore().save(this);
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return !(isExpired() || isRemoved());
|
||||
}
|
||||
|
||||
public boolean isExpired() {
|
||||
if (expiresAt == null) {
|
||||
return false; // Never expires
|
||||
} else {
|
||||
return expiresAt.after(new Date());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRemoved() {
|
||||
return removedBy != null;
|
||||
}
|
||||
|
||||
public enum PunishmentType {
|
||||
|
||||
BLACKLIST, BAN, MUTE, WARN
|
||||
|
||||
}
|
||||
|
||||
}
|
44
src/main/java/net/frozenorb/apiv3/models/Rank.java
Normal file
44
src/main/java/net/frozenorb/apiv3/models/Rank.java
Normal file
@ -0,0 +1,44 @@
|
||||
package net.frozenorb.apiv3.models;
|
||||
|
||||
import lombok.Getter;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import org.mongodb.morphia.annotations.Entity;
|
||||
import org.mongodb.morphia.annotations.Id;
|
||||
import org.mongodb.morphia.annotations.Indexed;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Entity(value = "ranks", noClassnameStored = true)
|
||||
public final class Rank {
|
||||
|
||||
@Getter @Id private String id;
|
||||
@Getter private int weight;
|
||||
@Getter private String displayName;
|
||||
@Getter private String gameColor;
|
||||
@Getter private String websiteColor;
|
||||
@Getter @Indexed private boolean staffRank;
|
||||
|
||||
public static Rank byId(String id) {
|
||||
return APIv3.getDatastore().createQuery(Rank.class).field("id").equal(id).get();
|
||||
}
|
||||
|
||||
public static List<Rank> values() {
|
||||
return APIv3.getDatastore().createQuery(Rank.class).order("weight").asList();
|
||||
}
|
||||
|
||||
public Rank() {} // For Morphia
|
||||
|
||||
public Rank(String id, int weight, String displayName, String gameColor, String websiteColor, boolean staffRank) {
|
||||
this.id = id;
|
||||
this.weight = weight;
|
||||
this.displayName = displayName;
|
||||
this.gameColor = gameColor;
|
||||
this.websiteColor = websiteColor;
|
||||
this.staffRank = staffRank;
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
APIv3.getDatastore().delete(this);
|
||||
}
|
||||
|
||||
}
|
52
src/main/java/net/frozenorb/apiv3/models/Server.java
Normal file
52
src/main/java/net/frozenorb/apiv3/models/Server.java
Normal file
@ -0,0 +1,52 @@
|
||||
package net.frozenorb.apiv3.models;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.serialization.ExcludeFromReplies;
|
||||
import org.mongodb.morphia.annotations.Entity;
|
||||
import org.mongodb.morphia.annotations.Id;
|
||||
import org.mongodb.morphia.annotations.Indexed;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Entity(value = "servers", noClassnameStored = true)
|
||||
public final class Server {
|
||||
|
||||
@Getter @Id private String id;
|
||||
@Getter private String bungeeId;
|
||||
@Getter private String displayName;
|
||||
@Getter @ExcludeFromReplies String apiKey;
|
||||
@Getter @Indexed private String group;
|
||||
@Getter private String ip;
|
||||
@Getter @Setter private Date lastUpdate;
|
||||
@Getter @Setter private double lastTps;
|
||||
@Getter @Setter @ExcludeFromReplies private Set<UUID> players;
|
||||
|
||||
public static Server byId(String id) {
|
||||
return APIv3.getDatastore().createQuery(Server.class).field("_id").equal(id).get();
|
||||
}
|
||||
|
||||
public static List<Server> values() {
|
||||
return APIv3.getDatastore().createQuery(Server.class).asList();
|
||||
}
|
||||
|
||||
public Server() {} // For Morphia
|
||||
|
||||
public Server(String id, String bungeeId, String displayName, String apiKey, ServerGroup group, String ip) {
|
||||
this.id = id;
|
||||
this.bungeeId = bungeeId;
|
||||
this.displayName = displayName;
|
||||
this.apiKey = apiKey;
|
||||
this.group = group.getId();
|
||||
this.ip = ip;
|
||||
this.lastUpdate = new Date();
|
||||
this.lastTps = 0;
|
||||
this.players = new HashSet<>();
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
APIv3.getDatastore().delete(this);
|
||||
}
|
||||
|
||||
}
|
47
src/main/java/net/frozenorb/apiv3/models/ServerGroup.java
Normal file
47
src/main/java/net/frozenorb/apiv3/models/ServerGroup.java
Normal file
@ -0,0 +1,47 @@
|
||||
package net.frozenorb.apiv3.models;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.serialization.ExcludeFromReplies;
|
||||
import net.frozenorb.apiv3.utils.PermissionUtils;
|
||||
import org.mongodb.morphia.annotations.Entity;
|
||||
import org.mongodb.morphia.annotations.Id;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Entity(value = "serverGroups", noClassnameStored = true)
|
||||
public final class ServerGroup {
|
||||
|
||||
@Getter @Id private String id;
|
||||
@Getter 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<>();
|
||||
@Getter private Map<String, List<String>> permissions = new HashMap<>();
|
||||
|
||||
public static ServerGroup byId(String id) {
|
||||
return APIv3.getDatastore().createQuery(ServerGroup.class).field("id").equal(id).get();
|
||||
}
|
||||
|
||||
public static List<ServerGroup> values() {
|
||||
return APIv3.getDatastore().createQuery(ServerGroup.class).asList();
|
||||
}
|
||||
|
||||
public ServerGroup() {} // For Morphia
|
||||
|
||||
public ServerGroup(String id, boolean isPublic) {
|
||||
this.id = id;
|
||||
this.isPublic = isPublic;
|
||||
}
|
||||
|
||||
public Map<String, Boolean> calculatePermissions(Rank userRank) {
|
||||
return PermissionUtils.mergeUpTo(permissions, userRank);
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
APIv3.getDatastore().delete(this);
|
||||
}
|
||||
|
||||
}
|
251
src/main/java/net/frozenorb/apiv3/models/User.java
Normal file
251
src/main/java/net/frozenorb/apiv3/models/User.java
Normal file
@ -0,0 +1,251 @@
|
||||
package net.frozenorb.apiv3.models;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.serialization.ExcludeFromReplies;
|
||||
import net.frozenorb.apiv3.utils.PermissionUtils;
|
||||
import net.frozenorb.apiv3.utils.TimeUtils;
|
||||
import org.bson.Document;
|
||||
import org.mindrot.jbcrypt.BCrypt;
|
||||
import org.mongodb.morphia.annotations.Entity;
|
||||
import org.mongodb.morphia.annotations.Id;
|
||||
import org.mongodb.morphia.annotations.Indexed;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Entity(value = "users", noClassnameStored = true)
|
||||
public final class User {
|
||||
|
||||
@Getter @Id private UUID id;
|
||||
@Getter @Indexed private String lastUsername;
|
||||
@Getter @ExcludeFromReplies private Map<String, Date> aliases;
|
||||
@Getter @Setter @ExcludeFromReplies private String totpSecret;
|
||||
@Getter @Indexed @ExcludeFromReplies @Setter private String emailToken;
|
||||
@Getter @ExcludeFromReplies @Setter private Date emailTokenSet;
|
||||
@Getter @ExcludeFromReplies private String password;
|
||||
@Getter @Setter private String email;
|
||||
@Getter private String phoneNumber;
|
||||
@Getter private String lastSeenOn;
|
||||
@Getter private Date lastSeenAt;
|
||||
@Getter private Date firstSeen;
|
||||
|
||||
public static User byId(String id) {
|
||||
try {
|
||||
return byId(UUID.fromString(id));
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static User byId(UUID id) {
|
||||
return APIv3.getDatastore().createQuery(User.class).field("id").equal(id).get();
|
||||
}
|
||||
|
||||
public static User byEmailToken(String name) {
|
||||
return APIv3.getDatastore().createQuery(User.class).field("emailToken").equal(name).get();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static User byLastUsername(String lastUsername) {
|
||||
return APIv3.getDatastore().createQuery(User.class).field("lastUsername").equal(lastUsername).get();
|
||||
}
|
||||
|
||||
public User() {} // For Morphia
|
||||
|
||||
public User(UUID id, String lastUsername) {
|
||||
this.id = id;
|
||||
this.lastUsername = lastUsername;
|
||||
this.aliases = new HashMap<>();
|
||||
this.totpSecret = null;
|
||||
this.password = null;
|
||||
this.email = null;
|
||||
this.phoneNumber = null;
|
||||
this.lastSeenOn = null;
|
||||
this.lastSeenAt = new Date();
|
||||
this.firstSeen = new Date();
|
||||
|
||||
aliases.put(lastUsername, new Date());
|
||||
}
|
||||
|
||||
public boolean hasPermissionScoped(String permission, ServerGroup scope) {
|
||||
Rank highestRank = getHighestRank(scope);
|
||||
Map<String, Boolean> scopedPermissions = PermissionUtils.mergePermissions(
|
||||
PermissionUtils.getDefaultPermissions(highestRank),
|
||||
scope.calculatePermissions(highestRank)
|
||||
);
|
||||
|
||||
return scopedPermissions.containsKey(permission) && scopedPermissions.get(permission);
|
||||
}
|
||||
|
||||
public boolean hasPermissionAnywhere(String permission) {
|
||||
Map<String, Boolean> globalPermissions = PermissionUtils.getDefaultPermissions(getHighestRank());
|
||||
|
||||
for (Map.Entry<ServerGroup, Rank> serverGroupEntry : getHighestRanks().entrySet()) {
|
||||
ServerGroup serverGroup = serverGroupEntry.getKey();
|
||||
Rank rank = serverGroupEntry.getValue();
|
||||
|
||||
globalPermissions = PermissionUtils.mergePermissions(
|
||||
globalPermissions,
|
||||
serverGroup.calculatePermissions(rank)
|
||||
);
|
||||
}
|
||||
|
||||
return globalPermissions.containsKey(permission) && globalPermissions.get(permission);
|
||||
}
|
||||
|
||||
public List<Grant> getGrants() {
|
||||
return APIv3.getDatastore().createQuery(Grant.class).field("target").equal(id).asList();
|
||||
}
|
||||
|
||||
public List<IPLogEntry> getIPLog() {
|
||||
return APIv3.getDatastore().createQuery(IPLogEntry.class).field("user").equal(id).asList();
|
||||
}
|
||||
|
||||
public IPLogEntry getIPLogEntry(String ip) {
|
||||
IPLogEntry existing = APIv3.getDatastore().createQuery(IPLogEntry.class).field("user").equal(id).field("ip").equal(ip).get();
|
||||
|
||||
if (existing == null) {
|
||||
existing = new IPLogEntry(this, ip);
|
||||
APIv3.getDatastore().save(existing);
|
||||
}
|
||||
|
||||
return existing;
|
||||
}
|
||||
|
||||
public List<Punishment> getPunishments() {
|
||||
return APIv3.getDatastore().createQuery(Punishment.class).field("target").equal(id).asList();
|
||||
}
|
||||
|
||||
public List<Punishment> getPunishments(Collection<Punishment.PunishmentType> types) {
|
||||
return APIv3.getDatastore().createQuery(Punishment.class).field("target").equal(id).field("type").in(types).asList();
|
||||
}
|
||||
|
||||
public UserMetaEntry getMeta(ServerGroup group) {
|
||||
return APIv3.getDatastore().createQuery(UserMetaEntry.class).field("user").equal(id).field("serverGroup").equal(group.getId()).get();
|
||||
}
|
||||
|
||||
public void saveMeta(ServerGroup group, Document data) {
|
||||
UserMetaEntry entry = getMeta(group);
|
||||
|
||||
if (entry == null) {
|
||||
APIv3.getDatastore().save(new UserMetaEntry(this, group, data));
|
||||
} else {
|
||||
entry.setData(data);
|
||||
APIv3.getDatastore().save(entry);
|
||||
}
|
||||
}
|
||||
|
||||
public void seenOnServer(String username, Server server) {
|
||||
this.lastSeenOn = server.getId();
|
||||
this.lastSeenAt = new Date();
|
||||
this.aliases.put(username, new Date());
|
||||
}
|
||||
|
||||
public void setPassword(char[] unencrypted) {
|
||||
this.password = BCrypt.hashpw(new String(unencrypted), BCrypt.gensalt());
|
||||
}
|
||||
|
||||
public boolean checkPassword(char[] unencrypted) {
|
||||
return BCrypt.checkpw(new String(unencrypted), password);
|
||||
}
|
||||
|
||||
public Rank getHighestRank() {
|
||||
return getHighestRank(null);
|
||||
}
|
||||
|
||||
public Rank getHighestRank(ServerGroup serverGroup) {
|
||||
Rank highest = null;
|
||||
|
||||
for (Grant grant : getGrants()) {
|
||||
if (!grant.isActive() || (serverGroup != null && !grant.appliesOn(serverGroup))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Rank rank = Rank.byId(grant.getRank());
|
||||
|
||||
if (highest == null || rank.getWeight() > highest.getWeight()) {
|
||||
highest = rank;
|
||||
}
|
||||
}
|
||||
|
||||
if (highest != null) {
|
||||
return highest;
|
||||
} else {
|
||||
return Rank.byId("default");
|
||||
}
|
||||
}
|
||||
|
||||
public Map<ServerGroup, Rank> getHighestRanks() {
|
||||
Map<ServerGroup, Rank> highestRanks = new HashMap<>();
|
||||
Rank defaultRank = Rank.byId("default");
|
||||
List<Grant> userGrants = getGrants();
|
||||
|
||||
for (ServerGroup serverGroup : ServerGroup.values()) {
|
||||
Rank highest = defaultRank;
|
||||
|
||||
for (Grant grant : userGrants) {
|
||||
if (!grant.isActive() || !grant.appliesOn(serverGroup)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Rank rank = Rank.byId(grant.getRank());
|
||||
|
||||
if (highest == null || rank.getWeight() > highest.getWeight()) {
|
||||
highest = rank;
|
||||
}
|
||||
}
|
||||
|
||||
highestRanks.put(serverGroup, highest);
|
||||
}
|
||||
|
||||
return highestRanks;
|
||||
}
|
||||
|
||||
public Map<String, Object> getLoginInfo(Server server) {
|
||||
String accessDenialReason = null;
|
||||
|
||||
for (Punishment punishment : getPunishments(ImmutableSet.of(
|
||||
Punishment.PunishmentType.BLACKLIST,
|
||||
Punishment.PunishmentType.BAN
|
||||
))) {
|
||||
if (!punishment.isActive()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (punishment.getType() == Punishment.PunishmentType.BLACKLIST) {
|
||||
accessDenialReason = "Your account has been blacklisted from the MineHQ Network. \n\nThis type of punishment cannot be appealed.";
|
||||
} else {
|
||||
accessDenialReason = "Your account has been suspended from the MineHQ Network. \n\n";
|
||||
|
||||
if (punishment.getExpiresAt() != null) {
|
||||
accessDenialReason += "Expires in " + TimeUtils.formatIntoDetailedString(TimeUtils.getSecondsBetween(punishment.getExpiresAt(), new Date()));
|
||||
} else {
|
||||
accessDenialReason += "Appeal at MineHQ.com/appeal";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ServerGroup actorGroup = ServerGroup.byId(server.getGroup());
|
||||
Rank highestRank = getHighestRank(actorGroup);
|
||||
Map<String, Boolean> scopedPermissions = PermissionUtils.mergePermissions(
|
||||
PermissionUtils.getDefaultPermissions(highestRank),
|
||||
actorGroup.calculatePermissions(highestRank)
|
||||
);
|
||||
|
||||
return ImmutableMap.of(
|
||||
"user", this,
|
||||
"access", ImmutableMap.of(
|
||||
"allowed", accessDenialReason == null,
|
||||
"message", accessDenialReason == null ? "Public server" : accessDenialReason
|
||||
),
|
||||
"rank", highestRank.getId(),
|
||||
"permissions", scopedPermissions,
|
||||
"totpSetup", getTotpSecret() != null
|
||||
);
|
||||
}
|
||||
|
||||
}
|
37
src/main/java/net/frozenorb/apiv3/models/UserMetaEntry.java
Normal file
37
src/main/java/net/frozenorb/apiv3/models/UserMetaEntry.java
Normal file
@ -0,0 +1,37 @@
|
||||
package net.frozenorb.apiv3.models;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import org.bson.Document;
|
||||
import org.bson.types.ObjectId;
|
||||
import org.mongodb.morphia.annotations.Entity;
|
||||
import org.mongodb.morphia.annotations.Id;
|
||||
import org.mongodb.morphia.annotations.Indexed;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity(value = "userMeta", noClassnameStored = true)
|
||||
public final class UserMetaEntry {
|
||||
|
||||
@Getter @Id private String id;
|
||||
@Getter @Indexed private UUID user;
|
||||
@Getter @Indexed private String serverGroup;
|
||||
@Getter @Setter private Map<String, Object> data;
|
||||
|
||||
public UserMetaEntry() {} // For Morphia
|
||||
|
||||
public UserMetaEntry(User user, ServerGroup serverGroup, Map<String, Object> data) {
|
||||
this.id = new ObjectId().toString();
|
||||
this.user = user.getId();
|
||||
this.serverGroup = serverGroup.getId();
|
||||
this.data = ImmutableMap.copyOf(data);
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
APIv3.getDatastore().delete(this);
|
||||
}
|
||||
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
package net.frozenorb.apiv3.mongoCodec;
|
||||
|
||||
import org.bson.BsonReader;
|
||||
import org.bson.BsonWriter;
|
||||
import org.bson.codecs.Codec;
|
||||
import org.bson.codecs.DecoderContext;
|
||||
import org.bson.codecs.EncoderContext;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
public final class InstantCodec implements Codec<Instant> {
|
||||
|
||||
public void encode(BsonWriter writer, Instant value, EncoderContext context) {
|
||||
writer.writeDateTime(value.toEpochMilli());
|
||||
}
|
||||
|
||||
public Instant decode(BsonReader reader, DecoderContext context) {
|
||||
long epochMillis = reader.readDateTime();
|
||||
return Instant.ofEpochMilli(epochMillis);
|
||||
}
|
||||
|
||||
public Class<Instant> getEncoderClass() {
|
||||
return Instant.class;
|
||||
}
|
||||
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package net.frozenorb.apiv3.routes;
|
||||
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.ext.web.Router;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
@UtilityClass
|
||||
public class AuditLogRouter {
|
||||
|
||||
public static Router create(Vertx vertx) {
|
||||
Router router = Router.router(vertx);
|
||||
|
||||
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
}
|
70
src/main/java/net/frozenorb/apiv3/routes/GETDump.java
Normal file
70
src/main/java/net/frozenorb/apiv3/routes/GETDump.java
Normal file
@ -0,0 +1,70 @@
|
||||
package net.frozenorb.apiv3.routes;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.models.Grant;
|
||||
import net.frozenorb.apiv3.models.Punishment;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public final class GETDump implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
String type = req.params("type");
|
||||
|
||||
switch (type.toLowerCase()) {
|
||||
case "blacklist":
|
||||
case "ban":
|
||||
case "mute":
|
||||
case "warn":
|
||||
List<UUID> effectedUsers = new ArrayList<>();
|
||||
|
||||
APIv3.getDatastore().createQuery(Punishment.class).field("type").equal(type.toUpperCase()).forEach((punishment) -> {
|
||||
if (punishment.isActive()) {
|
||||
effectedUsers.add(punishment.getTarget());
|
||||
}
|
||||
});
|
||||
|
||||
return effectedUsers;
|
||||
case "accessDeniable":
|
||||
// We have to name it effectedUsers2 because Java's
|
||||
// scoping in switch statements is really dumb.
|
||||
List<UUID> effectedUsers2 = new ArrayList<>();
|
||||
|
||||
APIv3.getDatastore().createQuery(Punishment.class).field("type").in(ImmutableSet.of(
|
||||
Punishment.PunishmentType.BAN,
|
||||
Punishment.PunishmentType.BLACKLIST
|
||||
)).forEach((punishment) -> {
|
||||
if (punishment.isActive()) {
|
||||
effectedUsers2.add(punishment.getTarget());
|
||||
}
|
||||
});
|
||||
|
||||
return effectedUsers2;
|
||||
case "grant":
|
||||
Map<String, List<UUID>> grantDump = new HashMap<>();
|
||||
|
||||
APIv3.getDatastore().createQuery(Grant.class).forEach((grant) -> {
|
||||
if (grant.isActive()) {
|
||||
List<UUID> users = grantDump.get(grant.getRank());
|
||||
|
||||
if (users == null) {
|
||||
users = new ArrayList<>();
|
||||
grantDump.put(grant.getRank(), users);
|
||||
}
|
||||
|
||||
users.add(grant.getTarget());
|
||||
}
|
||||
});
|
||||
|
||||
return grantDump;
|
||||
default:
|
||||
return ErrorUtils.invalidInput(type + " is not a valid type. Not in [blacklist, ban, mute, warn, accessDeniable, grant]");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
21
src/main/java/net/frozenorb/apiv3/routes/GETWhoAmI.java
Normal file
21
src/main/java/net/frozenorb/apiv3/routes/GETWhoAmI.java
Normal file
@ -0,0 +1,21 @@
|
||||
package net.frozenorb.apiv3.routes;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import net.frozenorb.apiv3.actors.Actor;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class GETWhoAmI implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
Actor actor = req.attribute("actor");
|
||||
|
||||
return ImmutableMap.of(
|
||||
"name", actor.getName(),
|
||||
"type", actor.getType(),
|
||||
"authorized", actor.isAuthorized()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package net.frozenorb.apiv3.routes;
|
||||
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.ext.web.Router;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
@UtilityClass
|
||||
public class GrantsRouter {
|
||||
|
||||
public static Router create(Vertx vertx) {
|
||||
Router router = Router.router(vertx);
|
||||
|
||||
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package net.frozenorb.apiv3.routes;
|
||||
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.ext.web.Router;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
@UtilityClass
|
||||
public class IPLogRouter {
|
||||
|
||||
public static Router create(Vertx vertx) {
|
||||
Router router = Router.router(vertx);
|
||||
|
||||
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
}
|
17
src/main/java/net/frozenorb/apiv3/routes/NotFound.java
Normal file
17
src/main/java/net/frozenorb/apiv3/routes/NotFound.java
Normal file
@ -0,0 +1,17 @@
|
||||
package net.frozenorb.apiv3.routes;
|
||||
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
import spark.Spark;
|
||||
|
||||
public final class NotFound implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
Spark.halt(404, APIv3.getGson().toJson(ErrorUtils.notFound("Route", req.url())));
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package net.frozenorb.apiv3.routes;
|
||||
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.ext.web.Router;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
@UtilityClass
|
||||
public class NotificationsRouter {
|
||||
|
||||
public static Router create(Vertx vertx) {
|
||||
Router router = Router.router(vertx);
|
||||
|
||||
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package net.frozenorb.apiv3.routes;
|
||||
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.ext.web.Router;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
@UtilityClass
|
||||
public class PunishmentsRouter {
|
||||
|
||||
public static Router create(Vertx vertx) {
|
||||
Router router = Router.router(vertx);
|
||||
|
||||
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package net.frozenorb.apiv3.routes;
|
||||
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.ext.web.Router;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
@UtilityClass
|
||||
public class ServerGroupsRouter {
|
||||
|
||||
public static Router create(Vertx vertx) {
|
||||
Router router = Router.router(vertx);
|
||||
|
||||
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
package net.frozenorb.apiv3.routes;
|
||||
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.ext.web.Router;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
@UtilityClass
|
||||
public class ServersRouter {
|
||||
|
||||
public static Router create(Vertx vertx) {
|
||||
Router router = Router.router(vertx);
|
||||
|
||||
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
/*
|
||||
coreHttpRouter.get("/servers").handler(ctx -> {
|
||||
Servers.findAll((servers, error) -> {
|
||||
if (error != null) {
|
||||
ctx.response().end(ErrorUtils.createResponse(error).toJson());
|
||||
} else {
|
||||
ctx.response().end(JsonUtils.toLiteJsonString(servers));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
coreHttpRouter.get("/server/:server").handler(ctx -> {
|
||||
String serverId = ctx.request().getParam("server");
|
||||
|
||||
Servers.findById(serverId, (server, error) -> {
|
||||
if (error != null) {
|
||||
ctx.response().end(ErrorUtils.createResponse(error).toJson());
|
||||
} else if (server != null) {
|
||||
ctx.response().end(JsonUtils.toLiteJsonString(server));
|
||||
} else {
|
||||
ctx.response().end(ErrorUtils.createResponse("Server '" + serverId + "' not found.").toJson());
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
coreHttpRouter.get("/user/:user").handler(ctx -> {
|
||||
UUID target = UUID.fromString(ctx.request().getParam("user"));
|
||||
|
||||
Users.findById(target.toString(), (user, error) -> {
|
||||
if (error != null) {
|
||||
ctx.response().end(ErrorUtils.createResponse(error).toJson());
|
||||
} else if (user != null) {
|
||||
ctx.response().end(JsonUtils.toLiteJsonString(user));
|
||||
} else {
|
||||
ctx.response().end(ErrorUtils.createResponse("User '" + target + "' not found.").toJson());
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
coreHttpRouter.get("/user/:user/grants").handler(ctx -> {
|
||||
UUID target = UUID.fromString(ctx.request().getParam("user"));
|
||||
|
||||
Grants.findByTarget(target, (grants, error) -> {
|
||||
if (error != null) {
|
||||
ctx.response().end(ErrorUtils.createResponse(error).toJson());
|
||||
} else {
|
||||
ctx.response().end(JsonUtils.toLiteJsonString(grants));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
coreHttpRouter.get("/auditLog").handler(ctx -> {
|
||||
AuditLog.findAll((auditLogEntries, error) -> {
|
||||
if (error != null) {
|
||||
ctx.response().end(ErrorUtils.createResponse(error).toJson());
|
||||
} else {
|
||||
ctx.response().end(JsonUtils.toLiteJsonString(auditLogEntries));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
coreHttpRouter.get("/doAction/:actionType").handler(ctx -> {
|
||||
String actionType = ctx.request().getParam("actionType");
|
||||
|
||||
//AuditLog.log(UUID.randomUUID(), "192.168.1.103", actionType, new Document());
|
||||
ctx.response().end("{'logged': true}");
|
||||
});
|
||||
*/
|
||||
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
package net.frozenorb.apiv3.routes;
|
||||
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.ext.web.Router;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import net.frozenorb.apiv3.accessor.Users;
|
||||
import net.frozenorb.apiv3.util.ErrorUtils;
|
||||
import net.frozenorb.apiv3.util.JsonUtils;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@UtilityClass
|
||||
public class UsersRouter {
|
||||
|
||||
public static Router create(Vertx vertx) {
|
||||
Router router = Router.router(vertx);
|
||||
|
||||
router.get("/info/:user").handler(ctx -> {
|
||||
UUID target = UUID.fromString(ctx.request().getParam("user"));
|
||||
|
||||
Users.findById(target, (user, error) -> {
|
||||
if (error != null) {
|
||||
ctx.response().end(ErrorUtils.toResponseString(error));
|
||||
} else if (user != null) {
|
||||
ctx.response().end(JsonUtils.toLiteJsonString(user));
|
||||
} else {
|
||||
ctx.response().end(ErrorUtils.toResponseString("User '" + target + "' not found."));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package net.frozenorb.apiv3.routes.announcements;
|
||||
|
||||
import net.frozenorb.apiv3.actors.Actor;
|
||||
import net.frozenorb.apiv3.actors.ActorType;
|
||||
import net.frozenorb.apiv3.models.Server;
|
||||
import net.frozenorb.apiv3.models.ServerGroup;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class GETAnnouncements implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
Actor actor = req.attribute("actor");
|
||||
|
||||
if (actor.getType() != ActorType.SERVER) {
|
||||
return ErrorUtils.serverOnly();
|
||||
}
|
||||
|
||||
Server sender = Server.byId(actor.getName());
|
||||
ServerGroup senderGroup = ServerGroup.byId(sender.getGroup());
|
||||
|
||||
return senderGroup.getAnnouncements();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package net.frozenorb.apiv3.routes.auditLog;
|
||||
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.models.AuditLogEntry;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class GETAuditLog implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
try {
|
||||
int limit = req.queryParams("limit") == null ? 100 : Integer.parseInt(req.queryParams("limit"));
|
||||
int offset = req.queryParams("offset") == null ? 0 : Integer.parseInt(req.queryParams("offset"));
|
||||
|
||||
return APIv3.getDatastore().createQuery(AuditLogEntry.class).order("performedAt").limit(limit).offset(offset).asList();
|
||||
} catch (NumberFormatException ex) {
|
||||
return ErrorUtils.invalidInput(";imit and offset must be numerical inputs.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package net.frozenorb.apiv3.routes.chatFilterList;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import net.frozenorb.apiv3.actors.Actor;
|
||||
import net.frozenorb.apiv3.actors.ActorType;
|
||||
import net.frozenorb.apiv3.models.Server;
|
||||
import net.frozenorb.apiv3.models.ServerGroup;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class GETChatFilterList implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
return ImmutableSet.of();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package net.frozenorb.apiv3.routes.grants;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import net.frozenorb.apiv3.auditLog.AuditLog;
|
||||
import net.frozenorb.apiv3.auditLog.AuditLogActionType;
|
||||
import net.frozenorb.apiv3.models.Grant;
|
||||
import net.frozenorb.apiv3.models.User;
|
||||
import net.frozenorb.apiv3.unsorted.Permissions;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import org.bson.Document;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class DELETEGrant implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
Grant grant = Grant.byId(req.params("id"));
|
||||
|
||||
if (grant == null) {
|
||||
return ErrorUtils.notFound("Grant", req.params("id"));
|
||||
} else if (!grant.isActive()) {
|
||||
return ErrorUtils.invalidInput("Cannot remove an inactive grant.");
|
||||
}
|
||||
|
||||
User removedBy = User.byId(req.queryParams("removedBy"));
|
||||
String requiredPermission = Permissions.REMOVE_GRANT + "." + grant.getRank();
|
||||
|
||||
if (removedBy == null) {
|
||||
return ErrorUtils.notFound("User", req.queryParams("removedBy"));
|
||||
} else if (!removedBy.hasPermissionAnywhere(requiredPermission)) {
|
||||
return ErrorUtils.unauthorized(requiredPermission);
|
||||
}
|
||||
|
||||
String reason = req.queryParams("reason");
|
||||
|
||||
if (reason == null || reason.trim().isEmpty()) {
|
||||
return ErrorUtils.requiredInput("reason");
|
||||
}
|
||||
|
||||
grant.delete(removedBy, reason);
|
||||
// TODO: Fix IP
|
||||
AuditLog.log(removedBy, "", req.attribute("actor"), AuditLogActionType.DELETE_GRANT, ImmutableMap.of());
|
||||
return grant;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package net.frozenorb.apiv3.routes.grants;
|
||||
|
||||
import net.frozenorb.apiv3.models.Grant;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class GETGrant implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
return Grant.byId(req.params("id"));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package net.frozenorb.apiv3.routes.grants;
|
||||
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.models.Grant;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class GETGrants implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
try {
|
||||
int limit = req.queryParams("limit") == null ? 100 : Integer.parseInt(req.queryParams("limit"));
|
||||
int offset = req.queryParams("offset") == null ? 0 : Integer.parseInt(req.queryParams("offset"));
|
||||
|
||||
return APIv3.getDatastore().createQuery(Grant.class).order("addedAt").limit(limit).offset(offset).asList();
|
||||
} catch (NumberFormatException ex) {
|
||||
return ErrorUtils.invalidInput("limit and offset must be numerical inputs.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package net.frozenorb.apiv3.routes.grants;
|
||||
|
||||
import net.frozenorb.apiv3.models.User;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class GETUserGrants implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
User target = User.byId(req.params("id"));
|
||||
|
||||
if (target == null) {
|
||||
return ErrorUtils.notFound("User", req.params("id"));
|
||||
}
|
||||
|
||||
return target.getGrants();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package net.frozenorb.apiv3.routes.grants;
|
||||
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.models.Grant;
|
||||
import net.frozenorb.apiv3.models.Rank;
|
||||
import net.frozenorb.apiv3.models.ServerGroup;
|
||||
import net.frozenorb.apiv3.models.User;
|
||||
import net.frozenorb.apiv3.unsorted.Permissions;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public final class POSTUserGrant implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
User target = User.byId(req.params("id"));
|
||||
|
||||
if (target == null) {
|
||||
return ErrorUtils.notFound("User", req.params("id"));
|
||||
}
|
||||
|
||||
String reason = req.queryParams("reason");
|
||||
|
||||
if (reason == null || reason.trim().isEmpty()) {
|
||||
return ErrorUtils.requiredInput("reason");
|
||||
}
|
||||
|
||||
Set<ServerGroup> scopes = new HashSet<>();
|
||||
|
||||
for (String serverGroupId : req.queryParams("scopes").split(",")) {
|
||||
ServerGroup serverGroup = ServerGroup.byId(serverGroupId);
|
||||
|
||||
if (serverGroup == null) {
|
||||
return ErrorUtils.notFound("Server group", serverGroupId);
|
||||
}
|
||||
|
||||
scopes.add(serverGroup);
|
||||
}
|
||||
|
||||
Rank rank = Rank.byId(req.queryParams("rank"));
|
||||
|
||||
if (rank == null) {
|
||||
return ErrorUtils.notFound("Rank", req.queryParams("rank"));
|
||||
}
|
||||
|
||||
Date expiresAt = new Date(Long.parseLong(req.queryParams("expiresAt")));
|
||||
|
||||
if (expiresAt.before(new Date())) {
|
||||
return ErrorUtils.invalidInput("Expiration date cannot be in the past.");
|
||||
}
|
||||
|
||||
User addedBy = User.byId(req.queryParams("addedBy"));
|
||||
String requiredPermission = Permissions.CREATE_GRANT + "." + rank.getId();
|
||||
|
||||
if (addedBy == null) {
|
||||
return ErrorUtils.notFound("User", req.queryParams("addedBy"));
|
||||
} else if (!addedBy.hasPermissionAnywhere(requiredPermission)) {
|
||||
return ErrorUtils.unauthorized(requiredPermission);
|
||||
}
|
||||
|
||||
Grant grant = new Grant(target, reason, scopes, rank, expiresAt, addedBy);
|
||||
APIv3.getDatastore().save(grant);
|
||||
return grant;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package net.frozenorb.apiv3.routes.ipLog;
|
||||
|
||||
import net.frozenorb.apiv3.models.User;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class GETUserIPLog implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
User target = User.byId(req.params("id"));
|
||||
|
||||
if (target == null) {
|
||||
return ErrorUtils.notFound("User", req.params("id"));
|
||||
}
|
||||
|
||||
return target.getIPLog();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package net.frozenorb.apiv3.routes.notificationTemplate;
|
||||
|
||||
import net.frozenorb.apiv3.models.NotificationTemplate;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class DELETENotificationTemplate implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
NotificationTemplate notificationTemplate = NotificationTemplate.byId(req.params("id"));
|
||||
|
||||
if (notificationTemplate == null) {
|
||||
return ErrorUtils.notFound("Notification template", req.params("id"));
|
||||
}
|
||||
|
||||
notificationTemplate.delete();
|
||||
return notificationTemplate;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package net.frozenorb.apiv3.routes.notificationTemplate;
|
||||
|
||||
import net.frozenorb.apiv3.models.NotificationTemplate;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class GETNotificationTemplate implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
return NotificationTemplate.byId(req.params("id"));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package net.frozenorb.apiv3.routes.notificationTemplate;
|
||||
|
||||
import net.frozenorb.apiv3.models.NotificationTemplate;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class GETNotificationTemplates implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
return NotificationTemplate.values();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package net.frozenorb.apiv3.routes.notificationTemplate;
|
||||
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.models.NotificationTemplate;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class POSTNotificationTemplate implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
String id = req.queryParams("id");
|
||||
String subject = req.queryParams("subject");
|
||||
String body = req.queryParams("body");
|
||||
|
||||
NotificationTemplate notificationTemplate = new NotificationTemplate(id, subject, body);
|
||||
APIv3.getDatastore().save(notificationTemplate);
|
||||
return notificationTemplate;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package net.frozenorb.apiv3.routes.notificationTemplate;
|
||||
|
||||
public class PUTNotificationTemplate {
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package net.frozenorb.apiv3.routes.punishments;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import net.frozenorb.apiv3.auditLog.AuditLog;
|
||||
import net.frozenorb.apiv3.auditLog.AuditLogActionType;
|
||||
import net.frozenorb.apiv3.models.Punishment;
|
||||
import net.frozenorb.apiv3.models.User;
|
||||
import net.frozenorb.apiv3.unsorted.Permissions;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import org.bson.Document;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class DELETEPunishment implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
Punishment punishment = Punishment.byId(req.params("id"));
|
||||
|
||||
if (punishment == null) {
|
||||
return ErrorUtils.notFound("Punishment", req.params("id"));
|
||||
} else if (!punishment.isActive()) {
|
||||
return ErrorUtils.invalidInput("Cannot remove an inactive punishment.");
|
||||
}
|
||||
|
||||
User removedBy = User.byId(req.queryParams("removedBy"));
|
||||
String requiredPermission = Permissions.REMOVE_PUNISHMENT + "." + punishment.getType().name();
|
||||
|
||||
if (removedBy == null) {
|
||||
return ErrorUtils.notFound("User", req.queryParams("removedBy"));
|
||||
} else if (!removedBy.hasPermissionAnywhere(requiredPermission)) {
|
||||
return ErrorUtils.unauthorized(requiredPermission);
|
||||
}
|
||||
|
||||
String reason = req.queryParams("reason");
|
||||
|
||||
if (reason == null || reason.trim().isEmpty()) {
|
||||
return ErrorUtils.requiredInput("reason");
|
||||
}
|
||||
|
||||
punishment.delete(removedBy, reason);
|
||||
// TODO: Fix IP
|
||||
AuditLog.log(removedBy, "", req.attribute("actor"), AuditLogActionType.DELETE_PUNISHMENT, ImmutableMap.of());
|
||||
return punishment;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package net.frozenorb.apiv3.routes.punishments;
|
||||
|
||||
import net.frozenorb.apiv3.models.Punishment;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class GETPunishment implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
return Punishment.byId(req.params("id"));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package net.frozenorb.apiv3.routes.punishments;
|
||||
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.models.Punishment;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class GETPunishments implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
try {
|
||||
int limit = req.queryParams("limit") == null ? 100 : Integer.parseInt(req.queryParams("limit"));
|
||||
int offset = req.queryParams("offset") == null ? 0 : Integer.parseInt(req.queryParams("offset"));
|
||||
|
||||
return APIv3.getDatastore().createQuery(Punishment.class).order("addedAt").limit(limit).offset(offset).asList();
|
||||
} catch (NumberFormatException ex) {
|
||||
return ErrorUtils.invalidInput("limit and offset must be numerical inputs.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package net.frozenorb.apiv3.routes.punishments;
|
||||
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.models.Punishment;
|
||||
import net.frozenorb.apiv3.models.Server;
|
||||
import net.frozenorb.apiv3.models.User;
|
||||
import net.frozenorb.apiv3.unsorted.Permissions;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public final class POSTUserPunish implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
User target = User.byId(req.params("id"));
|
||||
|
||||
if (target == null) {
|
||||
return ErrorUtils.notFound("User", req.params("id"));
|
||||
}
|
||||
|
||||
String reason = req.queryParams("reason");
|
||||
|
||||
if (reason == null || reason.trim().isEmpty()) {
|
||||
return ErrorUtils.requiredInput("reason");
|
||||
}
|
||||
|
||||
Punishment.PunishmentType type = Punishment.PunishmentType.valueOf(req.queryParams("type"));
|
||||
Date expiresAt = new Date(Long.parseLong(req.queryParams("expiresAt")));
|
||||
|
||||
if (expiresAt.before(new Date())) {
|
||||
return ErrorUtils.invalidInput("Expiration date cannot be in the past.");
|
||||
}
|
||||
|
||||
User addedBy = User.byId(req.queryParams("addedBy"));
|
||||
String requiredPermission = Permissions.CREATE_PUNISHMENT + "." + type.name();
|
||||
|
||||
if (addedBy == null) {
|
||||
return ErrorUtils.notFound("User", req.queryParams("addedBy"));
|
||||
} else if (!addedBy.hasPermissionAnywhere(requiredPermission)) {
|
||||
return ErrorUtils.unauthorized(requiredPermission);
|
||||
}
|
||||
|
||||
if (target.hasPermissionAnywhere(Permissions.PROTECTED_PUNISHMENT)) {
|
||||
return ErrorUtils.error(target.getLastSeenOn() + " is protected from punishments.");
|
||||
}
|
||||
|
||||
Punishment punishment = new Punishment(target, reason, type, expiresAt, addedBy, req.attribute("actor"));
|
||||
APIv3.getDatastore().save(punishment);
|
||||
return punishment;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package net.frozenorb.apiv3.routes.ranks;
|
||||
|
||||
import net.frozenorb.apiv3.models.Rank;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class DELETERank implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
Rank rank = Rank.byId(req.params("id"));
|
||||
|
||||
if (rank == null) {
|
||||
return ErrorUtils.notFound("Rank", req.params("id"));
|
||||
}
|
||||
|
||||
rank.delete();
|
||||
return rank;
|
||||
}
|
||||
|
||||
}
|
14
src/main/java/net/frozenorb/apiv3/routes/ranks/GETRank.java
Normal file
14
src/main/java/net/frozenorb/apiv3/routes/ranks/GETRank.java
Normal file
@ -0,0 +1,14 @@
|
||||
package net.frozenorb.apiv3.routes.ranks;
|
||||
|
||||
import net.frozenorb.apiv3.models.Rank;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class GETRank implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
return Rank.byId(req.params("id"));
|
||||
}
|
||||
|
||||
}
|
14
src/main/java/net/frozenorb/apiv3/routes/ranks/GETRanks.java
Normal file
14
src/main/java/net/frozenorb/apiv3/routes/ranks/GETRanks.java
Normal file
@ -0,0 +1,14 @@
|
||||
package net.frozenorb.apiv3.routes.ranks;
|
||||
|
||||
import net.frozenorb.apiv3.models.Rank;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class GETRanks implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
return Rank.values();
|
||||
}
|
||||
|
||||
}
|
24
src/main/java/net/frozenorb/apiv3/routes/ranks/POSTRank.java
Normal file
24
src/main/java/net/frozenorb/apiv3/routes/ranks/POSTRank.java
Normal file
@ -0,0 +1,24 @@
|
||||
package net.frozenorb.apiv3.routes.ranks;
|
||||
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.models.Rank;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class POSTRank implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
String id = req.queryParams("id");
|
||||
int weight = Integer.parseInt(req.queryParams("weight"));
|
||||
String displayName = req.queryParams("displayName");
|
||||
String gameColor = req.queryParams("gameColor");
|
||||
String websiteColor = req.queryParams("websiteColor");
|
||||
boolean staffRank = Boolean.parseBoolean(req.queryParams("staffRank"));
|
||||
|
||||
Rank rank = new Rank(id, weight, displayName, gameColor, websiteColor, staffRank);
|
||||
APIv3.getDatastore().save(rank);
|
||||
return rank;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package net.frozenorb.apiv3.routes.ranks;
|
||||
|
||||
public class PUTRank {
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package net.frozenorb.apiv3.routes.serverGroups;
|
||||
|
||||
import net.frozenorb.apiv3.models.ServerGroup;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class DELETEServerGroup implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
ServerGroup serverGroup = ServerGroup.byId(req.params("id"));
|
||||
|
||||
if (serverGroup == null) {
|
||||
return ErrorUtils.notFound("Server group", req.params("id"));
|
||||
}
|
||||
|
||||
serverGroup.delete();
|
||||
return serverGroup;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package net.frozenorb.apiv3.routes.serverGroups;
|
||||
|
||||
import net.frozenorb.apiv3.models.ServerGroup;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class GETServerGroup implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
return ServerGroup.byId(req.params("id"));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package net.frozenorb.apiv3.routes.serverGroups;
|
||||
|
||||
import net.frozenorb.apiv3.models.ServerGroup;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class GETServerGroups implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
return ServerGroup.values();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package net.frozenorb.apiv3.routes.serverGroups;
|
||||
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.models.ServerGroup;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class POSTServerGroup implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
String id = req.queryParams("id");
|
||||
boolean isPublic = Boolean.valueOf(req.queryParams("public"));
|
||||
|
||||
ServerGroup serverGroup = new ServerGroup(id, isPublic);
|
||||
APIv3.getDatastore().save(serverGroup);
|
||||
return serverGroup;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package net.frozenorb.apiv3.routes.serverGroups;
|
||||
|
||||
public class PUTServerGroup {
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package net.frozenorb.apiv3.routes.servers;
|
||||
|
||||
import net.frozenorb.apiv3.models.Server;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class DELETEServer implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
Server server = Server.byId(req.params("id"));
|
||||
|
||||
if (server == null) {
|
||||
return ErrorUtils.notFound("Server", req.params("id"));
|
||||
}
|
||||
|
||||
server.delete();
|
||||
return server;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package net.frozenorb.apiv3.routes.servers;
|
||||
|
||||
import net.frozenorb.apiv3.models.Server;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class GETServer implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
return Server.byId(req.params("id"));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package net.frozenorb.apiv3.routes.servers;
|
||||
|
||||
import net.frozenorb.apiv3.models.Server;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class GETServers implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
return Server.values();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package net.frozenorb.apiv3.routes.servers;
|
||||
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.models.Server;
|
||||
import net.frozenorb.apiv3.models.ServerGroup;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import net.frozenorb.apiv3.utils.IPUtils;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class POSTServer implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
String id = req.queryParams("id");
|
||||
String bungeeId = req.queryParams("id");
|
||||
String displayName = req.queryParams("displayName");
|
||||
String apiKey = req.queryParams("apiKey");
|
||||
ServerGroup group = ServerGroup.byId(req.queryParams("group"));
|
||||
String ip = req.queryParams("ip");
|
||||
|
||||
if (group == null) {
|
||||
return ErrorUtils.notFound("Server group", req.queryParams("group"));
|
||||
}
|
||||
|
||||
if (!IPUtils.isValidIP(ip)) {
|
||||
return ErrorUtils.invalidInput("IP address \"" + ip + "\" is not valid.");
|
||||
}
|
||||
|
||||
Server server = new Server(id, bungeeId, displayName, apiKey, group, ip);
|
||||
APIv3.getDatastore().save(server);
|
||||
return server;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package net.frozenorb.apiv3.routes.servers;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.actors.Actor;
|
||||
import net.frozenorb.apiv3.actors.ActorType;
|
||||
import net.frozenorb.apiv3.models.Server;
|
||||
import net.frozenorb.apiv3.models.User;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import org.bson.Document;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public final class POSTServerHeartbeat implements Route {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object handle(Request req, Response res) {
|
||||
Actor actor = req.attribute("actor");
|
||||
|
||||
if (actor.getType() != ActorType.SERVER) {
|
||||
return ErrorUtils.serverOnly();
|
||||
}
|
||||
|
||||
Server actorServer = Server.byId(actor.getName());
|
||||
Document reqJson = Document.parse(req.body());
|
||||
Set<UUID> onlinePlayers = new HashSet<>();
|
||||
Map<String, Object> playersResponse = new HashMap<>();
|
||||
|
||||
for (Object player : (List<Object>) reqJson.get("players")) {
|
||||
Document playerJson = (Document) player;
|
||||
User user = User.byId(playerJson.getString("uuid"));
|
||||
String username = playerJson.getString("username");
|
||||
|
||||
if (user == null) {
|
||||
// Will be saved by the save command a few lines down.
|
||||
user = new User(UUID.fromString(playerJson.getString("uuid")), username);
|
||||
}
|
||||
|
||||
user.seenOnServer(username, actorServer);
|
||||
APIv3.getDatastore().save(user);
|
||||
|
||||
onlinePlayers.add(user.getId());
|
||||
playersResponse.put(user.getId().toString(), user.getLoginInfo(actorServer));
|
||||
}
|
||||
|
||||
for (Object event : (List<Object>) reqJson.get("events")) {
|
||||
Document eventJson = (Document) event;
|
||||
String type = eventJson.getString("type");
|
||||
|
||||
switch (type) {
|
||||
case "join":
|
||||
break;
|
||||
case "leave":
|
||||
break;
|
||||
case "metrics":
|
||||
break;
|
||||
default:
|
||||
System.err.println("Recieved event with unknown type " + type + ".");
|
||||
}
|
||||
}
|
||||
|
||||
actorServer.setPlayers(onlinePlayers);
|
||||
actorServer.setLastTps(reqJson.getDouble("lastTps"));
|
||||
actorServer.setLastUpdate(new Date());
|
||||
APIv3.getDatastore().save(actorServer);
|
||||
|
||||
return ImmutableMap.of(
|
||||
"players", playersResponse
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package net.frozenorb.apiv3.routes.servers;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import net.frozenorb.apiv3.actors.Actor;
|
||||
import net.frozenorb.apiv3.actors.ActorType;
|
||||
import net.frozenorb.apiv3.models.Server;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class POSTServerMetrics implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
Actor actor = req.attribute("actor");
|
||||
|
||||
if (actor.getType() != ActorType.SERVER) {
|
||||
return ErrorUtils.serverOnly();
|
||||
}
|
||||
|
||||
Server actorServer = Server.byId(actor.getName());
|
||||
|
||||
//LibratoBatch batch = new LibratoBatch();
|
||||
|
||||
return ImmutableMap.of();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package net.frozenorb.apiv3.routes.servers;
|
||||
|
||||
public class PUTServer {
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package net.frozenorb.apiv3.routes.users;
|
||||
|
||||
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 spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class DELETEUserMeta implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
User user = User.byId(req.params("id"));
|
||||
|
||||
if (user == null) {
|
||||
return ErrorUtils.notFound("User", req.params("id"));
|
||||
}
|
||||
|
||||
ServerGroup serverGroup = ServerGroup.byId(req.params("serverGroup"));
|
||||
|
||||
if (serverGroup == null) {
|
||||
return ErrorUtils.notFound("Server group", req.params("serverGroup"));
|
||||
}
|
||||
|
||||
UserMetaEntry userMetaEntry = user.getMeta(serverGroup);
|
||||
|
||||
userMetaEntry.delete();
|
||||
return userMetaEntry.getData();
|
||||
}
|
||||
|
||||
}
|
45
src/main/java/net/frozenorb/apiv3/routes/users/GETStaff.java
Normal file
45
src/main/java/net/frozenorb/apiv3/routes/users/GETStaff.java
Normal file
@ -0,0 +1,45 @@
|
||||
package net.frozenorb.apiv3.routes.users;
|
||||
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.models.Grant;
|
||||
import net.frozenorb.apiv3.models.Rank;
|
||||
import net.frozenorb.apiv3.models.User;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public final class GETStaff implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
Map<String, Rank> staffRanks = new HashMap<>();
|
||||
|
||||
Rank.values().forEach(rank -> {
|
||||
if (rank.isStaffRank()) {
|
||||
staffRanks.put(rank.getId(), rank);
|
||||
}
|
||||
});
|
||||
|
||||
Map<Rank, Set<User>> result = new HashMap<>();
|
||||
|
||||
APIv3.getDatastore().createQuery(Grant.class).field("rank").in(staffRanks.keySet()).forEach(grant -> {
|
||||
if (grant.isActive()) {
|
||||
User user = User.byId(grant.getTarget());
|
||||
Rank rank = staffRanks.get(grant.getRank());
|
||||
|
||||
if (!result.containsKey(rank)) {
|
||||
result.put(rank, new HashSet<>());
|
||||
}
|
||||
|
||||
result.get(rank).add(user);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
14
src/main/java/net/frozenorb/apiv3/routes/users/GETUser.java
Normal file
14
src/main/java/net/frozenorb/apiv3/routes/users/GETUser.java
Normal file
@ -0,0 +1,14 @@
|
||||
package net.frozenorb.apiv3.routes.users;
|
||||
|
||||
import net.frozenorb.apiv3.models.User;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class GETUser implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
return User.byId(req.params("id"));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package net.frozenorb.apiv3.routes.users;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import net.frozenorb.apiv3.models.User;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class GETUserDetails implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
User user = User.byId(req.params("id"));
|
||||
|
||||
if (user == null) {
|
||||
return ErrorUtils.notFound("User", req.params("id"));
|
||||
}
|
||||
|
||||
// Too many fields to use .of()
|
||||
return ImmutableMap.builder()
|
||||
.put("user", user)
|
||||
.put("grants", user.getGrants())
|
||||
.put("ipLog", user.getIPLog())
|
||||
.put("punishments", user.getPunishments())
|
||||
.put("aliases", user.getAliases())
|
||||
.put("totpSetup", user.getTotpSecret() != null);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package net.frozenorb.apiv3.routes.users;
|
||||
|
||||
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 spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class GETUserMeta implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
User user = User.byId(req.params("id"));
|
||||
|
||||
if (user == null) {
|
||||
return ErrorUtils.notFound("User", req.params("id"));
|
||||
}
|
||||
|
||||
ServerGroup serverGroup = ServerGroup.byId(req.params("serverGroup"));
|
||||
|
||||
if (serverGroup == null) {
|
||||
return ErrorUtils.notFound("Server group", req.params("serverGroup"));
|
||||
}
|
||||
|
||||
UserMetaEntry userMetaEntry = user.getMeta(serverGroup);
|
||||
return userMetaEntry.getData();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package net.frozenorb.apiv3.routes.users;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import net.frozenorb.apiv3.models.User;
|
||||
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||
import net.frozenorb.apiv3.utils.IPUtils;
|
||||
import net.frozenorb.apiv3.utils.TOTPUtils;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
import spark.Route;
|
||||
|
||||
public final class GETUserRequiresTOTP implements Route {
|
||||
|
||||
public Object handle(Request req, Response res) {
|
||||
User user = User.byId(req.params("id"));
|
||||
|
||||
if (user == null) {
|
||||
return ErrorUtils.notFound("User", req.params("id"));
|
||||
}
|
||||
|
||||
if (user.getTotpSecret() == null) {
|
||||
return ImmutableMap.of(
|
||||
"required", false,
|
||||
"message", "User does not have TOTP setup."
|
||||
);
|
||||
}
|
||||
|
||||
String userIp = req.queryParams("userIp");
|
||||
|
||||
if (!IPUtils.isValidIP(userIp)) {
|
||||
return ErrorUtils.invalidInput("IP address \"" + userIp + "\" is not valid.");
|
||||
}
|
||||
|
||||
if (TOTPUtils.isPreAuthorized(user, userIp)) {
|
||||
return ImmutableMap.of(
|
||||
"required", false,
|
||||
"message", "User's IP has already been validated"
|
||||
);
|
||||
}
|
||||
|
||||
return ImmutableMap.of(
|
||||
"required", true,
|
||||
"message", "User has no TOTP exemptions."
|
||||
);
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user