Whoa stuff
This commit is contained in:
parent
1b05b16fed
commit
6009522090
|
@ -24,10 +24,7 @@ import net.frozenorb.apiv3.routes.notificationTemplate.DELETENotificationTemplat
|
||||||
import net.frozenorb.apiv3.routes.notificationTemplate.GETNotificationTemplate;
|
import net.frozenorb.apiv3.routes.notificationTemplate.GETNotificationTemplate;
|
||||||
import net.frozenorb.apiv3.routes.notificationTemplate.GETNotificationTemplates;
|
import net.frozenorb.apiv3.routes.notificationTemplate.GETNotificationTemplates;
|
||||||
import net.frozenorb.apiv3.routes.notificationTemplate.POSTNotificationTemplate;
|
import net.frozenorb.apiv3.routes.notificationTemplate.POSTNotificationTemplate;
|
||||||
import net.frozenorb.apiv3.routes.punishments.DELETEPunishment;
|
import net.frozenorb.apiv3.routes.punishments.*;
|
||||||
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.DELETERank;
|
||||||
import net.frozenorb.apiv3.routes.ranks.GETRank;
|
import net.frozenorb.apiv3.routes.ranks.GETRank;
|
||||||
import net.frozenorb.apiv3.routes.ranks.GETRanks;
|
import net.frozenorb.apiv3.routes.ranks.GETRanks;
|
||||||
|
@ -146,12 +143,14 @@ public final class APIv3 {
|
||||||
private void setupHttp() {
|
private void setupHttp() {
|
||||||
ipAddress(config.getProperty("http.address"));
|
ipAddress(config.getProperty("http.address"));
|
||||||
port(Integer.parseInt(config.getProperty("http.port")));
|
port(Integer.parseInt(config.getProperty("http.port")));
|
||||||
|
// TODO: if threadPool == null use default value
|
||||||
threadPool(Integer.parseInt(config.getProperty("http.workerThreads")));
|
threadPool(Integer.parseInt(config.getProperty("http.workerThreads")));
|
||||||
before(new ContentTypeFilter());
|
before(new ContentTypeFilter());
|
||||||
before(new ActorAttributeFilter());
|
before(new ActorAttributeFilter());
|
||||||
before(new AuthorizationFilter());
|
before(new AuthorizationFilter());
|
||||||
before(new MetricsBeforeFilter());
|
before(new MetricsBeforeFilter());
|
||||||
after(new MetricsAfterFilter());
|
after(new MetricsAfterFilter());
|
||||||
|
after(new LoggingFilter());
|
||||||
exception(Exception.class, new LoggingExceptionHandler());
|
exception(Exception.class, new LoggingExceptionHandler());
|
||||||
|
|
||||||
// TODO: The commented out routes
|
// TODO: The commented out routes
|
||||||
|
@ -200,13 +199,14 @@ public final class APIv3 {
|
||||||
get("/user/:id/details", new GETUserDetails(), gson::toJson);
|
get("/user/:id/details", new GETUserDetails(), gson::toJson);
|
||||||
get("/user/:id/meta/:serverGroup", new GETUserMeta(), gson::toJson);
|
get("/user/:id/meta/:serverGroup", new GETUserMeta(), gson::toJson);
|
||||||
get("/user/:id/grants", new GETUserGrants(), gson::toJson);
|
get("/user/:id/grants", new GETUserGrants(), gson::toJson);
|
||||||
|
get("/user/:id/punishments", new GETUserPunishments(), gson::toJson);
|
||||||
get("/user/:id/ipLog", new GETUserIPLog(), gson::toJson);
|
get("/user/:id/ipLog", new GETUserIPLog(), gson::toJson);
|
||||||
get("/user/:id/requiresTOTP", new GETUserRequiresTOTP(), gson::toJson);
|
get("/user/:id/requiresTOTP", new GETUserRequiresTOTP(), gson::toJson);
|
||||||
get("/user/:id/verifyPassword", new GETUserVerifyPassword(), gson::toJson);
|
get("/user/:id/verifyPassword", new GETUserVerifyPassword(), gson::toJson);
|
||||||
get("/user/:id", new GETUser(), gson::toJson);
|
get("/user/:id", new GETUser(), gson::toJson);
|
||||||
post("/user/:id/verifyTOTP", new POSTUserVerifyTOTP(), gson::toJson);
|
post("/user/:id/verifyTOTP", new POSTUserVerifyTOTP(), gson::toJson);
|
||||||
post("/user/:id:/grant", new POSTUserGrant(), gson::toJson);
|
post("/user/:id/grant", new POSTUserGrant(), gson::toJson);
|
||||||
post("/user/:id:/punish", new POSTUserPunish(), gson::toJson);
|
post("/user/:id/punish", new POSTUserPunish(), gson::toJson);
|
||||||
post("/user/:id/login", new POSTUserLogin(), gson::toJson);
|
post("/user/:id/login", new POSTUserLogin(), gson::toJson);
|
||||||
post("/user/:id/notify", new POSTUserNotify(), gson::toJson);
|
post("/user/:id/notify", new POSTUserNotify(), gson::toJson);
|
||||||
post("/user/:id/register", new POSTUserRegister(), gson::toJson);
|
post("/user/:id/register", new POSTUserRegister(), gson::toJson);
|
||||||
|
@ -214,6 +214,7 @@ public final class APIv3 {
|
||||||
post("/user/confirmRegister/:emailToken", new POSTUserConfirmRegister(), gson::toJson);
|
post("/user/confirmRegister/:emailToken", new POSTUserConfirmRegister(), gson::toJson);
|
||||||
put("/user/:id/meta/:serverGroup", new PUTUserMeta(), gson::toJson);
|
put("/user/:id/meta/:serverGroup", new PUTUserMeta(), gson::toJson);
|
||||||
delete("/user/:id/meta/:serverGroup", new DELETEUserMeta(), gson::toJson);
|
delete("/user/:id/meta/:serverGroup", new DELETEUserMeta(), gson::toJson);
|
||||||
|
delete("/user/:id/punishment", new DELETEUserPunishment(), gson::toJson);
|
||||||
|
|
||||||
// There's no way to do a JSON 404 page w/o doing this :(
|
// There's no way to do a JSON 404 page w/o doing this :(
|
||||||
get("/*", new NotFound(), gson::toJson);
|
get("/*", new NotFound(), gson::toJson);
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
package net.frozenorb.apiv3.filters;
|
||||||
|
|
||||||
|
import com.codahale.metrics.Histogram;
|
||||||
|
import com.codahale.metrics.MetricRegistry;
|
||||||
|
import com.codahale.metrics.Timer;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import net.frozenorb.apiv3.APIv3;
|
||||||
|
import spark.Filter;
|
||||||
|
import spark.Request;
|
||||||
|
import spark.Response;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public final class LoggingFilter implements Filter {
|
||||||
|
|
||||||
|
public void handle(Request req, Response res) {
|
||||||
|
if (req.url().toLowerCase().contains("password=")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info(req.requestMethod().toUpperCase() + " " + req.url());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -8,15 +8,18 @@ import spark.Filter;
|
||||||
import spark.Request;
|
import spark.Request;
|
||||||
import spark.Response;
|
import spark.Response;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public final class MetricsAfterFilter implements Filter {
|
public final class MetricsAfterFilter implements Filter {
|
||||||
|
|
||||||
private Histogram responseLengthMetric = APIv3.getMetrics().histogram(MetricRegistry.name("apiv3", "http", "responseLength"));
|
private Histogram responseLengthMetric = APIv3.getMetrics().histogram(MetricRegistry.name("apiv3", "http", "responseLength"));
|
||||||
|
private Timer responseTimesMetric = APIv3.getMetrics().timer(MetricRegistry.name("apiv3", "http", "responseTimes"));
|
||||||
|
|
||||||
public void handle(Request req, Response res) {
|
public void handle(Request req, Response res) {
|
||||||
responseLengthMetric.update(req.contentLength());
|
responseLengthMetric.update(req.contentLength());
|
||||||
|
|
||||||
Timer.Context timerMetric = req.attribute("timerMetric");
|
long started = req.attribute("requestStarted");
|
||||||
timerMetric.stop();
|
responseTimesMetric.update(System.currentTimeMillis() - started, TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -9,10 +9,8 @@ import spark.Response;
|
||||||
|
|
||||||
public final class MetricsBeforeFilter implements Filter {
|
public final class MetricsBeforeFilter implements Filter {
|
||||||
|
|
||||||
private Timer responseTimesMetric = APIv3.getMetrics().timer(MetricRegistry.name("apiv3", "http", "responseTimes"));
|
|
||||||
|
|
||||||
public void handle(Request req, Response res) {
|
public void handle(Request req, Response res) {
|
||||||
req.attribute("timerMetric", responseTimesMetric.time());
|
req.attribute("requestStarted", System.currentTimeMillis());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -19,7 +19,7 @@ public final class Grant {
|
||||||
@Getter @Id private String id;
|
@Getter @Id private String id;
|
||||||
@Getter @Indexed private UUID target;
|
@Getter @Indexed private UUID target;
|
||||||
@Getter private String reason;
|
@Getter private String reason;
|
||||||
@Getter private Set<String> scopes;
|
@Getter private Set<String> scopes = new HashSet<>(); // So on things w/o scopes we still load properly (Morphia drops empty sets)
|
||||||
@Getter @Indexed private String rank;
|
@Getter @Indexed private String rank;
|
||||||
@Getter private Date expiresAt;
|
@Getter private Date expiresAt;
|
||||||
|
|
||||||
|
@ -42,8 +42,8 @@ public final class Grant {
|
||||||
this.reason = reason;
|
this.reason = reason;
|
||||||
this.scopes = new HashSet<>(Collections2.transform(scopes, ServerGroup::getId));
|
this.scopes = new HashSet<>(Collections2.transform(scopes, ServerGroup::getId));
|
||||||
this.rank = rank.getId();
|
this.rank = rank.getId();
|
||||||
this.expiresAt = (Date) expiresAt.clone();
|
this.expiresAt = expiresAt;
|
||||||
this.addedBy = addedBy.getId();
|
this.addedBy = addedBy == null ? null : addedBy.getId();
|
||||||
this.addedAt = new Date();
|
this.addedAt = new Date();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ public final class Grant {
|
||||||
if (expiresAt == null) {
|
if (expiresAt == null) {
|
||||||
return false; // Never expires
|
return false; // Never expires
|
||||||
} else {
|
} else {
|
||||||
return expiresAt.after(new Date());
|
return expiresAt.before(new Date());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,8 +41,8 @@ public final class Punishment {
|
||||||
this.target = target.getId();
|
this.target = target.getId();
|
||||||
this.reason = reason;
|
this.reason = reason;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.expiresAt = (Date) expiresAt.clone();
|
this.expiresAt = expiresAt;
|
||||||
this.addedBy = addedBy.getId();
|
this.addedBy = addedBy == null ? null : addedBy.getId();
|
||||||
this.addedAt = new Date();
|
this.addedAt = new Date();
|
||||||
this.actorName = actor.getName();
|
this.actorName = actor.getName();
|
||||||
this.actorType = actor.getType();
|
this.actorType = actor.getType();
|
||||||
|
@ -64,7 +64,7 @@ public final class Punishment {
|
||||||
if (expiresAt == null) {
|
if (expiresAt == null) {
|
||||||
return false; // Never expires
|
return false; // Never expires
|
||||||
} else {
|
} else {
|
||||||
return expiresAt.after(new Date());
|
return expiresAt.before(new Date());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import net.frozenorb.apiv3.serialization.ExcludeFromReplies;
|
||||||
import net.frozenorb.apiv3.utils.PermissionUtils;
|
import net.frozenorb.apiv3.utils.PermissionUtils;
|
||||||
import org.mongodb.morphia.annotations.Entity;
|
import org.mongodb.morphia.annotations.Entity;
|
||||||
import org.mongodb.morphia.annotations.Id;
|
import org.mongodb.morphia.annotations.Id;
|
||||||
|
import org.mongodb.morphia.annotations.Property;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
@ -14,7 +15,8 @@ import java.util.*;
|
||||||
public final class ServerGroup {
|
public final class ServerGroup {
|
||||||
|
|
||||||
@Getter @Id private String id;
|
@Getter @Id private String id;
|
||||||
@Getter private boolean isPublic;
|
// We rename this to public, we just can't name it that because it's a Java identifier.
|
||||||
|
@Getter @Property("public") private boolean isPublic;
|
||||||
// We define these HashSets up here because, in the event they're
|
// We define these HashSets up here because, in the event they're
|
||||||
// empty, Morphia will load them as null, not empty sets.
|
// empty, Morphia will load them as null, not empty sets.
|
||||||
@Getter @Setter @ExcludeFromReplies private Set<String> announcements = new HashSet<>();
|
@Getter @Setter @ExcludeFromReplies private Set<String> announcements = new HashSet<>();
|
||||||
|
|
|
@ -30,7 +30,7 @@ public final class User {
|
||||||
@Getter private String phoneNumber;
|
@Getter private String phoneNumber;
|
||||||
@Getter private String lastSeenOn;
|
@Getter private String lastSeenOn;
|
||||||
@Getter private Date lastSeenAt;
|
@Getter private Date lastSeenAt;
|
||||||
@Getter private Date firstSeen;
|
@Getter private Date firstSeenAt;
|
||||||
|
|
||||||
public static User byId(String id) {
|
public static User byId(String id) {
|
||||||
try {
|
try {
|
||||||
|
@ -65,7 +65,7 @@ public final class User {
|
||||||
this.phoneNumber = null;
|
this.phoneNumber = null;
|
||||||
this.lastSeenOn = null;
|
this.lastSeenOn = null;
|
||||||
this.lastSeenAt = new Date();
|
this.lastSeenAt = new Date();
|
||||||
this.firstSeen = new Date();
|
this.firstSeenAt = new Date();
|
||||||
|
|
||||||
aliases.put(lastUsername, new Date());
|
aliases.put(lastUsername, new Date());
|
||||||
}
|
}
|
||||||
|
@ -157,7 +157,7 @@ public final class User {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Rank getHighestRank(ServerGroup serverGroup) {
|
public Rank getHighestRank(ServerGroup serverGroup) {
|
||||||
Rank highest = null;
|
Rank highest = null;;
|
||||||
|
|
||||||
for (Grant grant : getGrants()) {
|
for (Grant grant : getGrants()) {
|
||||||
if (!grant.isActive() || (serverGroup != null && !grant.appliesOn(serverGroup))) {
|
if (!grant.isActive() || (serverGroup != null && !grant.appliesOn(serverGroup))) {
|
||||||
|
@ -231,6 +231,7 @@ public final class User {
|
||||||
|
|
||||||
ServerGroup actorGroup = ServerGroup.byId(server.getGroup());
|
ServerGroup actorGroup = ServerGroup.byId(server.getGroup());
|
||||||
Rank highestRank = getHighestRank(actorGroup);
|
Rank highestRank = getHighestRank(actorGroup);
|
||||||
|
|
||||||
Map<String, Boolean> scopedPermissions = PermissionUtils.mergePermissions(
|
Map<String, Boolean> scopedPermissions = PermissionUtils.mergePermissions(
|
||||||
PermissionUtils.getDefaultPermissions(highestRank),
|
PermissionUtils.getDefaultPermissions(highestRank),
|
||||||
actorGroup.calculatePermissions(highestRank)
|
actorGroup.calculatePermissions(highestRank)
|
||||||
|
|
|
@ -23,12 +23,9 @@ public final class DELETEGrant implements Route {
|
||||||
}
|
}
|
||||||
|
|
||||||
User removedBy = User.byId(req.queryParams("removedBy"));
|
User removedBy = User.byId(req.queryParams("removedBy"));
|
||||||
String requiredPermission = Permissions.REMOVE_GRANT + "." + grant.getRank();
|
|
||||||
|
|
||||||
if (removedBy == null) {
|
if (removedBy == null) {
|
||||||
return ErrorUtils.notFound("User", req.queryParams("removedBy"));
|
return ErrorUtils.notFound("User", req.queryParams("removedBy"));
|
||||||
} else if (!removedBy.hasPermissionAnywhere(requiredPermission)) {
|
|
||||||
return ErrorUtils.unauthorized(requiredPermission);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String reason = req.queryParams("reason");
|
String reason = req.queryParams("reason");
|
||||||
|
|
|
@ -31,8 +31,10 @@ public final class POSTUserGrant implements Route {
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<ServerGroup> scopes = new HashSet<>();
|
Set<ServerGroup> scopes = new HashSet<>();
|
||||||
|
String scopesUnparsed = req.queryParams("scopes");
|
||||||
|
|
||||||
for (String serverGroupId : req.queryParams("scopes").split(",")) {
|
if (!scopesUnparsed.isEmpty()) {
|
||||||
|
for (String serverGroupId : scopesUnparsed.split(",")) {
|
||||||
ServerGroup serverGroup = ServerGroup.byId(serverGroupId);
|
ServerGroup serverGroup = ServerGroup.byId(serverGroupId);
|
||||||
|
|
||||||
if (serverGroup == null) {
|
if (serverGroup == null) {
|
||||||
|
@ -41,6 +43,7 @@ public final class POSTUserGrant implements Route {
|
||||||
|
|
||||||
scopes.add(serverGroup);
|
scopes.add(serverGroup);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Rank rank = Rank.byId(req.queryParams("rank"));
|
Rank rank = Rank.byId(req.queryParams("rank"));
|
||||||
|
|
||||||
|
@ -48,20 +51,20 @@ public final class POSTUserGrant implements Route {
|
||||||
return ErrorUtils.notFound("Rank", req.queryParams("rank"));
|
return ErrorUtils.notFound("Rank", req.queryParams("rank"));
|
||||||
}
|
}
|
||||||
|
|
||||||
Date expiresAt = new Date(Long.parseLong(req.queryParams("expiresAt")));
|
Date expiresAt;
|
||||||
|
|
||||||
if (expiresAt.before(new Date())) {
|
try {
|
||||||
|
expiresAt = new Date(Long.parseLong(req.queryParams("expiresAt")));
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
expiresAt = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expiresAt != null && expiresAt.before(new Date())) {
|
||||||
return ErrorUtils.invalidInput("Expiration date cannot be in the past.");
|
return ErrorUtils.invalidInput("Expiration date cannot be in the past.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We purposely don't do a null check, grants don't have to have a source.
|
||||||
User addedBy = User.byId(req.queryParams("addedBy"));
|
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);
|
Grant grant = new Grant(target, reason, scopes, rank, expiresAt, addedBy);
|
||||||
APIv3.getDatastore().save(grant);
|
APIv3.getDatastore().save(grant);
|
||||||
|
|
|
@ -23,12 +23,9 @@ public final class DELETEPunishment implements Route {
|
||||||
}
|
}
|
||||||
|
|
||||||
User removedBy = User.byId(req.queryParams("removedBy"));
|
User removedBy = User.byId(req.queryParams("removedBy"));
|
||||||
String requiredPermission = Permissions.REMOVE_PUNISHMENT + "." + punishment.getType().name();
|
|
||||||
|
|
||||||
if (removedBy == null) {
|
if (removedBy == null) {
|
||||||
return ErrorUtils.notFound("User", req.queryParams("removedBy"));
|
return ErrorUtils.notFound("User", req.queryParams("removedBy"));
|
||||||
} else if (!removedBy.hasPermissionAnywhere(requiredPermission)) {
|
|
||||||
return ErrorUtils.unauthorized(requiredPermission);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String reason = req.queryParams("reason");
|
String reason = req.queryParams("reason");
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package net.frozenorb.apiv3.routes.punishments;
|
||||||
|
|
||||||
|
import net.frozenorb.apiv3.models.User;
|
||||||
|
import net.frozenorb.apiv3.utils.ErrorUtils;
|
||||||
|
import spark.Request;
|
||||||
|
import spark.Response;
|
||||||
|
import spark.Route;
|
||||||
|
|
||||||
|
public final class GETUserPunishments 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.getPunishments();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,6 +1,10 @@
|
||||||
package net.frozenorb.apiv3.routes.punishments;
|
package net.frozenorb.apiv3.routes.punishments;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
import net.frozenorb.apiv3.APIv3;
|
import net.frozenorb.apiv3.APIv3;
|
||||||
|
import net.frozenorb.apiv3.auditLog.AuditLog;
|
||||||
|
import net.frozenorb.apiv3.auditLog.AuditLogActionType;
|
||||||
import net.frozenorb.apiv3.models.Punishment;
|
import net.frozenorb.apiv3.models.Punishment;
|
||||||
import net.frozenorb.apiv3.models.User;
|
import net.frozenorb.apiv3.models.User;
|
||||||
import net.frozenorb.apiv3.unsorted.Permissions;
|
import net.frozenorb.apiv3.unsorted.Permissions;
|
||||||
|
@ -27,20 +31,29 @@ public final class POSTUserPunish implements Route {
|
||||||
}
|
}
|
||||||
|
|
||||||
Punishment.PunishmentType type = Punishment.PunishmentType.valueOf(req.queryParams("type"));
|
Punishment.PunishmentType type = Punishment.PunishmentType.valueOf(req.queryParams("type"));
|
||||||
Date expiresAt = new Date(Long.parseLong(req.queryParams("expiresAt")));
|
|
||||||
|
|
||||||
if (expiresAt.before(new Date())) {
|
if (type != Punishment.PunishmentType.WARN) {
|
||||||
|
for (Punishment punishment : target.getPunishments(ImmutableSet.of(type))) {
|
||||||
|
if (punishment.isActive()) {
|
||||||
|
return ErrorUtils.error("A punishment by " + User.byId(punishment.getAddedBy()).getLastUsername() + " already covers this user.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Date expiresAt;
|
||||||
|
|
||||||
|
try {
|
||||||
|
expiresAt = new Date(Long.parseLong(req.queryParams("expiresAt")));
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
expiresAt = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expiresAt != null && expiresAt.before(new Date())) {
|
||||||
return ErrorUtils.invalidInput("Expiration date cannot be in the past.");
|
return ErrorUtils.invalidInput("Expiration date cannot be in the past.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We purposely don't do a null check, grants don't have to have a source.
|
||||||
User addedBy = User.byId(req.queryParams("addedBy"));
|
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)) {
|
if (target.hasPermissionAnywhere(Permissions.PROTECTED_PUNISHMENT)) {
|
||||||
return ErrorUtils.error(target.getLastSeenOn() + " is protected from punishments.");
|
return ErrorUtils.error(target.getLastSeenOn() + " is protected from punishments.");
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
package net.frozenorb.apiv3.routes.users;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
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.utils.ErrorUtils;
|
||||||
|
import spark.Request;
|
||||||
|
import spark.Response;
|
||||||
|
import spark.Route;
|
||||||
|
|
||||||
|
public final class DELETEUserPunishment 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"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Punishment.PunishmentType type = Punishment.PunishmentType.valueOf(req.queryParams("type").toUpperCase());
|
||||||
|
User removedBy = User.byId(req.queryParams("removedBy"));
|
||||||
|
|
||||||
|
if (removedBy == null) {
|
||||||
|
return ErrorUtils.notFound("User", req.queryParams("removedBy"));
|
||||||
|
}
|
||||||
|
|
||||||
|
String reason = req.queryParams("reason");
|
||||||
|
|
||||||
|
if (reason == null || reason.trim().isEmpty()) {
|
||||||
|
return ErrorUtils.requiredInput("reason");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Punishment punishment : target.getPunishments(ImmutableSet.of(type))) {
|
||||||
|
if (punishment.isActive()) {
|
||||||
|
punishment.delete(removedBy, reason);
|
||||||
|
// TODO: Fix IP
|
||||||
|
AuditLog.log(removedBy, "", req.attribute("actor"), AuditLogActionType.DELETE_PUNISHMENT, ImmutableMap.of());
|
||||||
|
return punishment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ErrorUtils.error("User provided has no active punishments");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -24,18 +24,18 @@ public final class GETStaff implements Route {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Map<Rank, Set<User>> result = new HashMap<>();
|
Map<String, Set<User>> result = new HashMap<>();
|
||||||
|
|
||||||
APIv3.getDatastore().createQuery(Grant.class).field("rank").in(staffRanks.keySet()).forEach(grant -> {
|
APIv3.getDatastore().createQuery(Grant.class).field("rank").in(staffRanks.keySet()).forEach(grant -> {
|
||||||
if (grant.isActive()) {
|
if (grant.isActive()) {
|
||||||
User user = User.byId(grant.getTarget());
|
User user = User.byId(grant.getTarget());
|
||||||
Rank rank = staffRanks.get(grant.getRank());
|
Rank rank = staffRanks.get(grant.getRank());
|
||||||
|
|
||||||
if (!result.containsKey(rank)) {
|
if (!result.containsKey(rank.getId())) {
|
||||||
result.put(rank, new HashSet<>());
|
result.put(rank.getId(), new HashSet<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
result.get(rank).add(user);
|
result.get(rank.getId()).add(user);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,8 @@ public final class GETUserDetails implements Route {
|
||||||
.put("ipLog", user.getIPLog())
|
.put("ipLog", user.getIPLog())
|
||||||
.put("punishments", user.getPunishments())
|
.put("punishments", user.getPunishments())
|
||||||
.put("aliases", user.getAliases())
|
.put("aliases", user.getAliases())
|
||||||
.put("totpSetup", user.getTotpSecret() != null);
|
.put("totpSetup", user.getTotpSecret() != null)
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -2,6 +2,7 @@ package net.frozenorb.apiv3.utils;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
|
import net.frozenorb.apiv3.APIv3;
|
||||||
import net.frozenorb.apiv3.models.Rank;
|
import net.frozenorb.apiv3.models.Rank;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -26,12 +27,10 @@ public class PermissionUtils {
|
||||||
List<String> unconvertedPermissions = unconverted.get(rank.getId());
|
List<String> unconvertedPermissions = unconverted.get(rank.getId());
|
||||||
|
|
||||||
// If there's no permissions defined for this rank just skip it.
|
// If there's no permissions defined for this rank just skip it.
|
||||||
if (unconvertedPermissions == null) {
|
if (unconvertedPermissions != null) {
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, Boolean> rankPermissions = convertToMap(unconvertedPermissions);
|
Map<String, Boolean> rankPermissions = convertToMap(unconvertedPermissions);
|
||||||
mergePermissions(result, rankPermissions);
|
result = mergePermissions(result, rankPermissions);
|
||||||
|
}
|
||||||
|
|
||||||
if (upTo.getId().equals(rank.getId())) {
|
if (upTo.getId().equals(rank.getId())) {
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue