Refactored /players page to use ResolverService

- Changed all css, js and png requests on player page to use relative address.
- Changed the export accordingly

Deprecated a lot of the old response factory methods
This commit is contained in:
Rsl1122 2020-02-14 10:43:47 +02:00 committed by Risto Lahtela
parent 2914966650
commit e997289a20
8 changed files with 183 additions and 129 deletions

View File

@ -131,48 +131,50 @@ public class PlayerPageExporter extends FileExporter {
private void exportRequiredResources(ExportPaths exportPaths, Path toDirectory) throws IOException { private void exportRequiredResources(ExportPaths exportPaths, Path toDirectory) throws IOException {
// Style // Style
exportResources(exportPaths, toDirectory, exportResources(exportPaths, toDirectory,
"img/Flaticon_circle.png", "../img/Flaticon_circle.png",
"css/sb-admin-2.css", "../css/sb-admin-2.css",
"css/style.css", "../css/style.css",
"vendor/jquery/jquery.min.js", "../vendor/jquery/jquery.min.js",
"vendor/bootstrap/js/bootstrap.bundle.min.js", "../vendor/bootstrap/js/bootstrap.bundle.min.js",
"vendor/jquery-easing/jquery.easing.min.js", "../vendor/jquery-easing/jquery.easing.min.js",
"vendor/datatables/jquery.dataTables.min.js", "../vendor/datatables/jquery.dataTables.min.js",
"vendor/datatables/dataTables.bootstrap4.min.js", "../vendor/datatables/dataTables.bootstrap4.min.js",
"vendor/highcharts/highstock.js", "../vendor/highcharts/highstock.js",
"vendor/highcharts/map.js", "../vendor/highcharts/map.js",
"vendor/highcharts/world.js", "../vendor/highcharts/world.js",
"vendor/highcharts/drilldown.js", "../vendor/highcharts/drilldown.js",
"vendor/highcharts/highcharts-more.js", "../vendor/highcharts/highcharts-more.js",
"vendor/highcharts/no-data-to-display.js", "../vendor/highcharts/no-data-to-display.js",
"vendor/fullcalendar/fullcalendar.min.css", "../vendor/fullcalendar/fullcalendar.min.css",
"vendor/momentjs/moment.js", "../vendor/momentjs/moment.js",
"vendor/fullcalendar/fullcalendar.min.js", "../vendor/fullcalendar/fullcalendar.min.js",
"vendor/fontawesome-free/css/all.min.css", "../vendor/fontawesome-free/css/all.min.css",
"vendor/fontawesome-free/webfonts/fa-brands-400.eot", "../vendor/fontawesome-free/webfonts/fa-brands-400.eot",
"vendor/fontawesome-free/webfonts/fa-brands-400.ttf", "../vendor/fontawesome-free/webfonts/fa-brands-400.ttf",
"vendor/fontawesome-free/webfonts/fa-brands-400.woff", "../vendor/fontawesome-free/webfonts/fa-brands-400.woff",
"vendor/fontawesome-free/webfonts/fa-brands-400.woff2", "../vendor/fontawesome-free/webfonts/fa-brands-400.woff2",
"vendor/fontawesome-free/webfonts/fa-regular-400.eot", "../vendor/fontawesome-free/webfonts/fa-regular-400.eot",
"vendor/fontawesome-free/webfonts/fa-regular-400.ttf", "../vendor/fontawesome-free/webfonts/fa-regular-400.ttf",
"vendor/fontawesome-free/webfonts/fa-regular-400.woff", "../vendor/fontawesome-free/webfonts/fa-regular-400.woff",
"vendor/fontawesome-free/webfonts/fa-regular-400.woff2", "../vendor/fontawesome-free/webfonts/fa-regular-400.woff2",
"vendor/fontawesome-free/webfonts/fa-solid-900.eot", "../vendor/fontawesome-free/webfonts/fa-solid-900.eot",
"vendor/fontawesome-free/webfonts/fa-solid-900.ttf", "../vendor/fontawesome-free/webfonts/fa-solid-900.ttf",
"vendor/fontawesome-free/webfonts/fa-solid-900.woff", "../vendor/fontawesome-free/webfonts/fa-solid-900.woff",
"vendor/fontawesome-free/webfonts/fa-solid-900.woff2", "../vendor/fontawesome-free/webfonts/fa-solid-900.woff2",
"js/sb-admin-2.js", "../js/sb-admin-2.js",
"js/xmlhttprequests.js", "../js/xmlhttprequests.js",
"js/color-selector.js", "../js/color-selector.js",
"js/sessionAccordion.js", "../js/sessionAccordion.js",
"js/graphs.js", "../js/graphs.js",
"js/player-values.js" "../js/player-values.js"
); );
} }
private void exportResources(ExportPaths exportPaths, Path toDirectory, String... resourceNames) throws IOException { private void exportResources(ExportPaths exportPaths, Path toDirectory, String... resourceNames) throws IOException {
for (String resourceName : resourceNames) { for (String resourceName : resourceNames) {
exportResource(exportPaths, toDirectory, resourceName); String nonRelativePath = toNonRelativePath(resourceName);
exportResource(exportPaths, toDirectory, nonRelativePath);
exportPaths.put(resourceName, toRelativePathFromRoot(nonRelativePath));
} }
} }
@ -187,8 +189,6 @@ public class PlayerPageExporter extends FileExporter {
} else { } else {
export(to, resource); export(to, resource);
} }
exportPaths.put(resourceName, toRelativePathFromRoot(resourceName));
} }
private String toRelativePathFromRoot(String resourceName) { private String toRelativePathFromRoot(String resourceName) {

View File

@ -174,14 +174,10 @@ public class PageFactory {
} }
} }
public Page errorPage(String title, String error) { public Page errorPage(String title, String error) throws IOException {
try { return new ErrorMessagePage(
return new ErrorMessagePage( getResource("web/error.html"), title, error,
getResource("web/error.html"), title, error, versionCheckSystem.get());
versionCheckSystem.get());
} catch (IOException noParse) {
return internalErrorPage("Failed to create error message page for error: '" + error + "'", noParse);
}
} }
public String getResource(String name) throws IOException { public String getResource(String name) throws IOException {

View File

@ -20,9 +20,7 @@ import com.djrapitops.plan.delivery.web.resolver.Resolver;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import java.util.ArrayList; import java.util.*;
import java.util.Collection;
import java.util.Optional;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -34,8 +32,8 @@ import java.util.regex.Pattern;
@Singleton @Singleton
public class ResolverSvc implements ResolverService { public class ResolverSvc implements ResolverService {
private final Collection<Container> basicResolvers; private final List<Container> basicResolvers;
private final Collection<Container> regexResolvers; private final List<Container> regexResolvers;
@Inject @Inject
public ResolverSvc() { public ResolverSvc() {
@ -49,12 +47,14 @@ public class ResolverSvc implements ResolverService {
@Override @Override
public void registerResolver(String pluginName, String start, Resolver resolver) { public void registerResolver(String pluginName, String start, Resolver resolver) {
basicResolvers.add(new Container(pluginName, checking -> checking.startsWith(start), resolver)); basicResolvers.add(new Container(pluginName, checking -> checking.startsWith(start), resolver, start));
Collections.sort(basicResolvers);
} }
@Override @Override
public void registerResolverForMatches(String pluginName, Pattern pattern, Resolver resolver) { public void registerResolverForMatches(String pluginName, Pattern pattern, Resolver resolver) {
regexResolvers.add(new Container(pluginName, pattern.asPredicate(), resolver)); regexResolvers.add(new Container(pluginName, pattern.asPredicate(), resolver, pattern.pattern()));
Collections.sort(regexResolvers);
} }
@Override @Override
@ -78,15 +78,39 @@ public class ResolverSvc implements ResolverService {
return Optional.empty(); return Optional.empty();
} }
private static class Container { private static class Container implements Comparable<Container> {
final String plugin; final String plugin;
final Predicate<String> matcher; final Predicate<String> matcher;
final Resolver resolver; final Resolver resolver;
final String sortBy;
public Container(String plugin, Predicate<String> matcher, Resolver resolver) { public Container(String plugin, Predicate<String> matcher, Resolver resolver, String sortBy) {
this.plugin = plugin; this.plugin = plugin;
this.matcher = matcher; this.matcher = matcher;
this.resolver = resolver; this.resolver = resolver;
this.sortBy = sortBy;
}
@Override
public int compareTo(Container o) {
// Longest first
return Integer.compare(o.sortBy.length(), this.sortBy.length());
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Container)) return false;
Container container = (Container) o;
return Objects.equals(plugin, container.plugin) &&
Objects.equals(matcher, container.matcher) &&
Objects.equals(resolver, container.resolver) &&
Objects.equals(sortBy, container.sortBy);
}
@Override
public int hashCode() {
return Objects.hash(plugin, matcher, resolver, sortBy);
} }
} }
} }

View File

@ -93,7 +93,7 @@ public class ResponseResolver extends CompositePageResolver {
public void registerPages() { public void registerPages() {
resolverService.registerResolver("Plan", "/debug", debugPageResolver); resolverService.registerResolver("Plan", "/debug", debugPageResolver);
resolverService.registerResolver("Plan", "/players", playersPageResolver); resolverService.registerResolver("Plan", "/players", playersPageResolver);
registerPage("player", playerPageResolver); resolverService.registerResolver("Plan", "/player", playerPageResolver);
registerPage("network", serverPageResolver); registerPage("network", serverPageResolver);
registerPage("server", serverPageResolver); registerPage("server", serverPageResolver);

View File

@ -16,21 +16,13 @@
*/ */
package com.djrapitops.plan.delivery.webserver.pages; package com.djrapitops.plan.delivery.webserver.pages;
import com.djrapitops.plan.delivery.domain.WebUser_old; import com.djrapitops.plan.delivery.web.resolver.*;
import com.djrapitops.plan.delivery.webserver.Request;
import com.djrapitops.plan.delivery.webserver.RequestTarget;
import com.djrapitops.plan.delivery.webserver.auth.Authentication;
import com.djrapitops.plan.delivery.webserver.response.ResponseFactory; 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.UUIDUtility; import com.djrapitops.plan.identification.UUIDUtility;
import com.djrapitops.plan.storage.database.DBSystem;
import com.djrapitops.plan.storage.database.Database;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import java.util.Optional;
import java.util.UUID; import java.util.UUID;
/** /**
@ -39,50 +31,39 @@ import java.util.UUID;
* @author Rsl1122 * @author Rsl1122
*/ */
@Singleton @Singleton
public class PlayerPageResolver implements PageResolver { public class PlayerPageResolver implements Resolver {
private final ResponseFactory responseFactory; private final ResponseFactory responseFactory;
private final DBSystem dbSystem;
private final UUIDUtility uuidUtility; private final UUIDUtility uuidUtility;
@Inject @Inject
public PlayerPageResolver( public PlayerPageResolver(
ResponseFactory responseFactory, ResponseFactory responseFactory,
DBSystem dbSystem,
UUIDUtility uuidUtility UUIDUtility uuidUtility
) { ) {
this.responseFactory = responseFactory; this.responseFactory = responseFactory;
this.dbSystem = dbSystem;
this.uuidUtility = uuidUtility; this.uuidUtility = uuidUtility;
} }
@Override @Override
public Response_old resolve(Request request, RequestTarget target) throws WebException { public boolean canAccess(WebUser user, URIPath target, URIQuery query) {
if (target.isEmpty()) { boolean isOwnPage = target.getPart(1).map(user.getName()::equalsIgnoreCase).orElse(true);
return responseFactory.pageNotFound404_old(); return user.hasPermission("page.player.other") || (user.hasPermission("page.player.self") && isOwnPage);
}
String playerName = target.get(0);
UUID playerUUID = uuidUtility.getUUIDOf(playerName);
boolean raw = target.size() >= 2 && target.get(1).equalsIgnoreCase("raw");
if (playerUUID == null) {
return responseFactory.uuidNotFound404_old();
}
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");
}
if (raw) {
return responseFactory.rawPlayerPageResponse_old(playerUUID);
}
return responseFactory.playerPageResponse_old(playerUUID);
} }
@Override @Override
public boolean isAuthorized(Authentication auth, RequestTarget target) throws WebUserAuthException { public Optional<Response> resolve(URIPath target, URIQuery query) {
WebUser_old webUser = auth.getWebUser(); Optional<String> part = target.getPart(1);
return webUser.getPermLevel() <= 1 || webUser.getName().equalsIgnoreCase(target.get(target.size() - 1)); if (!part.isPresent()) return Optional.empty();
String playerName = part.get();
UUID playerUUID = uuidUtility.getUUIDOf(playerName);
if (playerUUID == null) return Optional.of(responseFactory.uuidNotFound404());
boolean raw = target.getPart(2).map("raw"::equalsIgnoreCase).orElse(false);
return Optional.of(
raw ? responseFactory.rawPlayerPageResponse(playerUUID)
: responseFactory.playerPageResponse(playerUUID)
);
} }
} }

View File

@ -16,6 +16,7 @@
*/ */
package com.djrapitops.plan.delivery.webserver.response; package com.djrapitops.plan.delivery.webserver.response;
import com.djrapitops.plan.delivery.domain.container.PlayerContainer;
import com.djrapitops.plan.delivery.rendering.pages.Page; import com.djrapitops.plan.delivery.rendering.pages.Page;
import com.djrapitops.plan.delivery.rendering.pages.PageFactory; import com.djrapitops.plan.delivery.rendering.pages.PageFactory;
import com.djrapitops.plan.delivery.web.resolver.MimeType; import com.djrapitops.plan.delivery.web.resolver.MimeType;
@ -77,15 +78,17 @@ public class ResponseFactory {
} }
} }
public Response forPage(Page page) throws IOException { private Response forPage(Page page) {
return Response.builder().setContent(page.toHtml()) return Response.builder()
.setMimeType(MimeType.HTML) .setMimeType(MimeType.HTML)
.setContent(page.toHtml())
.build(); .build();
} }
public Response forInternalError(String cause, Throwable error) { private Response forInternalError(String cause, Throwable error) {
return Response.builder().setContent(pageFactory.internalErrorPage(cause, error).toHtml()) return Response.builder()
.setMimeType(MimeType.HTML) .setMimeType(MimeType.HTML)
.setContent(pageFactory.internalErrorPage(cause, error).toHtml())
.setStatus(500) .setStatus(500)
.build(); .build();
} }
@ -103,16 +106,26 @@ public class ResponseFactory {
private Optional<Response> checkIfDBIsOpen() { private Optional<Response> checkIfDBIsOpen() {
Database.State dbState = dbSystem.getDatabase().getState(); Database.State dbState = dbSystem.getDatabase().getState();
if (dbState != Database.State.OPEN) { if (dbState != Database.State.OPEN) {
return Optional.of(Response.builder().setContent(pageFactory.errorPage( try {
"503 Resources Unavailable", return Optional.of(buildDBNotOpenResponse(dbState));
"Database is " + dbState.name() + " - Please try again later. You can check database status with /plan info" } catch (IOException e) {
).toHtml()).setMimeType(MimeType.HTML) return Optional.of(forInternalError("Database was not open, additionally failed to generate error page for that", e));
.setStatus(503) }
.build());
} }
return Optional.empty(); return Optional.empty();
} }
private Response buildDBNotOpenResponse(Database.State dbState) throws IOException {
return Response.builder()
.setMimeType(MimeType.HTML)
.setContent(pageFactory.errorPage(
"503 Resources Unavailable",
"Database is " + dbState.name() + " - Please try again later. You can check database status with /plan info"
).toHtml())
.setStatus(503)
.build();
}
@Deprecated @Deprecated
public ErrorResponse internalErrorResponse_old(Throwable e, String s) { public ErrorResponse internalErrorResponse_old(Throwable e, String s) {
try { try {
@ -149,6 +162,14 @@ public class ResponseFactory {
return new RawPlayerDataResponse(dbSystem.getDatabase().query(ContainerFetchQueries.fetchPlayerContainer(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()
.setMimeType(MimeType.JSON)
.setJSONContent(RawDataResponse.mapToNormalMap(player))
.build();
}
@Deprecated @Deprecated
public Response_old javaScriptResponse_old(String fileName) { public Response_old javaScriptResponse_old(String fileName) {
try { try {
@ -213,11 +234,19 @@ public class ResponseFactory {
return notFound404_old(locale.getString(ErrorPageLang.UUID_404)); return notFound404_old(locale.getString(ErrorPageLang.UUID_404));
} }
public Response uuidNotFound404() {
return notFound404(locale.getString(ErrorPageLang.UUID_404));
}
@Deprecated @Deprecated
public ErrorResponse playerNotFound404_old() { public ErrorResponse playerNotFound404_old() {
return notFound404_old(locale.getString(ErrorPageLang.NOT_PLAYED_404)); return notFound404_old(locale.getString(ErrorPageLang.NOT_PLAYED_404));
} }
public Response playerNotFound404() {
return notFound404(locale.getString(ErrorPageLang.NOT_PLAYED_404));
}
@Deprecated @Deprecated
public ErrorResponse notFound404_old(String message) { public ErrorResponse notFound404_old(String message) {
try { try {
@ -227,6 +256,19 @@ public class ResponseFactory {
} }
} }
public Response notFound404(String message) {
try {
return Response.builder()
.setMimeType(MimeType.HTML)
.setContent(pageFactory.errorPage("404 " + message, message).toHtml())
.setStatus(404)
.build();
} catch (IOException e) {
return forInternalError("Failed to generate 404 page with message '" + message + "'", e);
}
}
@Deprecated @Deprecated
public ErrorResponse basicAuthFail_old(WebUserAuthException e) { public ErrorResponse basicAuthFail_old(WebUserAuthException e) {
try { try {
@ -265,6 +307,16 @@ public class ResponseFactory {
return new BadRequestResponse(errorMessage + " (when requesting '" + target + "')"); return new BadRequestResponse(errorMessage + " (when requesting '" + target + "')");
} }
public Response playerPageResponse(UUID playerUUID) {
try {
return forPage(pageFactory.playerPage(playerUUID));
} catch (IllegalStateException e) {
return playerNotFound404();
} catch (IOException e) {
return forInternalError("Failed to generate player page", e);
}
}
@Deprecated @Deprecated
public Response_old playerPageResponse_old(UUID playerUUID) { public Response_old playerPageResponse_old(UUID playerUUID) {
try { try {

View File

@ -38,7 +38,7 @@ public class RawDataResponse extends JSONResponse {
super(mapToNormalMap(dataContainer)); super(mapToNormalMap(dataContainer));
} }
private static Map<String, Object> mapToNormalMap(DataContainer player) { public static Map<String, Object> mapToNormalMap(DataContainer player) {
Map<String, Object> values = new HashMap<>(); Map<String, Object> values = new HashMap<>();
player.getMap().forEach((key, value) -> player.getMap().forEach((key, value) ->
{ {

View File

@ -13,14 +13,14 @@
<title>Plan | ${playerName}</title> <title>Plan | ${playerName}</title>
<!-- Custom fonts for this template--> <!-- 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" <link crossorigin="anonymous"
href="https://fonts.googleapis.com/css?family=Nunito:400,700,800,900&display=swap&subset=latin-ext" href="https://fonts.googleapis.com/css?family=Nunito:400,700,800,900&display=swap&subset=latin-ext"
rel="stylesheet"> rel="stylesheet">
<!-- Custom styles for this template--> <!-- Custom styles for this template-->
<link href="css/sb-admin-2.css" rel="stylesheet"> <link href="../css/sb-admin-2.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet"> <link href="../css/style.css" rel="stylesheet">
</head> </head>
@ -41,7 +41,7 @@
<!-- Sidebar - Brand --> <!-- Sidebar - Brand -->
<a class="sidebar-brand d-flex align-items-center justify-content-center"> <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> </a>
<!-- Divider --> <!-- Divider -->
@ -699,36 +699,37 @@
</a> </a>
<!-- Bootstrap core JavaScript--> <!-- Bootstrap core JavaScript-->
<script src="vendor/jquery/jquery.min.js"></script> <script src="../vendor/jquery/jquery.min.js"></script>
<script src="vendor/bootstrap/js/bootstrap.bundle.min.js"></script> <script src="../vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Core plugin JavaScript--> <!-- 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 --> <!-- Page level plugins -->
<script src="vendor/datatables/jquery.dataTables.min.js"></script> <script src="../vendor/datatables/jquery.dataTables.min.js"></script>
<script src="vendor/datatables/dataTables.bootstrap4.min.js"></script> <script src="../vendor/datatables/dataTables.bootstrap4.min.js"></script>
<script src="vendor/highcharts/highstock.js"></script> <script src="../vendor/highcharts/highstock.js"></script>
<script src="vendor/highcharts/drilldown.js"></script> <script src="../vendor/highcharts/drilldown.js"></script>
<script src="vendor/highcharts/highcharts-more.js"></script> <script src="../vendor/highcharts/highcharts-more.js"></script>
<script src="vendor/highcharts/no-data-to-display.js"></script> <script src="../vendor/highcharts/no-data-to-display.js"></script>
<link href='vendor/fullcalendar/fullcalendar.min.css' rel='stylesheet'/> <link href='../vendor/fullcalendar/fullcalendar.min.css' rel='stylesheet'/>
<script src='vendor/momentjs/moment.js'></script> <script src='../vendor/momentjs/moment.js'></script>
<script src='vendor/fullcalendar/fullcalendar.min.js'></script> <script src='../vendor/fullcalendar/fullcalendar.min.js'></script>
<!-- Custom scripts for all pages--> <!-- Custom scripts for all pages-->
<script src="js/sb-admin-2.js"></script> <script src="../js/sb-admin-2.js"></script>
<script src="js/xmlhttprequests.js"></script> <script src="../js/xmlhttprequests.js"></script>
<script src="js/color-selector.js"></script> <script src="../js/color-selector.js"></script>
<!-- Page level custom scripts --> <!-- Page level custom scripts -->
<script src="js/sessionAccordion.js"></script> <script src="../js/sessionAccordion.js"></script>
<script src="js/graphs.js"></script> <script src="../js/graphs.js"></script>
<script src="js/player-values.js"></script> <script src="../js/player-values.js"></script>
<script> <script>
try { try {
Highcharts.setOptions({lang: {noData: "No Data to Display"}, time: {timezoneOffset: ${timeZone} * 60} Highcharts.setOptions({
lang: {noData: "No Data to Display"}, time: {timezoneOffset: ${timeZone} * 60}
}); });
setLoadingText('Loading player values..'); setLoadingText('Loading player values..');
jsonRequest("../v1/player?player=${playerName}", function (json, error) { jsonRequest("../v1/player?player=${playerName}", function (json, error) {