Added player endpoint

This commit is contained in:
Rsl1122 2019-07-20 17:40:15 +03:00
parent 13668170b6
commit c41b8c201e
9 changed files with 301 additions and 59 deletions

View File

@ -30,6 +30,7 @@ import com.djrapitops.plan.utilities.html.graphs.Graphs;
import com.djrapitops.plan.utilities.html.graphs.pie.WorldPie;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@ -248,16 +249,35 @@ public class SessionsMutator {
.average().orElse(0.0);
}
public List<Map<String, Object>> toPlayerJSONMaps(
public List<Map<String, Object>> toPlayerNameJSONMaps(
Graphs graphs,
WorldAliasSettings worldAliasSettings,
Formatters formatters
) {
return toJSONMaps(graphs, worldAliasSettings, formatters,
sessionMap -> sessionMap.get("player_name"));
}
public List<Map<String, Object>> toServerNameJSONMaps(
Graphs graphs,
WorldAliasSettings worldAliasSettings,
Formatters formatters
) {
return toJSONMaps(graphs, worldAliasSettings, formatters,
sessionMap -> sessionMap.get("server_name"));
}
private List<Map<String, Object>> toJSONMaps(
Graphs graphs,
WorldAliasSettings worldAliasSettings,
Formatters formatters,
Function<Map<String, Object>, Object> nameFunction
) {
return sessions.stream().map(session -> {
Map<String, Object> sessionMap = new HashMap<>();
sessionMap.put("player_name", session.getValue(SessionKeys.NAME).orElse(session.getUnsafe(SessionKeys.UUID).toString()));
sessionMap.put("name", sessionMap.get("player_name"));
sessionMap.put("server_name", session.getValue(SessionKeys.SERVER_NAME).orElse(session.getUnsafe(SessionKeys.SERVER_UUID).toString()));
sessionMap.put("name", nameFunction.apply(sessionMap));
sessionMap.put("start", session.getValue(SessionKeys.START).map(formatters.yearLong()).orElse("-") +
(session.supports(SessionKeys.END) ? "" : " (Online)"));
sessionMap.put("end", session.getValue(SessionKeys.END).map(formatters.yearLong()).orElse("Online"));

View File

@ -18,6 +18,7 @@ package com.djrapitops.plan.system;
import com.djrapitops.plan.api.exceptions.connection.BadRequestException;
import com.djrapitops.plan.db.access.queries.objects.ServerQueries;
import com.djrapitops.plan.db.access.queries.objects.UserIdentifierQueries;
import com.djrapitops.plan.system.database.DBSystem;
import com.djrapitops.plan.system.info.server.Server;
import com.djrapitops.plan.system.webserver.RequestTarget;
@ -55,4 +56,18 @@ public class Identifiers {
.map(Server::getUuid)
.orElseThrow(() -> new BadRequestException("Given 'server' was not found in the database: '" + serverName + "'"));
}
public UUID getPlayerUUID(RequestTarget target) throws BadRequestException {
String playerIdentifier = target.getParameter("player")
.orElseThrow(() -> new BadRequestException("'player' parameter was not defined."));
return UUIDUtility.parseFromString(playerIdentifier)
.orElse(getPlayerUUIDFromName(playerIdentifier));
}
private UUID getPlayerUUIDFromName(String playerName) throws BadRequestException {
return dbSystem.getDatabase()
.query(UserIdentifierQueries.fetchPlayerUUIDOf(playerName))
.orElseThrow(() -> new BadRequestException("Given 'player' was not found in the database: '" + playerName + "'"));
}
}

View File

@ -84,7 +84,7 @@ public class JSONFactory {
List<Session> sessions = db.query(SessionQueries.fetchLatestSessionsOfServer(
serverUUID, config.get(DisplaySettings.SESSIONS_PER_PAGE)
));
return new SessionsMutator(sessions).toPlayerJSONMaps(graphs, config.getWorldAliasSettings(), formatters);
return new SessionsMutator(sessions).toPlayerNameJSONMaps(graphs, config.getWorldAliasSettings(), formatters);
}
public List<Map<String, Object>> serverPlayerKillsAsJSONMap(UUID serverUUID) {

View File

@ -0,0 +1,187 @@
package com.djrapitops.plan.system.json;
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.PerServerMutator;
import com.djrapitops.plan.data.store.mutators.PingMutator;
import com.djrapitops.plan.data.store.mutators.SessionsMutator;
import com.djrapitops.plan.db.Database;
import com.djrapitops.plan.db.access.queries.containers.PlayerContainerQuery;
import com.djrapitops.plan.db.access.queries.objects.ServerQueries;
import com.djrapitops.plan.system.cache.SessionCache;
import com.djrapitops.plan.system.database.DBSystem;
import com.djrapitops.plan.system.settings.config.PlanConfig;
import com.djrapitops.plan.system.settings.paths.TimeSettings;
import com.djrapitops.plan.utilities.formatting.Formatter;
import com.djrapitops.plan.utilities.formatting.Formatters;
import com.djrapitops.plan.utilities.html.graphs.Graphs;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Singleton
public class PlayerJSONParser {
private final PlanConfig config;
private final DBSystem dbSystem;
private final Graphs graphs;
private final Formatters formatters;
private final Formatter<Long> timeAmount;
private final Formatter<Double> decimals;
private final Formatter<Long> year;
@Inject
public PlayerJSONParser(
PlanConfig config,
DBSystem dbSystem,
Formatters formatters,
Graphs graphs
) {
this.config = config;
this.dbSystem = dbSystem;
this.formatters = formatters;
timeAmount = formatters.timeAmount();
decimals = formatters.decimals();
year = formatters.yearLong();
this.graphs = graphs;
}
public Map<String, Object> createJSONAsMap(UUID playerUUID) {
Database db = dbSystem.getDatabase();
Map<UUID, String> serverNames = db.query(ServerQueries.fetchServerNames());
PlayerContainer player = db.query(new PlayerContainerQuery(playerUUID));
SessionsMutator sessionsMutator = SessionsMutator.forContainer(player);
Map<String, Object> data = new HashMap<>();
data.put("info", createInfoJSONMap(player, serverNames));
data.put("online_activity", createOnlineActivityJSONMap(sessionsMutator));
data.put("nicknames", player.getValue(PlayerKeys.NICKNAMES)
.map(nicks -> Nickname.fromDataNicknames(nicks, serverNames, year))
.orElse(Collections.emptyList()));
data.put("connections", player.getValue(PlayerKeys.GEO_INFO)
.map(geoInfo -> ConnectionInfo.fromGeoInfo(geoInfo, year))
.orElse(Collections.emptyList()));
data.put("player_kills", player.getValue(PlayerKeys.PLAYER_KILLS).orElse(Collections.emptyList()));
data.put("player_deaths", player.getValue(PlayerKeys.PLAYER_DEATHS).orElse(Collections.emptyList()));
data.put("sessions", sessionsMutator.toServerNameJSONMaps(graphs, config.getWorldAliasSettings(), formatters));
return data;
}
private Map<String, Object> createOnlineActivityJSONMap(SessionsMutator sessionsMutator) {
long now = System.currentTimeMillis();
long monthAgo = now - TimeUnit.DAYS.toMillis(30L);
long weekAgo = now - TimeUnit.DAYS.toMillis(7L);
SessionsMutator sessionsMonth = sessionsMutator.filterSessionsBetween(monthAgo, now);
SessionsMutator sessionsWeek = sessionsMutator.filterSessionsBetween(weekAgo, now);
Map<String, Object> onlineActivity = new HashMap<>();
onlineActivity.put("playtime_30d", timeAmount.apply(sessionsMonth.toPlaytime()));
onlineActivity.put("active_playtime_30d", timeAmount.apply(sessionsMonth.toActivePlaytime()));
onlineActivity.put("afk_time_30d", timeAmount.apply(sessionsMonth.toAfkTime()));
onlineActivity.put("average_session_length_30d", timeAmount.apply(sessionsMonth.toAverageSessionLength()));
onlineActivity.put("session_count_30d", sessionsMonth.count());
onlineActivity.put("player_kill_count_30d", sessionsMonth.toPlayerKillCount());
onlineActivity.put("mob_kill_count_30d", sessionsMonth.toMobKillCount());
onlineActivity.put("death_count_30d", sessionsMonth.toDeathCount());
onlineActivity.put("playtime_7d", timeAmount.apply(sessionsWeek.toPlaytime()));
onlineActivity.put("active_playtime_7d", timeAmount.apply(sessionsWeek.toActivePlaytime()));
onlineActivity.put("afk_time_7d", timeAmount.apply(sessionsWeek.toAfkTime()));
onlineActivity.put("average_session_length_7d", timeAmount.apply(sessionsWeek.toAverageSessionLength()));
onlineActivity.put("session_count_7d", sessionsWeek.count());
onlineActivity.put("player_kill_count_7d", sessionsWeek.toPlayerKillCount());
onlineActivity.put("mob_kill_count_7d", sessionsWeek.toMobKillCount());
onlineActivity.put("death_count_7d", sessionsWeek.toDeathCount());
return onlineActivity;
}
private Map<String, Object> createInfoJSONMap(PlayerContainer player, Map<UUID, String> serverNames) {
SessionsMutator sessions = SessionsMutator.forContainer(player);
ActivityIndex activityIndex = player.getActivityIndex(System.currentTimeMillis(), config.get(TimeSettings.ACTIVE_PLAY_THRESHOLD));
PerServerMutator perServer = PerServerMutator.forContainer(player);
PingMutator ping = PingMutator.forContainer(player);
Map<String, Object> info = new HashMap<>();
info.put("online", SessionCache.getCachedSession(player.getUnsafe(PlayerKeys.UUID)).isPresent());
info.put("operator", player.getValue(PlayerKeys.OPERATOR).orElse(false));
info.put("banned", player.getValue(PlayerKeys.BANNED).orElse(false));
info.put("kick_count", player.getValue(PlayerKeys.KICK_COUNT).orElse(0));
info.put("player_kill_count", player.getValue(PlayerKeys.PLAYER_KILL_COUNT).orElse(0));
info.put("mob_kill_count", player.getValue(PlayerKeys.MOB_KILL_COUNT).orElse(0));
info.put("death_count", player.getValue(PlayerKeys.DEATH_COUNT).orElse(0));
info.put("playtime", timeAmount.apply(sessions.toPlaytime()));
info.put("active_playtime", timeAmount.apply(sessions.toActivePlaytime()));
info.put("afk_time", timeAmount.apply(sessions.toAfkTime()));
info.put("session_count", sessions.count());
info.put("longest_session_length", timeAmount.apply(sessions.toLongestSessionLength()));
info.put("session_median", timeAmount.apply(sessions.toMedianSessionLength()));
info.put("activity_index", decimals.apply(activityIndex.getValue()));
info.put("activity_index_group", activityIndex.getGroup());
UUID favoriteServer = perServer.favoriteServer();
info.put("favorite_server", serverNames.getOrDefault(favoriteServer, favoriteServer.toString()));
info.put("average_ping", decimals.apply(ping.average()) + " ms");
info.put("worst_ping", ping.max() + " ms");
info.put("best_ping", ping.min() + " ms");
info.put("registered", player.getValue(PlayerKeys.REGISTERED).map(year).orElse("-"));
info.put("last_seen", player.getValue(PlayerKeys.LAST_SEEN).map(year).orElse("-"));
return info;
}
public static class Nickname {
private String nickname;
private String server;
private String date;
public Nickname(String nickname, String server, String date) {
this.nickname = nickname;
this.server = server;
this.date = date;
}
public static List<Nickname> fromDataNicknames(
List<com.djrapitops.plan.data.store.objects.Nickname> nicknames,
Map<UUID, String> serverNames,
Formatter<Long> dateFormatter
) {
List<Nickname> mapped = new ArrayList<>();
for (com.djrapitops.plan.data.store.objects.Nickname nickname : nicknames) {
mapped.add(new Nickname(
nickname.getName(),
serverNames.getOrDefault(nickname.getServerUUID(), nickname.getServerUUID().toString()),
dateFormatter.apply(nickname.getDate())
));
}
return mapped;
}
}
public static class ConnectionInfo {
private String geolocation;
private String date;
public ConnectionInfo(String geolocation, String date) {
this.geolocation = geolocation;
this.date = date;
}
public static List<ConnectionInfo> fromGeoInfo(List<GeoInfo> geoInfo, Formatter<Long> dateFormatter) {
return geoInfo.stream()
.map(i -> new ConnectionInfo(i.getGeolocation(), dateFormatter.apply(i.getDate())))
.collect(Collectors.toList());
}
}
}

View File

@ -0,0 +1,43 @@
package com.djrapitops.plan.system.webserver.pages.json;
import com.djrapitops.plan.api.exceptions.WebUserAuthException;
import com.djrapitops.plan.api.exceptions.connection.WebException;
import com.djrapitops.plan.data.WebUser;
import com.djrapitops.plan.system.Identifiers;
import com.djrapitops.plan.system.json.PlayerJSONParser;
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 javax.inject.Inject;
import javax.inject.Singleton;
import java.util.UUID;
@Singleton
public class PlayerJSONHandler implements PageHandler {
private final Identifiers identifiers;
private final PlayerJSONParser jsonParser;
@Inject
public PlayerJSONHandler(Identifiers identifiers, PlayerJSONParser jsonParser) {
this.identifiers = identifiers;
this.jsonParser = jsonParser;
}
@Override
public Response getResponse(Request request, RequestTarget target) throws WebException {
UUID playerUUID = identifiers.getPlayerUUID(target); // Can throw BadRequestException
return new JSONResponse<>(jsonParser.createJSONAsMap(playerUUID));
}
@Override
public boolean isAuthorized(Authentication auth, RequestTarget target) throws WebUserAuthException {
WebUser webUser = auth.getWebUser();
return webUser.getPermLevel() <= 1 || webUser.getName().equalsIgnoreCase(target.get(target.size() - 1));
}
}

View File

@ -52,7 +52,8 @@ public class RootJSONHandler extends TreePageHandler {
PlayerKillsJSONHandler playerKillsJSONHandler,
PvPPvEJSONParser pvPPvEJSONParser,
PlayerBaseOverviewJSONParser playerBaseOverviewJSONParser,
PerformanceJSONParser performanceJSONParser
PerformanceJSONParser performanceJSONParser,
PlayerJSONHandler playerJSONHandler
) {
super(responseFactory);
@ -70,6 +71,8 @@ public class RootJSONHandler extends TreePageHandler {
registerPage("playerVersus", pvPPvEJSONParser);
registerPage("playerbaseOverview", playerBaseOverviewJSONParser);
registerPage("performanceOverview", performanceJSONParser);
registerPage("player", playerJSONHandler);
}
private <T> void registerPage(String identifier, TabJSONParser<T> tabJSONParser) {

View File

@ -25,7 +25,9 @@
</head>
<body id="page-top">
<script>
var gmPieColors = [${gmPieColors}];
</script>
<div class="page-loader">
<span class="loader"></span>
<span class="loader-text">Please wait..</span>
@ -1294,66 +1296,29 @@
<script src="js/sb-admin-2.js"></script>
<script src="js/xmlhttprequests.js"></script>
<script src="js/color-selector.js"></script>
<script src="js/graphs.js"></script>
<!-- Page level plugins -->
<script src="vendor/datatables/jquery.dataTables.min.js"></script>
<script src="vendor/datatables/dataTables.bootstrap4.min.js"></script>
<script src="vendor/highcharts/highstock.js"></script>
<script src="vendor/highcharts/drilldown.js"></script>
<script src="vendor/highcharts/highcharts-more.js"></script>
<script src="vendor/highcharts/no-data-to-display.js"></script>
<link href='vendor/fullcalendar/fullcalendar.min.css' rel='stylesheet'/>
<script src='vendor/momentjs/moment.js'></script>
<script src='vendor/fullcalendar/fullcalendar.min.js'></script>
<!-- Page level custom scripts -->
<script src="js/sessionAccordion.js"></script>
<script src="js/player-values.js"></script>
<script>
setLoadingText('Loading player values..');
loadPlayerOverviewValues(
{
info: {
online: true,
operator: true,
banned: true,
kick_count: 5,
player_kill_count: 20,
mob_kill_count: 1234,
death_count: 8,
playtime: '5m',
active_playtime: '2m',
afk_time: '3m',
session_count: 3,
longest_session_lenght: '4m',
session_median: '30s',
activity_index: 1.32,
activity_index_group: 'Irregular',
favorite_server: 'Server 1',
average_ping: '6 ms',
best_ping: '3 ms',
worst_ping: '123 ms',
registered: '10 January 2018',
last_seen: '30 July 2019'
},
nicknames: [
{nickname: 'Rsl1122', server: 'Server 1', date: '30 July 2019'}
],
connections: [
{geolocation: 'Local Machine', date: '30 July 2019'}
],
online_activity: {
playtime_30d: '4s',
playtime_7d: '4s',
active_playtime_30d: '2s',
active_playtime_7d: '2s',
afk_time_30d: '2s',
afk_time_7d: '2s',
average_session_length_30d: '2s',
average_session_length_7d: '2s',
session_count_30d: 3,
session_count_7d: 3,
player_kill_count_30d: 32,
player_kill_count_7d: 32,
mob_kill_count_30d: 32,
mob_kill_count_7d: 32,
death_count_30d: 32,
death_count_7d: 32,
}
},
null
);
jsonRequest("../v1/player?player=${playerName}", function (json, error) {
loadPlayerOverviewValues(json, error);
loadSessionAccordion(json, error);
});
setLoadingText('Rendering graphs..');
setLoadingText('Sorting players table..');
setLoadingText('Almost done..');

View File

@ -26,7 +26,6 @@
<body id="page-top">
<script>
var worldPieColors = [${worldPieColors}];
var gmPieColors = [${gmPieColors}];
</script>
<div class="page-loader">

View File

@ -105,4 +105,14 @@ Type | Description
`worldPie` | World Pie data of all sessions combined
`activity` | Activity stack graph and pie graph data
`geolocation` | World Map and bar graph data. World Map uses iso-a3 specification of Country codes and Bar graph uses country names.
`ping` | Min, Avg, Max ping graph data.
`ping` | Min, Avg, Max ping graph data.
### `GET /v1/player`
Fetch all data for a player page
Required parameters: `player`
Parameter|Expected value|Description
--|--|--
`player` | Name or UUID of a player | Used for identifying player the data should be about