diff --git a/Plan/api/src/main/java/com/djrapitops/plan/extension/icon/Icon.java b/Plan/api/src/main/java/com/djrapitops/plan/extension/icon/Icon.java index af66c0b1a..277510d6e 100644 --- a/Plan/api/src/main/java/com/djrapitops/plan/extension/icon/Icon.java +++ b/Plan/api/src/main/java/com/djrapitops/plan/extension/icon/Icon.java @@ -68,6 +68,11 @@ public class Icon { this.color = color; } + @Override + public String toString() { + return "Icon{" + type.name() + ", '" + name + '\'' + ", " + color.name() + '}'; + } + public static class Builder { private final Icon icon; diff --git a/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/results/player/ExtensionPlayerData.java b/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/results/player/ExtensionPlayerData.java index d500c6640..94be2a636 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/results/player/ExtensionPlayerData.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/results/player/ExtensionPlayerData.java @@ -25,7 +25,7 @@ import java.util.List; * * @author Rsl1122 */ -public class ExtensionPlayerData { +public class ExtensionPlayerData implements Comparable { private final int pluginID; @@ -47,10 +47,19 @@ public class ExtensionPlayerData { return extensionInformation; } + public boolean hasOnlyGenericTab() { + return tabs.size() == 1 && tabs.get(0).getTabInformation().getTabName().isEmpty(); + } + public List getTabs() { return tabs; } + @Override + public int compareTo(ExtensionPlayerData o) { + return String.CASE_INSENSITIVE_ORDER.compare(this.extensionInformation.getPluginName(), o.extensionInformation.getPluginName()); + } + public static class Factory { private final ExtensionPlayerData data; diff --git a/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/results/player/ExtensionTabData.java b/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/results/player/ExtensionTabData.java index 473f2c16a..cbaad10c0 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/results/player/ExtensionTabData.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/results/player/ExtensionTabData.java @@ -50,6 +50,10 @@ public class ExtensionTabData implements Comparable { stringData = new HashMap<>(); } + public TabInformation getTabInformation() { + return tabInformation; + } + public List getValueOrder() { return order; } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/storage/queries/ExtensionPlayerDataQuery.java b/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/storage/queries/ExtensionPlayerDataQuery.java index bc60de8dc..5079192ea 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/storage/queries/ExtensionPlayerDataQuery.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/storage/queries/ExtensionPlayerDataQuery.java @@ -105,9 +105,9 @@ public class ExtensionPlayerDataQuery implements Query { return name; } + public String getIdentifiableName() { + return !"Plan".equalsIgnoreCase(name) ? name : "Server " + id; + } + public void setName(String name) { this.name = name; } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/response/pages/InspectPageResponse.java b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/response/pages/InspectPageResponse.java index a52ff1225..c6669e137 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/response/pages/InspectPageResponse.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/response/pages/InspectPageResponse.java @@ -21,10 +21,7 @@ import com.djrapitops.plan.system.webserver.cache.ResponseCache; import com.djrapitops.plan.system.webserver.response.pages.parts.InspectPagePluginsContent; import org.apache.commons.text.StringSubstitutor; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.UUID; +import java.util.*; /** * @author Rsl1122 @@ -42,11 +39,12 @@ public class InspectPageResponse extends PageResponse { @Override public String getContent() { Map replaceMap = new HashMap<>(); - InspectPagePluginsContent pluginsTab = (InspectPagePluginsContent) - ResponseCache.loadResponse(PageId.PLAYER_PLUGINS_TAB.of(uuid)); - String[] inspectPagePluginsTab = pluginsTab != null ? pluginsTab.getContents() : getCalculating(); - replaceMap.put("navPluginsTabs", inspectPagePluginsTab[0]); - replaceMap.put("pluginsTabs", inspectPagePluginsTab[1]); + // PluginData compatibility + Optional pluginsTab = Optional.ofNullable((InspectPagePluginsContent) ResponseCache.loadResponse(PageId.PLAYER_PLUGINS_TAB.of(uuid))) + .map(InspectPagePluginsContent::getContents); + + replaceMap.put("navPluginsTabs", pluginsTab.map(nav -> nav[0]).orElse("")); + replaceMap.put("pluginsTabs", pluginsTab.map(tab -> tab[1]).orElse("")); return StringSubstitutor.replace(super.getContent(), replaceMap); } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/response/pages/parts/InspectPagePluginsContent.java b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/response/pages/parts/InspectPagePluginsContent.java index 927ce652c..d4c3cf9ff 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/response/pages/parts/InspectPagePluginsContent.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/response/pages/parts/InspectPagePluginsContent.java @@ -39,15 +39,15 @@ import java.util.*; public class InspectPagePluginsContent extends PageResponse { // ServerUUID, {nav, html} - private final Map pluginsTab; + private final Map pluginsTab; public InspectPagePluginsContent() { pluginsTab = new HashMap<>(); } - public InspectPagePluginsContent(UUID serverUUID, String nav, String html) { + public InspectPagePluginsContent(String nav, String html) { pluginsTab = new HashMap<>(); - addTab(serverUUID, nav, html); + addTab(nav, html); } public static InspectPagePluginsContent generateForThisServer(UUID playerUUID, ServerInfo serverInfo, HookHandler hookHandler) { @@ -56,16 +56,16 @@ public class InspectPagePluginsContent extends PageResponse { Map containers = hookHandler.getInspectContainersFor(playerUUID); if (containers.isEmpty()) { - return new InspectPagePluginsContent(playerUUID, "
  • " + actualServerName + " (No Data)
  • ", + return new InspectPagePluginsContent("
  • " + actualServerName + " (No Data)
  • ", "
    " + "
    " + Html.CARD.parse("

    No Data (" + actualServerName + ")

    ") + "
    "); } - String nav = "
  • " + actualServerName + "
  • "; + String nav = "
  • " + actualServerName + " (Legacy)
  • "; String tab = createTab(containers); - return new InspectPagePluginsContent(serverInfo.getServerUUID(), nav, tab); + return new InspectPagePluginsContent(nav, tab); } private static String createTab(Map containers) { @@ -84,8 +84,8 @@ public class InspectPagePluginsContent extends PageResponse { return tab.toString(); } - public void addTab(UUID serverUUID, String nav, String html) { - pluginsTab.put(serverUUID, new String[]{nav, html}); + public void addTab(String nav, String html) { + pluginsTab.put(nav, new String[]{nav, html}); } public void addTab(InspectPagePluginsContent content) { diff --git a/Plan/common/src/main/java/com/djrapitops/plan/utilities/html/icon/Color.java b/Plan/common/src/main/java/com/djrapitops/plan/utilities/html/icon/Color.java index 7d41f5ef9..71fbbe1be 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/utilities/html/icon/Color.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/utilities/html/icon/Color.java @@ -16,6 +16,8 @@ */ package com.djrapitops.plan.utilities.html.icon; +import java.util.Optional; + public enum Color { RED("col-red"), PINK("col-pink"), @@ -55,6 +57,14 @@ public enum Color { return Color.BLACK; } + public static Optional getByName(String name) { + try { + return Optional.of(valueOf(name)); + } catch (IllegalArgumentException e) { + return Optional.empty(); + } + } + public String getHtmlClass() { return htmlClass; } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/utilities/html/icon/Family.java b/Plan/common/src/main/java/com/djrapitops/plan/utilities/html/icon/Family.java index 530a54389..e2ebab3ee 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/utilities/html/icon/Family.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/utilities/html/icon/Family.java @@ -16,6 +16,8 @@ */ package com.djrapitops.plan.utilities.html.icon; +import java.util.Optional; + public enum Family { SOLID(" fa fa-", "\">"), REGULAR(" far fa-", "\">"), @@ -33,4 +35,12 @@ public enum Family { public String appendAround(String color, String name) { return " getByName(String name) { + try { + return Optional.of(valueOf(name)); + } catch (IllegalArgumentException e) { + return Optional.empty(); + } + } } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/utilities/html/icon/Icon.java b/Plan/common/src/main/java/com/djrapitops/plan/utilities/html/icon/Icon.java index aed13c8d3..d36b75fb1 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/utilities/html/icon/Icon.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/utilities/html/icon/Icon.java @@ -29,6 +29,14 @@ public class Icon { color = Color.NONE; } + public static Icon fromExtensionIcon(com.djrapitops.plan.extension.icon.Icon icon) { + return new Icon( + Family.getByName(icon.getFamily().name()).orElse(Family.SOLID), + icon.getName(), + Color.getByName(icon.getColor().name()).orElse(Color.NONE) + ); + } + public Icon(Family type, String name, Color color) { this.type = type; this.name = name; diff --git a/Plan/common/src/main/java/com/djrapitops/plan/utilities/html/pages/InspectPage.java b/Plan/common/src/main/java/com/djrapitops/plan/utilities/html/pages/InspectPage.java index 9c8872a30..c4989bdb6 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/utilities/html/pages/InspectPage.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/utilities/html/pages/InspectPage.java @@ -33,6 +33,9 @@ import com.djrapitops.plan.system.settings.paths.TimeSettings; import com.djrapitops.plan.system.settings.theme.Theme; import com.djrapitops.plan.system.settings.theme.ThemeVal; import com.djrapitops.plan.system.update.VersionCheckSystem; +import com.djrapitops.plan.system.webserver.cache.PageId; +import com.djrapitops.plan.system.webserver.cache.ResponseCache; +import com.djrapitops.plan.system.webserver.response.pages.parts.InspectPagePluginsContent; import com.djrapitops.plan.utilities.comparators.SessionStartComparator; import com.djrapitops.plan.utilities.formatting.Formatter; import com.djrapitops.plan.utilities.formatting.Formatters; @@ -67,6 +70,7 @@ public class InspectPage implements Page { private final PlanFiles files; private final PlanConfig config; + private final PageFactory pageFactory; private final Theme theme; private final Graphs graphs; private final HtmlTables tables; @@ -85,6 +89,7 @@ public class InspectPage implements Page { VersionCheckSystem versionCheckSystem, PlanFiles files, PlanConfig config, + PageFactory pageFactory, Theme theme, Graphs graphs, HtmlTables tables, @@ -98,6 +103,7 @@ public class InspectPage implements Page { this.versionCheckSystem = versionCheckSystem; this.files = files; this.config = config; + this.pageFactory = pageFactory; this.theme = theme; this.graphs = graphs; this.tables = tables; @@ -131,7 +137,7 @@ public class InspectPage implements Page { public String parse(PlayerContainer player, UUID serverUUID, Map serverNames) throws IOException { long now = System.currentTimeMillis(); - UUID uuid = player.getUnsafe(PlayerKeys.UUID); + UUID playerUUID = player.getUnsafe(PlayerKeys.UUID); PlaceholderReplacer replacer = new PlaceholderReplacer(); @@ -142,7 +148,7 @@ public class InspectPage implements Page { replacer.put("timeZone", config.getTimeZoneOffsetHours()); boolean online = false; - Optional activeSession = SessionCache.getCachedSession(uuid); + Optional activeSession = SessionCache.getCachedSession(playerUUID); if (activeSession.isPresent()) { Session session = activeSession.get(); session.setSessionID(Integer.MAX_VALUE); @@ -259,6 +265,12 @@ public class InspectPage implements Page { replacer.put("backButton", "
  • arrow_backstorage
  • "); } + InspectPluginTab pluginTabs = pageFactory.inspectPluginTabs(playerUUID); + + // Legacy PluginData support until moved to database. + InspectPagePluginsContent pluginsTab = (InspectPagePluginsContent) ResponseCache.loadResponse(PageId.PLAYER_PLUGINS_TAB.of(playerUUID), InspectPagePluginsContent::new); + pluginsTab.addTab(new InspectPagePluginsContent(pluginTabs.getNav(), pluginTabs.getTab())); + return replacer.apply(files.readCustomizableResourceFlat("web/player.html")); } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/utilities/html/pages/InspectPluginTab.java b/Plan/common/src/main/java/com/djrapitops/plan/utilities/html/pages/InspectPluginTab.java new file mode 100644 index 000000000..6229497cb --- /dev/null +++ b/Plan/common/src/main/java/com/djrapitops/plan/utilities/html/pages/InspectPluginTab.java @@ -0,0 +1,168 @@ +/* + * This file is part of Player Analytics (Plan). + * + * Plan is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License v3 as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Plan is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Plan. If not, see . + */ +package com.djrapitops.plan.utilities.html.pages; + +import com.djrapitops.plan.extension.FormatType; +import com.djrapitops.plan.extension.implementation.TabInformation; +import com.djrapitops.plan.extension.implementation.results.player.ExtensionDescriptive; +import com.djrapitops.plan.extension.implementation.results.player.ExtensionInformation; +import com.djrapitops.plan.extension.implementation.results.player.ExtensionPlayerData; +import com.djrapitops.plan.extension.implementation.results.player.ExtensionTabData; +import com.djrapitops.plan.utilities.formatting.Formatter; +import com.djrapitops.plan.utilities.formatting.Formatters; +import com.djrapitops.plan.utilities.html.Html; +import com.djrapitops.plan.utilities.html.icon.Icon; +import com.djrapitops.plan.utilities.html.structure.TabsElement; + +import java.util.*; + +/** + * Responsible for generating /player page plugin tabs based on DataExtension API data. + * + * @author Rsl1122 + */ +public class InspectPluginTab implements Comparable { + + private String serverName; + private List data; + + private Map> numberFormatters; + + private Formatter decimalFormatter; + private Formatter percentageFormatter; + + private String nav; + private String tab; + + public InspectPluginTab(String nav, String tab) { + this.nav = nav; + this.tab = tab; + } + + public InspectPluginTab( + String serverName, + List data, + Formatters formatters + ) { + this.serverName = serverName; + this.data = data; + + numberFormatters = new EnumMap<>(FormatType.class); + numberFormatters.put(FormatType.DATE_SECOND, formatters.secondLong()); + numberFormatters.put(FormatType.DATE_YEAR, formatters.yearLong()); + numberFormatters.put(FormatType.TIME_MILLISECONDS, formatters.timeAmount()); + numberFormatters.put(FormatType.NONE, Object::toString); + + this.decimalFormatter = formatters.decimals(); + this.percentageFormatter = formatters.percentage(); + + generate(); + } + + public String getNav() { + return nav; + } + + public String getTab() { + return tab; + } + + private void generate() { + if (data.isEmpty()) { + nav = "
  • " + serverName + " (No Data)
  • "; + tab = "
    " + + "
    " + Html.CARD.parse("

    No Data (" + serverName + ")

    ") + + "
    "; + } else { + nav = "
  • " + serverName + "
  • "; + tab = generatePageTab(); + } + } + + private String generatePageTab() { + Collections.sort(data); + + StringBuilder tabBuilder = new StringBuilder(); + + for (ExtensionPlayerData datum : data) { + ExtensionInformation extensionInformation = datum.getExtensionInformation(); + + boolean onlyGeneric = datum.hasOnlyGenericTab(); + + String tabsElement; + if (onlyGeneric) { + ExtensionTabData genericTabData = datum.getTabs().get(0); + tabsElement = Html.BODY.parse(parseDataHtml(genericTabData)); + } else { + tabsElement = new TabsElement( + datum.getTabs().stream().map(this::wrapToTabElementTab).toArray(TabsElement.Tab[]::new) + ).toHtmlFull(); + } + + tabBuilder.append(wrapInContainer(extensionInformation, tabsElement)); + } + + return wrapInTab(tabBuilder.toString()); + } + + private String wrapInTab(String content) { + return "
    " + content + "
    "; + } + + private TabsElement.Tab wrapToTabElementTab(ExtensionTabData tabData) { + TabInformation tabInformation = tabData.getTabInformation(); + + return new TabsElement.Tab(tabInformation.getTabName(), parseDataHtml(tabData)); + } + + private String parseDataHtml(ExtensionTabData tabData) { + StringBuilder builder = new StringBuilder(); + for (String key : tabData.getValueOrder()) { + tabData.getBoolean(key).ifPresent(data -> append(builder, data.getDescriptive(), data.getFormattedValue())); + tabData.getDouble(key).ifPresent(data -> append(builder, data.getDescriptive(), data.getFormattedValue(decimalFormatter))); + tabData.getPercentage(key).ifPresent(data -> append(builder, data.getDescriptive(), data.getFormattedValue(percentageFormatter))); + tabData.getNumber(key).ifPresent(data -> append(builder, data.getDescriptive(), data.getFormattedValue(numberFormatters.get(data.getFormatType())))); + tabData.getString(key).ifPresent(data -> append(builder, data.getDescriptive(), data.getFormattedValue())); + } + return builder.toString(); + } + + private void append(StringBuilder builder, ExtensionDescriptive descriptive, String formattedValue) { + Optional description = descriptive.getDescription(); + if (description.isPresent()) { + builder.append("

    "); + } else { + builder.append("

    "); + } + builder.append(Icon.fromExtensionIcon(descriptive.getIcon())) + .append(' ').append(descriptive.getText()).append(": ").append(formattedValue).append("

    "); + } + + private String wrapInContainer(ExtensionInformation information, String tabsElement) { + return "
    " + + "
    " + + "

    " + Icon.fromExtensionIcon(information.getIcon()) + ' ' + information.getPluginName() + "

    " + + "
    " + + tabsElement + + "
    "; + } + + @Override + public int compareTo(InspectPluginTab other) { + return String.CASE_INSENSITIVE_ORDER.compare(this.serverName, other.serverName); + } +} \ No newline at end of file diff --git a/Plan/common/src/main/java/com/djrapitops/plan/utilities/html/pages/PageFactory.java b/Plan/common/src/main/java/com/djrapitops/plan/utilities/html/pages/PageFactory.java index 6a86427fe..3ecf74e99 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/utilities/html/pages/PageFactory.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/utilities/html/pages/PageFactory.java @@ -23,9 +23,12 @@ import com.djrapitops.plan.data.store.containers.PlayerContainer; import com.djrapitops.plan.db.Database; import com.djrapitops.plan.db.access.queries.containers.ContainerFetchQueries; import com.djrapitops.plan.db.access.queries.objects.ServerQueries; +import com.djrapitops.plan.extension.implementation.results.player.ExtensionPlayerData; +import com.djrapitops.plan.extension.implementation.storage.queries.ExtensionPlayerDataQuery; import com.djrapitops.plan.system.database.DBSystem; import com.djrapitops.plan.system.file.PlanFiles; import com.djrapitops.plan.system.info.connection.ConnectionSystem; +import com.djrapitops.plan.system.info.server.Server; import com.djrapitops.plan.system.info.server.ServerInfo; import com.djrapitops.plan.system.settings.config.PlanConfig; import com.djrapitops.plan.system.settings.theme.Theme; @@ -43,8 +46,7 @@ import dagger.Lazy; import javax.inject.Inject; import javax.inject.Singleton; -import java.util.Map; -import java.util.UUID; +import java.util.*; /** * Factory for creating different {@link Page} objects. @@ -130,19 +132,52 @@ public class PageFactory { return new AnalysisPage(analysisContainer, connectionSystem.get(), versionCheckSystem.get(), fileSystem.get(), formatters.get().decimals(), timings.get()); } - public InspectPage inspectPage(UUID uuid) { + public InspectPage inspectPage(UUID playerUUID) { Database db = dbSystem.get().getDatabase(); - PlayerContainer player = db.query(ContainerFetchQueries.fetchPlayerContainer(uuid)); + PlayerContainer player = db.query(ContainerFetchQueries.fetchPlayerContainer(playerUUID)); Map serverNames = db.query(ServerQueries.fetchServerNames()); return new InspectPage( player, serverNames, versionCheckSystem.get(), - fileSystem.get(), config.get(), theme.get(), + fileSystem.get(), config.get(), this, theme.get(), graphs.get(), tables.get(), accordions.get(), formatters.get(), serverInfo.get(), timings.get() ); } + public InspectPluginTab inspectPluginTabs(UUID playerUUID) { + Database database = dbSystem.get().getDatabase(); + + Map> extensionPlayerData = database.query(new ExtensionPlayerDataQuery(playerUUID)); + + if (extensionPlayerData.isEmpty()) { + return new InspectPluginTab("No Extensions", Collections.emptyList(), formatters.get()); + } + + List inspectPluginTabs = new ArrayList<>(); + for (Map.Entry entry : database.query(ServerQueries.fetchPlanServerInformation()).entrySet()) { + UUID serverUUID = entry.getKey(); + String serverName = entry.getValue().getIdentifiableName(); + + List ofServer = extensionPlayerData.get(serverUUID); + if (ofServer == null) { + continue; + } + + inspectPluginTabs.add(new InspectPluginTab(serverName, ofServer, formatters.get())); + } + + StringBuilder navs = new StringBuilder(); + StringBuilder tabs = new StringBuilder(); + + inspectPluginTabs.stream().sorted().forEach(tab -> { + navs.append(tab.getNav()); + tabs.append(tab.getTab()); + }); + + return new InspectPluginTab(navs.toString(), tabs.toString()); + } + @Deprecated public InspectPagePluginsContent inspectPagePluginsContent(UUID playerUUID) { return InspectPagePluginsContent.generateForThisServer(playerUUID, serverInfo.get(), hookHandler.get());