Redo rank calculation to allow ranks that aren't part of the primary inheritance chain. Finishes #33
This commit is contained in:
parent
1b20362f4d
commit
983c428a09
@ -314,8 +314,8 @@ public final class APIv3 extends AbstractVerticle {
|
|||||||
|
|
||||||
http.get("/staff").blockingHandler(new GETStaff(), false);
|
http.get("/staff").blockingHandler(new GETStaff(), false);
|
||||||
http.get("/users/:id").handler(new GETUsersId());
|
http.get("/users/:id").handler(new GETUsersId());
|
||||||
|
http.get("/users/:id/compoundedPermissions").handler(new GETUsersIdCompoundedPermissions());
|
||||||
http.get("/users/:id/details").blockingHandler(new GETUsersIdDetails(), false);
|
http.get("/users/:id/details").blockingHandler(new GETUsersIdDetails(), false);
|
||||||
http.get("/users/:id/permissions").handler(new GETUsersIdPermissions());
|
|
||||||
http.get("/users/:id/requiresTotp").handler(new GETUsersIdRequiresTotp());
|
http.get("/users/:id/requiresTotp").handler(new GETUsersIdRequiresTotp());
|
||||||
http.get("/users/:id/verifyPassword").blockingHandler(new GETUsersIdVerifyPassword(), false);
|
http.get("/users/:id/verifyPassword").blockingHandler(new GETUsersIdVerifyPassword(), false);
|
||||||
http.post("/users/:id/changePassword").blockingHandler(new POSTUsersIdChangePassword(), false);
|
http.post("/users/:id/changePassword").blockingHandler(new POSTUsersIdChangePassword(), false);
|
||||||
@ -343,7 +343,7 @@ public final class APIv3 extends AbstractVerticle {
|
|||||||
ctx.response().setStatusCode(code);
|
ctx.response().setStatusCode(code);
|
||||||
|
|
||||||
if (!ctx.request().path().contains("dumps")) {
|
if (!ctx.request().path().contains("dumps")) {
|
||||||
//log.info(gson.toJson(response));
|
log.info(gson.toJson(response));
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.response().end(gson.toJson(response));
|
ctx.response().end(gson.toJson(response));
|
||||||
|
@ -7,6 +7,7 @@ import com.google.common.collect.ImmutableList;
|
|||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.hash.Hashing;
|
import com.google.common.hash.Hashing;
|
||||||
|
import com.google.common.primitives.Ints;
|
||||||
import com.mongodb.async.SingleResultCallback;
|
import com.mongodb.async.SingleResultCallback;
|
||||||
import com.mongodb.async.client.MongoCollection;
|
import com.mongodb.async.client.MongoCollection;
|
||||||
import com.mongodb.client.result.UpdateResult;
|
import com.mongodb.client.result.UpdateResult;
|
||||||
@ -34,6 +35,7 @@ import java.time.Instant;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@ -250,10 +252,12 @@ public final class User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Map<String, Object> result = new HashMap<>();
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
List<Rank> ranks = getRanksScoped(serverGroup, grants);
|
||||||
|
|
||||||
result.put("user", this);
|
result.put("user", this);
|
||||||
result.put("access", accessInfo);
|
result.put("access", accessInfo);
|
||||||
result.put("rank", getHighestRankScoped(serverGroup, grants).getId());
|
result.put("bestRank", ranks.get(0).getId());
|
||||||
|
result.put("ranks", ranks.stream().map(Rank::getId).collect(Collectors.toList()));
|
||||||
result.put("totpSetup", getTotpSecret() != null);
|
result.put("totpSetup", getTotpSecret() != null);
|
||||||
|
|
||||||
if (activeMute != null) {
|
if (activeMute != null) {
|
||||||
@ -472,7 +476,7 @@ public final class User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void hasPermissionAnywhere(String permission, SingleResultCallback<Boolean> callback) {
|
public void hasPermissionAnywhere(String permission, SingleResultCallback<Boolean> callback) {
|
||||||
getGlobalPermissions((permissions, error) -> {
|
getCompoundedPermissions((permissions, error) -> {
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
callback.onResult(null, error);
|
callback.onResult(null, error);
|
||||||
} else {
|
} else {
|
||||||
@ -482,58 +486,79 @@ public final class User {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void getGlobalPermissions(SingleResultCallback<Map<String, Boolean>> callback) {
|
public void getCompoundedPermissions(SingleResultCallback<Map<String, Boolean>> callback) {
|
||||||
Grant.findByUser(this, (grants, error) -> {
|
Grant.findByUser(this, (grants, error) -> {
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
callback.onResult(null, error);
|
callback.onResult(null, error);
|
||||||
} else {
|
} else {
|
||||||
Map<String, Boolean> globalPermissions = PermissionUtils.getDefaultPermissions(getHighestRankScoped(null, grants));
|
Map<String, Boolean> globalPermissions = new HashMap<>();
|
||||||
|
|
||||||
for (Map.Entry<ServerGroup, Rank> serverGroupEntry : getHighestRanks(grants).entrySet()) {
|
|
||||||
ServerGroup serverGroup = serverGroupEntry.getKey();
|
|
||||||
Rank rank = serverGroupEntry.getValue();
|
|
||||||
|
|
||||||
|
for (Rank globalRank : getRanksScoped(null, grants)) {
|
||||||
globalPermissions = PermissionUtils.mergePermissions(
|
globalPermissions = PermissionUtils.mergePermissions(
|
||||||
globalPermissions,
|
globalPermissions,
|
||||||
serverGroup.calculateScopedPermissions(rank)
|
PermissionUtils.getDefaultPermissions(globalRank)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (ServerGroup serverGroup : ServerGroup.findAll()) {
|
||||||
|
for (Rank scopedRank : getRanksScoped(serverGroup, grants)) {
|
||||||
|
globalPermissions = PermissionUtils.mergePermissions(
|
||||||
|
globalPermissions,
|
||||||
|
serverGroup.calculateScopedPermissions(scopedRank)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
callback.onResult(ImmutableMap.copyOf(globalPermissions), null);
|
callback.onResult(ImmutableMap.copyOf(globalPermissions), null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<ServerGroup, Rank> getHighestRanks(List<Grant> grants) {
|
private List<Rank> getRanksScoped(ServerGroup serverGroup, Iterable<Grant> grants) {
|
||||||
Map<ServerGroup, Rank> highestRanks = new HashMap<>();
|
List<Rank> grantedRanks = new LinkedList<>();
|
||||||
|
|
||||||
for (ServerGroup serverGroup : ServerGroup.findAll()) {
|
|
||||||
highestRanks.put(serverGroup, getHighestRankScoped(serverGroup, grants));
|
|
||||||
}
|
|
||||||
|
|
||||||
return highestRanks;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Rank getHighestRankScoped(ServerGroup serverGroup, Iterable<Grant> grants) {
|
|
||||||
Rank highest = null;
|
|
||||||
|
|
||||||
for (Grant grant : grants) {
|
for (Grant grant : grants) {
|
||||||
if (!grant.isActive() || (serverGroup != null && !grant.appliesOn(serverGroup))) {
|
if (!grant.isActive() || (serverGroup != null && !grant.appliesOn(serverGroup))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rank rank = Rank.findById(grant.getRank());
|
Rank grantedRank = Rank.findById(grant.getRank());
|
||||||
|
grantedRanks.add(grantedRank);
|
||||||
|
}
|
||||||
|
|
||||||
if (highest == null || rank.getWeight() > highest.getWeight()) {
|
if (grantedRanks.isEmpty()) {
|
||||||
highest = rank;
|
grantedRanks.add(Rank.findById("default"));
|
||||||
|
return grantedRanks;
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator<Rank> iterator = grantedRanks.iterator();
|
||||||
|
|
||||||
|
// This is to remove redundant ranks. Say they have mod, mod-plus, admin, and youtuber,
|
||||||
|
// we should remove mod and mod-plus as it'll be made redundant by the higher ranked admin.
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
Rank rank = iterator.next();
|
||||||
|
|
||||||
|
// Check all other ranks for inherited collision
|
||||||
|
for (Rank otherRank : grantedRanks) {
|
||||||
|
if (otherRank == rank) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rank parent = otherRank;
|
||||||
|
|
||||||
|
// Iterate up the inheritance tree to detect rank redundancies.
|
||||||
|
while (parent.getInheritsFromId() != null) {
|
||||||
|
if (parent == rank) {
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
parent = Rank.findById(otherRank.getInheritsFromId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (highest != null) {
|
grantedRanks.sort((a, b) -> Ints.compare(b.getWeight(), a.getWeight()));
|
||||||
return highest;
|
return grantedRanks;
|
||||||
} else {
|
|
||||||
return Rank.findById("default");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void insert(SingleResultCallback<Void> callback) {
|
public void insert(SingleResultCallback<Void> callback) {
|
||||||
|
@ -6,7 +6,7 @@ import net.frozenorb.apiv3.APIv3;
|
|||||||
import net.frozenorb.apiv3.model.User;
|
import net.frozenorb.apiv3.model.User;
|
||||||
import net.frozenorb.apiv3.util.ErrorUtils;
|
import net.frozenorb.apiv3.util.ErrorUtils;
|
||||||
|
|
||||||
public final class GETUsersIdPermissions implements Handler<RoutingContext> {
|
public final class GETUsersIdCompoundedPermissions implements Handler<RoutingContext> {
|
||||||
|
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
User.findById(ctx.request().getParam("id"), (user, error) -> {
|
User.findById(ctx.request().getParam("id"), (user, error) -> {
|
||||||
@ -15,7 +15,7 @@ public final class GETUsersIdPermissions implements Handler<RoutingContext> {
|
|||||||
} else if (user == null) {
|
} else if (user == null) {
|
||||||
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
ErrorUtils.respondNotFound(ctx, "User", ctx.request().getParam("id"));
|
||||||
} else {
|
} else {
|
||||||
user.getGlobalPermissions((permissions, error2) -> {
|
user.getCompoundedPermissions((permissions, error2) -> {
|
||||||
if (error2 != null) {
|
if (error2 != null) {
|
||||||
ErrorUtils.respondInternalError(ctx, error2);
|
ErrorUtils.respondInternalError(ctx, error2);
|
||||||
} else {
|
} else {
|
Loading…
Reference in New Issue
Block a user