use of me.lucko.luckperms.api.Node in project LuckPerms by lucko.
the class VaultPermissionHook method userGetGroups.
@Override
public String[] userGetGroups(String world, UUID uuid) {
if (uuid == null) {
return new String[0];
}
User user = getUser(uuid);
if (user == null) {
return new String[0];
}
ContextSet contexts = contextForLookup(user, world).getContexts();
String[] ret = user.getEnduringNodes().values().stream().filter(Node::isGroupNode).filter(n -> n.shouldApplyWithContext(contexts)).map(n -> {
Group group = this.plugin.getGroupManager().getIfLoaded(n.getGroupName());
if (group != null) {
return group.getDisplayName().orElse(group.getName());
}
return n.getGroupName();
}).toArray(String[]::new);
if (log()) {
logMsg("#userGetGroups: %s - %s - %s", user.getFriendlyName(), contexts, Arrays.toString(ret));
}
return ret;
}
use of me.lucko.luckperms.api.Node in project LuckPerms by lucko.
the class Exporter method run.
@Override
public void run() {
try (BufferedWriter writer = Files.newBufferedWriter(this.filePath, StandardCharsets.UTF_8)) {
this.log.log("Starting.");
write(writer, "# LuckPerms Export File");
write(writer, "# Generated by " + this.executor.getNameWithLocation() + " at " + DATE_FORMAT.format(new Date(System.currentTimeMillis())));
write(writer, "");
// Export Groups
this.log.log("Starting group export.");
// Create the actual groups first
write(writer, "# Create groups");
AtomicInteger groupCount = new AtomicInteger(0);
List<? extends Group> groups = this.plugin.getGroupManager().getAll().values().stream().sorted((o1, o2) -> {
int i = Integer.compare(o2.getWeight().orElse(0), o1.getWeight().orElse(0));
return i != 0 ? i : o1.getName().compareToIgnoreCase(o2.getName());
}).collect(Collectors.toList());
for (Group group : groups) {
if (!group.getName().equals(NodeFactory.DEFAULT_GROUP_NAME)) {
write(writer, "/lp creategroup " + group.getName());
}
}
for (Group group : groups) {
if (groupCount.get() == 0) {
write(writer, "");
}
write(writer, "# Export group: " + group.getName());
for (Node node : group.getEnduringNodes().values()) {
write(writer, "/lp " + NodeFactory.nodeAsCommand(node, group.getName(), HolderType.GROUP, true));
}
write(writer, "");
this.log.logAllProgress("Exported {} groups so far.", groupCount.incrementAndGet());
}
this.log.log("Exported " + groupCount.get() + " groups.");
write(writer, "");
write(writer, "");
// Export tracks
this.log.log("Starting track export.");
Collection<? extends Track> tracks = this.plugin.getTrackManager().getAll().values();
if (!tracks.isEmpty()) {
// Create the actual tracks first
write(writer, "# Create tracks");
for (Track track : tracks) {
write(writer, "/lp createtrack " + track.getName());
}
write(writer, "");
AtomicInteger trackCount = new AtomicInteger(0);
for (Track track : this.plugin.getTrackManager().getAll().values()) {
write(writer, "# Export track: " + track.getName());
for (String group : track.getGroups()) {
write(writer, "/lp track " + track.getName() + " append " + group);
}
write(writer, "");
this.log.logAllProgress("Exported {} tracks so far.", trackCount.incrementAndGet());
}
write(writer, "");
write(writer, "");
}
this.log.log("Exported " + tracks.size() + " tracks.");
// Users are migrated in separate threads.
// This is because there are likely to be a lot of them, and because we can.
// It's a big speed improvement, since the database/files are split up and can handle concurrent reads.
this.log.log("Starting user export. Finding a list of unique users to export.");
// Find all of the unique users we need to export
Storage ds = this.plugin.getStorage();
Set<UUID> users = ds.getUniqueUsers().join();
this.log.log("Found " + users.size() + " unique users to export.");
write(writer, "# Export users");
// divide into 16 pools.
Cycle<List<UUID>> userPools = new Cycle<>(nInstances(32, ArrayList::new));
for (UUID uuid : users) {
userPools.next().add(uuid);
}
this.log.log("Split users into " + userPools.getBacking().size() + " threads for export.");
// Setup a file writing lock. We don't want multiple threads writing at the same time.
// The write function accepts a list of strings, as we want a user's data to be grouped together.
// This means it can be processed and added in one go.
ReentrantLock lock = new ReentrantLock();
Consumer<List<String>> writeFunction = strings -> {
lock.lock();
try {
for (String s : strings) {
write(writer, s);
}
} finally {
lock.unlock();
}
};
// A set of futures, which are really just the threads we need to wait for.
Set<CompletableFuture<Void>> futures = new HashSet<>();
AtomicInteger userCount = new AtomicInteger(0);
// iterate through each user sublist.
for (List<UUID> subList : userPools.getBacking()) {
// register and start a new thread to process the sublist
futures.add(CompletableFuture.runAsync(() -> {
// iterate through each user in the sublist, and grab their data.
for (UUID uuid : subList) {
try {
// actually export the user. this output will be fed to the writing function when we have all of the user's data.
List<String> output = new ArrayList<>();
User user = this.plugin.getStorage().loadUser(uuid, null).join();
output.add("# Export user: " + user.getUuid().toString() + " - " + user.getName().orElse("unknown username"));
boolean inDefault = false;
for (Node node : user.getEnduringNodes().values()) {
if (node.isGroupNode() && node.getGroupName().equalsIgnoreCase(NodeFactory.DEFAULT_GROUP_NAME)) {
inDefault = true;
continue;
}
output.add("/lp " + NodeFactory.nodeAsCommand(node, user.getUuid().toString(), HolderType.USER, true));
}
if (!user.getPrimaryGroup().getStoredValue().orElse(NodeFactory.DEFAULT_GROUP_NAME).equalsIgnoreCase(NodeFactory.DEFAULT_GROUP_NAME)) {
output.add("/lp user " + user.getUuid().toString() + " switchprimarygroup " + user.getPrimaryGroup().getStoredValue().get());
}
if (!inDefault) {
output.add("/lp user " + user.getUuid().toString() + " parent remove default");
}
this.plugin.getUserManager().cleanup(user);
writeFunction.accept(output);
this.log.logProgress("Exported {} users so far.", userCount.incrementAndGet());
} catch (Exception e) {
e.printStackTrace();
}
}
}, this.plugin.getBootstrap().getScheduler().async()));
}
// all of the threads have been scheduled now and are running. we just need to wait for them all to complete
CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])).join();
this.log.log("Exported " + userCount.get() + " users.");
writer.flush();
this.log.getListeners().forEach(l -> Message.LOG_EXPORT_SUCCESS.send(l, this.filePath.toFile().getAbsolutePath()));
} catch (Exception e) {
e.printStackTrace();
}
}
use of me.lucko.luckperms.api.Node in project LuckPerms by lucko.
the class ApplyEditsCommand method read.
private boolean read(JsonObject data, String code, Sender sender, LuckPermsPlugin plugin) {
if (!data.has("who") || data.get("who").getAsString().isEmpty()) {
Message.APPLY_EDITS_NO_TARGET.send(sender);
return false;
}
String who = data.get("who").getAsString();
PermissionHolder holder = WebEditor.getHolderFromIdentifier(plugin, sender, who);
if (holder == null) {
// the #getHolderFromIdentifier method will send the error message onto the sender
return false;
}
if (ArgumentPermissions.checkModifyPerms(plugin, sender, getPermission().get(), holder)) {
Message.COMMAND_NO_PERMISSION.send(sender);
return false;
}
Set<NodeModel> nodes = WebEditor.deserializePermissions(data.getAsJsonArray("nodes"));
Set<Node> before = new HashSet<>(holder.getEnduringNodes().values());
Set<Node> after = nodes.stream().map(NodeModel::toNode).collect(Collectors.toSet());
Map.Entry<Set<Node>, Set<Node>> diff = diff(before, after);
int additions = diff.getKey().size();
int deletions = diff.getValue().size();
if (additions == 0 && deletions == 0) {
return false;
}
ExtendedLogEntry.build().actor(sender).acted(holder).action("applyedits", code).build().submit(plugin, sender);
holder.setEnduringNodes(after);
String additionsSummary = "addition" + (additions == 1 ? "" : "s");
String deletionsSummary = "deletion" + (deletions == 1 ? "" : "s");
Message.APPLY_EDITS_SUCCESS.send(sender, holder.getFriendlyName());
Message.APPLY_EDITS_SUCCESS_SUMMARY.send(sender, additions, additionsSummary, deletions, deletionsSummary);
for (Node n : diff.getKey()) {
Message.APPLY_EDITS_DIFF_ADDED.send(sender, formatNode(n));
}
for (Node n : diff.getValue()) {
Message.APPLY_EDITS_DIFF_REMOVED.send(sender, formatNode(n));
}
StorageAssistant.save(holder, sender, plugin);
return true;
}
use of me.lucko.luckperms.api.Node in project LuckPerms by lucko.
the class GroupInfo method execute.
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
if (ArgumentPermissions.checkViewPerms(plugin, sender, getPermission().get(), group)) {
Message.COMMAND_NO_PERMISSION.send(sender);
return CommandResult.NO_PERMISSION;
}
Message.GROUP_INFO_GENERAL.send(sender, group.getName(), group.getDisplayName().orElse(group.getName()), group.getWeight().isPresent() ? group.getWeight().getAsInt() : "None");
Set<Node> parents = group.getEnduringData().asSet().stream().filter(Node::isGroupNode).filter(Node::isPermanent).collect(Collectors.toSet());
Set<Node> tempParents = group.getEnduringData().asSet().stream().filter(Node::isGroupNode).filter(Node::isTemporary).collect(Collectors.toSet());
if (!parents.isEmpty()) {
Message.INFO_PARENT_HEADER.send(sender);
for (Node node : parents) {
Message.EMPTY.send(sender, "&f- &3> &f" + node.getGroupName() + MessageUtils.getAppendableNodeContextString(node));
}
}
if (!tempParents.isEmpty()) {
Message.INFO_TEMP_PARENT_HEADER.send(sender);
for (Node node : tempParents) {
Message.EMPTY.send(sender, "&f- &3> &f" + node.getGroupName() + MessageUtils.getAppendableNodeContextString(node));
Message.EMPTY.send(sender, "&f- &2- expires in " + DateUtil.formatDateDiff(node.getExpiryUnixTime()));
}
}
return CommandResult.SUCCESS;
}
use of me.lucko.luckperms.api.Node in project LuckPerms by lucko.
the class ParentAddTemp method execute.
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args, String label, CommandPermission permission) throws CommandException {
if (ArgumentPermissions.checkModifyPerms(plugin, sender, permission, holder)) {
Message.COMMAND_NO_PERMISSION.send(sender);
return CommandResult.NO_PERMISSION;
}
String groupName = ArgumentParser.parseName(0, args);
long duration = ArgumentParser.parseDuration(1, args);
TemporaryModifier modifier = ArgumentParser.parseTemporaryModifier(2, args).orElseGet(() -> plugin.getConfiguration().get(ConfigKeys.TEMPORARY_ADD_BEHAVIOUR));
MutableContextSet context = ArgumentParser.parseContext(2, args, plugin);
Group group = StorageAssistant.loadGroup(groupName, sender, plugin, false);
if (group == null) {
return CommandResult.INVALID_ARGS;
}
if (ArgumentPermissions.checkContext(plugin, sender, permission, context)) {
Message.COMMAND_NO_PERMISSION.send(sender);
return CommandResult.NO_PERMISSION;
}
if (ArgumentPermissions.checkArguments(plugin, sender, permission, group.getName())) {
Message.COMMAND_NO_PERMISSION.send(sender);
return CommandResult.NO_PERMISSION;
}
if (group.getName().equalsIgnoreCase(holder.getObjectName())) {
Message.ALREADY_TEMP_INHERITS.send(sender, holder.getFriendlyName(), group.getFriendlyName(), MessageUtils.contextSetToString(context));
return CommandResult.STATE_ERROR;
}
Map.Entry<DataMutateResult, Node> ret = holder.setPermission(NodeFactory.buildGroupNode(group.getName()).setExpiry(duration).withExtraContext(context).build(), modifier);
if (ret.getKey().asBoolean()) {
duration = ret.getValue().getExpiryUnixTime();
Message.SET_TEMP_INHERIT_SUCCESS.send(sender, holder.getFriendlyName(), group.getFriendlyName(), DateUtil.formatDateDiff(duration), MessageUtils.contextSetToString(context));
ExtendedLogEntry.build().actor(sender).acted(holder).action("parent", "addtemp", group.getName(), duration, context).build().submit(plugin, sender);
StorageAssistant.save(holder, sender, plugin);
return CommandResult.SUCCESS;
} else {
Message.ALREADY_TEMP_INHERITS.send(sender, holder.getFriendlyName(), group.getFriendlyName(), MessageUtils.contextSetToString(context));
return CommandResult.STATE_ERROR;
}
}
Aggregations