diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/JoinAddressCount.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/JoinAddressCount.java index f9cf75f15a..fc2cccc3e1 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/JoinAddressCount.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/JoinAddressCount.java @@ -28,7 +28,7 @@ */ public class JoinAddressCount implements Comparable { - private final int count; + private int count; private String joinAddress; public JoinAddressCount(Map.Entry entry) { @@ -52,6 +52,10 @@ public int getCount() { return count; } + public void setCount(int count) { + this.count = count; + } + @Override public int compareTo(@NotNull JoinAddressCount other) { return String.CASE_INSENSITIVE_ORDER.compare(this.joinAddress, other.joinAddress); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/JSONFactory.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/JSONFactory.java index b861024087..397aeec22b 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/JSONFactory.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/JSONFactory.java @@ -35,6 +35,7 @@ import com.djrapitops.plan.identification.ServerInfo; import com.djrapitops.plan.identification.ServerUUID; import com.djrapitops.plan.settings.config.PlanConfig; +import com.djrapitops.plan.settings.config.paths.DataGatheringSettings; import com.djrapitops.plan.settings.config.paths.DisplaySettings; import com.djrapitops.plan.settings.config.paths.TimeSettings; import com.djrapitops.plan.settings.locale.Locale; @@ -49,6 +50,7 @@ import com.djrapitops.plan.storage.database.queries.objects.*; import com.djrapitops.plan.storage.database.queries.objects.playertable.NetworkTablePlayersQuery; import com.djrapitops.plan.storage.database.queries.objects.playertable.ServerTablePlayersQuery; +import com.djrapitops.plan.storage.database.sql.tables.JoinAddressTable; import com.djrapitops.plan.utilities.comparators.SessionStartComparator; import com.djrapitops.plan.utilities.dev.Untrusted; import com.djrapitops.plan.utilities.java.Maps; @@ -161,25 +163,52 @@ public List networkPlayerRetentionAsJSONMap() { return db.query(PlayerRetentionQueries.fetchRetentionData()); } + private static void removeFiltered(Map addressByPlayerUUID, List filteredJoinAddresses) { + if (filteredJoinAddresses.isEmpty() || filteredJoinAddresses.equals(List.of("play.example.com"))) return; + + Set toRemove = new HashSet<>(); + // Remove filtered addresses from the data + for (Map.Entry entry : addressByPlayerUUID.entrySet()) { + if (filteredJoinAddresses.contains(entry.getValue())) { + toRemove.add(entry.getKey()); + } + } + for (UUID playerUUID : toRemove) { + addressByPlayerUUID.put(playerUUID, JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP); + } + } + public PlayerJoinAddresses playerJoinAddresses(ServerUUID serverUUID, boolean includeByPlayerMap) { Database db = dbSystem.getDatabase(); + List filteredJoinAddresses = config.get(DataGatheringSettings.FILTER_JOIN_ADDRESSES); if (includeByPlayerMap) { Map addresses = db.query(JoinAddressQueries.latestJoinAddressesOfPlayers(serverUUID)); + + removeFiltered(addresses, filteredJoinAddresses); + return new PlayerJoinAddresses( addresses.values().stream().distinct().sorted().collect(Collectors.toList()), addresses ); } else { - return new PlayerJoinAddresses(db.query(JoinAddressQueries.uniqueJoinAddresses(serverUUID)), null); + List addresses = db.query(JoinAddressQueries.uniqueJoinAddresses(serverUUID)); + addresses.removeAll(filteredJoinAddresses); + return new PlayerJoinAddresses(addresses, null); } } public PlayerJoinAddresses playerJoinAddresses(boolean includeByPlayerMap) { Database db = dbSystem.getDatabase(); - return new PlayerJoinAddresses( - db.query(JoinAddressQueries.uniqueJoinAddresses()), - includeByPlayerMap ? db.query(JoinAddressQueries.latestJoinAddressesOfPlayers()) : null - ); + List filteredJoinAddresses = config.get(DataGatheringSettings.FILTER_JOIN_ADDRESSES); + List unique = db.query(JoinAddressQueries.uniqueJoinAddresses()); + unique.removeAll(filteredJoinAddresses); + if (includeByPlayerMap) { + Map latest = db.query(JoinAddressQueries.latestJoinAddressesOfPlayers()); + removeFiltered(latest, filteredJoinAddresses); + return new PlayerJoinAddresses(unique, latest); + } else { + return new PlayerJoinAddresses(unique, null); + } } public List> serverSessionsAsJSONMap(ServerUUID serverUUID) { diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/graphs/GraphJSONCreator.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/graphs/GraphJSONCreator.java index f2007ae8e2..7cf745202a 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/graphs/GraphJSONCreator.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/graphs/GraphJSONCreator.java @@ -478,19 +478,51 @@ public Map joinAddressesByDay(long after, long before, @Untruste return mapToJson(pieColors, joinAddresses); } + private static void removeFilteredAddresses(List addresses, List filteredJoinAddresses) { + if (filteredJoinAddresses.isEmpty() || filteredJoinAddresses.equals(List.of("play.example.com"))) return; + + List addressesToRemove = addresses.stream() + .filter(address -> filteredJoinAddresses.contains(address.getJoinAddress())) + .collect(Collectors.toList()); + + if (!addressesToRemove.isEmpty()) { + Optional foundUnknownAddressCount = addresses.stream() + .filter(address -> address.getJoinAddress().equals(JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP)) + .findFirst(); + JoinAddressCount unknownAddressCount; + if (foundUnknownAddressCount.isEmpty()) { + unknownAddressCount = new JoinAddressCount(JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP, 0); + addresses.add(unknownAddressCount); + } else { + unknownAddressCount = foundUnknownAddressCount.get(); + } + + for (JoinAddressCount toRemove : addressesToRemove) { + unknownAddressCount.setCount(unknownAddressCount.getCount() + toRemove.getCount()); + addresses.remove(toRemove); + } + } + } + private Map mapToJson(String[] pieColors, List>> joinAddresses) { for (DateObj> addressesByDate : joinAddresses) { translateUnknown(addressesByDate.getValue()); } + List filteredJoinAddresses = config.get(DataGatheringSettings.FILTER_JOIN_ADDRESSES); + List joinAddressCounts = joinAddresses.stream() - .map(addressesOnDay -> new JoinAddressCounts( - addressesOnDay.getDate(), - addressesOnDay.getValue().entrySet() - .stream() - .map(JoinAddressCount::new) - .sorted() - .collect(Collectors.toList()))) + .map(addressesOnDay -> { + List addresses = addressesOnDay.getValue().entrySet() + .stream() + .map(JoinAddressCount::new) + .sorted() + .collect(Collectors.toList()); + + removeFilteredAddresses(addresses, filteredJoinAddresses); + + return new JoinAddressCounts(addressesOnDay.getDate(), addresses); + }) .sorted(new DateHolderOldestComparator()) .collect(Collectors.toList()); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/gathering/JoinAddressValidator.java b/Plan/common/src/main/java/com/djrapitops/plan/gathering/JoinAddressValidator.java index 229c5bfb8d..f00d53c9c5 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/gathering/JoinAddressValidator.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/gathering/JoinAddressValidator.java @@ -25,6 +25,7 @@ import javax.inject.Singleton; import java.net.URI; import java.net.URISyntaxException; +import java.util.List; /** * Utility for validating and sanitizing join addresses. @@ -35,6 +36,7 @@ public class JoinAddressValidator { private final PlanConfig config; + private List filteredAddresses; @Inject public JoinAddressValidator(PlanConfig config) { @@ -42,9 +44,15 @@ public JoinAddressValidator(PlanConfig config) { this.config = config; } + private void prepareFilteredAddresses() { + if (filteredAddresses == null) { + filteredAddresses = config.get(DataGatheringSettings.FILTER_JOIN_ADDRESSES); + } + } + @Untrusted public String sanitize(@Untrusted String address) { - if (address == null) return ""; + if (address == null || config.isFalse(DataGatheringSettings.JOIN_ADDRESSES)) return ""; if (!address.isEmpty()) { // Remove port if (address.contains(":")) { @@ -61,6 +69,10 @@ public String sanitize(@Untrusted String address) { if (config.isFalse(DataGatheringSettings.PRESERVE_JOIN_ADDRESS_CASE)) { address = StringUtils.lowerCase(address); } + prepareFilteredAddresses(); + if (filteredAddresses.contains(address)) { + address = ""; + } } return address; } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/settings/config/changes/ConfigUpdater.java b/Plan/common/src/main/java/com/djrapitops/plan/settings/config/changes/ConfigUpdater.java index 9ba6e94190..267662ce28 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/settings/config/changes/ConfigUpdater.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/settings/config/changes/ConfigUpdater.java @@ -177,6 +177,9 @@ ConfigChange[] configEnhancementPatch() { new ConfigChange.Removed("Plugin.Use_Legacy_Frontend"), new ConfigChange.Removed("Customized_files.Enable_web_dev_mode"), new ConfigChange.Removed("Customized_files.Plan"), + + new ConfigChange.Moved("Data_gathering.Preserve_join_address_case", "Data_gathering.Join_addresses.Preserve_case"), + new ConfigChange.Moved("Data_gathering.Preserve_invalid_join_addresses", "Data_gathering.Join_addresses.Preserve_invalid"), }; } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/settings/config/paths/DataGatheringSettings.java b/Plan/common/src/main/java/com/djrapitops/plan/settings/config/paths/DataGatheringSettings.java index beaaa6f121..438cdbd476 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/settings/config/paths/DataGatheringSettings.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/settings/config/paths/DataGatheringSettings.java @@ -18,8 +18,11 @@ import com.djrapitops.plan.settings.config.paths.key.BooleanSetting; import com.djrapitops.plan.settings.config.paths.key.Setting; +import com.djrapitops.plan.settings.config.paths.key.StringListSetting; import com.djrapitops.plan.settings.config.paths.key.StringSetting; +import java.util.List; + /** * {@link Setting} values that are in "Data_gathering" section. * @@ -34,8 +37,10 @@ public class DataGatheringSettings { public static final Setting DISK_SPACE = new BooleanSetting("Data_gathering.Disk_space"); public static final Setting LOG_UNKNOWN_COMMANDS = new BooleanSetting("Data_gathering.Commands.Log_unknown"); public static final Setting COMBINE_COMMAND_ALIASES = new BooleanSetting("Data_gathering.Commands.Log_aliases_as_main_command"); - public static final Setting PRESERVE_JOIN_ADDRESS_CASE = new BooleanSetting("Data_gathering.Preserve_join_address_case"); - public static final Setting PRESERVE_INVALID_JOIN_ADDRESS = new BooleanSetting("Data_gathering.Preserve_invalid_join_addresses"); + public static final Setting JOIN_ADDRESSES = new BooleanSetting("Data_gathering.Join_addresses.Enabled"); + public static final Setting PRESERVE_JOIN_ADDRESS_CASE = new BooleanSetting("Data_gathering.Join_addresses.Preserve_case"); + public static final Setting PRESERVE_INVALID_JOIN_ADDRESS = new BooleanSetting("Data_gathering.Join_addresses.Preserve_invalid"); + public static final Setting> FILTER_JOIN_ADDRESSES = new StringListSetting("Data_gathering.Join_addresses.Filter_out_from_data"); private DataGatheringSettings() { /* static variable class */ diff --git a/Plan/common/src/main/resources/assets/plan/bungeeconfig.yml b/Plan/common/src/main/resources/assets/plan/bungeeconfig.yml index 340fe348ea..0c87f507eb 100644 --- a/Plan/common/src/main/resources/assets/plan/bungeeconfig.yml +++ b/Plan/common/src/main/resources/assets/plan/bungeeconfig.yml @@ -114,9 +114,14 @@ Data_gathering: Geolocation_Download_URL: "https://geodb.playeranalytics.net/GeoLite2-Country.mmdb" Ping: true Disk_space: true - # Does not affect already gathered data - Preserve_join_address_case: false - Preserve_invalid_join_addresses: false + Join_addresses: + Enabled: true + # Does not affect already gathered data + Preserve_case: false + Preserve_invalid: false + # Replaces these join addresses with unknown + Filter_out_from_data: + - "play.example.com" # ----------------------------------------------------- # Supported time units: MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS # ----------------------------------------------------- diff --git a/Plan/common/src/main/resources/assets/plan/config.yml b/Plan/common/src/main/resources/assets/plan/config.yml index 1aabbbbd66..51395d71de 100644 --- a/Plan/common/src/main/resources/assets/plan/config.yml +++ b/Plan/common/src/main/resources/assets/plan/config.yml @@ -118,9 +118,14 @@ Data_gathering: Commands: Log_unknown: false Log_aliases_as_main_command: true - # Does not affect already gathered data - Preserve_join_address_case: false - Preserve_invalid_join_addresses: false + Join_addresses: + Enabled: true + # Does not affect already gathered data + Preserve_case: false + Preserve_invalid: false + # Replaces these join addresses with unknown + Filter_out_from_data: + - "play.example.com" # ----------------------------------------------------- # Supported time units: MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS # -----------------------------------------------------