mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2025-02-05 16:30:24 +08:00
JSON parser for player table data
This commit is contained in:
parent
7b5739995e
commit
71250c3d65
@ -64,8 +64,9 @@ public class Icon {
|
||||
return color;
|
||||
}
|
||||
|
||||
public void setColor(Color color) {
|
||||
public Icon setColor(Color color) {
|
||||
this.color = color;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -39,6 +39,7 @@ public class ExtensionTabData implements Comparable<ExtensionTabData> {
|
||||
private final List<ExtensionTableData> tableData;
|
||||
|
||||
private List<String> order;
|
||||
private List<ExtensionDescriptive> descriptives;
|
||||
|
||||
// Table and Graph data will be added later.
|
||||
|
||||
@ -52,6 +53,7 @@ public class ExtensionTabData implements Comparable<ExtensionTabData> {
|
||||
stringData = new HashMap<>();
|
||||
|
||||
tableData = new ArrayList<>();
|
||||
descriptives = new ArrayList<>();
|
||||
}
|
||||
|
||||
public TabInformation getTabInformation() {
|
||||
@ -86,6 +88,17 @@ public class ExtensionTabData implements Comparable<ExtensionTabData> {
|
||||
return tableData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all Descriptives for this tabs data.
|
||||
* <p>
|
||||
* Only available after the Tab has been built.
|
||||
*
|
||||
* @return List of {@link ExtensionDescriptive}s.
|
||||
*/
|
||||
public List<ExtensionDescriptive> getDescriptives() {
|
||||
return descriptives;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(ExtensionTabData other) {
|
||||
return Integer.compare(this.tabInformation.getTabPriority(), other.tabInformation.getTabPriority()); // Lower is first
|
||||
@ -118,7 +131,6 @@ public class ExtensionTabData implements Comparable<ExtensionTabData> {
|
||||
}
|
||||
|
||||
private void createOrderingList() {
|
||||
List<ExtensionDescriptive> descriptives = new ArrayList<>();
|
||||
booleanData.values().stream().map(ExtensionData::getDescriptive).forEach(descriptives::add);
|
||||
doubleData.values().stream().map(ExtensionData::getDescriptive).forEach(descriptives::add);
|
||||
percentageData.values().stream().map(ExtensionData::getDescriptive).forEach(descriptives::add);
|
||||
|
@ -14,7 +14,6 @@ public class JSONResponse<T> extends Response {
|
||||
|
||||
public JSONResponse(T object) {
|
||||
super(ResponseType.JSON);
|
||||
|
||||
super.setHeader("HTTP/1.1 200 OK");
|
||||
|
||||
try {
|
||||
@ -27,4 +26,10 @@ public class JSONResponse<T> extends Response {
|
||||
super.setContent("{\"error\":\"Gson for json responses not available on this server: " + e.toString() + "\"}");
|
||||
}
|
||||
}
|
||||
|
||||
public JSONResponse(String jsonString) {
|
||||
super(ResponseType.JSON);
|
||||
super.setHeader("HTTP/1.1 200 OK");
|
||||
super.setContent(jsonString);
|
||||
}
|
||||
}
|
@ -0,0 +1,235 @@
|
||||
package com.djrapitops.plan.utilities.html.tables;
|
||||
|
||||
import com.djrapitops.plan.api.PlanAPI;
|
||||
import com.djrapitops.plan.data.container.GeoInfo;
|
||||
import com.djrapitops.plan.data.store.containers.PlayerContainer;
|
||||
import com.djrapitops.plan.data.store.keys.PlayerKeys;
|
||||
import com.djrapitops.plan.data.store.mutators.ActivityIndex;
|
||||
import com.djrapitops.plan.data.store.mutators.GeoInfoMutator;
|
||||
import com.djrapitops.plan.data.store.mutators.SessionsMutator;
|
||||
import com.djrapitops.plan.extension.FormatType;
|
||||
import com.djrapitops.plan.extension.icon.Color;
|
||||
import com.djrapitops.plan.extension.implementation.results.*;
|
||||
import com.djrapitops.plan.utilities.comparators.PlayerContainerLastPlayedComparator;
|
||||
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.Family;
|
||||
import com.djrapitops.plan.utilities.html.icon.Icon;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Parsing utility for creating jQuery Datatables JSON for a Players Table.
|
||||
* <p>
|
||||
* See https://www.datatables.net/manual/data/orthogonal-data#HTML-5 for sort kinds
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class PlayersTableJSONParser {
|
||||
|
||||
private final List<PlayerContainer> players;
|
||||
private final List<ExtensionDescriptive> extensionDescriptives;
|
||||
private final Map<UUID, ExtensionTabData> extensionData;
|
||||
|
||||
private final int maxPlayers;
|
||||
private final long activeMsThreshold;
|
||||
private final int activeLoginThreshold;
|
||||
private final boolean openPlayerPageInNewTab;
|
||||
|
||||
private Map<FormatType, Formatter<Long>> numberFormatters;
|
||||
|
||||
private Formatter<Double> decimalFormatter;
|
||||
private Formatter<Double> percentageFormatter;
|
||||
|
||||
public PlayersTableJSONParser(
|
||||
// Data
|
||||
List<PlayerContainer> players,
|
||||
Map<UUID, ExtensionTabData> extensionData,
|
||||
// Settings
|
||||
int maxPlayers, long activeMsThreshold, int activeLoginThreshold, boolean openPlayerPageInNewTab,
|
||||
// Formatters
|
||||
Formatters formatters
|
||||
) {
|
||||
// Data
|
||||
this.players = players;
|
||||
this.extensionData = extensionData;
|
||||
extensionDescriptives = extensionData.values().stream()
|
||||
.map(ExtensionTabData::getDescriptives)
|
||||
.flatMap(Collection::stream)
|
||||
.distinct().sorted()
|
||||
.collect(Collectors.toList());
|
||||
// Settings
|
||||
this.maxPlayers = maxPlayers;
|
||||
this.activeMsThreshold = activeMsThreshold;
|
||||
this.activeLoginThreshold = activeLoginThreshold;
|
||||
this.openPlayerPageInNewTab = openPlayerPageInNewTab;
|
||||
// Formatters
|
||||
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();
|
||||
|
||||
}
|
||||
|
||||
public String toJSONString() {
|
||||
String data = parseData();
|
||||
String columnHeaders = parseColumnHeaders();
|
||||
return "{columns:" + columnHeaders + ",data:" + data + '}';
|
||||
}
|
||||
|
||||
private String parseData() {
|
||||
StringBuilder dataJSON = new StringBuilder("[");
|
||||
|
||||
PlanAPI planAPI = PlanAPI.getInstance();
|
||||
long now = System.currentTimeMillis();
|
||||
players.sort(new PlayerContainerLastPlayedComparator());
|
||||
|
||||
int currentPlayerNumber = 0;
|
||||
for (PlayerContainer player : players) {
|
||||
if (currentPlayerNumber >= maxPlayers) {
|
||||
break;
|
||||
}
|
||||
|
||||
UUID playerUUID = player.getValue(PlayerKeys.UUID).orElse(null);
|
||||
if (playerUUID == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
appendPlayerData(dataJSON, planAPI, now, player);
|
||||
appendExtensionData(dataJSON, extensionData.get(playerUUID));
|
||||
|
||||
currentPlayerNumber++;
|
||||
}
|
||||
return dataJSON.append(']').toString();
|
||||
}
|
||||
|
||||
private void appendPlayerData(StringBuilder dataJSON, PlanAPI planAPI, long now, PlayerContainer player) {
|
||||
String name = player.getValue(PlayerKeys.NAME).orElse("Unknown");
|
||||
String url = planAPI.getPlayerInspectPageLink(name);
|
||||
|
||||
SessionsMutator sessionsMutator = SessionsMutator.forContainer(player);
|
||||
int loginTimes = sessionsMutator.count();
|
||||
long playtime = sessionsMutator.toPlaytime();
|
||||
long registered = player.getValue(PlayerKeys.REGISTERED).orElse(0L);
|
||||
long lastSeen = sessionsMutator.toLastSeen();
|
||||
|
||||
ActivityIndex activityIndex = player.getActivityIndex(now, activeMsThreshold, activeLoginThreshold);
|
||||
boolean isBanned = player.getValue(PlayerKeys.BANNED).orElse(false);
|
||||
String activityString = activityIndex.getFormattedValue(decimalFormatter)
|
||||
+ (isBanned ? " (<b>Banned</b>)" : " (" + activityIndex.getGroup() + ")");
|
||||
|
||||
String geolocation = GeoInfoMutator.forContainer(player).mostRecent().map(GeoInfo::getGeolocation).orElse("-");
|
||||
|
||||
Html link = openPlayerPageInNewTab ? Html.LINK_EXTERNAL : Html.LINK;
|
||||
|
||||
appendData(dataJSON,
|
||||
'"' + link.parse(url, name) + '"',
|
||||
"{display:\"" + activityString + "\",sort: " + activityIndex + '}',
|
||||
"{display:\"" + numberFormatters.get(FormatType.TIME_MILLISECONDS).apply(playtime) + "\",sort: " + playtime + '}',
|
||||
loginTimes,
|
||||
"{display:\"" + numberFormatters.get(FormatType.DATE_YEAR).apply(registered) + "\",sort: " + registered + '}',
|
||||
"{display:\"" + numberFormatters.get(FormatType.DATE_YEAR).apply(lastSeen) + "\",sort: " + lastSeen + '}',
|
||||
geolocation
|
||||
);
|
||||
}
|
||||
|
||||
private void appendExtensionData(StringBuilder dataJSON, ExtensionTabData tabData) {
|
||||
for (ExtensionDescriptive descriptive : extensionDescriptives) {
|
||||
dataJSON.append(',');
|
||||
String key = descriptive.getName();
|
||||
|
||||
// If it's a double, append a double
|
||||
Optional<ExtensionDoubleData> doubleValue = tabData.getDouble(key);
|
||||
if (doubleValue.isPresent()) {
|
||||
dataJSON.append(doubleValue.get().getFormattedValue(decimalFormatter));
|
||||
continue;
|
||||
}
|
||||
|
||||
// If it's a percentage, append a percentage
|
||||
Optional<ExtensionDoubleData> percentageValue = tabData.getPercentage(key);
|
||||
if (percentageValue.isPresent()) {
|
||||
dataJSON.append(percentageValue.get().getFormattedValue(percentageFormatter));
|
||||
continue;
|
||||
}
|
||||
|
||||
Optional<ExtensionNumberData> numberValue = tabData.getNumber(key);
|
||||
if (numberValue.isPresent()) {
|
||||
ExtensionNumberData numberData = numberValue.get();
|
||||
FormatType formatType = numberData.getFormatType();
|
||||
if (formatType == FormatType.NONE) {
|
||||
// If it's a number, append a number
|
||||
dataJSON.append(numberData.getFormattedValue(numberFormatters.get(formatType)));
|
||||
} else {
|
||||
// If it's a formatted number, append a formatted number and sort by the number value
|
||||
dataJSON.append("{display: \"").append(numberData.getFormattedValue(numberFormatters.get(formatType)))
|
||||
.append("\",sort: ").append(numberData.getRawValue()).append('}');
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// If it's a String append a String, otherwise the player has no value for this extension provider.
|
||||
String stringValue = tabData.getString(key).map(ExtensionStringData::getFormattedValue).orElse("-");
|
||||
dataJSON.append('"').append(stringValue).append('"');
|
||||
}
|
||||
}
|
||||
|
||||
private String getValue(ExtensionTabData tabData, String key) {
|
||||
tabData.getPercentage(key).map(data -> data.getFormattedValue(percentageFormatter));
|
||||
tabData.getNumber(key).map(data -> data.getFormattedValue(numberFormatters.get(data.getFormatType())));
|
||||
tabData.getString(key).map(ExtensionStringData::getFormattedValue);
|
||||
|
||||
return "-";
|
||||
}
|
||||
|
||||
private void appendData(StringBuilder dataJSON, Serializable... dataRows) {
|
||||
int max = dataRows.length;
|
||||
for (int i = 0; i < max; i++) {
|
||||
dataJSON.append("{").append(dataRows[i]).append("}");
|
||||
if (i < max - 1) {
|
||||
dataJSON.append(',');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String parseColumnHeaders() {
|
||||
StringBuilder columnHeaders = new StringBuilder("[");
|
||||
|
||||
appendDataHeaders(columnHeaders,
|
||||
Icon.called("user") + " Name",
|
||||
Icon.called("check") + " Activity Index",
|
||||
Icon.called("clock").of(Family.REGULAR) + " Playtime",
|
||||
Icon.called("calendar-plus").of(Family.REGULAR) + " Sessions",
|
||||
Icon.called("user-plus") + " Registered",
|
||||
Icon.called("calendar-check").of(Family.REGULAR) + " Last Seen",
|
||||
Icon.called("globe") + " Geolocation"
|
||||
);
|
||||
|
||||
appendExtensionHeaders(columnHeaders);
|
||||
|
||||
return columnHeaders.append(']').toString();
|
||||
}
|
||||
|
||||
private void appendDataHeaders(StringBuilder columnHeaders, Serializable... headers) {
|
||||
int max = headers.length;
|
||||
for (int i = 0; i < max; i++) {
|
||||
columnHeaders.append("{title: \"").append(headers[i]).append("\"}");
|
||||
if (i < max - 1) {
|
||||
columnHeaders.append(',');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void appendExtensionHeaders(StringBuilder columnHeaders) {
|
||||
for (ExtensionDescriptive provider : extensionDescriptives) {
|
||||
columnHeaders.append(',');
|
||||
columnHeaders.append(Icon.fromExtensionIcon(provider.getIcon().setColor(Color.NONE)).toHtml()).append(' ').append(provider.getText());
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user