mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2025-01-06 15:44:49 +08:00
/server Players table data JSON response
Data access points at - /json/players?serverName=Name of the server (Preferred) - /json/players?serverUUID=UUID of the server (Avoid) Data format (JSON): {columns: [{title}, ...], data: [[...rows for columns], [...row2], ...]} This access point should not be considered an API. serverUUID parameter should be avoided until Server-Bungee connection system has been removed due to possible XSS Attack https://github.com/plan-player-analytics/Plan/issues/840
This commit is contained in:
parent
ebb4314ab9
commit
e035dc67fc
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package com.djrapitops.plan.db.access.queries.containers;
|
||||||
|
|
||||||
|
import com.djrapitops.plan.data.container.BaseUser;
|
||||||
|
import com.djrapitops.plan.data.container.GeoInfo;
|
||||||
|
import com.djrapitops.plan.data.container.Session;
|
||||||
|
import com.djrapitops.plan.data.store.containers.PlayerContainer;
|
||||||
|
import com.djrapitops.plan.data.store.keys.PlayerKeys;
|
||||||
|
import com.djrapitops.plan.db.SQLDB;
|
||||||
|
import com.djrapitops.plan.db.access.Query;
|
||||||
|
import com.djrapitops.plan.db.access.queries.objects.BaseUserQueries;
|
||||||
|
import com.djrapitops.plan.db.access.queries.objects.GeoInfoQueries;
|
||||||
|
import com.djrapitops.plan.db.access.queries.objects.SessionQueries;
|
||||||
|
import com.djrapitops.plan.db.access.queries.objects.UserInfoQueries;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optimized version of {@link ServerPlayerContainersQuery} for /server page Players table.
|
||||||
|
*
|
||||||
|
* @author Rsl1122
|
||||||
|
* @see com.djrapitops.plan.utilities.html.tables.PlayersTableJSONParser For what needs to be included.
|
||||||
|
*/
|
||||||
|
public class ServerPlayersTableContainersQuery implements Query<List<PlayerContainer>> {
|
||||||
|
|
||||||
|
private final UUID serverUUID;
|
||||||
|
|
||||||
|
public ServerPlayersTableContainersQuery(UUID serverUUID) {
|
||||||
|
this.serverUUID = serverUUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PlayerContainer> executeQuery(SQLDB db) {
|
||||||
|
List<PlayerContainer> containers = new ArrayList<>();
|
||||||
|
|
||||||
|
Collection<BaseUser> baseUsers = db.query(BaseUserQueries.fetchServerBaseUsers(serverUUID));
|
||||||
|
|
||||||
|
Map<UUID, List<GeoInfo>> geoInformation = db.query(GeoInfoQueries.fetchServerGeoInformation(serverUUID));
|
||||||
|
Map<UUID, List<Session>> sessions = db.query(SessionQueries.fetchSessionsOfServer(serverUUID));
|
||||||
|
Set<UUID> bannedUsers = db.query(UserInfoQueries.fetchBannedUUIDsOfServer(serverUUID));
|
||||||
|
|
||||||
|
for (BaseUser user : baseUsers) {
|
||||||
|
PlayerContainer container = new PlayerContainer();
|
||||||
|
|
||||||
|
// BaseUser
|
||||||
|
UUID uuid = user.getUuid();
|
||||||
|
container.putRawData(PlayerKeys.UUID, uuid);
|
||||||
|
container.putRawData(PlayerKeys.NAME, user.getName());
|
||||||
|
container.putRawData(PlayerKeys.REGISTERED, user.getRegistered());
|
||||||
|
container.putRawData(PlayerKeys.BANNED, bannedUsers.contains(uuid));
|
||||||
|
|
||||||
|
// GeoInfo
|
||||||
|
container.putRawData(PlayerKeys.GEO_INFO, geoInformation.getOrDefault(uuid, new ArrayList<>()));
|
||||||
|
|
||||||
|
container.putCachingSupplier(PlayerKeys.SESSIONS, () -> {
|
||||||
|
List<Session> playerSessions = sessions.getOrDefault(uuid, new ArrayList<>());
|
||||||
|
container.getValue(PlayerKeys.ACTIVE_SESSION).ifPresent(playerSessions::add);
|
||||||
|
return playerSessions;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
containers.add(container);
|
||||||
|
}
|
||||||
|
return containers;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -114,6 +114,12 @@ public class UserInfoQueries {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query database for all User information of a specific server.
|
||||||
|
*
|
||||||
|
* @param serverUUID UUID of the Plan server.
|
||||||
|
* @return Map: Player UUID - user information
|
||||||
|
*/
|
||||||
public static Query<Map<UUID, UserInfo>> fetchUserInformationOfServer(UUID serverUUID) {
|
public static Query<Map<UUID, UserInfo>> fetchUserInformationOfServer(UUID serverUUID) {
|
||||||
String sql = SELECT +
|
String sql = SELECT +
|
||||||
UserInfoTable.REGISTERED + ", " +
|
UserInfoTable.REGISTERED + ", " +
|
||||||
@ -146,4 +152,34 @@ public class UserInfoQueries {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query database for UUIDs of banned players on a server.
|
||||||
|
*
|
||||||
|
* @param serverUUID UUID of the Plan server.
|
||||||
|
* @return Set: Player UUID of a banned player.
|
||||||
|
*/
|
||||||
|
public static Query<Set<UUID>> fetchBannedUUIDsOfServer(UUID serverUUID) {
|
||||||
|
String sql = SELECT +
|
||||||
|
UserInfoTable.USER_UUID +
|
||||||
|
FROM + UserInfoTable.TABLE_NAME +
|
||||||
|
WHERE + UserInfoTable.SERVER_UUID + "=?" +
|
||||||
|
AND + UserInfoTable.BANNED + "=?";
|
||||||
|
return new QueryStatement<Set<UUID>>(sql, 1000) {
|
||||||
|
@Override
|
||||||
|
public void prepare(PreparedStatement statement) throws SQLException {
|
||||||
|
statement.setString(1, serverUUID.toString());
|
||||||
|
statement.setBoolean(2, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<UUID> processResults(ResultSet set) throws SQLException {
|
||||||
|
Set<UUID> bannedUsers = new HashSet<>();
|
||||||
|
while (set.next()) {
|
||||||
|
bannedUsers.add(UUID.fromString(set.getString(UserInfoTable.USER_UUID)));
|
||||||
|
}
|
||||||
|
return bannedUsers;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
@ -40,4 +40,8 @@ public class ExtensionDoubleData implements ExtensionData {
|
|||||||
public String getFormattedValue(Formatter<Double> formatter) {
|
public String getFormattedValue(Formatter<Double> formatter) {
|
||||||
return formatter.apply(value);
|
return formatter.apply(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double getRawValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
}
|
}
|
@ -23,6 +23,7 @@ import com.djrapitops.plan.system.webserver.auth.Authentication;
|
|||||||
import com.djrapitops.plan.system.webserver.cache.PageId;
|
import com.djrapitops.plan.system.webserver.cache.PageId;
|
||||||
import com.djrapitops.plan.system.webserver.cache.ResponseCache;
|
import com.djrapitops.plan.system.webserver.cache.ResponseCache;
|
||||||
import com.djrapitops.plan.system.webserver.pages.*;
|
import com.djrapitops.plan.system.webserver.pages.*;
|
||||||
|
import com.djrapitops.plan.system.webserver.pages.json.RootJSONHandler;
|
||||||
import com.djrapitops.plan.system.webserver.response.Response;
|
import com.djrapitops.plan.system.webserver.response.Response;
|
||||||
import com.djrapitops.plan.system.webserver.response.ResponseFactory;
|
import com.djrapitops.plan.system.webserver.response.ResponseFactory;
|
||||||
import com.djrapitops.plan.system.webserver.response.errors.BadRequestResponse;
|
import com.djrapitops.plan.system.webserver.response.errors.BadRequestResponse;
|
||||||
@ -32,9 +33,6 @@ import dagger.Lazy;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,6 +48,7 @@ public class ResponseHandler extends TreePageHandler {
|
|||||||
private final PlayerPageHandler playerPageHandler;
|
private final PlayerPageHandler playerPageHandler;
|
||||||
private final ServerPageHandler serverPageHandler;
|
private final ServerPageHandler serverPageHandler;
|
||||||
private final InfoRequestPageHandler infoRequestPageHandler;
|
private final InfoRequestPageHandler infoRequestPageHandler;
|
||||||
|
private final RootJSONHandler rootJSONHandler;
|
||||||
private final ErrorHandler errorHandler;
|
private final ErrorHandler errorHandler;
|
||||||
|
|
||||||
private Lazy<WebServer> webServer;
|
private Lazy<WebServer> webServer;
|
||||||
@ -64,6 +63,7 @@ public class ResponseHandler extends TreePageHandler {
|
|||||||
PlayerPageHandler playerPageHandler,
|
PlayerPageHandler playerPageHandler,
|
||||||
ServerPageHandler serverPageHandler,
|
ServerPageHandler serverPageHandler,
|
||||||
InfoRequestPageHandler infoRequestPageHandler,
|
InfoRequestPageHandler infoRequestPageHandler,
|
||||||
|
RootJSONHandler rootJSONHandler,
|
||||||
|
|
||||||
ErrorHandler errorHandler
|
ErrorHandler errorHandler
|
||||||
) {
|
) {
|
||||||
@ -74,6 +74,7 @@ public class ResponseHandler extends TreePageHandler {
|
|||||||
this.playerPageHandler = playerPageHandler;
|
this.playerPageHandler = playerPageHandler;
|
||||||
this.serverPageHandler = serverPageHandler;
|
this.serverPageHandler = serverPageHandler;
|
||||||
this.infoRequestPageHandler = infoRequestPageHandler;
|
this.infoRequestPageHandler = infoRequestPageHandler;
|
||||||
|
this.rootJSONHandler = rootJSONHandler;
|
||||||
this.errorHandler = errorHandler;
|
this.errorHandler = errorHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,14 +93,10 @@ public class ResponseHandler extends TreePageHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
registerPage("info", infoRequestPageHandler);
|
registerPage("info", infoRequestPageHandler);
|
||||||
|
registerPage("json", rootJSONHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Response getResponse(Request request) {
|
public Response getResponse(Request request) {
|
||||||
String targetString = request.getTargetString();
|
|
||||||
List<String> target = new ArrayList<>(Arrays.asList(targetString.split("/")));
|
|
||||||
if (!target.isEmpty()) {
|
|
||||||
target.remove(0);
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
return tryToGetResponse(request);
|
return tryToGetResponse(request);
|
||||||
} catch (NoServersException | NotFoundException e) {
|
} catch (NoServersException | NotFoundException e) {
|
||||||
@ -109,7 +106,7 @@ public class ResponseHandler extends TreePageHandler {
|
|||||||
} catch (ForbiddenException e) {
|
} catch (ForbiddenException e) {
|
||||||
return responseFactory.forbidden403(e.getMessage());
|
return responseFactory.forbidden403(e.getMessage());
|
||||||
} catch (BadRequestException e) {
|
} catch (BadRequestException e) {
|
||||||
return new BadRequestResponse(e.getMessage());
|
return new BadRequestResponse(e.getMessage() + " (when requesting '" + request.getTargetString() + "')");
|
||||||
} catch (UnauthorizedServerException e) {
|
} catch (UnauthorizedServerException e) {
|
||||||
return responseFactory.unauthorizedServer(e.getMessage());
|
return responseFactory.unauthorizedServer(e.getMessage());
|
||||||
} catch (GatewayException e) {
|
} catch (GatewayException e) {
|
||||||
|
@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package com.djrapitops.plan.system.webserver.pages.json;
|
||||||
|
|
||||||
|
import com.djrapitops.plan.api.exceptions.WebUserAuthException;
|
||||||
|
import com.djrapitops.plan.api.exceptions.connection.BadRequestException;
|
||||||
|
import com.djrapitops.plan.api.exceptions.connection.WebException;
|
||||||
|
import com.djrapitops.plan.db.Database;
|
||||||
|
import com.djrapitops.plan.db.access.queries.containers.ServerPlayersTableContainersQuery;
|
||||||
|
import com.djrapitops.plan.db.access.queries.objects.ServerQueries;
|
||||||
|
import com.djrapitops.plan.extension.implementation.storage.queries.ExtensionServerPlayerDataTableQuery;
|
||||||
|
import com.djrapitops.plan.system.database.DBSystem;
|
||||||
|
import com.djrapitops.plan.system.info.server.Server;
|
||||||
|
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||||
|
import com.djrapitops.plan.system.settings.paths.DisplaySettings;
|
||||||
|
import com.djrapitops.plan.system.settings.paths.TimeSettings;
|
||||||
|
import com.djrapitops.plan.system.webserver.Request;
|
||||||
|
import com.djrapitops.plan.system.webserver.RequestTarget;
|
||||||
|
import com.djrapitops.plan.system.webserver.auth.Authentication;
|
||||||
|
import com.djrapitops.plan.system.webserver.pages.PageHandler;
|
||||||
|
import com.djrapitops.plan.system.webserver.response.Response;
|
||||||
|
import com.djrapitops.plan.system.webserver.response.data.JSONResponse;
|
||||||
|
import com.djrapitops.plan.utilities.formatting.Formatters;
|
||||||
|
import com.djrapitops.plan.utilities.html.tables.PlayersTableJSONParser;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON handler for different Player table JSON requests.
|
||||||
|
*
|
||||||
|
* @author Rsl1122
|
||||||
|
* @see com.djrapitops.plan.utilities.html.tables.PlayersTableJSONParser For JSON parsing of /server players table.
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
public class PlayersTableJSONHandler implements PageHandler {
|
||||||
|
|
||||||
|
private final PlanConfig config;
|
||||||
|
private final DBSystem dbSystem;
|
||||||
|
private final Formatters formatters;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public PlayersTableJSONHandler(
|
||||||
|
PlanConfig config,
|
||||||
|
DBSystem dbSystem,
|
||||||
|
Formatters formatters
|
||||||
|
) {
|
||||||
|
this.config = config;
|
||||||
|
this.dbSystem = dbSystem;
|
||||||
|
this.formatters = formatters;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response getResponse(Request request, RequestTarget target) throws WebException {
|
||||||
|
UUID serverUUID = getServerUUID(target); // Can throw BadRequestException
|
||||||
|
return new JSONResponse(parseJSON(serverUUID));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String parseJSON(UUID serverUUID) {
|
||||||
|
Integer xMostRecentPlayers = config.get(DisplaySettings.PLAYERS_PER_SERVER_PAGE);
|
||||||
|
Integer loginThreshold = config.get(TimeSettings.ACTIVE_LOGIN_THRESHOLD);
|
||||||
|
Long playtimeThreshold = config.get(TimeSettings.ACTIVE_PLAY_THRESHOLD);
|
||||||
|
Boolean openPlayerLinksInNewTab = config.get(DisplaySettings.OPEN_PLAYER_LINKS_IN_NEW_TAB);
|
||||||
|
|
||||||
|
Database database = dbSystem.getDatabase();
|
||||||
|
|
||||||
|
return new PlayersTableJSONParser(
|
||||||
|
database.query(new ServerPlayersTableContainersQuery(serverUUID)),
|
||||||
|
database.query(new ExtensionServerPlayerDataTableQuery(serverUUID, xMostRecentPlayers)),
|
||||||
|
xMostRecentPlayers, playtimeThreshold, loginThreshold, openPlayerLinksInNewTab,
|
||||||
|
formatters
|
||||||
|
).toJSONString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private UUID getServerUUID(RequestTarget target) throws BadRequestException {
|
||||||
|
Optional<String> serverUUID = target.getParameter("serverUUID");
|
||||||
|
if (serverUUID.isPresent()) {
|
||||||
|
return getServerUUIDDirectly(serverUUID.get());
|
||||||
|
} else {
|
||||||
|
return getServerUUIDFromName(target); // Preferred
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private UUID getServerUUIDFromName(RequestTarget target) throws BadRequestException {
|
||||||
|
String serverName = target.getParameter("serverName")
|
||||||
|
.orElseThrow(() -> new BadRequestException("'serverName' parameter was not defined."));
|
||||||
|
return dbSystem.getDatabase().query(ServerQueries.fetchServerMatchingIdentifier(serverName))
|
||||||
|
.map(Server::getUuid)
|
||||||
|
.orElseThrow(() -> new BadRequestException("'serverName' was not found in the database.: '" + serverName + "'"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private UUID getServerUUIDDirectly(String serverUUIDString) throws BadRequestException {
|
||||||
|
try {
|
||||||
|
return UUID.fromString(serverUUIDString);
|
||||||
|
} catch (IllegalArgumentException malformedUUIDException) {
|
||||||
|
throw new BadRequestException("'serverName' was not a valid UUID: " + malformedUUIDException.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAuthorized(Authentication auth, RequestTarget target) throws WebUserAuthException {
|
||||||
|
return auth.getWebUser().getPermLevel() <= 0;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package com.djrapitops.plan.system.webserver.pages.json;
|
||||||
|
|
||||||
|
import com.djrapitops.plan.api.exceptions.WebUserAuthException;
|
||||||
|
import com.djrapitops.plan.system.webserver.RequestTarget;
|
||||||
|
import com.djrapitops.plan.system.webserver.auth.Authentication;
|
||||||
|
import com.djrapitops.plan.system.webserver.pages.TreePageHandler;
|
||||||
|
import com.djrapitops.plan.system.webserver.response.ResponseFactory;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Root handler for different JSON end points.
|
||||||
|
*
|
||||||
|
* @author Rsl1122
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
public class RootJSONHandler extends TreePageHandler {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public RootJSONHandler(
|
||||||
|
ResponseFactory responseFactory,
|
||||||
|
PlayersTableJSONHandler playersTableJSONHandler
|
||||||
|
) {
|
||||||
|
super(responseFactory);
|
||||||
|
|
||||||
|
registerPage("players", playersTableJSONHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAuthorized(Authentication auth, RequestTarget target) throws WebUserAuthException {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -97,7 +97,7 @@ public class PlayersTableJSONParser {
|
|||||||
public String toJSONString() {
|
public String toJSONString() {
|
||||||
String data = parseData();
|
String data = parseData();
|
||||||
String columnHeaders = parseColumnHeaders();
|
String columnHeaders = parseColumnHeaders();
|
||||||
return "{columns:" + columnHeaders + ",data:" + data + '}';
|
return "{\"columns\":" + columnHeaders + ",\"data\":" + data + '}';
|
||||||
}
|
}
|
||||||
|
|
||||||
private String parseData() {
|
private String parseData() {
|
||||||
@ -112,14 +112,20 @@ public class PlayersTableJSONParser {
|
|||||||
if (currentPlayerNumber >= maxPlayers) {
|
if (currentPlayerNumber >= maxPlayers) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
UUID playerUUID = player.getValue(PlayerKeys.UUID).orElse(null);
|
UUID playerUUID = player.getValue(PlayerKeys.UUID).orElse(null);
|
||||||
if (playerUUID == null) {
|
if (playerUUID == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (currentPlayerNumber > 0) {
|
||||||
|
dataJSON.append(','); // Previous item
|
||||||
|
}
|
||||||
|
dataJSON.append('['); // Start new item
|
||||||
|
|
||||||
appendPlayerData(dataJSON, planAPI, now, player);
|
appendPlayerData(dataJSON, planAPI, now, player);
|
||||||
appendExtensionData(dataJSON, extensionData.get(playerUUID));
|
appendExtensionData(dataJSON, extensionData.getOrDefault(playerUUID, new ExtensionTabData.Factory(null).build()));
|
||||||
|
|
||||||
|
dataJSON.append(']'); // Close new item
|
||||||
|
|
||||||
currentPlayerNumber++;
|
currentPlayerNumber++;
|
||||||
}
|
}
|
||||||
@ -145,17 +151,17 @@ public class PlayersTableJSONParser {
|
|||||||
|
|
||||||
Html link = openPlayerPageInNewTab ? Html.LINK_EXTERNAL : Html.LINK;
|
Html link = openPlayerPageInNewTab ? Html.LINK_EXTERNAL : Html.LINK;
|
||||||
|
|
||||||
String display = "{display:\"";
|
String display = "{\"display\":\"";
|
||||||
String sort = "\",sort: ";
|
String sort = "\",\"sort\": ";
|
||||||
|
|
||||||
appendData(dataJSON,
|
appendData(dataJSON,
|
||||||
'"' + link.parse(url, name) + '"',
|
'"' + link.parse(url, name).replace('"', '\'') + '"',
|
||||||
display + activityString + sort + activityIndex + '}',
|
display + activityString + sort + activityIndex.getValue() + '}',
|
||||||
display + numberFormatters.get(FormatType.TIME_MILLISECONDS).apply(playtime) + sort + playtime + '}',
|
display + numberFormatters.get(FormatType.TIME_MILLISECONDS).apply(playtime) + sort + playtime + '}',
|
||||||
loginTimes,
|
loginTimes,
|
||||||
display + numberFormatters.get(FormatType.DATE_YEAR).apply(registered) + sort + registered + '}',
|
display + numberFormatters.get(FormatType.DATE_YEAR).apply(registered) + sort + registered + '}',
|
||||||
display + numberFormatters.get(FormatType.DATE_YEAR).apply(lastSeen) + sort + lastSeen + '}',
|
display + numberFormatters.get(FormatType.DATE_YEAR).apply(lastSeen) + sort + lastSeen + '}',
|
||||||
geolocation
|
'"' + geolocation + '"'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,7 +180,8 @@ public class PlayersTableJSONParser {
|
|||||||
// If it's a percentage, append a percentage
|
// If it's a percentage, append a percentage
|
||||||
Optional<ExtensionDoubleData> percentageValue = tabData.getPercentage(key);
|
Optional<ExtensionDoubleData> percentageValue = tabData.getPercentage(key);
|
||||||
if (percentageValue.isPresent()) {
|
if (percentageValue.isPresent()) {
|
||||||
dataJSON.append(percentageValue.get().getFormattedValue(percentageFormatter));
|
dataJSON.append("{\"display\": \"").append(percentageValue.get().getFormattedValue(percentageFormatter))
|
||||||
|
.append("\",\"sort\": ").append(percentageValue.get().getRawValue()).append('}');
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,8 +194,8 @@ public class PlayersTableJSONParser {
|
|||||||
dataJSON.append(numberData.getFormattedValue(numberFormatters.get(formatType)));
|
dataJSON.append(numberData.getFormattedValue(numberFormatters.get(formatType)));
|
||||||
} else {
|
} else {
|
||||||
// If it's a formatted number, append a formatted number and sort by the number value
|
// 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)))
|
dataJSON.append("{\"display\": \"").append(numberData.getFormattedValue(numberFormatters.get(formatType)))
|
||||||
.append("\",sort: ").append(numberData.getRawValue()).append('}');
|
.append("\",\"sort\": ").append(numberData.getRawValue()).append('}');
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -202,7 +209,7 @@ public class PlayersTableJSONParser {
|
|||||||
private void appendData(StringBuilder dataJSON, Serializable... dataRows) {
|
private void appendData(StringBuilder dataJSON, Serializable... dataRows) {
|
||||||
int max = dataRows.length;
|
int max = dataRows.length;
|
||||||
for (int i = 0; i < max; i++) {
|
for (int i = 0; i < max; i++) {
|
||||||
dataJSON.append("{").append(dataRows[i]).append("}");
|
dataJSON.append(dataRows[i]);
|
||||||
if (i < max - 1) {
|
if (i < max - 1) {
|
||||||
dataJSON.append(',');
|
dataJSON.append(',');
|
||||||
}
|
}
|
||||||
@ -230,7 +237,7 @@ public class PlayersTableJSONParser {
|
|||||||
private void appendDataHeaders(StringBuilder columnHeaders, Serializable... headers) {
|
private void appendDataHeaders(StringBuilder columnHeaders, Serializable... headers) {
|
||||||
int max = headers.length;
|
int max = headers.length;
|
||||||
for (int i = 0; i < max; i++) {
|
for (int i = 0; i < max; i++) {
|
||||||
columnHeaders.append("{title: \"").append(headers[i]).append("\"}");
|
columnHeaders.append("{\"title\": \"").append(headers[i].toString().replace('"', '\'')).append("\"}");
|
||||||
if (i < max - 1) {
|
if (i < max - 1) {
|
||||||
columnHeaders.append(',');
|
columnHeaders.append(',');
|
||||||
}
|
}
|
||||||
@ -240,7 +247,10 @@ public class PlayersTableJSONParser {
|
|||||||
private void appendExtensionHeaders(StringBuilder columnHeaders) {
|
private void appendExtensionHeaders(StringBuilder columnHeaders) {
|
||||||
for (ExtensionDescriptive provider : extensionDescriptives) {
|
for (ExtensionDescriptive provider : extensionDescriptives) {
|
||||||
columnHeaders.append(',');
|
columnHeaders.append(',');
|
||||||
columnHeaders.append(Icon.fromExtensionIcon(provider.getIcon().setColor(Color.NONE)).toHtml()).append(' ').append(provider.getText());
|
columnHeaders.append("{\"title\": \"")
|
||||||
|
.append(Icon.fromExtensionIcon(provider.getIcon().setColor(Color.NONE)).toHtml().replace('"', '\''))
|
||||||
|
.append(' ').append(provider.getText())
|
||||||
|
.append("\"}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user