mirror of
https://github.com/BentoBoxWorld/BentoBox.git
synced 2024-11-23 19:25:12 +01:00
Implements placeholder permissions for addons (#1305)
Implements #1303. Addons will no longer need to see their permissions updated each time there is a new gamemode. They can use [gamemode] in their permissions to automatically register the permissions on all available gamemodes.
This commit is contained in:
parent
fe58159db3
commit
1f3a79127a
@ -8,15 +8,12 @@ import java.net.URLClassLoader;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
import org.bukkit.permissions.PermissionDefault;
|
|
||||||
import org.bukkit.plugin.InvalidDescriptionException;
|
import org.bukkit.plugin.InvalidDescriptionException;
|
||||||
import org.bukkit.util.permissions.DefaultPermissions;
|
|
||||||
import org.eclipse.jdt.annotation.NonNull;
|
import org.eclipse.jdt.annotation.NonNull;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
|
||||||
@ -31,7 +28,6 @@ import world.bentobox.bentobox.managers.AddonsManager;
|
|||||||
*/
|
*/
|
||||||
public class AddonClassLoader extends URLClassLoader {
|
public class AddonClassLoader extends URLClassLoader {
|
||||||
|
|
||||||
private static final String DEFAULT = ".default";
|
|
||||||
private final Map<String, Class<?>> classes = new HashMap<>();
|
private final Map<String, Class<?>> classes = new HashMap<>();
|
||||||
private Addon addon;
|
private Addon addon;
|
||||||
private AddonsManager loader;
|
private AddonsManager loader;
|
||||||
@ -70,31 +66,16 @@ public class AddonClassLoader extends URLClassLoader {
|
|||||||
|
|
||||||
addon = addonClass.getDeclaredConstructor().newInstance();
|
addon = addonClass.getDeclaredConstructor().newInstance();
|
||||||
addon.setDescription(asDescription(data));
|
addon.setDescription(asDescription(data));
|
||||||
// Set permissions
|
|
||||||
if (data.isConfigurationSection("permissions")) {
|
|
||||||
ConfigurationSection perms = data.getConfigurationSection("permissions");
|
|
||||||
perms.getKeys(true).forEach(perm -> {
|
|
||||||
if (perms.contains(perm + DEFAULT) && perms.contains(perm + ".description")) {
|
|
||||||
registerPermission(perms, perm);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerPermission(ConfigurationSection perms, String perm) {
|
|
||||||
if (perms.getString(perm + DEFAULT) == null) {
|
|
||||||
Bukkit.getLogger().severe("Permission default is invalid : " + perms.getName());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
PermissionDefault pd = PermissionDefault.getByName(perms.getString(perm + DEFAULT));
|
|
||||||
if (pd == null) {
|
|
||||||
Bukkit.getLogger().severe("Permission default is invalid : " + perms.getName());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String desc = perms.getString(perm + ".description");
|
|
||||||
DefaultPermissions.registerPermission(perm, desc, pd);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convers the addon.yml to an AddonDescription
|
||||||
|
* @param data - yaml config (addon.yml)
|
||||||
|
* @return Addon Description
|
||||||
|
* @throws InvalidAddonDescriptionException - if there's a bug in the addon.yml
|
||||||
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
private AddonDescription asDescription(YamlConfiguration data) throws InvalidAddonDescriptionException {
|
private AddonDescription asDescription(YamlConfiguration data) throws InvalidAddonDescriptionException {
|
||||||
AddonDescription.Builder builder = new AddonDescription.Builder(data.getString("main"), data.getString("name"), data.getString("version"))
|
AddonDescription.Builder builder = new AddonDescription.Builder(data.getString("main"), data.getString("name"), data.getString("version"))
|
||||||
@ -119,6 +100,10 @@ public class AddonClassLoader extends URLClassLoader {
|
|||||||
}
|
}
|
||||||
builder.apiVersion(apiVersion);
|
builder.apiVersion(apiVersion);
|
||||||
}
|
}
|
||||||
|
// Set permissions
|
||||||
|
if (data.isConfigurationSection("permissions")) {
|
||||||
|
builder.permissions(Objects.requireNonNull(data.getConfigurationSection("permissions")));
|
||||||
|
}
|
||||||
|
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,9 @@ import java.util.Arrays;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
import org.eclipse.jdt.annotation.NonNull;
|
import org.eclipse.jdt.annotation.NonNull;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author tastybento, Poslovitch
|
* @author tastybento, Poslovitch
|
||||||
@ -19,6 +21,7 @@ public final class AddonDescription {
|
|||||||
private final @NonNull List<String> authors;
|
private final @NonNull List<String> authors;
|
||||||
private final @NonNull List<String> dependencies;
|
private final @NonNull List<String> dependencies;
|
||||||
private final @NonNull List<String> softDependencies;
|
private final @NonNull List<String> softDependencies;
|
||||||
|
private final @Nullable ConfigurationSection permissions;
|
||||||
/**
|
/**
|
||||||
* Whether the addon should be included in Metrics or not.
|
* Whether the addon should be included in Metrics or not.
|
||||||
* @since 1.1
|
* @since 1.1
|
||||||
@ -54,6 +57,7 @@ public final class AddonDescription {
|
|||||||
this.repository = builder.repository;
|
this.repository = builder.repository;
|
||||||
this.icon = builder.icon;
|
this.icon = builder.icon;
|
||||||
this.apiVersion = builder.apiVersion;
|
this.apiVersion = builder.apiVersion;
|
||||||
|
this.permissions = builder.permissions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@ -150,6 +154,14 @@ public final class AddonDescription {
|
|||||||
return apiVersion;
|
return apiVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the permissions
|
||||||
|
* @since 1.13.0
|
||||||
|
*/
|
||||||
|
public ConfigurationSection getPermissions() {
|
||||||
|
return permissions;
|
||||||
|
}
|
||||||
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
private @NonNull String main;
|
private @NonNull String main;
|
||||||
private @NonNull String name;
|
private @NonNull String name;
|
||||||
@ -162,6 +174,7 @@ public final class AddonDescription {
|
|||||||
private @NonNull String repository = "";
|
private @NonNull String repository = "";
|
||||||
private @NonNull Material icon = Material.PAPER;
|
private @NonNull Material icon = Material.PAPER;
|
||||||
private @NonNull String apiVersion = "1";
|
private @NonNull String apiVersion = "1";
|
||||||
|
private @Nullable ConfigurationSection permissions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since 1.1
|
* @since 1.1
|
||||||
@ -243,5 +256,17 @@ public final class AddonDescription {
|
|||||||
public AddonDescription build() {
|
public AddonDescription build() {
|
||||||
return new AddonDescription(this);
|
return new AddonDescription(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the permission config section. Taken from the addon.yml
|
||||||
|
* @param permissions - YAML configuration section
|
||||||
|
* @return Builder
|
||||||
|
* @since 1.13.0
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public Builder permissions(ConfigurationSection permissions) {
|
||||||
|
this.permissions = permissions;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,11 +21,14 @@ import java.util.logging.Level;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
import org.bukkit.configuration.InvalidConfigurationException;
|
import org.bukkit.configuration.InvalidConfigurationException;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.generator.ChunkGenerator;
|
import org.bukkit.generator.ChunkGenerator;
|
||||||
|
import org.bukkit.permissions.PermissionDefault;
|
||||||
|
import org.bukkit.util.permissions.DefaultPermissions;
|
||||||
import org.eclipse.jdt.annotation.NonNull;
|
import org.eclipse.jdt.annotation.NonNull;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
|
||||||
@ -34,6 +37,7 @@ import world.bentobox.bentobox.api.addons.Addon;
|
|||||||
import world.bentobox.bentobox.api.addons.Addon.State;
|
import world.bentobox.bentobox.api.addons.Addon.State;
|
||||||
import world.bentobox.bentobox.api.addons.AddonClassLoader;
|
import world.bentobox.bentobox.api.addons.AddonClassLoader;
|
||||||
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
||||||
|
import world.bentobox.bentobox.api.addons.exceptions.InvalidAddonDescriptionException;
|
||||||
import world.bentobox.bentobox.api.addons.exceptions.InvalidAddonFormatException;
|
import world.bentobox.bentobox.api.addons.exceptions.InvalidAddonFormatException;
|
||||||
import world.bentobox.bentobox.api.configuration.ConfigObject;
|
import world.bentobox.bentobox.api.configuration.ConfigObject;
|
||||||
import world.bentobox.bentobox.api.events.addon.AddonEvent;
|
import world.bentobox.bentobox.api.events.addon.AddonEvent;
|
||||||
@ -46,6 +50,10 @@ import world.bentobox.bentobox.util.Util;
|
|||||||
*/
|
*/
|
||||||
public class AddonsManager {
|
public class AddonsManager {
|
||||||
|
|
||||||
|
private static final String DEFAULT = ".default";
|
||||||
|
|
||||||
|
private static final String GAMEMODE = "[gamemode].";
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private List<Addon> addons;
|
private List<Addon> addons;
|
||||||
@NonNull
|
@NonNull
|
||||||
@ -154,10 +162,42 @@ public class AddonsManager {
|
|||||||
* Enables all the addons
|
* Enables all the addons
|
||||||
*/
|
*/
|
||||||
public void enableAddons() {
|
public void enableAddons() {
|
||||||
if (!getLoadedAddons().isEmpty()) {
|
if (getLoadedAddons().isEmpty()) return;
|
||||||
plugin.log("Enabling addons...");
|
plugin.log("Enabling addons...");
|
||||||
getLoadedAddons().forEach(this::enableAddon);
|
getLoadedAddons().forEach(this::enableAddon);
|
||||||
plugin.log("Addons successfully enabled.");
|
// Set perms for enabled addons
|
||||||
|
this.getEnabledAddons().forEach(this::setPerms);
|
||||||
|
plugin.log("Addons successfully enabled.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPerms(Addon addon) {
|
||||||
|
ConfigurationSection perms = addon.getDescription().getPermissions();
|
||||||
|
perms.getKeys(true).parallelStream().filter(perm -> perms.contains(perm + DEFAULT) && perms.contains(perm + ".description"))
|
||||||
|
.forEach(perm -> {
|
||||||
|
try {
|
||||||
|
registerPermission(perms, perm);
|
||||||
|
} catch (InvalidAddonDescriptionException e) {
|
||||||
|
plugin.logError("Addon " + addon.getDescription().getName() + ": " + e.getMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void registerPermission(ConfigurationSection perms, String perm) throws InvalidAddonDescriptionException {
|
||||||
|
if (perms.getString(perm + DEFAULT) == null) {
|
||||||
|
throw new InvalidAddonDescriptionException("Permission default is invalid : " + perm + DEFAULT);
|
||||||
|
}
|
||||||
|
PermissionDefault pd = PermissionDefault.getByName(perms.getString(perm + DEFAULT));
|
||||||
|
if (pd == null) {
|
||||||
|
throw new InvalidAddonDescriptionException("Permission default is invalid : " + perm + DEFAULT);
|
||||||
|
}
|
||||||
|
String desc = perms.getString(perm + ".description");
|
||||||
|
// Replace placeholders for Game Mode Addon names
|
||||||
|
if (perm.contains(GAMEMODE)) {
|
||||||
|
getGameModeAddons().stream().map(g -> g.getPermissionPrefix())
|
||||||
|
.forEach(p -> DefaultPermissions.registerPermission(perm.replace(GAMEMODE, p), desc, pd));
|
||||||
|
} else {
|
||||||
|
// Single perm
|
||||||
|
DefaultPermissions.registerPermission(perm, desc, pd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,6 +420,9 @@ public class AddonsManager {
|
|||||||
classes.putIfAbsent(name, clazz);
|
classes.putIfAbsent(name, clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts the addons into loading order taking into account dependencies
|
||||||
|
*/
|
||||||
private void sortAddons() {
|
private void sortAddons() {
|
||||||
// Lists all available addons as names.
|
// Lists all available addons as names.
|
||||||
List<String> names = addons.stream().map(a -> a.getDescription().getName()).collect(Collectors.toList());
|
List<String> names = addons.stream().map(a -> a.getDescription().getName()).collect(Collectors.toList());
|
||||||
|
@ -5,6 +5,9 @@ import static org.junit.Assert.assertFalse;
|
|||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
@ -14,9 +17,15 @@ import java.io.File;
|
|||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.configuration.InvalidConfigurationException;
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.generator.ChunkGenerator;
|
||||||
|
import org.bukkit.permissions.PermissionDefault;
|
||||||
import org.bukkit.plugin.PluginManager;
|
import org.bukkit.plugin.PluginManager;
|
||||||
|
import org.bukkit.util.permissions.DefaultPermissions;
|
||||||
import org.eclipse.jdt.annotation.NonNull;
|
import org.eclipse.jdt.annotation.NonNull;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@ -31,12 +40,16 @@ import org.powermock.reflect.Whitebox;
|
|||||||
import world.bentobox.bentobox.BentoBox;
|
import world.bentobox.bentobox.BentoBox;
|
||||||
import world.bentobox.bentobox.Settings;
|
import world.bentobox.bentobox.Settings;
|
||||||
import world.bentobox.bentobox.api.addons.Addon;
|
import world.bentobox.bentobox.api.addons.Addon;
|
||||||
|
import world.bentobox.bentobox.api.addons.Addon.State;
|
||||||
import world.bentobox.bentobox.api.addons.AddonDescription;
|
import world.bentobox.bentobox.api.addons.AddonDescription;
|
||||||
|
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
||||||
|
import world.bentobox.bentobox.api.addons.exceptions.InvalidAddonDescriptionException;
|
||||||
|
import world.bentobox.bentobox.api.configuration.WorldSettings;
|
||||||
import world.bentobox.bentobox.database.DatabaseSetup.DatabaseType;
|
import world.bentobox.bentobox.database.DatabaseSetup.DatabaseType;
|
||||||
import world.bentobox.bentobox.database.objects.DataObject;
|
import world.bentobox.bentobox.database.objects.DataObject;
|
||||||
|
|
||||||
@RunWith(PowerMockRunner.class)
|
@RunWith(PowerMockRunner.class)
|
||||||
@PrepareForTest( {Bukkit.class, BentoBox.class} )
|
@PrepareForTest( {Bukkit.class, BentoBox.class, DefaultPermissions.class} )
|
||||||
public class AddonsManagerTest {
|
public class AddonsManagerTest {
|
||||||
|
|
||||||
private BentoBox plugin;
|
private BentoBox plugin;
|
||||||
@ -67,6 +80,8 @@ public class AddonsManagerTest {
|
|||||||
when(s.getDatabaseType()).thenReturn(DatabaseType.MYSQL);
|
when(s.getDatabaseType()).thenReturn(DatabaseType.MYSQL);
|
||||||
// settings
|
// settings
|
||||||
when(plugin.getSettings()).thenReturn(s);
|
when(plugin.getSettings()).thenReturn(s);
|
||||||
|
|
||||||
|
PowerMockito.mockStatic(DefaultPermissions.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -335,5 +350,78 @@ public class AddonsManagerTest {
|
|||||||
assertFalse(am.isAddonCompatibleWithBentoBox(addon, "1.11.1"));
|
assertFalse(am.isAddonCompatibleWithBentoBox(addon, "1.11.1"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test method for {@link world.bentobox.bentobox.managers.AddonsManager#registerPermission(org.bukkit.configuration.ConfigurationSection, String)}
|
||||||
|
* @throws InvalidAddonDescriptionException
|
||||||
|
* @throws InvalidConfigurationException
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testRegisterPermissionStandardPerm() throws InvalidAddonDescriptionException, InvalidConfigurationException {
|
||||||
|
String perms =
|
||||||
|
" 'bskyblock.intopten':\n" +
|
||||||
|
" description: Player is in the top ten.\n" +
|
||||||
|
" default: true\n";
|
||||||
|
YamlConfiguration config = new YamlConfiguration();
|
||||||
|
config.loadFromString(perms);
|
||||||
|
am.registerPermission(config, "bskyblock.intopten");
|
||||||
|
PowerMockito.verifyStatic(DefaultPermissions.class);
|
||||||
|
DefaultPermissions.registerPermission(eq("bskyblock.intopten"), anyString(), any(PermissionDefault.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test method for {@link world.bentobox.bentobox.managers.AddonsManager#registerPermission(org.bukkit.configuration.ConfigurationSection, String)}
|
||||||
|
* @throws InvalidAddonDescriptionException
|
||||||
|
* @throws InvalidConfigurationException
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testRegisterPermissionGameModePerm() throws InvalidAddonDescriptionException, InvalidConfigurationException {
|
||||||
|
String perms =
|
||||||
|
" '[gamemode].intopten':\n" +
|
||||||
|
" description: Player is in the top ten.\n" +
|
||||||
|
" default: true\n";
|
||||||
|
YamlConfiguration config = new YamlConfiguration();
|
||||||
|
config.loadFromString(perms);
|
||||||
|
GameModeAddon addon = new MyGameMode();
|
||||||
|
AddonDescription addonDesc = new AddonDescription.Builder("main.class", "mygame", "1.0.0").apiVersion("1.11.1.0.0.0.1")
|
||||||
|
.permissions(config)
|
||||||
|
.build();
|
||||||
|
addon.setDescription(addonDesc);
|
||||||
|
addon.setState(State.ENABLED);
|
||||||
|
am.getAddons().add(addon);
|
||||||
|
am.registerPermission(config, "[gamemode].intopten");
|
||||||
|
PowerMockito.verifyStatic(DefaultPermissions.class);
|
||||||
|
DefaultPermissions.registerPermission(eq("mygame.intopten"), anyString(), any(PermissionDefault.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class MyGameMode extends GameModeAddon {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createWorlds() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WorldSettings getWorldSettings() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable ChunkGenerator getDefaultWorldGenerator(String worldName, String id) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveWorldSettings() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user