diff --git a/Plan/common/src/main/java/com/djrapitops/plan/db/access/queries/objects/SessionQueries.java b/Plan/common/src/main/java/com/djrapitops/plan/db/access/queries/objects/SessionQueries.java index 6bb2ed444..d89350c25 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/db/access/queries/objects/SessionQueries.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/db/access/queries/objects/SessionQueries.java @@ -144,19 +144,22 @@ public class SessionQueries { * @return Map: Player UUID - List of sessions on the server. */ public static Query>> fetchSessionsOfServer(UUID serverUUID) { + return db -> SessionsMutator.sortByPlayers(db.query(fetchSessionsOfServerFlat(serverUUID))); + } + + public static QueryStatement> fetchSessionsOfServerFlat(UUID serverUUID) { String sql = SELECT_SESSIONS_STATEMENT + WHERE + SessionsTable.TABLE_NAME + '.' + SessionsTable.SERVER_UUID + "=?" + ORDER_BY_SESSION_START_DESC; - return new QueryStatement>>(sql, 50000) { + return new QueryStatement>(sql, 50000) { @Override public void prepare(PreparedStatement statement) throws SQLException { statement.setString(1, serverUUID.toString()); } @Override - public Map> processResults(ResultSet set) throws SQLException { - List sessions = extractDataFromSessionSelectStatement(set); - return SessionsMutator.sortByPlayers(sessions); + public List processResults(ResultSet set) throws SQLException { + return extractDataFromSessionSelectStatement(set); } }; } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/ResponseHandler.java b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/ResponseHandler.java index 404106a3c..34a4ef1f1 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/ResponseHandler.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/ResponseHandler.java @@ -93,7 +93,7 @@ public class ResponseHandler extends TreePageHandler { } registerPage("info", infoRequestPageHandler); - registerPage("json", rootJSONHandler); + registerPage("v1", rootJSONHandler); } public Response getResponse(Request request) { diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/json/GraphsJSONHandler.java b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/json/GraphsJSONHandler.java new file mode 100644 index 000000000..b901b9796 --- /dev/null +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/json/GraphsJSONHandler.java @@ -0,0 +1,115 @@ +/* + * 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.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.data.store.mutators.MutatorFunctions; +import com.djrapitops.plan.data.store.mutators.PlayersMutator; +import com.djrapitops.plan.data.store.mutators.SessionsMutator; +import com.djrapitops.plan.data.store.mutators.TPSMutator; +import com.djrapitops.plan.db.Database; +import com.djrapitops.plan.db.access.queries.containers.ServerPlayerContainersQuery; +import com.djrapitops.plan.db.access.queries.objects.SessionQueries; +import com.djrapitops.plan.db.access.queries.objects.TPSQueries; +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.system.webserver.Request; +import com.djrapitops.plan.system.webserver.RequestTarget; +import com.djrapitops.plan.system.webserver.auth.Authentication; +import com.djrapitops.plan.system.webserver.response.Response; +import com.djrapitops.plan.system.webserver.response.data.JSONResponse; +import com.djrapitops.plan.utilities.html.graphs.Graphs; +import com.djrapitops.plan.utilities.html.graphs.line.LineGraphFactory; + +import javax.inject.Inject; +import javax.inject.Singleton; +import java.util.TimeZone; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +/** + * JSON handler for different graph data JSON requests. + * + * @author Rsl1122 + */ +@Singleton +public class GraphsJSONHandler extends ServerParameterJSONHandler { + + private final Graphs graphs; + private final TimeZone timeZone; + + @Inject + public GraphsJSONHandler( + PlanConfig config, + DBSystem dbSystem, + Graphs graphs + ) { + super(dbSystem); + this.graphs = graphs; + + this.timeZone = config.get(TimeSettings.USE_SERVER_TIME) ? TimeZone.getDefault() : TimeZone.getTimeZone("GMT"); + } + + @Override + public Response getResponse(Request request, RequestTarget target) throws WebException { + UUID serverUUID = getServerUUID(target); // Can throw BadRequestException + String type = target.getParameter("type") + .orElseThrow(() -> new BadRequestException("'type' parameter was not defined.")); + String graphDataJSON = generateGraphDataJSONOfType(type, serverUUID); + return new JSONResponse(graphDataJSON); + } + + private String generateGraphDataJSONOfType(String type, UUID serverUUID) throws BadRequestException { + Database db = dbSystem.getDatabase(); + LineGraphFactory lineGraphs = graphs.line(); + switch (type) { + case "performance": + TPSMutator tpsMutator = new TPSMutator(db.query(TPSQueries.fetchTPSDataOfServer(serverUUID))) + .filterDataBetween(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(180L), System.currentTimeMillis()); + return '{' + + "\"playersOnline\":" + lineGraphs.playersOnlineGraph(tpsMutator).toHighChartsSeries() + + ",\"tps\":" + lineGraphs.tpsGraph(tpsMutator).toHighChartsSeries() + + ",\"cpu\":" + lineGraphs.cpuGraph(tpsMutator).toHighChartsSeries() + + ",\"ram\":" + lineGraphs.ramGraph(tpsMutator).toHighChartsSeries() + + ",\"entities\":" + lineGraphs.entityGraph(tpsMutator).toHighChartsSeries() + + ",\"chunks\":" + lineGraphs.chunkGraph(tpsMutator).toHighChartsSeries() + + ",\"disk\":" + lineGraphs.diskGraph(tpsMutator).toHighChartsSeries() + + '}'; + case "uniqueAndNew": + SessionsMutator sessionsMutator = new SessionsMutator(db.query(SessionQueries.fetchSessionsOfServerFlat(serverUUID))) + .filterSessionsBetween(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(180L), System.currentTimeMillis()); + PlayersMutator playersMutator = new PlayersMutator(db.query(new ServerPlayerContainersQuery(serverUUID))) + .filterRegisteredBetween(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(180L), System.currentTimeMillis()); + + return "{\"uniquePlayers\":" + + lineGraphs.lineGraph(MutatorFunctions.toPointsWithRemovedOffset(sessionsMutator.uniqueJoinsPerDay(timeZone), timeZone)).toHighChartsSeries() + + ",\"newPlayers\":" + + lineGraphs.lineGraph(MutatorFunctions.toPointsWithRemovedOffset(playersMutator.newPerDay(timeZone), timeZone)).toHighChartsSeries() + + '}'; + default: + throw new BadRequestException("unknown 'type' parameter: " + type); + } + } + + @Override + public boolean isAuthorized(Authentication auth, RequestTarget target) throws WebUserAuthException { + return auth.getWebUser().getPermLevel() <= 0; + } +} \ No newline at end of file diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/json/PlayersTableJSONHandler.java b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/json/PlayersTableJSONHandler.java index c426605db..fae3356d8 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/json/PlayersTableJSONHandler.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/json/PlayersTableJSONHandler.java @@ -17,21 +17,16 @@ 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.access.queries.objects.ServerQueries; import com.djrapitops.plan.system.database.DBSystem; -import com.djrapitops.plan.system.info.server.Server; 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.Optional; import java.util.UUID; /** @@ -41,9 +36,8 @@ import java.util.UUID; * @see com.djrapitops.plan.utilities.html.tables.PlayersTableJSONParser For JSON parsing of /server players table. */ @Singleton -public class PlayersTableJSONHandler implements PageHandler { +public class PlayersTableJSONHandler extends ServerParameterJSONHandler { - private final DBSystem dbSystem; private final JSONFactory jsonFactory; @Inject @@ -51,8 +45,8 @@ public class PlayersTableJSONHandler implements PageHandler { DBSystem dbSystem, JSONFactory jsonFactory ) { + super(dbSystem); this.jsonFactory = jsonFactory; - this.dbSystem = dbSystem; } @Override @@ -61,31 +55,6 @@ public class PlayersTableJSONHandler implements PageHandler { return new JSONResponse(jsonFactory.serverPlayersTableJSON(serverUUID)); } - private UUID getServerUUID(RequestTarget target) throws BadRequestException { - Optional 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; diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/json/RootJSONHandler.java b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/json/RootJSONHandler.java index b5690a138..449759826 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/json/RootJSONHandler.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/json/RootJSONHandler.java @@ -36,11 +36,13 @@ public class RootJSONHandler extends TreePageHandler { @Inject public RootJSONHandler( ResponseFactory responseFactory, + GraphsJSONHandler graphsJSONHandler, PlayersTableJSONHandler playersTableJSONHandler ) { super(responseFactory); registerPage("players", playersTableJSONHandler); + registerPage("graph", graphsJSONHandler); } @Override diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/json/ServerParameterJSONHandler.java b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/json/ServerParameterJSONHandler.java new file mode 100644 index 000000000..0029ba928 --- /dev/null +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/json/ServerParameterJSONHandler.java @@ -0,0 +1,66 @@ +/* + * 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.system.webserver.pages.json; + +import com.djrapitops.plan.api.exceptions.connection.BadRequestException; +import com.djrapitops.plan.db.access.queries.objects.ServerQueries; +import com.djrapitops.plan.system.database.DBSystem; +import com.djrapitops.plan.system.info.server.Server; +import com.djrapitops.plan.system.webserver.RequestTarget; +import com.djrapitops.plan.system.webserver.pages.PageHandler; + +import java.util.Optional; +import java.util.UUID; + +/** + * JSON handler for different graph data JSON requests. + * + * @author Rsl1122 + */ +public abstract class ServerParameterJSONHandler implements PageHandler { + + protected final DBSystem dbSystem; + + protected ServerParameterJSONHandler(DBSystem dbSystem) { + this.dbSystem = dbSystem; + } + + protected UUID getServerUUID(RequestTarget target) throws BadRequestException { + Optional serverUUID = target.getParameter("serverUUID"); + if (serverUUID.isPresent()) { + return getServerUUIDDirectly(serverUUID.get()); + } else { + return getServerUUIDFromName(target); // Preferred + } + } + + protected 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 + "'")); + } + + protected 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()); + } + } +} \ No newline at end of file diff --git a/Plan/common/src/main/resources/assets/plan/web/css/sb-admin-2.css b/Plan/common/src/main/resources/assets/plan/web/css/sb-admin-2.css index 5857803b0..a99d645d2 100644 --- a/Plan/common/src/main/resources/assets/plan/web/css/sb-admin-2.css +++ b/Plan/common/src/main/resources/assets/plan/web/css/sb-admin-2.css @@ -12086,6 +12086,8 @@ a:focus { position: relative; height: 12rem; width: 100%; + padding: 0.5rem; + text-align: center; } @media (min-width: 768px) { diff --git a/Plan/common/src/main/resources/assets/plan/web/js/xmlhttprequests.js b/Plan/common/src/main/resources/assets/plan/web/js/xmlhttprequests.js index 9b4fcbbda..d82083cda 100644 --- a/Plan/common/src/main/resources/assets/plan/web/js/xmlhttprequests.js +++ b/Plan/common/src/main/resources/assets/plan/web/js/xmlhttprequests.js @@ -4,27 +4,25 @@ * @param callback function with (json, error) parameters to call after the request. */ function jsonRequest(address, callback) { - var xhttp = new XMLHttpRequest(); - xhttp.onreadystatechange = function () { - if (this.readyState === 4) { - try { - if (this.status === 200) { - var json = JSON.parse(this.responseText); - callback(json, null) - } else if (this.status === 404 || this.status === 403 || this.status === 500) { - callback(null, this.status) - } - } catch (e) { - callback(null, e.message) - } - } - }; - xhttp.open("GET", address, true); - xhttp.send(); -} - -function asyncJsonRequest(address, callback) { setTimeout(function () { - jsonRequest(address, callback) + var xhttp = new XMLHttpRequest(); + xhttp.onreadystatechange = function () { + if (this.readyState === 4) { + try { + if (this.status === 200) { + var json = JSON.parse(this.responseText); + setTimeout(function () { + callback(json, null) + }, 0); + } else if (this.status === 404 || this.status === 403 || this.status === 500) { + callback(null, this.status) + } + } catch (e) { + callback(null, e.message) + } + } + }; + xhttp.open("GET", address, true); + xhttp.send(); }, 0); } \ No newline at end of file diff --git a/Plan/common/src/main/resources/assets/plan/web/server.html b/Plan/common/src/main/resources/assets/plan/web/server.html index d7008d20c..e72458a77 100644 --- a/Plan/common/src/main/resources/assets/plan/web/server.html +++ b/Plan/common/src/main/resources/assets/plan/web/server.html @@ -31,7 +31,7 @@
- Please wait.. +

Please wait..

@@ -175,7 +175,7 @@ class="fas fa-fw fa-chart-area col-blue"> Online Activity -
+
@@ -352,9 +352,7 @@ class="fas fa-fw fa-chart-area col-blue"> New & Unique Players -
- -
+
@@ -368,7 +366,7 @@ Calendar
- +
@@ -823,9 +821,7 @@ class="fas fa-fw fa-chart-line col-amber"> Playerbase development -
- -
+
@@ -980,7 +976,11 @@ Player List
-
+ + + + +
Loading..
@@ -1014,7 +1014,7 @@ Geolocations
- +
@@ -1075,49 +1075,66 @@
-
... +
+
-
... +
+
-
... +
+
+
+
+
+
+
+
+
+
+
@@ -1494,6 +1511,20 @@ + + + + + + + + + + + + + +