mirror of
https://github.com/CivMC/Civ.git
synced 2026-07-18 00:20:44 +00:00
more cleanup
This commit is contained in:
@@ -10,7 +10,6 @@ sql:
|
||||
max_lifetime: 7200000
|
||||
groups:
|
||||
enable: true
|
||||
interact: false
|
||||
grouplimit: 35
|
||||
creationOnFirstJoin: true
|
||||
rabbitmq:
|
||||
|
||||
@@ -16,6 +16,12 @@ subprojects {
|
||||
options.release = javaVersion
|
||||
}
|
||||
|
||||
tasks.withType<Javadoc> {
|
||||
options {
|
||||
(this as CoreJavadocOptions).addBooleanOption("Xdoclint:none", true)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<ProcessResources> {
|
||||
filteringCharset = "UTF-8"
|
||||
}
|
||||
|
||||
@@ -2,22 +2,57 @@ package net.civmc.namelayer.sync;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public record NameLayerInvalidationMessage(Set<Integer> affectedGroupIds, boolean requiresFullResync) {
|
||||
public record NameLayerInvalidationMessage(
|
||||
Set<Integer> affectedGroupIds,
|
||||
Set<UUID> affectedDefaultGroupPlayers,
|
||||
Set<UUID> affectedAutoAcceptPlayers,
|
||||
boolean requiresFullResync
|
||||
) {
|
||||
|
||||
public NameLayerInvalidationMessage {
|
||||
affectedGroupIds = affectedGroupIds == null ? Set.of() : affectedGroupIds;
|
||||
affectedDefaultGroupPlayers = affectedDefaultGroupPlayers == null ? Set.of() : affectedDefaultGroupPlayers;
|
||||
affectedAutoAcceptPlayers = affectedAutoAcceptPlayers == null ? Set.of() : affectedAutoAcceptPlayers;
|
||||
affectedGroupIds = Set.copyOf(validateGroupIds(affectedGroupIds));
|
||||
if (!requiresFullResync && affectedGroupIds.isEmpty()) {
|
||||
throw new IllegalArgumentException("affectedGroupIds must not be empty unless requiresFullResync is true");
|
||||
affectedDefaultGroupPlayers = Set.copyOf(validateUuids(affectedDefaultGroupPlayers, "affectedDefaultGroupPlayers"));
|
||||
affectedAutoAcceptPlayers = Set.copyOf(validateUuids(affectedAutoAcceptPlayers, "affectedAutoAcceptPlayers"));
|
||||
if (!requiresFullResync
|
||||
&& affectedGroupIds.isEmpty()
|
||||
&& affectedDefaultGroupPlayers.isEmpty()
|
||||
&& affectedAutoAcceptPlayers.isEmpty()) {
|
||||
throw new IllegalArgumentException("targeted invalidations must affect at least one cache entry");
|
||||
}
|
||||
}
|
||||
|
||||
public static NameLayerInvalidationMessage targeted(final Set<Integer> affectedGroupIds) {
|
||||
return new NameLayerInvalidationMessage(affectedGroupIds, false);
|
||||
return new NameLayerInvalidationMessage(affectedGroupIds, Set.of(), Set.of(), false);
|
||||
}
|
||||
|
||||
public static NameLayerInvalidationMessage defaultGroups(final Set<UUID> affectedPlayers) {
|
||||
return new NameLayerInvalidationMessage(Set.of(), affectedPlayers, Set.of(), false);
|
||||
}
|
||||
|
||||
public static NameLayerInvalidationMessage autoAccepts(final Set<UUID> affectedPlayers) {
|
||||
return new NameLayerInvalidationMessage(Set.of(), Set.of(), affectedPlayers, false);
|
||||
}
|
||||
|
||||
public static NameLayerInvalidationMessage targeted(
|
||||
final Set<Integer> affectedGroupIds,
|
||||
final Set<UUID> affectedDefaultGroupPlayers,
|
||||
final Set<UUID> affectedAutoAcceptPlayers
|
||||
) {
|
||||
return new NameLayerInvalidationMessage(
|
||||
affectedGroupIds,
|
||||
affectedDefaultGroupPlayers,
|
||||
affectedAutoAcceptPlayers,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
public static NameLayerInvalidationMessage fullResync() {
|
||||
return new NameLayerInvalidationMessage(Set.of(), true);
|
||||
return new NameLayerInvalidationMessage(Set.of(), Set.of(), Set.of(), true);
|
||||
}
|
||||
|
||||
private static Set<Integer> validateGroupIds(final Set<Integer> groupIds) {
|
||||
@@ -29,4 +64,14 @@ public record NameLayerInvalidationMessage(Set<Integer> affectedGroupIds, boolea
|
||||
}
|
||||
return groupIds;
|
||||
}
|
||||
|
||||
private static Set<UUID> validateUuids(final Set<UUID> uuids, final String fieldName) {
|
||||
Objects.requireNonNull(uuids, fieldName);
|
||||
for (final UUID uuid : uuids) {
|
||||
if (uuid == null) {
|
||||
throw new IllegalArgumentException(fieldName + " must not contain null values");
|
||||
}
|
||||
}
|
||||
return uuids;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
package net.civmc.namelayer.sync;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonParseException;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Objects;
|
||||
|
||||
public final class NameLayerSyncCodec {
|
||||
|
||||
private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().create();
|
||||
|
||||
private NameLayerSyncCodec() {
|
||||
}
|
||||
|
||||
public static byte[] encodeWriteRequest(final NameLayerWriteRequest request) {
|
||||
return encode(request);
|
||||
}
|
||||
|
||||
public static NameLayerWriteRequest decodeWriteRequest(final byte[] body) {
|
||||
return decode(body, NameLayerWriteRequest.class);
|
||||
}
|
||||
|
||||
public static byte[] encodeWriteResponse(final NameLayerWriteResponse response) {
|
||||
return encode(response);
|
||||
}
|
||||
|
||||
public static NameLayerWriteResponse decodeWriteResponse(final byte[] body) {
|
||||
return decode(body, NameLayerWriteResponse.class);
|
||||
}
|
||||
|
||||
public static byte[] encodeInvalidation(final NameLayerInvalidationMessage invalidation) {
|
||||
return encode(invalidation);
|
||||
}
|
||||
|
||||
public static NameLayerInvalidationMessage decodeInvalidation(final byte[] body) {
|
||||
return decode(body, NameLayerInvalidationMessage.class);
|
||||
}
|
||||
|
||||
private static byte[] encode(final Object message) {
|
||||
Objects.requireNonNull(message, "message");
|
||||
return GSON.toJson(message).getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private static <T> T decode(final byte[] body, final Class<T> messageType) {
|
||||
Objects.requireNonNull(body, "body");
|
||||
Objects.requireNonNull(messageType, "messageType");
|
||||
try {
|
||||
return GSON.fromJson(new String(body, StandardCharsets.UTF_8), messageType);
|
||||
} catch (final JsonParseException exception) {
|
||||
throw new IllegalArgumentException("Invalid NameLayer synchronization message", exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ public enum NameLayerWriteFailureCode {
|
||||
DATABASE_UNAVAILABLE,
|
||||
GROUP_NOT_FOUND,
|
||||
INVALID_REQUEST,
|
||||
MAX_GROUPS_REACHED,
|
||||
MEMBER_NOT_FOUND,
|
||||
NAME_CONFLICT,
|
||||
PLAYER_NOT_FOUND,
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
package net.civmc.namelayer.sync;
|
||||
|
||||
public final class NameLayerWriteRequestPolicy {
|
||||
|
||||
public static final long DEFAULT_TIMEOUT_MILLIS = 5_000L;
|
||||
public static final int AUTOMATIC_RETRY_ATTEMPTS = 0;
|
||||
|
||||
private NameLayerWriteRequestPolicy() {
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,14 @@
|
||||
package vg.civcraft.mc.namelayer;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import java.util.Collection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.logging.Level;
|
||||
import net.civmc.namelayer.sync.NameLayerWriteOperation;
|
||||
@@ -34,11 +33,6 @@ public class GroupManager {
|
||||
private static NameLayerReadDao nameLayerReadDao;
|
||||
private PermissionHandler permhandle;
|
||||
|
||||
private static Map<String, Group> groupsByName = new ConcurrentHashMap<>();
|
||||
private static Map<Integer, Group> groupsById = new ConcurrentHashMap<>();
|
||||
|
||||
private static boolean mergingInProgress = false;
|
||||
|
||||
public GroupManager() {
|
||||
nameLayerReadDao = NameLayerPlugin.getNameLayerReadDao();
|
||||
permhandle = new PermissionHandler();
|
||||
@@ -52,10 +46,6 @@ public class GroupManager {
|
||||
NameLayerPlugin.fullResyncGroupCache();
|
||||
}
|
||||
|
||||
public static boolean reloadGroupById(final int groupId) {
|
||||
return reloadGroupsById(List.of(groupId));
|
||||
}
|
||||
|
||||
public static boolean reloadGroupsById(final List<Integer> groupIds) {
|
||||
if (groupIds == null) {
|
||||
NameLayerPlugin.recordTargetedReloadFailure(0);
|
||||
@@ -82,10 +72,20 @@ public class GroupManager {
|
||||
return true;
|
||||
}
|
||||
|
||||
public int countGroups(final UUID ownerUuid) {
|
||||
final NameLayerGroupCache cache = getCache();
|
||||
if (cache == null) {
|
||||
return 0;
|
||||
}
|
||||
return cache.countGroups(ownerUuid);
|
||||
}
|
||||
|
||||
public void createGroupAsync(
|
||||
final UUID actorUuid,
|
||||
final String groupName,
|
||||
final String password,
|
||||
final int maxGroups,
|
||||
final boolean adminOverride,
|
||||
final Consumer<GroupWriteResult> callback
|
||||
) {
|
||||
final GroupCreateEvent event = new GroupCreateEvent(groupName, actorUuid, password);
|
||||
@@ -101,6 +101,8 @@ public class GroupManager {
|
||||
arguments.put("password", event.getPassword());
|
||||
}
|
||||
arguments.put("defaultPermissions", encodeDefaultPermissions(PermissionType.getAllPermissions()));
|
||||
arguments.put("maxGroups", Integer.toString(maxGroups));
|
||||
arguments.put("adminOverride", Boolean.toString(adminOverride));
|
||||
sendGroupWrite(actorUuid, NameLayerWriteOperation.CREATE_GROUP, arguments, callback);
|
||||
}
|
||||
|
||||
@@ -241,7 +243,7 @@ public class GroupManager {
|
||||
* @param checkBeforeCreate Checks if the group already exists (asynchronously) prior to creating it. Runs the CreateEvent
|
||||
* synchronously, then behaves as normal after that (running async create).
|
||||
*/
|
||||
public void createGroupAsync(final Group group, final Consumer<Group> postCreate, boolean checkBeforeCreate) {
|
||||
public void createGroupAsync(final Group group, final Consumer<Group> postCreate, boolean checkBeforeCreate, final int maxGroups, final boolean adminOverride) {
|
||||
if (group == null) {
|
||||
NameLayerPlugin.getInstance().getLogger().log(Level.INFO, "Group create failed, caller passed in null", new Exception());
|
||||
Bukkit.getScheduler().runTask(NameLayerPlugin.getInstance(), () -> postCreate.accept(null));
|
||||
@@ -252,7 +254,7 @@ public class GroupManager {
|
||||
Bukkit.getScheduler().runTask(NameLayerPlugin.getInstance(), () -> postCreate.accept(null));
|
||||
return;
|
||||
}
|
||||
createGroupAsync(group.getOwner(), group.getName(), group.getPassword(), result -> {
|
||||
createGroupAsync(group.getOwner(), group.getName(), group.getPassword(), maxGroups, adminOverride, result -> {
|
||||
Group createdGroup = result.group();
|
||||
if (!result.success() || createdGroup == null) {
|
||||
createdGroup = null;
|
||||
@@ -270,113 +272,30 @@ public class GroupManager {
|
||||
NameLayerPlugin.getInstance().getLogger().log(Level.INFO, "getGroup failed, caller passed in null", new Exception());
|
||||
return null;
|
||||
}
|
||||
|
||||
String lower = name.toLowerCase();
|
||||
if (getCache() != null) {
|
||||
Group group = getCache().getByName(lower);
|
||||
NameLayerGroupCache cache = getCache();
|
||||
if (cache != null) {
|
||||
Group group = cache.getByName(lower);
|
||||
if (group != null) {
|
||||
return group;
|
||||
}
|
||||
} else if (groupsByName.containsKey(lower)) {
|
||||
return groupsByName.get(lower);
|
||||
}
|
||||
|
||||
Group group = nameLayerReadDao.getGroup(name);
|
||||
if (group != null) {
|
||||
if (getCache() != null) {
|
||||
getCache().putGroup(group);
|
||||
} else {
|
||||
groupsByName.put(lower, group);
|
||||
for (int j : group.getGroupIds()) {
|
||||
groupsById.put(j, group);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
NameLayerPlugin.getInstance().getLogger().log(Level.INFO, "getGroup by Name failed, unable to find the group " + name);
|
||||
}
|
||||
return group;
|
||||
NameLayerPlugin.getInstance().getLogger().log(Level.INFO, "getGroup by Name failed, unable to find the group " + name);
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Group getGroup(int groupId) {
|
||||
if (getCache() != null) {
|
||||
Group group = getCache().getById(groupId);
|
||||
NameLayerGroupCache cache = getCache();
|
||||
if (cache != null) {
|
||||
Group group = cache.getById(groupId);
|
||||
if (group != null) {
|
||||
return group;
|
||||
}
|
||||
} else if (groupsById.containsKey(groupId)) {
|
||||
return groupsById.get(groupId);
|
||||
}
|
||||
|
||||
Group group = nameLayerReadDao.getGroup(groupId);
|
||||
if (group != null) {
|
||||
if (getCache() != null) {
|
||||
getCache().putGroup(group);
|
||||
} else {
|
||||
groupsByName.put(group.getName().toLowerCase(), group);
|
||||
for (int j : group.getGroupIds()) {
|
||||
groupsById.put(j, group);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
NameLayerPlugin.getInstance().getLogger().log(Level.INFO, "getGroup by ID failed, unable to find the group " + groupId);
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
public static boolean hasGroup(String groupName) {
|
||||
if (groupName == null) {
|
||||
NameLayerPlugin.getInstance().getLogger().log(Level.INFO, "HasGroup Name failed, name was null ", new Exception());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (getCache() != null) {
|
||||
return getCache().containsName(groupName) || getGroup(groupName.toLowerCase()) != null;
|
||||
} else if (!groupsByName.containsKey(groupName.toLowerCase())) {
|
||||
return (getGroup(groupName.toLowerCase()) != null);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the admin group for groups if the group was found to be null.
|
||||
* Good for when you have to have a group that can't be null.
|
||||
*
|
||||
* @param name - The group name for the group
|
||||
* @return Either the group or the special admin group.
|
||||
*/
|
||||
public static Group getSpecialCircumstanceGroup(String name) {
|
||||
if (name == null) {
|
||||
NameLayerPlugin.getInstance().getLogger().log(Level.INFO, "getSpecialCircumstance failed, caller passed in null", new Exception());
|
||||
return null;
|
||||
}
|
||||
String lower = name.toLowerCase();
|
||||
if (getCache() != null) {
|
||||
Group group = getCache().getByName(lower);
|
||||
if (group != null) {
|
||||
return group;
|
||||
}
|
||||
} else if (groupsByName.containsKey(lower)) {
|
||||
return groupsByName.get(lower);
|
||||
}
|
||||
|
||||
Group group = nameLayerReadDao.getGroup(name);
|
||||
if (group != null) {
|
||||
if (getCache() != null) {
|
||||
getCache().putGroup(group);
|
||||
} else {
|
||||
groupsByName.put(lower, group);
|
||||
for (int j : group.getGroupIds()) {
|
||||
groupsById.put(j, group);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
group = nameLayerReadDao.getGroup(NameLayerPlugin.getSpecialAdminGroup());
|
||||
if (group != null && getCache() != null) {
|
||||
getCache().putGroup(group);
|
||||
}
|
||||
}
|
||||
return group;
|
||||
NameLayerPlugin.getInstance().getLogger().log(Level.INFO, "getGroup by ID failed, unable to find the group " + groupId);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -449,67 +368,6 @@ public class GroupManager {
|
||||
return NameLayerPlugin.getDefaultGroupHandler().getDefaultGroup(uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates a group from cache.
|
||||
*
|
||||
* @param group the group to invalidate cache for
|
||||
*/
|
||||
public static void invalidateCache(String group) {
|
||||
if (group == null) {
|
||||
NameLayerPlugin.getInstance().getLogger().log(Level.INFO, "invalidateCache failed, caller passed in null", new Exception());
|
||||
return;
|
||||
}
|
||||
|
||||
Group g = groupsByName.get(group.toLowerCase());
|
||||
if (getCache() != null) {
|
||||
g = getCache().getByName(group);
|
||||
}
|
||||
if (g != null) {
|
||||
if (getCache() != null) {
|
||||
getCache().removeGroup(g);
|
||||
} else {
|
||||
List<Integer> k = g.getGroupIds();
|
||||
groupsByName.remove(group.toLowerCase());
|
||||
boolean fail = true;
|
||||
for (int j : k) {
|
||||
if (groupsById.remove(j) != null) {
|
||||
fail = false;
|
||||
}
|
||||
}
|
||||
|
||||
// FALLBACK is hardloop
|
||||
if (fail) { // can't find ID or cache is wrong.
|
||||
for (Group x : groupsById.values()) {
|
||||
if (x.getName().equals(g.getName())) {
|
||||
groupsById.remove(x.getGroupId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
NameLayerPlugin.getInstance().getLogger().log(Level.INFO, "Invalidate cache by name failed, unable to find the group " + group);
|
||||
}
|
||||
}
|
||||
|
||||
public static void invalidateCache(int groupId) {
|
||||
if (getCache() != null) {
|
||||
getCache().removeGroupById(groupId);
|
||||
return;
|
||||
}
|
||||
Group group = groupsById.remove(groupId);
|
||||
if (group != null) {
|
||||
groupsByName.remove(group.getName().toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
public int countGroups(UUID uuid) {
|
||||
if (uuid == null) {
|
||||
NameLayerPlugin.getInstance().getLogger().log(Level.INFO, "countGroups failed, caller passed in null", new Exception());
|
||||
return 0;
|
||||
}
|
||||
return nameLayerReadDao.countGroups(uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* In ascending order
|
||||
* Add an enum here if you wish to add more than the four default tiers of
|
||||
@@ -555,23 +413,6 @@ public class GroupManager {
|
||||
//dont yell at player for nllpt
|
||||
}
|
||||
|
||||
public static PlayerType getByID(int id) {
|
||||
switch (id) {
|
||||
case 0:
|
||||
return PlayerType.NOT_BLACKLISTED;
|
||||
case 1:
|
||||
return PlayerType.MEMBERS;
|
||||
case 2:
|
||||
return PlayerType.MODS;
|
||||
case 3:
|
||||
return PlayerType.ADMINS;
|
||||
case 4:
|
||||
return PlayerType.OWNER;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static int getID(PlayerType type) {
|
||||
if (type == null) {
|
||||
return -1;
|
||||
|
||||
@@ -240,23 +240,6 @@ public class NameLayerPlugin extends ACivMod {
|
||||
if (loadGroups) {
|
||||
nameLayerReadDao = new NameLayerReadDao(getLogger(), db);
|
||||
}
|
||||
|
||||
long begin_time = System.currentTimeMillis();
|
||||
|
||||
try {
|
||||
getLogger().log(Level.INFO, "Update prepared, starting database update.");
|
||||
if (!db.updateDatabase()) {
|
||||
getLogger().log(Level.SEVERE, "Update failed, terminating Bukkit.");
|
||||
Bukkit.shutdown();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
getLogger().log(Level.SEVERE, "Update failed, terminating Bukkit. Cause:", e);
|
||||
Bukkit.shutdown();
|
||||
}
|
||||
|
||||
getLogger()
|
||||
.log(Level.INFO, "Database update took {0} seconds", (System.currentTimeMillis() - begin_time) / 1000);
|
||||
|
||||
}
|
||||
|
||||
private DataSource getNameApiDataSource() {
|
||||
|
||||
@@ -47,10 +47,6 @@ public final class NameLayerGroupCache {
|
||||
return groupsById.get(groupId);
|
||||
}
|
||||
|
||||
public synchronized boolean containsName(final String name) {
|
||||
return getByName(name) != null;
|
||||
}
|
||||
|
||||
public synchronized void putGroup(final Group group) {
|
||||
if (group == null || group.getName() == null) {
|
||||
return;
|
||||
@@ -98,16 +94,6 @@ public final class NameLayerGroupCache {
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized Group removeGroupById(final int groupId) {
|
||||
final Group group = groupsById.get(groupId);
|
||||
if (group != null) {
|
||||
removeGroup(group);
|
||||
} else {
|
||||
groupsById.remove(groupId);
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
public synchronized List<String> getGroupNames(final UUID uuid) {
|
||||
final Set<Integer> groupIds = groupIdsByPlayer.get(uuid);
|
||||
if (groupIds == null || groupIds.isEmpty()) {
|
||||
@@ -130,4 +116,21 @@ public final class NameLayerGroupCache {
|
||||
public synchronized void setAppliedVersion(final long appliedVersion) {
|
||||
this.appliedVersion = Math.max(0L, appliedVersion);
|
||||
}
|
||||
|
||||
public synchronized int countGroups() {
|
||||
return this.groupsById.size();
|
||||
}
|
||||
|
||||
public synchronized int countGroups(final UUID ownerUuid) {
|
||||
if (ownerUuid == null) {
|
||||
return 0;
|
||||
}
|
||||
int count = 0;
|
||||
for (final Group group : this.groupsByName.values()) {
|
||||
if (ownerUuid.equals(group.getOwner())) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,6 @@ import vg.civcraft.mc.namelayer.command.commands.SetPassword;
|
||||
import vg.civcraft.mc.namelayer.command.commands.ShowBlacklist;
|
||||
import vg.civcraft.mc.namelayer.command.commands.ToggleAutoAcceptInvites;
|
||||
import vg.civcraft.mc.namelayer.command.commands.TransferGroup;
|
||||
import vg.civcraft.mc.namelayer.command.commands.UpdateName;
|
||||
import vg.civcraft.mc.namelayer.permission.PermissionType;
|
||||
|
||||
public class CommandHandler extends CommandManager {
|
||||
@@ -79,7 +78,6 @@ public class CommandHandler extends CommandManager {
|
||||
registerCommand(new RevokeInvite());
|
||||
registerCommand(new SetDefaultGroup());
|
||||
registerCommand(new GetDefaultGroup());
|
||||
registerCommand(new UpdateName());
|
||||
registerCommand(new AddBlacklist());
|
||||
registerCommand(new RemoveBlacklist());
|
||||
registerCommand(new ShowBlacklist());
|
||||
|
||||
@@ -24,12 +24,8 @@ public class CreateGroup extends BaseCommandMiddle {
|
||||
@Description("Create a group (Public or Private). Password is optional.")
|
||||
public void execute(Player sender, String groupName, @Optional String userPassword) {
|
||||
String name = groupName;
|
||||
int currentGroupCount = gm.countGroups(sender.getUniqueId());
|
||||
|
||||
if (NameLayerPlugin.getInstance().getGroupLimit() < currentGroupCount + 1 && !(sender.isOp() || sender.hasPermission("namelayer.admin"))) {
|
||||
sender.sendMessage(ChatColor.RED + "You cannot create any more groups! Please delete an un-needed group before making more.");
|
||||
return;
|
||||
}
|
||||
final boolean adminOverride = sender.isOp() || sender.hasPermission("namelayer.admin");
|
||||
final int groupLimit = NameLayerPlugin.getInstance().getGroupLimit();
|
||||
|
||||
//enforce regulations on the name
|
||||
if (name.length() > 32) {
|
||||
@@ -72,14 +68,11 @@ public class CreateGroup extends BaseCommandMiddle {
|
||||
return;
|
||||
}
|
||||
if (createdGroup == null) {
|
||||
player.sendMessage(ChatColor.RED + "That group is already taken or creation failed.");
|
||||
player.sendMessage(ChatColor.RED + "That group is already taken, you have reached the group limit, or creation failed.");
|
||||
} else {
|
||||
player.sendMessage(ChatColor.GREEN + "The group " + createdGroup.getName() + " was successfully created.");
|
||||
}
|
||||
}, false);
|
||||
if (NameLayerPlugin.getInstance().getGroupLimit() == (currentGroupCount + 1)) {
|
||||
sender.sendMessage(ChatColor.YELLOW + "You have reached the group limit with " + NameLayerPlugin.getInstance().getGroupLimit() + " groups! Please delete un-needed groups if you wish to create more.");
|
||||
}
|
||||
}, false, groupLimit, adminOverride);
|
||||
sender.sendMessage(ChatColor.GREEN + "Group creation request is in process.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,14 +15,10 @@ public class GlobalStats extends BaseCommandMiddle {
|
||||
@CommandPermission("namelayer.admin")
|
||||
@Description("Get the amount of global groups.")
|
||||
public void execute(final CommandSender sender) {
|
||||
Bukkit.getScheduler().runTaskAsynchronously(NameLayerPlugin.getInstance(), new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
int count = NameLayerPlugin.getNameLayerReadDao().countGroups();
|
||||
sender.sendMessage(ChatColor.GREEN + "The amount of groups are: " + count);
|
||||
}
|
||||
Bukkit.getScheduler().runTaskAsynchronously(NameLayerPlugin.getInstance(), () -> {
|
||||
int count = NameLayerPlugin.getGroupCache().countGroups();
|
||||
|
||||
sender.sendMessage(ChatColor.GREEN + "The amount of groups are: " + count);
|
||||
});
|
||||
sender.sendMessage(ChatColor.GREEN + "Stats are being retrieved, please wait.");
|
||||
}
|
||||
|
||||
@@ -18,11 +18,10 @@ public class ToggleAutoAcceptInvites extends BaseCommandMiddle {
|
||||
@CommandAlias("nltaai|autoaccept")
|
||||
@Description("Toggle the acceptance of invites.")
|
||||
public void execute(CommandSender sender) {
|
||||
if (!(sender instanceof Player)) {
|
||||
if (!(sender instanceof Player p)) {
|
||||
sender.sendMessage("how would this even work");
|
||||
return;
|
||||
}
|
||||
Player p = (Player) sender;
|
||||
UUID uuid = NameLayerAPI.getUUID(p.getName());
|
||||
final boolean enable = !handler.getAutoAccept(uuid);
|
||||
handler.setAutoAcceptAsync(uuid, enable, result -> {
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
package vg.civcraft.mc.namelayer.command.commands;
|
||||
|
||||
import co.aikar.commands.annotation.CommandAlias;
|
||||
import co.aikar.commands.annotation.Description;
|
||||
import co.aikar.commands.annotation.Syntax;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.entity.Player;
|
||||
import vg.civcraft.mc.namelayer.NameLayerAPI;
|
||||
import vg.civcraft.mc.namelayer.NameLayerPlugin;
|
||||
import vg.civcraft.mc.namelayer.command.BaseCommandMiddle;
|
||||
import vg.civcraft.mc.namelayer.misc.NameFetcher;
|
||||
|
||||
public class UpdateName extends BaseCommandMiddle {
|
||||
|
||||
private Map<UUID, String> newNames = Collections.synchronizedSortedMap(new TreeMap<UUID, String>());
|
||||
|
||||
@CommandAlias("nlun|updatename|")
|
||||
@Syntax("[confirm]")
|
||||
@Description("Updates your name on this server to the one your minecraft account currently has")
|
||||
public void execute(Player sender, String newNameOrConfirm) {
|
||||
final Player p = (Player) sender;
|
||||
final UUID uuid = p.getUniqueId();
|
||||
final String oldName = NameLayerAPI.getCurrentName(uuid);
|
||||
|
||||
if (NameLayerPlugin.getNameLayerReadDao().hasChangedNameBefore(uuid)) {
|
||||
p.sendMessage(ChatColor.RED + "You already changed your name");
|
||||
return;
|
||||
}
|
||||
|
||||
if (newNameOrConfirm.isEmpty()) {
|
||||
Bukkit.getScheduler().runTaskAsynchronously(
|
||||
NameLayerPlugin.getInstance(), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
NameFetcher fetcher = new NameFetcher(Collections.singletonList(uuid));
|
||||
Map<UUID, String> fetchedNames = null;
|
||||
try {
|
||||
fetchedNames = fetcher.call();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (fetchedNames == null) {
|
||||
p.sendMessage(ChatColor.RED
|
||||
+ "An error occured. Try again later");
|
||||
return;
|
||||
}
|
||||
String newName = fetchedNames.get(uuid);
|
||||
if (newName == null) {
|
||||
p.sendMessage(ChatColor.RED
|
||||
+ "An error occured. Try again later");
|
||||
return;
|
||||
}
|
||||
UUID existingNameUUID = NameLayerAPI.getUUID(newName);
|
||||
if (existingNameUUID != null) {
|
||||
if (!uuid.equals(existingNameUUID)) {
|
||||
// different person has the name
|
||||
p.sendMessage(ChatColor.RED
|
||||
+ "Someone already has the new name of your minecraft account on this server. Because of that you may not update your name");
|
||||
return;
|
||||
}
|
||||
if (oldName.equals(newName)) {
|
||||
// name hasnt changed
|
||||
p.sendMessage(ChatColor.RED
|
||||
+ "The name of your minecraft account is the same one as on this server");
|
||||
return;
|
||||
}
|
||||
// Player wants to change name to one which is
|
||||
// the same one as his current name, but with
|
||||
// different capitalization. We'll allow it
|
||||
}
|
||||
|
||||
p.sendMessage(ChatColor.GREEN
|
||||
+ "The current name of your minecraft account is \""
|
||||
+ newName
|
||||
+ "\". Run \"/nlun CONFIRM\" to update your name on the server to this name. Be careful though as this change can not be reverted!");
|
||||
newNames.put(uuid, newName);
|
||||
}
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
String newName = newNames.get(uuid);
|
||||
if (newName == null) {
|
||||
sender.sendMessage(ChatColor.RED
|
||||
+ "Run \"/nlun\" first to initiate the name changes process");
|
||||
return;
|
||||
}
|
||||
if (!newNameOrConfirm.equals("CONFIRM")) {
|
||||
sender.sendMessage(ChatColor.RED
|
||||
+ "Run \"/nlun CONFIRM\" to confirm your name change to \""
|
||||
+ newName + "\"");
|
||||
return;
|
||||
}
|
||||
NameLayerPlugin.getNameLayerReadDao().logNameChange(uuid, oldName,
|
||||
newName);
|
||||
// uncomment following to directly change name
|
||||
// NameAPI.getAssociationList().changePlayer(newName, uuid);
|
||||
// NameAPI.resetCache(uuid);
|
||||
sender.sendMessage(ChatColor.GREEN
|
||||
+ "Your name was changed to \""
|
||||
+ newName
|
||||
+ "\". This change will be applied together with all other name changes at a previously announced date.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,27 +37,15 @@ public final class NameLayerReadDao {
|
||||
private static final String GET_MEMBERS = "select fm.member_name from faction_member fm "
|
||||
+ "inner join faction_id id on id.group_name = ? "
|
||||
+ "where fm.group_id = id.group_id and fm.role = ?";
|
||||
private static final String COUNT_GROUPS = "select count(DISTINCT group_name) as count from faction";
|
||||
private static final String COUNT_GROUPS_FROM_UUID = "select count(DISTINCT group_name) as count from faction where founder = ?";
|
||||
private static final String LOAD_ALL_AUTO_ACCEPT = "select uuid from toggleAutoAccept";
|
||||
private static final String GET_AUTO_ACCEPT = "select uuid from toggleAutoAccept where uuid = ?";
|
||||
private static final String GET_DEFAULT_GROUP = "select defaultgroup from default_group where uuid = ?";
|
||||
private static final String GET_ALL_DEFAULT_GROUPS = "select uuid,defaultgroup from default_group";
|
||||
private static final String LOAD_GROUPS_INVITATIONS = "select uuid, groupName, role from group_invitation";
|
||||
private static final String LOAD_GROUP_INVITATION = "select role from group_invitation where uuid = ? and groupName = ?";
|
||||
private static final String LOAD_GROUP_INVITATIONS_FOR_GROUP = "select uuid,role from group_invitation where groupName=?";
|
||||
private static final String GET_GROUP_NAME_FROM_ROLE = "SELECT DISTINCT faction_id.group_name FROM faction_member "
|
||||
+ "inner join faction_id on faction_member.group_id = faction_id.group_id "
|
||||
+ "WHERE member_name = ? "
|
||||
+ "AND role = ?";
|
||||
private static final String GET_PLAYER_TYPE = "SELECT role FROM faction_member WHERE group_id = ? AND member_name = ?";
|
||||
private static final String LOG_NAME_CHANGE = "insert into nameLayerNameChanges (uuid,oldName,newName) values(?,?,?)";
|
||||
private static final String CHECK_FOR_NAME_CHANGE = "select * from nameLayerNameChanges where uuid=?";
|
||||
private static final String GET_PERMISSION = "select pg.role,pg.permission_name from permission_by_group_name pg inner join faction_id fi on fi.group_name=? "
|
||||
+ "where pg.group_id = fi.group_id";
|
||||
private static final String GET_BLACKLIST_MEMBERS = "select b.member_name from blacklist b inner join faction_id fi on fi.group_name=? where b.group_id=fi.group_id";
|
||||
private static final String GET_GROUP_IDS = "SELECT f.group_id, count(DISTINCT fm.member_name) AS sz FROM faction_id f "
|
||||
+ "LEFT JOIN faction_member fm ON f.group_id = fm.group_id WHERE f.group_name = ? GROUP BY f.group_id ORDER BY sz DESC";
|
||||
private static final String LOAD_ALL_GROUP_IDS = "SELECT f.group_name, f.group_id, count(DISTINCT fm.member_name) AS sz "
|
||||
+ "FROM faction_id f LEFT JOIN faction_member fm ON f.group_id = fm.group_id "
|
||||
+ "GROUP BY f.group_name, f.group_id ORDER BY f.group_name, sz DESC";
|
||||
@@ -403,23 +391,6 @@ public final class NameLayerReadDao {
|
||||
return groups;
|
||||
}
|
||||
|
||||
public List<String> getGroupNames(final UUID uuid, final String role) {
|
||||
final List<String> groups = new ArrayList<>();
|
||||
try (Connection connection = db.getConnection();
|
||||
PreparedStatement getGroupNameFromRole = connection.prepareStatement(GET_GROUP_NAME_FROM_ROLE)) {
|
||||
getGroupNameFromRole.setString(1, uuid.toString());
|
||||
getGroupNameFromRole.setString(2, role);
|
||||
try (ResultSet set = getGroupNameFromRole.executeQuery()) {
|
||||
while (set.next()) {
|
||||
groups.add(set.getString(1));
|
||||
}
|
||||
}
|
||||
} catch (final SQLException exception) {
|
||||
logger.log(Level.WARNING, "Problem getting player " + uuid + " groups by role " + role, exception);
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
|
||||
public PlayerType getPlayerType(final int groupId, final UUID uuid) {
|
||||
try (Connection connection = db.getConnection();
|
||||
PreparedStatement getPlayerType = connection.prepareStatement(GET_PLAYER_TYPE)) {
|
||||
@@ -478,30 +449,6 @@ public final class NameLayerReadDao {
|
||||
return perms;
|
||||
}
|
||||
|
||||
public int countGroups() {
|
||||
try (Connection connection = db.getConnection();
|
||||
Statement countGroups = connection.createStatement();
|
||||
ResultSet set = countGroups.executeQuery(COUNT_GROUPS)) {
|
||||
return set.next() ? set.getInt("count") : 0;
|
||||
} catch (final SQLException exception) {
|
||||
logger.log(Level.WARNING, "Problem counting groups", exception);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int countGroups(final UUID uuid) {
|
||||
try (Connection connection = db.getConnection();
|
||||
PreparedStatement countGroupsFromUUID = connection.prepareStatement(COUNT_GROUPS_FROM_UUID)) {
|
||||
countGroupsFromUUID.setString(1, uuid.toString());
|
||||
try (ResultSet set = countGroupsFromUUID.executeQuery()) {
|
||||
return set.next() ? set.getInt("count") : 0;
|
||||
}
|
||||
} catch (final SQLException exception) {
|
||||
logger.log(Level.WARNING, "Problem counting groups for " + uuid, exception);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public Set<UUID> loadAllAutoAccept() {
|
||||
final Set<UUID> accepts = new HashSet<>();
|
||||
try (Connection connection = db.getConnection();
|
||||
@@ -516,8 +463,7 @@ public final class NameLayerReadDao {
|
||||
return accepts;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public boolean shouldAutoAcceptGroups(final UUID uuid) {
|
||||
public boolean isAutoAcceptEnabled(final UUID uuid) {
|
||||
try (Connection connection = db.getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement(GET_AUTO_ACCEPT)) {
|
||||
statement.setString(1, uuid.toString());
|
||||
@@ -557,26 +503,6 @@ public final class NameLayerReadDao {
|
||||
return groups;
|
||||
}
|
||||
|
||||
public void loadGroupInvitation(final UUID playerUUID, final Group group) {
|
||||
if (group == null) {
|
||||
return;
|
||||
}
|
||||
try (Connection connection = db.getConnection();
|
||||
PreparedStatement loadGroupInvitation = connection.prepareStatement(LOAD_GROUP_INVITATION)) {
|
||||
loadGroupInvitation.setString(1, playerUUID.toString());
|
||||
loadGroupInvitation.setString(2, group.getName());
|
||||
try (ResultSet set = loadGroupInvitation.executeQuery()) {
|
||||
while (set.next()) {
|
||||
final String role = set.getString("role");
|
||||
final PlayerType type = role == null ? null : PlayerType.getPlayerType(role);
|
||||
GroupManager.reloadGroupById(group.getGroupId());
|
||||
}
|
||||
}
|
||||
} catch (final SQLException exception) {
|
||||
logger.log(Level.WARNING, "Problem loading group " + group.getName() + " invites for " + playerUUID, exception);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<UUID, PlayerType> getInvitesForGroup(final String groupName) {
|
||||
final Map<UUID, PlayerType> invitations = new TreeMap<>();
|
||||
if (groupName == null) {
|
||||
@@ -608,9 +534,7 @@ public final class NameLayerReadDao {
|
||||
while (set.next()) {
|
||||
final String uuid = set.getString("uuid");
|
||||
final String group = set.getString("groupName");
|
||||
final String role = set.getString("role");
|
||||
final Group cachedGroup = group == null ? null : GroupManager.getGroup(group);
|
||||
final PlayerType type = role == null ? null : PlayerType.getPlayerType(role);
|
||||
if (uuid != null && cachedGroup != null) {
|
||||
final UUID playerUUID = UUID.fromString(uuid);
|
||||
PlayerListener.addNotification(playerUUID, cachedGroup);
|
||||
@@ -621,67 +545,6 @@ public final class NameLayerReadDao {
|
||||
}
|
||||
}
|
||||
|
||||
public void logNameChange(final UUID uuid, final String oldName, final String newName) {
|
||||
try (Connection connection = db.getConnection();
|
||||
PreparedStatement logNameChange = connection.prepareStatement(LOG_NAME_CHANGE)) {
|
||||
logNameChange.setString(1, uuid.toString());
|
||||
logNameChange.setString(2, oldName);
|
||||
logNameChange.setString(3, newName);
|
||||
logNameChange.executeUpdate();
|
||||
} catch (final SQLException exception) {
|
||||
logger.log(Level.WARNING, "Failed to log a name change for " + uuid + " from " + oldName + " -> " + newName, exception);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasChangedNameBefore(final UUID uuid) {
|
||||
try (Connection connection = db.getConnection();
|
||||
PreparedStatement checkForNameChange = connection.prepareStatement(CHECK_FOR_NAME_CHANGE)) {
|
||||
checkForNameChange.setString(1, uuid.toString());
|
||||
try (ResultSet set = checkForNameChange.executeQuery()) {
|
||||
return set.next();
|
||||
}
|
||||
} catch (final SQLException exception) {
|
||||
logger.log(Level.WARNING, "Failed to check if " + uuid + " has previously changed names", exception);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Set<UUID> getBlackListMembers(final String groupName) {
|
||||
final Set<UUID> uuids = new HashSet<>();
|
||||
try (Connection connection = db.getConnection();
|
||||
PreparedStatement getBlackListMembers = connection.prepareStatement(GET_BLACKLIST_MEMBERS)) {
|
||||
getBlackListMembers.setString(1, groupName);
|
||||
try (ResultSet set = getBlackListMembers.executeQuery()) {
|
||||
while (set.next()) {
|
||||
uuids.add(UUID.fromString(set.getString(1)));
|
||||
}
|
||||
}
|
||||
} catch (final SQLException exception) {
|
||||
logger.log(Level.WARNING, "Unable to retrieve black list members for group " + groupName, exception);
|
||||
}
|
||||
return uuids;
|
||||
}
|
||||
|
||||
public List<Integer> getAllIDs(final String groupName) {
|
||||
if (groupName == null) {
|
||||
return null;
|
||||
}
|
||||
try (Connection connection = db.getConnection();
|
||||
PreparedStatement getGroupIDs = connection.prepareStatement(GET_GROUP_IDS)) {
|
||||
getGroupIDs.setString(1, groupName);
|
||||
try (ResultSet set = getGroupIDs.executeQuery()) {
|
||||
final List<Integer> ids = new ArrayList<>();
|
||||
while (set.next()) {
|
||||
ids.add(set.getInt(1));
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
} catch (final SQLException exception) {
|
||||
logger.log(Level.WARNING, "Unable to fully load group ID set", exception);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public GroupLoadSnapshot loadAllGroupsSnapshot() {
|
||||
final GroupSnapshotData data = newSnapshotData();
|
||||
final long cacheVersion;
|
||||
|
||||
@@ -24,9 +24,7 @@ public class AutoAcceptHandler {
|
||||
if (accept && !autoAccepts.contains(player)) {
|
||||
autoAccepts.add(player);
|
||||
} else {
|
||||
if (autoAccepts.contains(player)) {
|
||||
autoAccepts.remove(player);
|
||||
}
|
||||
autoAccepts.remove(player);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -49,10 +47,6 @@ public class AutoAcceptHandler {
|
||||
});
|
||||
}
|
||||
|
||||
public void toggleAutoAcceptAsync(final UUID player, final Consumer<AutoAcceptWriteResult> callback) {
|
||||
setAutoAcceptAsync(player, !getAutoAccept(player), callback);
|
||||
}
|
||||
|
||||
public boolean getAutoAccept(UUID uuid) {
|
||||
return autoAccepts.contains(uuid);
|
||||
}
|
||||
@@ -61,6 +55,10 @@ public class AutoAcceptHandler {
|
||||
this.autoAccepts = autoAccepts;
|
||||
}
|
||||
|
||||
public void reload(final UUID player, final boolean accept) {
|
||||
cacheAutoAccept(player, accept);
|
||||
}
|
||||
|
||||
private void handleWriteResponse(
|
||||
final UUID player,
|
||||
final boolean accept,
|
||||
|
||||
@@ -15,7 +15,7 @@ import vg.civcraft.mc.namelayer.rabbitmq.NameLayerWriteClient;
|
||||
|
||||
public class DefaultGroupHandler {
|
||||
|
||||
private NameLayerReadDao dao;
|
||||
private final NameLayerReadDao dao;
|
||||
|
||||
private Map<UUID, String> defaultGroups;
|
||||
|
||||
@@ -36,6 +36,15 @@ public class DefaultGroupHandler {
|
||||
defaultGroups = dao.getAllDefaultGroups();
|
||||
}
|
||||
|
||||
public void reload(final UUID uuid) {
|
||||
final String groupName = dao.getDefaultGroup(uuid);
|
||||
if (groupName == null) {
|
||||
defaultGroups.remove(uuid);
|
||||
return;
|
||||
}
|
||||
defaultGroups.put(uuid, groupName);
|
||||
}
|
||||
|
||||
public void cacheDefaultGroup(UUID uuid, Group g) {
|
||||
defaultGroups.put(uuid, g.getName());
|
||||
}
|
||||
@@ -101,9 +110,4 @@ public class DefaultGroupHandler {
|
||||
}
|
||||
}
|
||||
|
||||
public String recacheDefaultGroup(UUID uuid) {
|
||||
String gName = dao.getDefaultGroup(uuid);
|
||||
defaultGroups.put(uuid, gName);
|
||||
return gName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,15 +276,6 @@ public class GUIGroupOverview {
|
||||
showScreen();
|
||||
return;
|
||||
}
|
||||
if (NameLayerPlugin.getInstance().getGroupLimit() < gm
|
||||
.countGroups(p.getUniqueId()) + 1
|
||||
&& !(p.isOp() || p
|
||||
.hasPermission("namelayer.admin"))) {
|
||||
p.sendMessage(ChatColor.RED
|
||||
+ "You cannot create any more groups! Please delete an un-needed group before making more.");
|
||||
showScreen();
|
||||
return;
|
||||
}
|
||||
// enforce regulations on the name
|
||||
if (groupName.length() > 32) {
|
||||
p.sendMessage(ChatColor.RED
|
||||
@@ -319,6 +310,8 @@ public class GUIGroupOverview {
|
||||
}
|
||||
|
||||
final UUID uuid = p.getUniqueId();
|
||||
final boolean adminOverride = p.isOp() || p.hasPermission("namelayer.admin");
|
||||
final int groupLimit = NameLayerPlugin.getInstance().getGroupLimit();
|
||||
Group g = new Group(groupName, uuid, false, null, -1, System.currentTimeMillis(), "GRAY");
|
||||
gm.createGroupAsync(g, createdGroup -> {
|
||||
if (createdGroup != null) {
|
||||
@@ -332,17 +325,12 @@ public class GUIGroupOverview {
|
||||
}
|
||||
|
||||
if (createdGroup == null) { // failure
|
||||
player.sendMessage(ChatColor.RED + "That group is already taken or creation failed.");
|
||||
player.sendMessage(ChatColor.RED + "That group is already taken, you have reached the group limit, or creation failed.");
|
||||
} else {
|
||||
player.sendMessage(ChatColor.GREEN + "The group " + createdGroup.getName() + " was successfully created.");
|
||||
if (NameLayerPlugin.getInstance().getGroupLimit() == gm.countGroups(player.getUniqueId())) {
|
||||
player.sendMessage(ChatColor.YELLOW + "You have reached the group limit with "
|
||||
+ NameLayerPlugin.getInstance().getGroupLimit()
|
||||
+ " groups! Please delete un-needed groups if you wish to create more.");
|
||||
}
|
||||
}
|
||||
showScreen();
|
||||
}, false);
|
||||
}, false, groupLimit, adminOverride);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,24 +1,32 @@
|
||||
package vg.civcraft.mc.namelayer.rabbitmq;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.rabbitmq.client.AMQP;
|
||||
import com.rabbitmq.client.Channel;
|
||||
import com.rabbitmq.client.Connection;
|
||||
import com.rabbitmq.client.ConnectionFactory;
|
||||
import com.rabbitmq.client.DeliverCallback;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import net.civmc.namelayer.sync.NameLayerInvalidationMessage;
|
||||
import net.civmc.namelayer.sync.NameLayerRabbitMqTopology;
|
||||
import net.civmc.namelayer.sync.NameLayerSyncCodec;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import vg.civcraft.mc.namelayer.GroupManager;
|
||||
import vg.civcraft.mc.namelayer.NameLayerPlugin;
|
||||
import vg.civcraft.mc.namelayer.group.AutoAcceptHandler;
|
||||
import vg.civcraft.mc.namelayer.group.DefaultGroupHandler;
|
||||
|
||||
public final class NameLayerInvalidationConsumer implements AutoCloseable {
|
||||
|
||||
private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().create();
|
||||
|
||||
private final ConnectionFactory connectionFactory;
|
||||
private final String serverId;
|
||||
private final Logger logger;
|
||||
@@ -101,13 +109,16 @@ public final class NameLayerInvalidationConsumer implements AutoCloseable {
|
||||
|
||||
private void handleDelivery(final byte[] body, final long deliveryTag) throws IOException {
|
||||
try {
|
||||
final NameLayerInvalidationMessage invalidation = NameLayerSyncCodec.decodeInvalidation(body);
|
||||
final NameLayerInvalidationMessage invalidation = GSON.fromJson(
|
||||
new String(body, StandardCharsets.UTF_8),
|
||||
NameLayerInvalidationMessage.class
|
||||
);
|
||||
if (applyInvalidation(invalidation)) {
|
||||
channel.basicAck(deliveryTag, false);
|
||||
} else {
|
||||
channel.basicNack(deliveryTag, false, true);
|
||||
}
|
||||
} catch (final IllegalArgumentException exception) {
|
||||
} catch (final JsonParseException exception) {
|
||||
logger.log(Level.WARNING, "Rejecting malformed NameLayer invalidation", exception);
|
||||
channel.basicReject(deliveryTag, false);
|
||||
} catch (final RuntimeException exception) {
|
||||
@@ -122,8 +133,30 @@ public final class NameLayerInvalidationConsumer implements AutoCloseable {
|
||||
GroupManager.fullResyncCache();
|
||||
return true;
|
||||
}
|
||||
logger.log(Level.INFO, "Applying NameLayer targeted invalidation for " + invalidation.affectedGroupIds().size() + " groups");
|
||||
return GroupManager.reloadGroupsById(new ArrayList<>(invalidation.affectedGroupIds()));
|
||||
logger.log(Level.INFO, "Applying NameLayer targeted invalidation for "
|
||||
+ invalidation.affectedGroupIds().size() + " groups, "
|
||||
+ invalidation.affectedDefaultGroupPlayers().size() + " default groups, "
|
||||
+ invalidation.affectedAutoAcceptPlayers().size() + " auto-accept entries");
|
||||
if (!invalidation.affectedGroupIds().isEmpty()
|
||||
&& !GroupManager.reloadGroupsById(new ArrayList<>(invalidation.affectedGroupIds()))) {
|
||||
return false;
|
||||
}
|
||||
final DefaultGroupHandler defaultGroupHandler = NameLayerPlugin.getDefaultGroupHandler();
|
||||
if (defaultGroupHandler != null) {
|
||||
for (final UUID playerUuid : invalidation.affectedDefaultGroupPlayers()) {
|
||||
defaultGroupHandler.reload(playerUuid);
|
||||
}
|
||||
}
|
||||
final AutoAcceptHandler autoAcceptHandler = NameLayerPlugin.getAutoAcceptHandler();
|
||||
if (autoAcceptHandler != null) {
|
||||
for (final UUID playerUuid : invalidation.affectedAutoAcceptPlayers()) {
|
||||
autoAcceptHandler.reload(
|
||||
playerUuid,
|
||||
NameLayerPlugin.getNameLayerReadDao().isAutoAcceptEnabled(playerUuid)
|
||||
);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
package vg.civcraft.mc.namelayer.rabbitmq;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.rabbitmq.client.AMQP;
|
||||
import com.rabbitmq.client.Channel;
|
||||
import com.rabbitmq.client.Connection;
|
||||
import com.rabbitmq.client.ConnectionFactory;
|
||||
import com.rabbitmq.client.DeliverCallback;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
@@ -15,13 +19,13 @@ import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import net.civmc.namelayer.sync.NameLayerRabbitMqTopology;
|
||||
import net.civmc.namelayer.sync.NameLayerSyncCodec;
|
||||
import net.civmc.namelayer.sync.NameLayerWriteRequest;
|
||||
import net.civmc.namelayer.sync.NameLayerWriteResponse;
|
||||
|
||||
public final class NameLayerWriteClient implements AutoCloseable {
|
||||
|
||||
private static final long RESPONSE_TIMEOUT_SECONDS = 10L;
|
||||
private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().create();
|
||||
|
||||
private final ConnectionFactory connectionFactory;
|
||||
private final String responseQueue;
|
||||
@@ -45,7 +49,7 @@ public final class NameLayerWriteClient implements AutoCloseable {
|
||||
connection = connectionFactory.newConnection("namelayer-paper-writes");
|
||||
channel = connection.createChannel();
|
||||
channel.queueDeclare(responseQueue, false, true, true, null);
|
||||
final DeliverCallback deliverCallback = (consumerTag, delivery) -> handleResponse(delivery.getBody(), delivery.getProperties());
|
||||
final DeliverCallback deliverCallback = (consumerTag, delivery) -> handleResponse(delivery.getBody());
|
||||
channel.basicConsume(responseQueue, true, deliverCallback, consumerTag -> {
|
||||
});
|
||||
return true;
|
||||
@@ -73,7 +77,12 @@ public final class NameLayerWriteClient implements AutoCloseable {
|
||||
.deliveryMode(2)
|
||||
.build();
|
||||
synchronized (this) {
|
||||
channel.basicPublish("", NameLayerRabbitMqTopology.WRITE_REQUEST_QUEUE, properties, NameLayerSyncCodec.encodeWriteRequest(request));
|
||||
channel.basicPublish(
|
||||
"",
|
||||
NameLayerRabbitMqTopology.WRITE_REQUEST_QUEUE,
|
||||
properties,
|
||||
GSON.toJson(request).getBytes(StandardCharsets.UTF_8)
|
||||
);
|
||||
}
|
||||
} catch (final IOException exception) {
|
||||
pendingResponses.remove(request.requestId());
|
||||
@@ -82,11 +91,11 @@ public final class NameLayerWriteClient implements AutoCloseable {
|
||||
return responseFuture;
|
||||
}
|
||||
|
||||
private void handleResponse(final byte[] body, final AMQP.BasicProperties properties) {
|
||||
private void handleResponse(final byte[] body) {
|
||||
final NameLayerWriteResponse response;
|
||||
try {
|
||||
response = NameLayerSyncCodec.decodeWriteResponse(body);
|
||||
} catch (final IllegalArgumentException exception) {
|
||||
response = GSON.fromJson(new String(body, StandardCharsets.UTF_8), NameLayerWriteResponse.class);
|
||||
} catch (final JsonParseException exception) {
|
||||
logger.log(Level.WARNING, "Dropping malformed NameLayer write response", exception);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -43,6 +43,11 @@ public final class NameLayerVelocityPlugin {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Class.forName("org.mariadb.jdbc.Driver");
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
dataSource = config.database().createDataSource();
|
||||
if (!NameLayerDatabaseMigrator.migrate(dataSource, logger)) {
|
||||
return;
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
package net.civmc.namelayer.velocity.rabbitmq;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.rabbitmq.client.AMQP;
|
||||
import com.rabbitmq.client.Channel;
|
||||
import com.rabbitmq.client.Connection;
|
||||
import com.rabbitmq.client.ConnectionFactory;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import net.civmc.namelayer.sync.NameLayerInvalidationMessage;
|
||||
import net.civmc.namelayer.sync.NameLayerRabbitMqTopology;
|
||||
import net.civmc.namelayer.sync.NameLayerSyncCodec;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
public final class NameLayerInvalidationPublisher implements AutoCloseable {
|
||||
|
||||
private static final long PUBLISH_CONFIRM_TIMEOUT_MILLIS = 5_000L;
|
||||
private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().create();
|
||||
|
||||
private final ConnectionFactory connectionFactory;
|
||||
private final Logger logger;
|
||||
@@ -44,6 +48,7 @@ public final class NameLayerInvalidationPublisher implements AutoCloseable {
|
||||
}
|
||||
|
||||
public boolean publish(final NameLayerInvalidationMessage invalidation) {
|
||||
Objects.requireNonNull(invalidation, "invalidation");
|
||||
if (channel == null || !channel.isOpen()) {
|
||||
logger.error("NameLayer invalidation publisher is not connected");
|
||||
return false;
|
||||
@@ -57,7 +62,7 @@ public final class NameLayerInvalidationPublisher implements AutoCloseable {
|
||||
NameLayerRabbitMqTopology.INVALIDATION_EXCHANGE,
|
||||
"",
|
||||
properties,
|
||||
NameLayerSyncCodec.encodeInvalidation(invalidation)
|
||||
GSON.toJson(invalidation).getBytes(StandardCharsets.UTF_8)
|
||||
);
|
||||
return channel.waitForConfirms(PUBLISH_CONFIRM_TIMEOUT_MILLIS);
|
||||
} catch (final IOException | InterruptedException | TimeoutException exception) {
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
package net.civmc.namelayer.velocity.rabbitmq;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.rabbitmq.client.AMQP;
|
||||
import com.rabbitmq.client.Channel;
|
||||
import com.rabbitmq.client.Connection;
|
||||
import com.rabbitmq.client.ConnectionFactory;
|
||||
import com.rabbitmq.client.DeliverCallback;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import net.civmc.namelayer.sync.NameLayerRabbitMqTopology;
|
||||
import net.civmc.namelayer.sync.NameLayerSyncCodec;
|
||||
import net.civmc.namelayer.sync.NameLayerWriteFailureCode;
|
||||
import net.civmc.namelayer.sync.NameLayerWriteRequest;
|
||||
import net.civmc.namelayer.sync.NameLayerWriteResponse;
|
||||
@@ -18,6 +21,8 @@ import org.slf4j.Logger;
|
||||
|
||||
public final class NameLayerWriteRequestConsumer implements AutoCloseable {
|
||||
|
||||
private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().create();
|
||||
|
||||
private final ConnectionFactory connectionFactory;
|
||||
private final NameLayerWriteCoordinator coordinator;
|
||||
private final Logger logger;
|
||||
@@ -61,9 +66,9 @@ public final class NameLayerWriteRequestConsumer implements AutoCloseable {
|
||||
NameLayerWriteRequest request = null;
|
||||
NameLayerWriteResponse response;
|
||||
try {
|
||||
request = NameLayerSyncCodec.decodeWriteRequest(body);
|
||||
request = GSON.fromJson(new String(body, StandardCharsets.UTF_8), NameLayerWriteRequest.class);
|
||||
response = coordinator.handle(request);
|
||||
} catch (final IllegalArgumentException exception) {
|
||||
} catch (final JsonParseException exception) {
|
||||
logger.warn("Rejecting malformed NameLayer write request", exception);
|
||||
response = malformedRequestResponse(properties);
|
||||
} catch (final RuntimeException exception) {
|
||||
@@ -113,7 +118,7 @@ public final class NameLayerWriteRequestConsumer implements AutoCloseable {
|
||||
.correlationId(response.requestId().toString())
|
||||
.deliveryMode(1)
|
||||
.build();
|
||||
channel.basicPublish("", replyQueue, responseProperties, NameLayerSyncCodec.encodeWriteResponse(response));
|
||||
channel.basicPublish("", replyQueue, responseProperties, GSON.toJson(response).getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
private String responseQueue(final AMQP.BasicProperties properties, final NameLayerWriteRequest request) {
|
||||
|
||||
@@ -32,6 +32,7 @@ public final class NameLayerWriteCoordinator {
|
||||
private static final String SET_GROUP_OWNER = "UPDATE faction f JOIN faction_id fi ON fi.group_name = f.group_name SET f.founder = ? WHERE fi.group_id = ?";
|
||||
private static final String SET_OWNER_MEMBER_ROLE = "UPDATE faction_member SET role = 'OWNER' WHERE group_id = ? AND member_name = ?";
|
||||
private static final String CREATE_GROUP = "CALL createGroup(?, ?, ?, ?)";
|
||||
private static final String COUNT_OWNED_GROUPS = "SELECT COUNT(*) FROM faction_id WHERE founder = ?";
|
||||
private static final String ADD_PERMISSION_BY_NAME = "INSERT IGNORE INTO permission_by_group_name(group_id, role, permission_name) VALUES (?, ?, ?)";
|
||||
private static final String GET_DEFAULT_GROUP_ID = "SELECT dg.defaultgroup, fi.group_id FROM default_group dg "
|
||||
+ "INNER JOIN faction_id fi ON fi.group_name = dg.defaultgroup WHERE dg.uuid = ? LIMIT 1 FOR UPDATE";
|
||||
@@ -108,6 +109,17 @@ public final class NameLayerWriteCoordinator {
|
||||
try (Connection connection = dataSource.getConnection()) {
|
||||
connection.setAutoCommit(false);
|
||||
try {
|
||||
if (!createWrite.adminOverride() && createWrite.maxGroups() > 0) {
|
||||
final int ownedGroups = countOwnedGroups(connection, request.actorUuid());
|
||||
if (ownedGroups >= createWrite.maxGroups()) {
|
||||
connection.rollback();
|
||||
return NameLayerWriteResponse.failure(
|
||||
request.requestId(),
|
||||
NameLayerWriteFailureCode.MAX_GROUPS_REACHED,
|
||||
"You have reached the group limit of " + createWrite.maxGroups()
|
||||
);
|
||||
}
|
||||
}
|
||||
final int groupId;
|
||||
try (PreparedStatement statement = connection.prepareStatement(CREATE_GROUP)) {
|
||||
statement.setString(1, createWrite.groupName());
|
||||
@@ -166,8 +178,12 @@ public final class NameLayerWriteCoordinator {
|
||||
setDefaultGroup(connection, request.actorUuid(), createdGroup.groupName());
|
||||
incrementCacheVersion(connection);
|
||||
connection.commit();
|
||||
publishFullInvalidation();
|
||||
return successFullResync(request, Set.of(createdGroup.groupId()));
|
||||
publishInvalidation(NameLayerInvalidationMessage.targeted(
|
||||
Set.of(createdGroup.groupId()),
|
||||
Set.of(request.actorUuid()),
|
||||
Set.of()
|
||||
));
|
||||
return NameLayerWriteResponse.success(request.requestId(), Set.of(createdGroup.groupId()));
|
||||
} catch (final SQLException exception) {
|
||||
connection.rollback();
|
||||
throw exception;
|
||||
@@ -504,7 +520,7 @@ public final class NameLayerWriteCoordinator {
|
||||
setDefaultGroup(connection, request.actorUuid(), groupName);
|
||||
incrementCacheVersion(connection);
|
||||
connection.commit();
|
||||
publishFullInvalidation();
|
||||
publishInvalidation(NameLayerInvalidationMessage.defaultGroups(Set.of(request.actorUuid())));
|
||||
return NameLayerWriteResponse.success(request.requestId(), Set.of());
|
||||
} catch (final SQLException exception) {
|
||||
connection.rollback();
|
||||
@@ -534,7 +550,7 @@ public final class NameLayerWriteCoordinator {
|
||||
statement.executeUpdate();
|
||||
incrementCacheVersion(connection);
|
||||
connection.commit();
|
||||
publishFullInvalidation();
|
||||
publishInvalidation(NameLayerInvalidationMessage.autoAccepts(Set.of(request.actorUuid())));
|
||||
return NameLayerWriteResponse.success(request.requestId(), Set.of());
|
||||
} catch (final SQLException exception) {
|
||||
connection.rollback();
|
||||
@@ -632,6 +648,18 @@ public final class NameLayerWriteCoordinator {
|
||||
}
|
||||
}
|
||||
|
||||
private int countOwnedGroups(final Connection connection, final UUID ownerUuid) throws SQLException {
|
||||
try (PreparedStatement statement = connection.prepareStatement(COUNT_OWNED_GROUPS)) {
|
||||
statement.setString(1, ownerUuid.toString());
|
||||
try (ResultSet resultSet = statement.executeQuery()) {
|
||||
if (!resultSet.next()) {
|
||||
return 0;
|
||||
}
|
||||
return resultSet.getInt(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private NameLayerWriteResponse handleMetadataWrite(
|
||||
final NameLayerWriteRequest request,
|
||||
final String sql,
|
||||
@@ -884,31 +912,16 @@ public final class NameLayerWriteCoordinator {
|
||||
}
|
||||
|
||||
private void publishInvalidation(final int groupId) {
|
||||
final boolean published = invalidationPublisher.publish(NameLayerInvalidationMessage.targeted(Set.of(groupId)));
|
||||
if (!published) {
|
||||
logger.error("NameLayer write committed, but failed to publish invalidation for group {}", groupId);
|
||||
}
|
||||
publishInvalidation(NameLayerInvalidationMessage.targeted(Set.of(groupId)));
|
||||
}
|
||||
|
||||
private void publishFullInvalidation() {
|
||||
final boolean published = invalidationPublisher.publish(NameLayerInvalidationMessage.fullResync());
|
||||
private void publishInvalidation(final NameLayerInvalidationMessage invalidation) {
|
||||
final boolean published = invalidationPublisher.publish(invalidation);
|
||||
if (!published) {
|
||||
logger.error("NameLayer write committed, but failed to publish full resync invalidation");
|
||||
logger.error("NameLayer write committed, but failed to publish invalidation {}", invalidation);
|
||||
}
|
||||
}
|
||||
|
||||
private NameLayerWriteResponse successFullResync(final NameLayerWriteRequest request, final Set<Integer> affectedGroupIds) {
|
||||
return new NameLayerWriteResponse(
|
||||
request.requestId(),
|
||||
true,
|
||||
null,
|
||||
"",
|
||||
affectedGroupIds,
|
||||
true,
|
||||
System.currentTimeMillis()
|
||||
);
|
||||
}
|
||||
|
||||
private boolean acquireLock(final Connection connection, final String lockName) throws SQLException {
|
||||
try (PreparedStatement statement = connection.prepareStatement(GET_PLAYER_LOCK)) {
|
||||
statement.setString(1, lockName);
|
||||
@@ -1263,14 +1276,33 @@ public final class NameLayerWriteCoordinator {
|
||||
}
|
||||
}
|
||||
|
||||
private record CreateGroupWrite(String groupName, String password, Set<DefaultPermission> defaultPermissions) {
|
||||
private record CreateGroupWrite(
|
||||
String groupName,
|
||||
String password,
|
||||
Set<DefaultPermission> defaultPermissions,
|
||||
int maxGroups,
|
||||
boolean adminOverride
|
||||
) {
|
||||
|
||||
private static CreateGroupWrite from(final Map<String, String> arguments) {
|
||||
final String groupName = PermissionWrite.requireNonBlank(arguments, "groupName");
|
||||
final String password = Boolean.parseBoolean(arguments.getOrDefault("hasPassword", "false"))
|
||||
? arguments.getOrDefault("password", "")
|
||||
: null;
|
||||
return new CreateGroupWrite(groupName, password, DefaultPermission.parse(arguments.getOrDefault("defaultPermissions", "")));
|
||||
final int maxGroups;
|
||||
try {
|
||||
maxGroups = Integer.parseInt(arguments.getOrDefault("maxGroups", "0"));
|
||||
} catch (final NumberFormatException exception) {
|
||||
throw new IllegalArgumentException("maxGroups must be an integer");
|
||||
}
|
||||
final boolean adminOverride = Boolean.parseBoolean(arguments.getOrDefault("adminOverride", "false"));
|
||||
return new CreateGroupWrite(
|
||||
groupName,
|
||||
password,
|
||||
DefaultPermission.parse(arguments.getOrDefault("defaultPermissions", "")),
|
||||
maxGroups,
|
||||
adminOverride
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user