mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2024-12-27 09:00:28 +08:00
Fix server page server name
Server name came from metadata endpoint, but it is incorrect if viewing a server page on a network Added a new endpoint /v1/serverIdentity?server=... to get the identifiable name of the server.
This commit is contained in:
parent
eaae1456d6
commit
d39c377756
@ -175,6 +175,12 @@ public class JSONFactory {
|
||||
return new PlayerKillMutator(kills).toJSONAsMap(formatters);
|
||||
}
|
||||
|
||||
public Optional<ServerDto> serverForIdentifier(String identifier) {
|
||||
return dbSystem.getDatabase()
|
||||
.query(ServerQueries.fetchServerMatchingIdentifier(identifier))
|
||||
.map(ServerDto::fromServer);
|
||||
}
|
||||
|
||||
public Map<String, Object> serversAsJSONMaps() {
|
||||
Database db = dbSystem.getDatabase();
|
||||
long now = System.currentTimeMillis();
|
||||
|
@ -62,7 +62,8 @@ public class RootJSONResolver {
|
||||
QueryJSONResolver queryJSONResolver,
|
||||
VersionJSONResolver versionJSONResolver,
|
||||
MetadataJSONResolver metadataJSONResolver,
|
||||
WhoAmIJSONResolver whoAmIJSONResolver
|
||||
WhoAmIJSONResolver whoAmIJSONResolver,
|
||||
ServerIdentityJSONResolver serverIdentityJSONResolver
|
||||
) {
|
||||
this.identifiers = identifiers;
|
||||
this.asyncJSONResolverService = asyncJSONResolverService;
|
||||
@ -87,6 +88,7 @@ public class RootJSONResolver {
|
||||
.add("version", versionJSONResolver)
|
||||
.add("locale", localeJSONResolver)
|
||||
.add("metadata", metadataJSONResolver)
|
||||
.add("serverIdentity", serverIdentityJSONResolver)
|
||||
.add("whoami", whoAmIJSONResolver)
|
||||
.build();
|
||||
}
|
||||
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.webserver.resolver.json;
|
||||
|
||||
import com.djrapitops.plan.delivery.domain.datatransfer.ServerDto;
|
||||
import com.djrapitops.plan.delivery.rendering.json.JSONFactory;
|
||||
import com.djrapitops.plan.delivery.web.resolver.MimeType;
|
||||
import com.djrapitops.plan.delivery.web.resolver.Resolver;
|
||||
import com.djrapitops.plan.delivery.web.resolver.Response;
|
||||
import com.djrapitops.plan.delivery.web.resolver.exception.BadRequestException;
|
||||
import com.djrapitops.plan.delivery.web.resolver.exception.NotFoundException;
|
||||
import com.djrapitops.plan.delivery.web.resolver.request.Request;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.ExampleObject;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import jakarta.ws.rs.GET;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author AuroraLS3
|
||||
*/
|
||||
@Singleton
|
||||
public class ServerIdentityJSONResolver implements Resolver {
|
||||
|
||||
private final JSONFactory jsonFactory;
|
||||
|
||||
@Inject
|
||||
public ServerIdentityJSONResolver(JSONFactory jsonFactory) {
|
||||
this.jsonFactory = jsonFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAccess(Request request) {
|
||||
return request.getUser()
|
||||
.map(user -> user.hasPermission("page.server"))
|
||||
.orElse(false);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Operation(
|
||||
description = "Get server identity for an identifier",
|
||||
responses = {
|
||||
@ApiResponse(responseCode = "200", content = @Content(mediaType = MimeType.JSON, schema = @Schema(implementation = ServerDto.class))),
|
||||
@ApiResponse(responseCode = "400", description = "If 'server' parameter is not given"),
|
||||
@ApiResponse(responseCode = "404", description = "If 'server' parameter is not an existing server")
|
||||
},
|
||||
parameters = @Parameter(in = ParameterIn.QUERY, required = true, name = "server", description = "Server identifier to get data for", examples = {
|
||||
@ExampleObject("Server 1"),
|
||||
@ExampleObject("1"),
|
||||
@ExampleObject("1fb39d2a-eb82-4868-b245-1fad17d823b3"),
|
||||
}),
|
||||
requestBody = @RequestBody(content = @Content(examples = @ExampleObject()))
|
||||
)
|
||||
@Override
|
||||
public Optional<Response> resolve(Request request) {
|
||||
String serverIdentifier = request.getQuery().get("server")
|
||||
.orElseThrow(() -> new BadRequestException("Missing 'server' query parameter"));
|
||||
ServerDto server = jsonFactory.serverForIdentifier(serverIdentifier)
|
||||
.orElseThrow(() -> new NotFoundException("Server with identifier '" + serverIdentifier + "' was not found in the database"));
|
||||
return Optional.of(Response.builder()
|
||||
.setJSONContent(server)
|
||||
.build());
|
||||
}
|
||||
}
|
@ -32,6 +32,7 @@ public enum ErrorPageLang implements Lang {
|
||||
FORBIDDEN_403("html.error.403Forbidden", "Forbidden"),
|
||||
ACCESS_DENIED_403("403AccessDenied", "Access Denied"),
|
||||
NOT_FOUND_404("html.error.404NotFound", "Not Found"),
|
||||
NO_SUCH_SERVER_404("html.error.serverNotSeen", "Server doesn't exist"),
|
||||
PAGE_NOT_FOUND_404("html.error.404PageNotFound", "Page does not exist.");
|
||||
|
||||
private final String key;
|
||||
|
@ -55,19 +55,19 @@ const MainPageRedirect = () => {
|
||||
}
|
||||
|
||||
if (authRequired && !loggedIn) {
|
||||
return (<Navigate to="login" replace={true}/>)
|
||||
return (<Navigate to="/login" replace={true}/>)
|
||||
} else if (authRequired && loggedIn) {
|
||||
if (isProxy && user.permissions.includes('page.network')) {
|
||||
return (<Navigate to={"network/overview"} replace={true}/>)
|
||||
return (<Navigate to={"/network/overview"} replace={true}/>)
|
||||
} else if (user.permissions.includes('page.server')) {
|
||||
return (<Navigate to={"server/" + encodeURIComponent(serverName) + "/overview"} replace={true}/>)
|
||||
return (<Navigate to={"/server/" + encodeURIComponent(serverName) + "/overview"} replace={true}/>)
|
||||
} else if (user.permissions.includes('page.player.other')) {
|
||||
return (<Navigate to={"players"} replace={true}/>)
|
||||
return (<Navigate to={"/players"} replace={true}/>)
|
||||
} else if (user.permissions.includes('page.player.self')) {
|
||||
return (<Navigate to={"player/" + user.linkedToUuid} replace={true}/>)
|
||||
return (<Navigate to={"/player/" + user.linkedToUuid} replace={true}/>)
|
||||
}
|
||||
} else {
|
||||
return (<Navigate to={isProxy ? "network/overview" : "server/" + encodeURIComponent(serverName) + "/overview"}
|
||||
return (<Navigate to={isProxy ? "/network/overview" : "/server/" + encodeURIComponent(serverName) + "/overview"}
|
||||
replace={true}/>)
|
||||
}
|
||||
}
|
||||
|
@ -217,8 +217,6 @@ const Sidebar = ({items, showBackButton}) => {
|
||||
const collapseSidebar = () => setSidebarExpanded(windowWidth > 1350);
|
||||
useEffect(collapseSidebar, [windowWidth, currentTab, setSidebarExpanded]);
|
||||
|
||||
if (!items.length) return <></>
|
||||
|
||||
return (
|
||||
<>
|
||||
{sidebarExpanded &&
|
||||
@ -227,9 +225,9 @@ const Sidebar = ({items, showBackButton}) => {
|
||||
<Divider/>
|
||||
{showBackButton && <>
|
||||
<Item active={false} href="/" icon={faArrowLeft} name={t('html.label.toMainPage')}/>
|
||||
<Divider showMargin={!items[0].contents && items[0].href === undefined}/>
|
||||
<Divider showMargin={items.length && !items[0].contents && items[0].href === undefined}/>
|
||||
</>}
|
||||
{items.map((item, i) => renderItem(item, i, openCollapse, toggleCollapse, t))}
|
||||
{items.length ? items.map((item, i) => renderItem(item, i, openCollapse, toggleCollapse, t)) : ''}
|
||||
<Divider/>
|
||||
<FooterButtons/>
|
||||
</ul>}
|
||||
|
@ -13,6 +13,7 @@ export const useDataRequest = (fetchMethod, parameters) => {
|
||||
setData(json);
|
||||
finishUpdate(json.timestamp, json.timestamp_f);
|
||||
} else if (error) {
|
||||
console.warn(error);
|
||||
setLoadingError(error);
|
||||
}
|
||||
});
|
||||
|
@ -26,6 +26,7 @@ export const doSomeRequest = async (url, statusOptions, axiosFunction) => {
|
||||
for (const statusOption of statusOptions) {
|
||||
if (response.status === statusOption.status) {
|
||||
return {
|
||||
status: response.status,
|
||||
data: statusOption.get(response),
|
||||
error: undefined
|
||||
};
|
||||
@ -37,6 +38,7 @@ export const doSomeRequest = async (url, statusOptions, axiosFunction) => {
|
||||
for (const statusOption of statusOptions) {
|
||||
if (e.response.status === statusOption.status) {
|
||||
return {
|
||||
status: e.response.status,
|
||||
data: undefined,
|
||||
error: statusOption.get(response, e)
|
||||
};
|
||||
@ -45,6 +47,7 @@ export const doSomeRequest = async (url, statusOptions, axiosFunction) => {
|
||||
return {
|
||||
data: undefined,
|
||||
error: {
|
||||
status: e.response.status,
|
||||
message: e.message,
|
||||
url,
|
||||
data: e.response.data
|
||||
@ -54,6 +57,7 @@ export const doSomeRequest = async (url, statusOptions, axiosFunction) => {
|
||||
return {
|
||||
data: undefined,
|
||||
error: {
|
||||
status: undefined,
|
||||
message: e.message,
|
||||
url
|
||||
}
|
||||
|
@ -1,5 +1,11 @@
|
||||
import {doGetRequest} from "./backendConfiguration";
|
||||
|
||||
|
||||
export const fetchServerIdentity = async (identifier) => {
|
||||
const url = `/v1/serverIdentity?server=${identifier}`;
|
||||
return doGetRequest(url);
|
||||
}
|
||||
|
||||
export const fetchServerOverview = async (identifier) => {
|
||||
const timestamp = Date.now();
|
||||
const url = `/v1/serverOverview?server=${identifier}×tamp=${timestamp}`;
|
||||
|
@ -9,7 +9,7 @@ export const ErrorViewText = ({error}) => {
|
||||
<>
|
||||
<p>{error.message} {error.url && <a href={error.url}>{error.url}</a>}</p>
|
||||
{error.data && <><br/>
|
||||
<pre>{error.data}</pre>
|
||||
<pre>{JSON.stringify(error.data)}</pre>
|
||||
</>}
|
||||
</>
|
||||
)
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, {useEffect, useState} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {Outlet} from "react-router-dom";
|
||||
import {Outlet, useParams} from "react-router-dom";
|
||||
import {useNavigation} from "../../hooks/navigationHook";
|
||||
import {
|
||||
faCampground,
|
||||
@ -23,11 +23,17 @@ import {useMetadata} from "../../hooks/metadataHook";
|
||||
import {faCalendarCheck} from "@fortawesome/free-regular-svg-icons";
|
||||
import ErrorPage from "./ErrorPage";
|
||||
import {SwitchTransition} from "react-transition-group";
|
||||
import MainPageRedirect from "../../components/navigation/MainPageRedirect";
|
||||
import {useDataRequest} from "../../hooks/dataFetchHook";
|
||||
import {fetchServerIdentity} from "../../service/serverService";
|
||||
|
||||
const ServerPage = () => {
|
||||
const {t, i18n} = useTranslation();
|
||||
const {identifier} = useParams();
|
||||
const {isProxy, serverName} = useMetadata();
|
||||
|
||||
const {data: serverIdentity, loadingError: identityLoadingError} = useDataRequest(fetchServerIdentity, [identifier])
|
||||
|
||||
const [error] = useState(undefined);
|
||||
const [sidebarItems, setSidebarItems] = useState([]);
|
||||
|
||||
@ -82,12 +88,32 @@ const ServerPage = () => {
|
||||
window.document.title = `Plan | Server Analysis`;
|
||||
}, [t, i18n])
|
||||
|
||||
const {authRequired, user} = useAuth();
|
||||
const {authRequired, loggedIn, user} = useAuth();
|
||||
if (authRequired && !loggedIn) return <MainPageRedirect/>
|
||||
|
||||
const showBackButton = isProxy && (!authRequired || user.permissions.filter(perm => perm !== 'page.network').length);
|
||||
|
||||
if (error) return <ErrorPage error={error}/>;
|
||||
|
||||
const displayedServerName = !isProxy && serverName && serverName.startsWith('Server') ? "Plan" : serverName;
|
||||
const getDisplayedServerName = () => {
|
||||
if (serverIdentity) {
|
||||
return serverIdentity.serverName;
|
||||
}
|
||||
|
||||
if (isProxy) {
|
||||
return identifier;
|
||||
} else {
|
||||
return serverName && serverName.startsWith('Server') ? "Plan" : serverName
|
||||
}
|
||||
}
|
||||
const displayedServerName = getDisplayedServerName();
|
||||
|
||||
if (error) return <ErrorPage error={error}/>;
|
||||
if (identityLoadingError) {
|
||||
if (identityLoadingError.status === 404) return <ErrorPage
|
||||
error={{title: t('html.error.404NotFound'), message: t('html.error.serverNotSeen')}}/>
|
||||
return <ErrorPage error={identityLoadingError}/>
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<NightModeCss/>
|
||||
|
Loading…
Reference in New Issue
Block a user