mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2024-12-30 13:08:00 +01:00
Refactored /server page to use ResolverService
This commit is contained in:
parent
e997289a20
commit
4a1234f9b4
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.delivery.web.resolver;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Special Resolver that gives responses without user authentication.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public interface NoAuthResolver extends Resolver {
|
||||
|
||||
default boolean canAccess(WebUser permissions, URIPath target, URIQuery query) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement request resolution.
|
||||
*
|
||||
* @param target Target that is being accessed, /example/target
|
||||
* @param query Parameters in the URL, ?param=value etc.
|
||||
* @return Response or empty if the response should be 404 (not found).
|
||||
* @see Response for return value
|
||||
*/
|
||||
Optional<Response> resolve(URIPath target, URIQuery query);
|
||||
|
||||
default ResponseBuilder newResponseBuilder() {
|
||||
return Response.builder();
|
||||
}
|
||||
|
||||
default boolean requiresAuth(URIPath target, URIQuery query) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -18,6 +18,12 @@ package com.djrapitops.plan.delivery.web.resolver;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Interface for resolving requests of Plan webserver.
|
||||
*
|
||||
* @author Rsl1122
|
||||
* @see NoAuthResolver if resource is always accessible regardless of user.
|
||||
*/
|
||||
public interface Resolver {
|
||||
|
||||
/**
|
||||
@ -46,15 +52,6 @@ public interface Resolver {
|
||||
return Response.builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method with false to always allow using this resolver.
|
||||
* <p>
|
||||
* Use this when content/style is needed for displaying pages where authentication is not available/needed.
|
||||
*
|
||||
* @param target Target that is being accessed, /example/target
|
||||
* @param query Parameters in the URL, ?param=value etc.
|
||||
* @return true by default. If false is returned {@link #canAccess(WebUser, URIPath, URIQuery)} will not be called.
|
||||
*/
|
||||
default boolean requiresAuth(URIPath target, URIQuery query) {
|
||||
return true;
|
||||
}
|
||||
|
@ -71,12 +71,13 @@ public class ResponseBuilder {
|
||||
* @return https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location
|
||||
*/
|
||||
public ResponseBuilder redirectTo(String url) {
|
||||
return setStatus(302).setHeader("Location", url).setContent(new byte[]{});
|
||||
return setStatus(302).setHeader("Location", url).setContent(new byte[0]);
|
||||
}
|
||||
|
||||
public ResponseBuilder setContent(byte[] bytes) {
|
||||
response.bytes = bytes;
|
||||
return setHeader("Content-Length", bytes.length);
|
||||
return setHeader("Content-Length", bytes.length)
|
||||
.setHeader("Accept-Ranges", "bytes"); // Does not compress
|
||||
}
|
||||
|
||||
public ResponseBuilder setContent(String utf8String) {
|
||||
|
@ -68,7 +68,7 @@ public class NetworkCommand extends CommandNode {
|
||||
|
||||
// Link
|
||||
String address = PlanSystem.getMainAddress(webServer, dbSystem);
|
||||
String url = address + "/network/";
|
||||
String url = address + "/network";
|
||||
String linkPrefix = locale.getString(CommandLang.LINK_PREFIX);
|
||||
boolean console = !CommandUtils.isPlayer(sender);
|
||||
if (console) {
|
||||
|
@ -20,6 +20,7 @@ import com.djrapitops.plan.delivery.rendering.html.Html;
|
||||
import com.djrapitops.plan.storage.file.Resource;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@ -70,6 +71,17 @@ abstract class FileExporter {
|
||||
}
|
||||
}
|
||||
|
||||
void export(Path to, byte[] resource) throws IOException {
|
||||
Files.createDirectories(to.getParent());
|
||||
|
||||
try (
|
||||
InputStream in = new ByteArrayInputStream(resource);
|
||||
OutputStream out = Files.newOutputStream(to, OPEN_OPTIONS)
|
||||
) {
|
||||
copy(in, out);
|
||||
}
|
||||
}
|
||||
|
||||
String toFileName(String resourceName) {
|
||||
return StringUtils.replaceEach(
|
||||
Html.encodeToURL(resourceName),
|
||||
|
@ -128,11 +128,15 @@ public class NetworkPageExporter extends FileExporter {
|
||||
|
||||
String jsonResourceName = toFileName(toJSONResourceName(resource)) + ".json";
|
||||
|
||||
String relativePlayerLink = toRelativePathFromRoot("player");
|
||||
export(toDirectory.resolve("data").resolve(jsonResourceName),
|
||||
// Replace ../player in urls to fix player page links
|
||||
StringUtils.replace(found.getContent(), "../player", toRelativePathFromRoot("player"))
|
||||
StringUtils.replaceEach(found.getContent(),
|
||||
new String[]{"../player", "./player"},
|
||||
new String[]{relativePlayerLink, relativePlayerLink}
|
||||
)
|
||||
);
|
||||
exportPaths.put("../v1/" + resource, toRelativePathFromRoot("data/" + jsonResourceName));
|
||||
exportPaths.put("./v1/" + resource, toRelativePathFromRoot("data/" + jsonResourceName));
|
||||
}
|
||||
|
||||
private String toJSONResourceName(String resource) {
|
||||
@ -150,46 +154,48 @@ public class NetworkPageExporter extends FileExporter {
|
||||
|
||||
private void exportRequiredResources(Path toDirectory) throws IOException {
|
||||
exportResources(toDirectory,
|
||||
"img/Flaticon_circle.png",
|
||||
"css/sb-admin-2.css",
|
||||
"css/style.css",
|
||||
"vendor/jquery/jquery.min.js",
|
||||
"vendor/bootstrap/js/bootstrap.bundle.min.js",
|
||||
"vendor/jquery-easing/jquery.easing.min.js",
|
||||
"vendor/datatables/jquery.dataTables.min.js",
|
||||
"vendor/datatables/dataTables.bootstrap4.min.js",
|
||||
"vendor/highcharts/highstock.js",
|
||||
"vendor/highcharts/map.js",
|
||||
"vendor/highcharts/world.js",
|
||||
"vendor/highcharts/drilldown.js",
|
||||
"vendor/highcharts/highcharts-more.js",
|
||||
"vendor/highcharts/no-data-to-display.js",
|
||||
"vendor/fontawesome-free/css/all.min.css",
|
||||
"vendor/fontawesome-free/webfonts/fa-brands-400.eot",
|
||||
"vendor/fontawesome-free/webfonts/fa-brands-400.ttf",
|
||||
"vendor/fontawesome-free/webfonts/fa-brands-400.woff",
|
||||
"vendor/fontawesome-free/webfonts/fa-brands-400.woff2",
|
||||
"vendor/fontawesome-free/webfonts/fa-regular-400.eot",
|
||||
"vendor/fontawesome-free/webfonts/fa-regular-400.ttf",
|
||||
"vendor/fontawesome-free/webfonts/fa-regular-400.woff",
|
||||
"vendor/fontawesome-free/webfonts/fa-regular-400.woff2",
|
||||
"vendor/fontawesome-free/webfonts/fa-solid-900.eot",
|
||||
"vendor/fontawesome-free/webfonts/fa-solid-900.ttf",
|
||||
"vendor/fontawesome-free/webfonts/fa-solid-900.woff",
|
||||
"vendor/fontawesome-free/webfonts/fa-solid-900.woff2",
|
||||
"js/sb-admin-2.js",
|
||||
"js/xmlhttprequests.js",
|
||||
"js/color-selector.js",
|
||||
"js/sessionAccordion.js",
|
||||
"js/pingTable.js",
|
||||
"js/graphs.js",
|
||||
"js/network-values.js"
|
||||
"./img/Flaticon_circle.png",
|
||||
"./css/sb-admin-2.css",
|
||||
"./css/style.css",
|
||||
"./vendor/jquery/jquery.min.js",
|
||||
"./vendor/bootstrap/js/bootstrap.bundle.min.js",
|
||||
"./vendor/jquery-easing/jquery.easing.min.js",
|
||||
"./vendor/datatables/jquery.dataTables.min.js",
|
||||
"./vendor/datatables/dataTables.bootstrap4.min.js",
|
||||
"./vendor/highcharts/highstock.js",
|
||||
"./vendor/highcharts/map.js",
|
||||
"./vendor/highcharts/world.js",
|
||||
"./vendor/highcharts/drilldown.js",
|
||||
"./vendor/highcharts/highcharts-more.js",
|
||||
"./vendor/highcharts/no-data-to-display.js",
|
||||
"./vendor/fontawesome-free/css/all.min.css",
|
||||
"./vendor/fontawesome-free/webfonts/fa-brands-400.eot",
|
||||
"./vendor/fontawesome-free/webfonts/fa-brands-400.ttf",
|
||||
"./vendor/fontawesome-free/webfonts/fa-brands-400.woff",
|
||||
"./vendor/fontawesome-free/webfonts/fa-brands-400.woff2",
|
||||
"./vendor/fontawesome-free/webfonts/fa-regular-400.eot",
|
||||
"./vendor/fontawesome-free/webfonts/fa-regular-400.ttf",
|
||||
"./vendor/fontawesome-free/webfonts/fa-regular-400.woff",
|
||||
"./vendor/fontawesome-free/webfonts/fa-regular-400.woff2",
|
||||
"./vendor/fontawesome-free/webfonts/fa-solid-900.eot",
|
||||
"./vendor/fontawesome-free/webfonts/fa-solid-900.ttf",
|
||||
"./vendor/fontawesome-free/webfonts/fa-solid-900.woff",
|
||||
"./vendor/fontawesome-free/webfonts/fa-solid-900.woff2",
|
||||
"./js/sb-admin-2.js",
|
||||
"./js/xmlhttprequests.js",
|
||||
"./js/color-selector.js",
|
||||
"./js/sessionAccordion.js",
|
||||
"./js/pingTable.js",
|
||||
"./js/graphs.js",
|
||||
"./js/network-values.js"
|
||||
);
|
||||
}
|
||||
|
||||
private void exportResources(Path toDirectory, String... resourceNames) throws IOException {
|
||||
for (String resourceName : resourceNames) {
|
||||
exportResource(toDirectory, resourceName);
|
||||
String nonRelativePath = toNonRelativePath(resourceName);
|
||||
exportResource(toDirectory, nonRelativePath);
|
||||
exportPaths.put(resourceName, toRelativePathFromRoot(nonRelativePath));
|
||||
}
|
||||
}
|
||||
|
||||
@ -199,16 +205,18 @@ public class NetworkPageExporter extends FileExporter {
|
||||
|
||||
if (resourceName.endsWith(".css")) {
|
||||
export(to, theme.replaceThemeColors(resource.asString()));
|
||||
} else if ("js/network-values.js".equalsIgnoreCase(resourceName)) {
|
||||
// Replace /server in urls to fix server page links
|
||||
export(to, StringUtils.replaceOnce(resource.asString(), "server/", toRelativePathFromRoot("server") + '/'));
|
||||
} else if ("js/network-values.js".equalsIgnoreCase(resourceName) || "js/sessionAccordion.js".equalsIgnoreCase(resourceName)) {
|
||||
String relativePlayerLink = toRelativePathFromRoot("player");
|
||||
String relativeServerLink = toRelativePathFromRoot("server/");
|
||||
export(to, StringUtils.replaceEach(resource.asString(),
|
||||
new String[]{"../player", "./player", "./server/", "server/"},
|
||||
new String[]{relativePlayerLink, relativePlayerLink, relativeServerLink, relativeServerLink}
|
||||
));
|
||||
} else if (Resource.isTextResource(resourceName)) {
|
||||
export(to, resource.asLines());
|
||||
} else {
|
||||
export(to, resource);
|
||||
}
|
||||
|
||||
exportPaths.put(resourceName, toRelativePathFromRoot(resourceName));
|
||||
}
|
||||
|
||||
private String toRelativePathFromRoot(String resourceName) {
|
||||
@ -217,7 +225,7 @@ public class NetworkPageExporter extends FileExporter {
|
||||
}
|
||||
|
||||
private String toNonRelativePath(String resourceName) {
|
||||
return StringUtils.remove(resourceName, "../");
|
||||
return StringUtils.remove(StringUtils.remove(resourceName, "../"), "./");
|
||||
}
|
||||
|
||||
}
|
@ -57,6 +57,6 @@ public class PlayerJSONExporter extends FileExporter {
|
||||
}
|
||||
|
||||
private void exportJSON(Path to, UUID playerUUID) throws IOException {
|
||||
export(to, responseFactory.rawPlayerPageResponse_old(playerUUID).getContent());
|
||||
export(to, responseFactory.rawPlayerPageResponse(playerUUID).getBytes());
|
||||
}
|
||||
}
|
@ -78,7 +78,7 @@ public class PlayerPageExporter extends FileExporter {
|
||||
if (!dbSystem.getDatabase().query(PlayerFetchQueries.isPlayerRegistered(playerUUID))) return;
|
||||
|
||||
ExportPaths exportPaths = new ExportPaths();
|
||||
exportPaths.put("../network/", toRelativePathFromRoot("network"));
|
||||
exportPaths.put("../network", toRelativePathFromRoot("network"));
|
||||
exportPaths.put("../server/", toRelativePathFromRoot("server"));
|
||||
exportRequiredResources(exportPaths, toDirectory);
|
||||
|
||||
@ -197,7 +197,7 @@ public class PlayerPageExporter extends FileExporter {
|
||||
}
|
||||
|
||||
private String toNonRelativePath(String resourceName) {
|
||||
return StringUtils.remove(resourceName, "../");
|
||||
return StringUtils.remove(StringUtils.remove(resourceName, "../"), "./");
|
||||
}
|
||||
|
||||
}
|
@ -84,7 +84,7 @@ public class ServerPageExporter extends FileExporter {
|
||||
Database.State dbState = dbSystem.getDatabase().getState();
|
||||
if (dbState == Database.State.CLOSED || dbState == Database.State.CLOSING) return;
|
||||
|
||||
exportPaths.put("../network/", toRelativePathFromRoot("network"));
|
||||
exportPaths.put("../network", toRelativePathFromRoot("network"));
|
||||
exportRequiredResources(toDirectory);
|
||||
exportJSON(toDirectory, server);
|
||||
exportHtml(toDirectory, server);
|
||||
@ -163,49 +163,51 @@ public class ServerPageExporter extends FileExporter {
|
||||
private void exportRequiredResources(Path toDirectory) throws IOException {
|
||||
// Style
|
||||
exportResources(toDirectory,
|
||||
"img/Flaticon_circle.png",
|
||||
"css/sb-admin-2.css",
|
||||
"css/style.css",
|
||||
"vendor/jquery/jquery.min.js",
|
||||
"vendor/bootstrap/js/bootstrap.bundle.min.js",
|
||||
"vendor/jquery-easing/jquery.easing.min.js",
|
||||
"vendor/datatables/jquery.dataTables.min.js",
|
||||
"vendor/datatables/dataTables.bootstrap4.min.js",
|
||||
"vendor/highcharts/highstock.js",
|
||||
"vendor/highcharts/map.js",
|
||||
"vendor/highcharts/world.js",
|
||||
"vendor/highcharts/drilldown.js",
|
||||
"vendor/highcharts/highcharts-more.js",
|
||||
"vendor/highcharts/no-data-to-display.js",
|
||||
"vendor/fullcalendar/fullcalendar.min.css",
|
||||
"vendor/momentjs/moment.js",
|
||||
"vendor/fullcalendar/fullcalendar.min.js",
|
||||
"vendor/fontawesome-free/css/all.min.css",
|
||||
"vendor/fontawesome-free/webfonts/fa-brands-400.eot",
|
||||
"vendor/fontawesome-free/webfonts/fa-brands-400.ttf",
|
||||
"vendor/fontawesome-free/webfonts/fa-brands-400.woff",
|
||||
"vendor/fontawesome-free/webfonts/fa-brands-400.woff2",
|
||||
"vendor/fontawesome-free/webfonts/fa-regular-400.eot",
|
||||
"vendor/fontawesome-free/webfonts/fa-regular-400.ttf",
|
||||
"vendor/fontawesome-free/webfonts/fa-regular-400.woff",
|
||||
"vendor/fontawesome-free/webfonts/fa-regular-400.woff2",
|
||||
"vendor/fontawesome-free/webfonts/fa-solid-900.eot",
|
||||
"vendor/fontawesome-free/webfonts/fa-solid-900.ttf",
|
||||
"vendor/fontawesome-free/webfonts/fa-solid-900.woff",
|
||||
"vendor/fontawesome-free/webfonts/fa-solid-900.woff2",
|
||||
"js/sb-admin-2.js",
|
||||
"js/xmlhttprequests.js",
|
||||
"js/color-selector.js",
|
||||
"js/sessionAccordion.js",
|
||||
"js/pingTable.js",
|
||||
"js/graphs.js",
|
||||
"js/server-values.js"
|
||||
"../img/Flaticon_circle.png",
|
||||
"../css/sb-admin-2.css",
|
||||
"../css/style.css",
|
||||
"../vendor/jquery/jquery.min.js",
|
||||
"../vendor/bootstrap/js/bootstrap.bundle.min.js",
|
||||
"../vendor/jquery-easing/jquery.easing.min.js",
|
||||
"../vendor/datatables/jquery.dataTables.min.js",
|
||||
"../vendor/datatables/dataTables.bootstrap4.min.js",
|
||||
"../vendor/highcharts/highstock.js",
|
||||
"../vendor/highcharts/map.js",
|
||||
"../vendor/highcharts/world.js",
|
||||
"../vendor/highcharts/drilldown.js",
|
||||
"../vendor/highcharts/highcharts-more.js",
|
||||
"../vendor/highcharts/no-data-to-display.js",
|
||||
"../vendor/fullcalendar/fullcalendar.min.css",
|
||||
"../vendor/momentjs/moment.js",
|
||||
"../vendor/fullcalendar/fullcalendar.min.js",
|
||||
"../vendor/fontawesome-free/css/all.min.css",
|
||||
"../vendor/fontawesome-free/webfonts/fa-brands-400.eot",
|
||||
"../vendor/fontawesome-free/webfonts/fa-brands-400.ttf",
|
||||
"../vendor/fontawesome-free/webfonts/fa-brands-400.woff",
|
||||
"../vendor/fontawesome-free/webfonts/fa-brands-400.woff2",
|
||||
"../vendor/fontawesome-free/webfonts/fa-regular-400.eot",
|
||||
"../vendor/fontawesome-free/webfonts/fa-regular-400.ttf",
|
||||
"../vendor/fontawesome-free/webfonts/fa-regular-400.woff",
|
||||
"../vendor/fontawesome-free/webfonts/fa-regular-400.woff2",
|
||||
"../vendor/fontawesome-free/webfonts/fa-solid-900.eot",
|
||||
"../vendor/fontawesome-free/webfonts/fa-solid-900.ttf",
|
||||
"../vendor/fontawesome-free/webfonts/fa-solid-900.woff",
|
||||
"../vendor/fontawesome-free/webfonts/fa-solid-900.woff2",
|
||||
"../js/sb-admin-2.js",
|
||||
"../js/xmlhttprequests.js",
|
||||
"../js/color-selector.js",
|
||||
"../js/sessionAccordion.js",
|
||||
"../js/pingTable.js",
|
||||
"../js/graphs.js",
|
||||
"../js/server-values.js"
|
||||
);
|
||||
}
|
||||
|
||||
private void exportResources(Path toDirectory, String... resourceNames) throws IOException {
|
||||
for (String resourceName : resourceNames) {
|
||||
exportResource(toDirectory, resourceName);
|
||||
String nonRelativePath = toNonRelativePath(resourceName);
|
||||
exportResource(toDirectory, nonRelativePath);
|
||||
exportPaths.put(resourceName, toRelativePathFromRoot(nonRelativePath));
|
||||
}
|
||||
}
|
||||
|
||||
@ -220,8 +222,6 @@ public class ServerPageExporter extends FileExporter {
|
||||
} else {
|
||||
export(to, resource);
|
||||
}
|
||||
|
||||
exportPaths.put(resourceName, toRelativePathFromRoot(resourceName));
|
||||
}
|
||||
|
||||
private String toRelativePathFromRoot(String resourceName) {
|
||||
@ -230,7 +230,7 @@ public class ServerPageExporter extends FileExporter {
|
||||
}
|
||||
|
||||
private String toNonRelativePath(String resourceName) {
|
||||
return StringUtils.remove(resourceName, "../");
|
||||
return StringUtils.remove(StringUtils.remove(resourceName, "../"), "./");
|
||||
}
|
||||
|
||||
}
|
@ -52,7 +52,7 @@ public enum Html {
|
||||
LINK("<a class=\"link\" href=\"${0}\">${1}</a>"),
|
||||
LINK_EXTERNAL("<a class=\"link\" rel=\"noopener noreferrer\" target=\"_blank\" href=\"${0}\">${1}</a>"),
|
||||
|
||||
BACK_BUTTON_NETWORK("<a class=\"btn bg-plan btn-icon-split\" href=\"../network/\">" +
|
||||
BACK_BUTTON_NETWORK("<a class=\"btn bg-plan btn-icon-split\" href=\"../network\">" +
|
||||
"<span class=\"icon text-white-50\">" +
|
||||
"<i class=\"fas fa-fw fa-arrow-left\"></i><i class=\"fas fa-fw fa-cloud\"></i>" +
|
||||
"</span>" +
|
||||
|
@ -18,9 +18,7 @@ package com.djrapitops.plan.delivery.webserver;
|
||||
|
||||
import com.djrapitops.plan.delivery.web.ResolverService;
|
||||
import com.djrapitops.plan.delivery.web.ResolverSvc;
|
||||
import com.djrapitops.plan.delivery.web.resolver.Resolver;
|
||||
import com.djrapitops.plan.delivery.web.resolver.URIPath;
|
||||
import com.djrapitops.plan.delivery.web.resolver.URIQuery;
|
||||
import com.djrapitops.plan.delivery.web.resolver.*;
|
||||
import com.djrapitops.plan.delivery.webserver.auth.Authentication;
|
||||
import com.djrapitops.plan.delivery.webserver.pages.*;
|
||||
import com.djrapitops.plan.delivery.webserver.pages.json.RootJSONResolver;
|
||||
@ -91,12 +89,13 @@ public class ResponseResolver extends CompositePageResolver {
|
||||
}
|
||||
|
||||
public void registerPages() {
|
||||
resolverService.registerResolver("Plan", "/debug", debugPageResolver);
|
||||
resolverService.registerResolver("Plan", "/players", playersPageResolver);
|
||||
resolverService.registerResolver("Plan", "/player", playerPageResolver);
|
||||
|
||||
registerPage("network", serverPageResolver);
|
||||
registerPage("server", serverPageResolver);
|
||||
String pluginName = "Plan";
|
||||
resolverService.registerResolver(pluginName, "/debug", debugPageResolver);
|
||||
resolverService.registerResolver(pluginName, "/players", playersPageResolver);
|
||||
resolverService.registerResolver(pluginName, "/player", playerPageResolver);
|
||||
resolverService.registerResolver(pluginName, "/favicon.ico", noAuthResolverFor(responseFactory.faviconResponse()));
|
||||
resolverService.registerResolver(pluginName, "/network", serverPageResolver);
|
||||
resolverService.registerResolver(pluginName, "/server", serverPageResolver);
|
||||
|
||||
// TODO Figure out how to deal with stuff like this
|
||||
registerPage("", new RootPageResolver(responseFactory, webServer.get(), serverInfo));
|
||||
@ -104,6 +103,10 @@ public class ResponseResolver extends CompositePageResolver {
|
||||
registerPage("v1", rootJSONResolver);
|
||||
}
|
||||
|
||||
public NoAuthResolver noAuthResolverFor(Response response) {
|
||||
return (target, query) -> Optional.of(response);
|
||||
}
|
||||
|
||||
public Response_old getResponse(Request request) {
|
||||
try {
|
||||
return tryToGetResponse(request);
|
||||
@ -171,9 +174,6 @@ public class ResponseResolver extends CompositePageResolver {
|
||||
if (target.endsWith(".png")) {
|
||||
return responseFactory.imageResponse_old(resource);
|
||||
}
|
||||
if (target.endsWith("favicon.ico")) {
|
||||
return responseFactory.faviconResponse_old();
|
||||
}
|
||||
if (target.endsWithAny(".woff", ".woff2", ".eot", ".ttf")) {
|
||||
return responseFactory.fontResponse_old(resource);
|
||||
}
|
||||
|
@ -17,19 +17,12 @@
|
||||
package com.djrapitops.plan.delivery.webserver.pages;
|
||||
|
||||
import com.djrapitops.plan.delivery.rendering.html.Html;
|
||||
import com.djrapitops.plan.delivery.webserver.Request;
|
||||
import com.djrapitops.plan.delivery.webserver.RequestTarget;
|
||||
import com.djrapitops.plan.delivery.web.resolver.*;
|
||||
import com.djrapitops.plan.delivery.webserver.WebServer;
|
||||
import com.djrapitops.plan.delivery.webserver.auth.Authentication;
|
||||
import com.djrapitops.plan.delivery.webserver.response.ResponseFactory;
|
||||
import com.djrapitops.plan.delivery.webserver.response.Response_old;
|
||||
import com.djrapitops.plan.exceptions.WebUserAuthException;
|
||||
import com.djrapitops.plan.exceptions.connection.ForbiddenException;
|
||||
import com.djrapitops.plan.exceptions.connection.WebException;
|
||||
import com.djrapitops.plan.identification.Server;
|
||||
import com.djrapitops.plan.identification.ServerInfo;
|
||||
import com.djrapitops.plan.storage.database.DBSystem;
|
||||
import com.djrapitops.plan.storage.database.Database;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.ServerQueries;
|
||||
import dagger.Lazy;
|
||||
|
||||
@ -44,7 +37,7 @@ import java.util.UUID;
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Singleton
|
||||
public class ServerPageResolver implements PageResolver {
|
||||
public class ServerPageResolver implements Resolver {
|
||||
|
||||
private final ResponseFactory responseFactory;
|
||||
private final DBSystem dbSystem;
|
||||
@ -65,45 +58,42 @@ public class ServerPageResolver implements PageResolver {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response_old resolve(Request request, RequestTarget target) throws WebException {
|
||||
Optional<UUID> serverUUID = getServerUUID(target);
|
||||
boolean proxy = serverInfo.getServer().isProxy();
|
||||
if (serverUUID.isPresent()) {
|
||||
checkDBState();
|
||||
if (proxy && serverInfo.getServerUUID().equals(serverUUID.get())) {
|
||||
return responseFactory.networkPageResponse_old();
|
||||
}
|
||||
return responseFactory.serverPageResponse_old(serverUUID.get());
|
||||
} else {
|
||||
// Redirect to base server page.
|
||||
String directTo = proxy ? "/network" : "/server/" + Html.encodeToURL(serverInfo.getServer().getIdentifiableName());
|
||||
return responseFactory.redirectResponse_old(webServer.get().getAccessAddress() + directTo);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkDBState() throws ForbiddenException {
|
||||
Database.State dbState = dbSystem.getDatabase().getState();
|
||||
if (dbState != Database.State.OPEN) {
|
||||
throw new ForbiddenException("Database is " + dbState.name() + " - Please try again later. You can check database status with /plan info");
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<UUID> getServerUUID(RequestTarget target) {
|
||||
if (!target.isEmpty()) {
|
||||
try {
|
||||
String serverName = target.get(0);
|
||||
return dbSystem.getDatabase()
|
||||
.query(ServerQueries.fetchServerMatchingIdentifier(serverName))
|
||||
.map(Server::getUuid);
|
||||
} catch (IllegalArgumentException ignore) {
|
||||
/*ignored*/
|
||||
}
|
||||
}
|
||||
return Optional.of(serverInfo.getServer().getUuid());
|
||||
public boolean canAccess(WebUser permissions, URIPath target, URIQuery query) {
|
||||
String firstPart = target.getPart(0).orElse("");
|
||||
boolean forServerPage = firstPart.equalsIgnoreCase("server") && permissions.hasPermission("page.server");
|
||||
boolean forNetworkPage = firstPart.equalsIgnoreCase("network") && permissions.hasPermission("page.network");
|
||||
return forServerPage || forNetworkPage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAuthorized(Authentication auth, RequestTarget target) throws WebUserAuthException {
|
||||
return auth.getWebUser().getPermLevel() <= 0;
|
||||
public Optional<Response> resolve(URIPath target, URIQuery query) {
|
||||
return getServerUUID(target)
|
||||
.map(this::getServerPage)
|
||||
.orElseGet(this::redirectToCurrentServer);
|
||||
}
|
||||
|
||||
private Optional<Response> redirectToCurrentServer() {
|
||||
String directTo = serverInfo.getServer().isProxy()
|
||||
? "/network"
|
||||
: "/server/" + Html.encodeToURL(serverInfo.getServer().getIdentifiableName());
|
||||
return Optional.of(responseFactory.redirectResponse(webServer.get().getAccessAddress() + directTo));
|
||||
}
|
||||
|
||||
private Optional<Response> getServerPage(UUID serverUUID) {
|
||||
boolean toNetworkPage = serverInfo.getServer().isProxy() && serverInfo.getServerUUID().equals(serverUUID);
|
||||
if (toNetworkPage) return Optional.of(responseFactory.networkPageResponse());
|
||||
return Optional.of(responseFactory.serverPageResponse(serverUUID));
|
||||
}
|
||||
|
||||
private Optional<UUID> getServerUUID(URIPath path) {
|
||||
if (serverInfo.getServer().isProxy()
|
||||
&& path.getPart(0).map("network"::equals).orElse(false)
|
||||
&& !path.getPart(1).isPresent() // No slash at the end.
|
||||
) {
|
||||
return Optional.of(serverInfo.getServerUUID());
|
||||
}
|
||||
return path.getPart(1).flatMap(serverName -> dbSystem.getDatabase()
|
||||
.query(ServerQueries.fetchServerMatchingIdentifier(serverName))
|
||||
.map(Server::getUuid));
|
||||
}
|
||||
}
|
||||
|
@ -22,9 +22,7 @@ import com.djrapitops.plan.delivery.rendering.pages.PageFactory;
|
||||
import com.djrapitops.plan.delivery.web.resolver.MimeType;
|
||||
import com.djrapitops.plan.delivery.web.resolver.Response;
|
||||
import com.djrapitops.plan.delivery.webserver.response.errors.*;
|
||||
import com.djrapitops.plan.delivery.webserver.response.pages.PageResponse;
|
||||
import com.djrapitops.plan.delivery.webserver.response.pages.RawDataResponse;
|
||||
import com.djrapitops.plan.delivery.webserver.response.pages.RawPlayerDataResponse;
|
||||
import com.djrapitops.plan.exceptions.WebUserAuthException;
|
||||
import com.djrapitops.plan.exceptions.connection.NotFoundException;
|
||||
import com.djrapitops.plan.settings.locale.Locale;
|
||||
@ -74,7 +72,7 @@ public class ResponseFactory {
|
||||
try {
|
||||
return forPage(pageFactory.debugPage());
|
||||
} catch (IOException e) {
|
||||
return forInternalError("Failed to generate debug page", e);
|
||||
return forInternalError(e, "Failed to generate debug page");
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,7 +83,7 @@ public class ResponseFactory {
|
||||
.build();
|
||||
}
|
||||
|
||||
private Response forInternalError(String cause, Throwable error) {
|
||||
private Response forInternalError(Throwable error, String cause) {
|
||||
return Response.builder()
|
||||
.setMimeType(MimeType.HTML)
|
||||
.setContent(pageFactory.internalErrorPage(cause, error).toHtml())
|
||||
@ -95,21 +93,21 @@ public class ResponseFactory {
|
||||
|
||||
public Response playersPageResponse() {
|
||||
try {
|
||||
Optional<Response> error = checkIfDBIsOpen();
|
||||
Optional<Response> error = checkDbClosedError();
|
||||
if (error.isPresent()) return error.get();
|
||||
return forPage(pageFactory.playersPage());
|
||||
} catch (IOException e) {
|
||||
return forInternalError("Failed to generate players page", e);
|
||||
return forInternalError(e, "Failed to generate players page");
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<Response> checkIfDBIsOpen() {
|
||||
private Optional<Response> checkDbClosedError() {
|
||||
Database.State dbState = dbSystem.getDatabase().getState();
|
||||
if (dbState != Database.State.OPEN) {
|
||||
try {
|
||||
return Optional.of(buildDBNotOpenResponse(dbState));
|
||||
} catch (IOException e) {
|
||||
return Optional.of(forInternalError("Database was not open, additionally failed to generate error page for that", e));
|
||||
return Optional.of(forInternalError(e, "Database was not open, additionally failed to generate error page for that"));
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
@ -139,29 +137,28 @@ public class ResponseFactory {
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Response_old networkPageResponse_old() {
|
||||
public Response networkPageResponse() {
|
||||
Optional<Response> error = checkDbClosedError();
|
||||
if (error.isPresent()) return error.get();
|
||||
try {
|
||||
return new PageResponse(pageFactory.networkPage());
|
||||
return forPage(pageFactory.networkPage());
|
||||
} catch (IOException e) {
|
||||
return internalErrorResponse_old(e, "Failed to generate network page");
|
||||
return forInternalError(e, "Failed to generate network page");
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Response_old serverPageResponse_old(UUID serverUUID) throws NotFoundException {
|
||||
public Response serverPageResponse(UUID serverUUID) {
|
||||
Optional<Response> error = checkDbClosedError();
|
||||
if (error.isPresent()) return error.get();
|
||||
try {
|
||||
return new PageResponse(pageFactory.serverPage(serverUUID));
|
||||
return forPage(pageFactory.serverPage(serverUUID));
|
||||
} catch (NotFoundException e) {
|
||||
return notFound404(e.getMessage());
|
||||
} catch (IOException e) {
|
||||
return internalErrorResponse_old(e, "Failed to generate server page");
|
||||
return forInternalError(e, "Failed to generate server page");
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public RawDataResponse rawPlayerPageResponse_old(UUID uuid) {
|
||||
return new RawPlayerDataResponse(dbSystem.getDatabase().query(ContainerFetchQueries.fetchPlayerContainer(uuid)));
|
||||
}
|
||||
|
||||
public Response rawPlayerPageResponse(UUID playerUUID) {
|
||||
PlayerContainer player = dbSystem.getDatabase().query(ContainerFetchQueries.fetchPlayerContainer(playerUUID));
|
||||
return Response.builder()
|
||||
@ -219,9 +216,19 @@ public class ResponseFactory {
|
||||
return new RedirectResponse(location);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Response_old faviconResponse_old() {
|
||||
return new ByteResponse(ResponseType.X_ICON, "web/favicon.ico", files);
|
||||
public Response redirectResponse(String location) {
|
||||
return Response.builder().redirectTo(location).build();
|
||||
}
|
||||
|
||||
public Response faviconResponse() {
|
||||
try {
|
||||
return Response.builder()
|
||||
.setMimeType(MimeType.FAVICON)
|
||||
.setContent(files.getCustomizableResourceOrDefault("web/favicon.ico").asBytes())
|
||||
.build();
|
||||
} catch (IOException e) {
|
||||
return forInternalError(e, "Could not read favicon");
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@ -229,20 +236,10 @@ public class ResponseFactory {
|
||||
return notFound404_old(locale.getString(ErrorPageLang.UNKNOWN_PAGE_404));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public ErrorResponse uuidNotFound404_old() {
|
||||
return notFound404_old(locale.getString(ErrorPageLang.UUID_404));
|
||||
}
|
||||
|
||||
public Response uuidNotFound404() {
|
||||
return notFound404(locale.getString(ErrorPageLang.UUID_404));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public ErrorResponse playerNotFound404_old() {
|
||||
return notFound404_old(locale.getString(ErrorPageLang.NOT_PLAYED_404));
|
||||
}
|
||||
|
||||
public Response playerNotFound404() {
|
||||
return notFound404(locale.getString(ErrorPageLang.NOT_PLAYED_404));
|
||||
}
|
||||
@ -265,7 +262,7 @@ public class ResponseFactory {
|
||||
.setStatus(404)
|
||||
.build();
|
||||
} catch (IOException e) {
|
||||
return forInternalError("Failed to generate 404 page with message '" + message + "'", e);
|
||||
return forInternalError(e, "Failed to generate 404 page with message '" + message + "'");
|
||||
}
|
||||
}
|
||||
|
||||
@ -313,18 +310,7 @@ public class ResponseFactory {
|
||||
} catch (IllegalStateException e) {
|
||||
return playerNotFound404();
|
||||
} catch (IOException e) {
|
||||
return forInternalError("Failed to generate player page", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Response_old playerPageResponse_old(UUID playerUUID) {
|
||||
try {
|
||||
return new PageResponse(pageFactory.playerPage(playerUUID));
|
||||
} catch (IllegalStateException e) {
|
||||
return playerNotFound404_old();
|
||||
} catch (IOException e) {
|
||||
return internalErrorResponse_old(e, "Failed to generate player page");
|
||||
return forInternalError(e, "Failed to generate player page");
|
||||
}
|
||||
}
|
||||
}
|
@ -103,6 +103,10 @@ public abstract class Response_old {
|
||||
.orElse(new String(apiResponse.getBytes())));
|
||||
response.setHeader("HTTP/1.1 " + apiResponse.getCode() + " ");
|
||||
for (Map.Entry<String, String> header : apiResponse.getHeaders().entrySet()) {
|
||||
if (header.getKey().equals("Content-Type")) {
|
||||
response.type = header.getValue();
|
||||
continue;
|
||||
}
|
||||
response.header += header.getKey() + ": " + header.getValue() + ";\r\n";
|
||||
}
|
||||
return response;
|
||||
@ -132,6 +136,7 @@ public abstract class Response_old {
|
||||
public void send(HttpExchange exchange, Locale locale, Theme theme) throws IOException {
|
||||
responseHeaders.set("Content-Type", type);
|
||||
responseHeaders.set("Content-Encoding", "gzip");
|
||||
// TODO handle case of ByteResponse when "Accept-Ranges", "bytes" is set
|
||||
exchange.sendResponseHeaders(getCode(), 0);
|
||||
|
||||
try (
|
||||
|
@ -63,6 +63,11 @@ public class FileResource implements Resource {
|
||||
return new FileInputStream(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] asBytes() throws IOException {
|
||||
return Files.readAllBytes(file.toPath());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> asLines() throws IOException {
|
||||
return lines(file);
|
||||
|
@ -16,6 +16,9 @@
|
||||
*/
|
||||
package com.djrapitops.plan.storage.file;
|
||||
|
||||
import org.apache.commons.compress.utils.IOUtils;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@ -77,6 +80,17 @@ public class JarResource implements Resource {
|
||||
return flat.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] asBytes() throws IOException {
|
||||
try (
|
||||
InputStream in = asInputStream();
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream()
|
||||
) {
|
||||
IOUtils.copy(in, out);
|
||||
return out.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResourceName() {
|
||||
return resourceName;
|
||||
|
@ -36,6 +36,8 @@ public interface Resource {
|
||||
*/
|
||||
String getResourceName();
|
||||
|
||||
byte[] asBytes() throws IOException;
|
||||
|
||||
/**
|
||||
* Get the resource as an InputStream.
|
||||
*
|
||||
|
@ -54,4 +54,9 @@ public class StringCachingResource implements Resource {
|
||||
ResourceCache.cache(implementation.getResourceName(), got);
|
||||
return got;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] asBytes() throws IOException {
|
||||
return implementation.asBytes();
|
||||
}
|
||||
}
|
@ -58,4 +58,9 @@ public class StringResource implements Resource {
|
||||
public String asString() {
|
||||
return resource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] asBytes() {
|
||||
return resource.getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
@ -13,14 +13,14 @@
|
||||
<title>Plan | Network</title>
|
||||
|
||||
<!-- Custom fonts for this template-->
|
||||
<link href="vendor/fontawesome-free/css/all.min.css" rel="stylesheet">
|
||||
<link href="./vendor/fontawesome-free/css/all.min.css" rel="stylesheet">
|
||||
<link crossorigin="anonymous"
|
||||
href="https://fonts.googleapis.com/css?family=Nunito:400,700,800,900&display=swap&subset=latin-ext"
|
||||
rel="stylesheet">
|
||||
|
||||
<!-- Custom styles for this template-->
|
||||
<link href="css/sb-admin-2.css" rel="stylesheet">
|
||||
<link href="css/style.css" rel="stylesheet">
|
||||
<link href="./css/sb-admin-2.css" rel="stylesheet">
|
||||
<link href="./css/style.css" rel="stylesheet">
|
||||
|
||||
</head>
|
||||
|
||||
@ -41,7 +41,7 @@
|
||||
|
||||
<!-- Sidebar - Brand -->
|
||||
<a class="sidebar-brand d-flex align-items-center justify-content-center">
|
||||
<img class="w-22" src="img/Flaticon_circle.png">
|
||||
<img class="w-22" src="./img/Flaticon_circle.png">
|
||||
</a>
|
||||
|
||||
<!-- Divider -->
|
||||
@ -777,41 +777,41 @@
|
||||
</a>
|
||||
|
||||
<!-- Bootstrap core JavaScript-->
|
||||
<script src="vendor/jquery/jquery.min.js"></script>
|
||||
<script src="vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="./vendor/jquery/jquery.min.js"></script>
|
||||
<script src="./vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
<!-- Core plugin JavaScript-->
|
||||
<script src="vendor/jquery-easing/jquery.easing.min.js"></script>
|
||||
<script src="./vendor/jquery-easing/jquery.easing.min.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/map.js"></script>
|
||||
<script src="vendor/highcharts/world.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>
|
||||
<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/map.js"></script>
|
||||
<script src="./vendor/highcharts/world.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>
|
||||
|
||||
<!-- Custom scripts for all pages-->
|
||||
<script src="js/sb-admin-2.js"></script>
|
||||
<script src="js/xmlhttprequests.js"></script>
|
||||
<script src="js/color-selector.js"></script>
|
||||
<script src="./js/sb-admin-2.js"></script>
|
||||
<script src="./js/xmlhttprequests.js"></script>
|
||||
<script src="./js/color-selector.js"></script>
|
||||
|
||||
<!-- Page level custom scripts -->
|
||||
<script src="js/sessionAccordion.js"></script>
|
||||
<script src="js/pingTable.js"></script>
|
||||
<script src="js/graphs.js"></script>
|
||||
<script src="js/network-values.js"></script>
|
||||
<script src="./js/sessionAccordion.js"></script>
|
||||
<script src="./js/pingTable.js"></script>
|
||||
<script src="./js/graphs.js"></script>
|
||||
<script src="./js/network-values.js"></script>
|
||||
|
||||
<script>
|
||||
try {
|
||||
setLoadingText('Calculating values..');
|
||||
jsonRequest("../v1/network/overview", loadNetworkOverviewValues);
|
||||
jsonRequest("../v1/network/servers", loadservers);
|
||||
jsonRequest("../v1/network/sessionsOverview", loadSessionValues);
|
||||
jsonRequest("../v1/network/playerbaseOverview", loadPlayerbaseOverviewValues);
|
||||
jsonRequest("../v1/sessions", loadSessionAccordion);
|
||||
jsonRequest("./v1/network/overview", loadNetworkOverviewValues);
|
||||
jsonRequest("./v1/network/servers", loadservers);
|
||||
jsonRequest("./v1/network/sessionsOverview", loadSessionValues);
|
||||
jsonRequest("./v1/network/playerbaseOverview", loadPlayerbaseOverviewValues);
|
||||
jsonRequest("./v1/sessions", loadSessionAccordion);
|
||||
setLoadingText('Rendering graphs..');
|
||||
|
||||
var v = {
|
||||
@ -858,7 +858,7 @@
|
||||
}
|
||||
};
|
||||
|
||||
jsonRequest("../v1/graph?type=playersOnline&server=${serverUUID}", function (json, error) {
|
||||
jsonRequest("./v1/graph?type=playersOnline&server=${serverUUID}", function (json, error) {
|
||||
if (json) {
|
||||
var series = {
|
||||
playersOnline: {
|
||||
@ -872,7 +872,7 @@
|
||||
}
|
||||
});
|
||||
|
||||
jsonRequest("../v1/graph?type=uniqueAndNew", function (json, error) {
|
||||
jsonRequest("./v1/graph?type=uniqueAndNew", function (json, error) {
|
||||
if (json) {
|
||||
var uniquePlayers = {
|
||||
name: s.name.uniquePlayers, type: s.type.spline, tooltip: s.tooltip.zeroDecimals,
|
||||
@ -888,7 +888,7 @@
|
||||
}
|
||||
});
|
||||
|
||||
jsonRequest("../v1/graph?type=serverPie", function (json, error) {
|
||||
jsonRequest("./v1/graph?type=serverPie", function (json, error) {
|
||||
if (json) {
|
||||
serverPieSeries = {
|
||||
name: 'Server Playtime',
|
||||
@ -902,7 +902,7 @@
|
||||
}
|
||||
});
|
||||
|
||||
jsonRequest("../v1/graph?type=activity", function (json, error) {
|
||||
jsonRequest("./v1/graph?type=activity", function (json, error) {
|
||||
if (json) {
|
||||
activityPie('activityPie', {
|
||||
name: 'Players', colorByPoint: true, data: json.activity_pie_series
|
||||
@ -914,7 +914,7 @@
|
||||
}
|
||||
});
|
||||
|
||||
jsonRequest("../v1/graph?type=geolocation", function (json, error) {
|
||||
jsonRequest("./v1/graph?type=geolocation", function (json, error) {
|
||||
if (json) {
|
||||
var geolocationSeries = {
|
||||
name: 'Players',
|
||||
@ -943,7 +943,7 @@
|
||||
|
||||
setLoadingText('Sorting out plugin tables..');
|
||||
|
||||
jsonRequest("../v1/network/pingTable", loadPingTable);
|
||||
jsonRequest("./v1/network/pingTable", loadPingTable);
|
||||
|
||||
$('.player-plugin-table').DataTable({
|
||||
responsive: true
|
||||
|
@ -12,14 +12,14 @@
|
||||
<title>Plan | Server Analysis</title>
|
||||
|
||||
<!-- Custom fonts for this template-->
|
||||
<link href="vendor/fontawesome-free/css/all.min.css" rel="stylesheet">
|
||||
<link href="../vendor/fontawesome-free/css/all.min.css" rel="stylesheet">
|
||||
<link crossorigin="anonymous"
|
||||
href="https://fonts.googleapis.com/css?family=Nunito:400,700,800,900&display=swap&subset=latin-ext"
|
||||
rel="stylesheet">
|
||||
|
||||
<!-- Custom styles for this template-->
|
||||
<link href="css/sb-admin-2.css" rel="stylesheet">
|
||||
<link href="css/style.css" rel="stylesheet">
|
||||
<link href="../css/sb-admin-2.css" rel="stylesheet">
|
||||
<link href="../css/style.css" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body id="page-top">
|
||||
@ -39,7 +39,7 @@
|
||||
|
||||
<!-- Sidebar - Brand -->
|
||||
<a class="sidebar-brand d-flex align-items-center justify-content-center">
|
||||
<img class="w-22" src="img/Flaticon_circle.png">
|
||||
<img class="w-22" src="../img/Flaticon_circle.png">
|
||||
</a>
|
||||
|
||||
<!-- Divider -->
|
||||
@ -1252,35 +1252,35 @@
|
||||
</a>
|
||||
|
||||
<!-- Bootstrap core JavaScript-->
|
||||
<script src="vendor/jquery/jquery.min.js"></script>
|
||||
<script src="vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="../vendor/jquery/jquery.min.js"></script>
|
||||
<script src="../vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
<!-- Core plugin JavaScript-->
|
||||
<script src="vendor/jquery-easing/jquery.easing.min.js"></script>
|
||||
<script src="../vendor/jquery-easing/jquery.easing.min.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/map.js"></script>
|
||||
<script src="vendor/highcharts/world.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>
|
||||
<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/map.js"></script>
|
||||
<script src="../vendor/highcharts/world.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>
|
||||
|
||||
<!-- Custom scripts for all pages-->
|
||||
<script src="js/sb-admin-2.js"></script>
|
||||
<script src="js/xmlhttprequests.js"></script>
|
||||
<script src="js/color-selector.js"></script>
|
||||
<script src="../js/sb-admin-2.js"></script>
|
||||
<script src="../js/xmlhttprequests.js"></script>
|
||||
<script src="../js/color-selector.js"></script>
|
||||
|
||||
<!-- Page level custom scripts -->
|
||||
<script src="js/sessionAccordion.js"></script>
|
||||
<script src="js/pingTable.js"></script>
|
||||
<script src="js/graphs.js"></script>
|
||||
<script src="js/server-values.js"></script>
|
||||
<script src="../js/sessionAccordion.js"></script>
|
||||
<script src="../js/pingTable.js"></script>
|
||||
<script src="../js/graphs.js"></script>
|
||||
<script src="../js/server-values.js"></script>
|
||||
|
||||
<script>
|
||||
try {
|
||||
|
@ -68,4 +68,9 @@ public class SpongeAssetResource implements Resource {
|
||||
public String asString() throws IOException {
|
||||
return asset.readString(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] asBytes() throws IOException {
|
||||
return asset.readBytes();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user