mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2025-03-10 05:39:19 +01:00
parent
fd84341a77
commit
d06c753be1
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.domain.datatransfer;
|
||||
|
||||
import com.djrapitops.plan.storage.database.queries.filter.Filter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents a query filter.
|
||||
*
|
||||
* @see Filter
|
||||
* @see com.djrapitops.plan.modules.FiltersModule
|
||||
*/
|
||||
public class FilterDto implements Comparable<FilterDto> {
|
||||
private final String kind;
|
||||
private final Map<String, Object> options;
|
||||
private final String[] expectedParameters;
|
||||
|
||||
public FilterDto(String kind, Filter filter) {
|
||||
this.kind = kind;
|
||||
this.options = filter.getOptions();
|
||||
this.expectedParameters = filter.getExpectedParameters();
|
||||
}
|
||||
|
||||
public String getKind() {
|
||||
return kind;
|
||||
}
|
||||
|
||||
public Map<String, Object> getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
public String[] getExpectedParameters() {
|
||||
return expectedParameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
FilterDto that = (FilterDto) o;
|
||||
return Objects.equals(kind, that.kind) && Objects.equals(options, that.options) && Arrays.equals(expectedParameters, that.expectedParameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = Objects.hash(kind, options);
|
||||
result = 31 * result + Arrays.hashCode(expectedParameters);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(FilterDto o) {
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(this.kind, o.kind);
|
||||
}
|
||||
}
|
@ -14,8 +14,9 @@
|
||||
* 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.storage.database.queries.filter;
|
||||
package com.djrapitops.plan.delivery.domain.datatransfer;
|
||||
|
||||
import com.djrapitops.plan.storage.database.queries.filter.Filter;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
@ -27,18 +28,18 @@ import java.util.*;
|
||||
*
|
||||
* @author AuroraLS3
|
||||
*/
|
||||
public class SpecifiedFilterInformation {
|
||||
public class InputFilterDto {
|
||||
|
||||
private final String kind;
|
||||
private final Map<String, String> parameters;
|
||||
|
||||
public SpecifiedFilterInformation(String kind, Map<String, String> parameters) {
|
||||
public InputFilterDto(String kind, Map<String, String> parameters) {
|
||||
this.kind = kind;
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
public static List<SpecifiedFilterInformation> parse(String json) throws IOException {
|
||||
return new Gson().getAdapter(new TypeToken<List<SpecifiedFilterInformation>>() {}).fromJson(json);
|
||||
public static List<InputFilterDto> parse(String json, Gson gson) throws IOException {
|
||||
return gson.getAdapter(new TypeToken<List<InputFilterDto>>() {}).fromJson(json);
|
||||
}
|
||||
|
||||
public String getKind() {
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.domain.datatransfer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class InputQueryDto {
|
||||
|
||||
public final List<InputFilterDto> filters;
|
||||
private final ViewDto view;
|
||||
|
||||
public InputQueryDto(ViewDto view, List<InputFilterDto> filters) {
|
||||
this.view = view;
|
||||
this.filters = filters;
|
||||
}
|
||||
|
||||
public ViewDto getView() {
|
||||
return view;
|
||||
}
|
||||
|
||||
public List<InputFilterDto> getFilters() {
|
||||
return filters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
InputQueryDto that = (InputQueryDto) o;
|
||||
return Objects.equals(getView(), that.getView()) && Objects.equals(getFilters(), that.getFilters());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getView(), getFilters());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "InputQueryDto{" +
|
||||
"view=" + view +
|
||||
", filters=" + filters +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.domain.datatransfer;
|
||||
|
||||
import com.djrapitops.plan.identification.Server;
|
||||
|
||||
/**
|
||||
* Represents outgoing server information json.
|
||||
*/
|
||||
public class ServerDto {
|
||||
|
||||
private final String serverUUID;
|
||||
private final String serverName;
|
||||
private final boolean proxy;
|
||||
|
||||
public ServerDto(String serverUUID, String serverName, boolean proxy) {
|
||||
this.serverUUID = serverUUID;
|
||||
this.serverName = serverName;
|
||||
this.proxy = proxy;
|
||||
}
|
||||
|
||||
public static ServerDto fromServer(Server server) {
|
||||
return new ServerDto(server.getUuid().toString(), server.getIdentifiableName(), server.isProxy());
|
||||
}
|
||||
|
||||
public String getServerUUID() {
|
||||
return serverUUID;
|
||||
}
|
||||
|
||||
public String getServerName() {
|
||||
return serverName;
|
||||
}
|
||||
|
||||
public boolean isProxy() {
|
||||
return proxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ServerDto{" +
|
||||
"serverUUID='" + serverUUID + '\'' +
|
||||
", serverName='" + serverName + '\'' +
|
||||
", proxy=" + proxy +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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.domain.datatransfer;
|
||||
|
||||
import com.djrapitops.plan.delivery.formatting.Formatter;
|
||||
import com.djrapitops.plan.delivery.formatting.Formatters;
|
||||
import com.djrapitops.plan.identification.ServerUUID;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Represents query page view that the user wants to see data for.
|
||||
*/
|
||||
public class ViewDto {
|
||||
private static final String DATE_PATTERN = "dd/MM/yyyy kk:mm";
|
||||
|
||||
private final String afterDate;
|
||||
private final String afterTime;
|
||||
private final String beforeDate;
|
||||
private final String beforeTime;
|
||||
private final List<ServerDto> servers;
|
||||
|
||||
public ViewDto(Formatters formatters, List<ServerDto> servers) {
|
||||
this.servers = servers;
|
||||
long now = System.currentTimeMillis();
|
||||
long monthAgo = now - TimeUnit.DAYS.toMillis(30);
|
||||
|
||||
Formatter<Long> formatter = formatters.javascriptDateFormatterLong();
|
||||
String[] after = StringUtils.split(formatter.apply(monthAgo), " ");
|
||||
String[] before = StringUtils.split(formatter.apply(now), " ");
|
||||
|
||||
this.afterDate = after[0];
|
||||
this.afterTime = after[1];
|
||||
this.beforeDate = before[0];
|
||||
this.beforeTime = before[1];
|
||||
}
|
||||
|
||||
public long getAfterEpochMs() throws ParseException {
|
||||
return new SimpleDateFormat(DATE_PATTERN).parse(afterDate + " " + afterTime).getTime();
|
||||
}
|
||||
|
||||
public long getBeforeEpochMs() throws ParseException {
|
||||
return new SimpleDateFormat(DATE_PATTERN).parse(beforeDate + " " + beforeTime).getTime();
|
||||
}
|
||||
|
||||
public List<ServerUUID> getServerUUIDs() {
|
||||
return servers.stream()
|
||||
.map(ServerDto::getServerUUID)
|
||||
.map(ServerUUID::fromString)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
ViewDto viewDto = (ViewDto) o;
|
||||
return Objects.equals(afterDate, viewDto.afterDate) && Objects.equals(afterTime, viewDto.afterTime) && Objects.equals(beforeDate, viewDto.beforeDate) && Objects.equals(beforeTime, viewDto.beforeTime) && Objects.equals(servers, viewDto.servers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(afterDate, afterTime, beforeDate, beforeTime, servers);
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Data transfer objects or DTOs, which represent the outgoing or incoming serialized json.
|
||||
*/
|
||||
package com.djrapitops.plan.delivery.domain.datatransfer;
|
@ -17,6 +17,7 @@
|
||||
package com.djrapitops.plan.delivery.rendering.json;
|
||||
|
||||
import com.djrapitops.plan.delivery.domain.DateObj;
|
||||
import com.djrapitops.plan.delivery.domain.datatransfer.ServerDto;
|
||||
import com.djrapitops.plan.delivery.domain.mutators.PlayerKillMutator;
|
||||
import com.djrapitops.plan.delivery.domain.mutators.SessionsMutator;
|
||||
import com.djrapitops.plan.delivery.domain.mutators.TPSMutator;
|
||||
@ -266,16 +267,10 @@ public class JSONFactory {
|
||||
return tableEntries;
|
||||
}
|
||||
|
||||
public Map<String, Object> listServers() {
|
||||
public Map<String, List<ServerDto>> listServers() {
|
||||
Collection<Server> servers = dbSystem.getDatabase().query(ServerQueries.fetchPlanServerInformationCollection());
|
||||
return Maps.builder(String.class, Object.class)
|
||||
.put("servers", servers.stream()
|
||||
.map(server -> Maps.builder(String.class, Object.class)
|
||||
.put("serverUUID", server.getUuid().toString())
|
||||
.put("serverName", server.getIdentifiableName())
|
||||
.put("proxy", server.isProxy())
|
||||
.build())
|
||||
.collect(Collectors.toList()))
|
||||
.build();
|
||||
return Collections.singletonMap("servers", servers.stream()
|
||||
.map(ServerDto::fromServer)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
}
|
@ -89,6 +89,7 @@ public class WebAssetVersionCheckTask extends TaskSystem.Task {
|
||||
if (!outdated.isEmpty()) {
|
||||
logger.warn("You have customized files which are out of date due to recent updates!");
|
||||
logger.warn("Plan may not work properly until these files are updated to include the new modifications.");
|
||||
logger.warn("See https://github.com/plan-player-analytics/Plan/commits/html to compare changes");
|
||||
}
|
||||
for (AssetInfo asset : outdated) {
|
||||
logger.warn(String.format("- %s was modified %s, but the plugin contains a version from %s",
|
||||
|
@ -18,6 +18,10 @@ package com.djrapitops.plan.delivery.webserver;
|
||||
|
||||
import com.djrapitops.plan.delivery.web.resolver.request.Request;
|
||||
import com.djrapitops.plan.delivery.web.resolver.request.URIQuery;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class RequestBodyConverter {
|
||||
|
||||
@ -35,9 +39,17 @@ public class RequestBodyConverter {
|
||||
"POST".equalsIgnoreCase(request.getMethod()) &&
|
||||
"application/x-www-form-urlencoded".equalsIgnoreCase(request.getHeader("Content-type").orElse(""))
|
||||
) {
|
||||
return new URIQuery(new String(request.getRequestBody()));
|
||||
return new URIQuery(new String(request.getRequestBody(), StandardCharsets.UTF_8));
|
||||
} else {
|
||||
return new URIQuery("");
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T bodyJson(Request request, Gson gson, Class<T> ofType) {
|
||||
return gson.fromJson(new String(request.getRequestBody(), StandardCharsets.UTF_8), ofType);
|
||||
}
|
||||
|
||||
public static <T> T bodyJson(Request request, Gson gson, TypeToken<T> ofType) {
|
||||
return gson.fromJson(new String(request.getRequestBody(), StandardCharsets.UTF_8), ofType.getType());
|
||||
}
|
||||
}
|
||||
|
@ -17,8 +17,10 @@
|
||||
package com.djrapitops.plan.delivery.webserver.resolver.json;
|
||||
|
||||
import com.djrapitops.plan.delivery.domain.DateObj;
|
||||
import com.djrapitops.plan.delivery.formatting.Formatter;
|
||||
import com.djrapitops.plan.delivery.domain.datatransfer.FilterDto;
|
||||
import com.djrapitops.plan.delivery.domain.datatransfer.ViewDto;
|
||||
import com.djrapitops.plan.delivery.formatting.Formatters;
|
||||
import com.djrapitops.plan.delivery.rendering.json.JSONFactory;
|
||||
import com.djrapitops.plan.delivery.rendering.json.graphs.Graphs;
|
||||
import com.djrapitops.plan.delivery.rendering.json.graphs.line.LineGraph;
|
||||
import com.djrapitops.plan.delivery.rendering.json.graphs.line.Point;
|
||||
@ -36,7 +38,6 @@ import com.djrapitops.plan.storage.database.queries.objects.TPSQueries;
|
||||
import com.djrapitops.plan.utilities.java.Lists;
|
||||
import com.djrapitops.plan.utilities.logging.ErrorContext;
|
||||
import com.djrapitops.plan.utilities.logging.ErrorLogger;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
@ -50,6 +51,7 @@ public class FiltersJSONResolver implements Resolver {
|
||||
private final ServerInfo serverInfo;
|
||||
private final DBSystem dbSystem;
|
||||
private final QueryFilters filters;
|
||||
private final JSONFactory jsonFactory;
|
||||
private final Graphs graphs;
|
||||
private final Formatters formatters;
|
||||
private final ErrorLogger errorLogger;
|
||||
@ -59,6 +61,7 @@ public class FiltersJSONResolver implements Resolver {
|
||||
ServerInfo serverInfo,
|
||||
DBSystem dbSystem,
|
||||
QueryFilters filters,
|
||||
JSONFactory jsonFactory,
|
||||
Graphs graphs,
|
||||
Formatters formatters,
|
||||
ErrorLogger errorLogger
|
||||
@ -66,6 +69,7 @@ public class FiltersJSONResolver implements Resolver {
|
||||
this.serverInfo = serverInfo;
|
||||
this.dbSystem = dbSystem;
|
||||
this.filters = filters;
|
||||
this.jsonFactory = jsonFactory;
|
||||
this.graphs = graphs;
|
||||
this.formatters = formatters;
|
||||
this.errorLogger = errorLogger;
|
||||
@ -85,9 +89,9 @@ public class FiltersJSONResolver implements Resolver {
|
||||
private Response getResponse() {
|
||||
return Response.builder()
|
||||
.setMimeType(MimeType.JSON)
|
||||
.setJSONContent(new FilterResponseJSON(
|
||||
.setJSONContent(new FilterResponseDto(
|
||||
filters.getFilters(),
|
||||
new ViewJSON(formatters),
|
||||
new ViewDto(formatters, jsonFactory.listServers().get("servers")),
|
||||
fetchViewGraphPoints()
|
||||
)).build();
|
||||
}
|
||||
@ -111,17 +115,17 @@ public class FiltersJSONResolver implements Resolver {
|
||||
/**
|
||||
* JSON serialization class.
|
||||
*/
|
||||
class FilterResponseJSON {
|
||||
final List<FilterJSON> filters;
|
||||
final ViewJSON view;
|
||||
class FilterResponseDto {
|
||||
final List<FilterDto> filters;
|
||||
final ViewDto view;
|
||||
final List<Double[]> viewPoints;
|
||||
|
||||
public FilterResponseJSON(Map<String, Filter> filtersByKind, ViewJSON view, List<Double[]> viewPoints) {
|
||||
public FilterResponseDto(Map<String, Filter> filtersByKind, ViewDto view, List<Double[]> viewPoints) {
|
||||
this.viewPoints = viewPoints;
|
||||
this.filters = new ArrayList<>();
|
||||
for (Map.Entry<String, Filter> entry : filtersByKind.entrySet()) {
|
||||
try {
|
||||
filters.add(new FilterJSON(entry.getKey(), entry.getValue()));
|
||||
filters.add(new FilterDto(entry.getKey(), entry.getValue()));
|
||||
} catch (Exception e) {
|
||||
errorLogger.error(e, ErrorContext.builder()
|
||||
.whatToDo("Report this, filter '" + entry.getKey() + "' has implementation error.")
|
||||
@ -133,63 +137,4 @@ public class FiltersJSONResolver implements Resolver {
|
||||
this.view = view;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON serialization class.
|
||||
*/
|
||||
static class FilterJSON implements Comparable<FilterJSON> {
|
||||
final String kind;
|
||||
final Map<String, Object> options;
|
||||
final String[] expectedParameters;
|
||||
|
||||
public FilterJSON(String kind, Filter filter) {
|
||||
this.kind = kind;
|
||||
this.options = filter.getOptions();
|
||||
this.expectedParameters = filter.getExpectedParameters();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
FilterJSON that = (FilterJSON) o;
|
||||
return Objects.equals(kind, that.kind) && Objects.equals(options, that.options) && Arrays.equals(expectedParameters, that.expectedParameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = Objects.hash(kind, options);
|
||||
result = 31 * result + Arrays.hashCode(expectedParameters);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(FilterJSON o) {
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(this.kind, o.kind);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON serialization class.
|
||||
*/
|
||||
static class ViewJSON {
|
||||
final String afterDate;
|
||||
final String afterTime;
|
||||
final String beforeDate;
|
||||
final String beforeTime;
|
||||
|
||||
public ViewJSON(Formatters formatters) {
|
||||
long now = System.currentTimeMillis();
|
||||
long monthAgo = now - TimeUnit.DAYS.toMillis(30);
|
||||
|
||||
Formatter<Long> formatter = formatters.javascriptDateFormatterLong();
|
||||
String[] after = StringUtils.split(formatter.apply(monthAgo), " ");
|
||||
String[] before = StringUtils.split(formatter.apply(now), " ");
|
||||
|
||||
this.afterDate = after[0];
|
||||
this.afterTime = after[1];
|
||||
this.beforeDate = before[0];
|
||||
this.beforeTime = before[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -57,13 +57,15 @@ public class NetworkPerformanceJSONResolver implements Resolver {
|
||||
private final Formatter<Long> timeAmount;
|
||||
private final Formatter<Double> percentage;
|
||||
private final Formatter<Double> byteSize;
|
||||
private final Gson gson;
|
||||
|
||||
@Inject
|
||||
public NetworkPerformanceJSONResolver(
|
||||
PlanConfig config,
|
||||
Locale locale,
|
||||
DBSystem dbSystem,
|
||||
Formatters formatters
|
||||
Formatters formatters,
|
||||
Gson gson
|
||||
) {
|
||||
this.config = config;
|
||||
this.locale = locale;
|
||||
@ -73,6 +75,7 @@ public class NetworkPerformanceJSONResolver implements Resolver {
|
||||
percentage = formatters.percentage();
|
||||
timeAmount = formatters.timeAmount();
|
||||
byteSize = formatters.byteSize();
|
||||
this.gson = gson;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -93,7 +96,7 @@ public class NetworkPerformanceJSONResolver implements Resolver {
|
||||
}
|
||||
|
||||
private List<UUID> getUUIDList(String jsonString) {
|
||||
return new Gson().fromJson(jsonString, new TypeToken<List<UUID>>() {}.getType());
|
||||
return gson.fromJson(jsonString, new TypeToken<List<UUID>>() {}.getType());
|
||||
}
|
||||
|
||||
public Map<String, Object> createJSONAsMap(Collection<ServerUUID> serverUUIDs) {
|
||||
|
@ -17,6 +17,9 @@
|
||||
package com.djrapitops.plan.delivery.webserver.resolver.json;
|
||||
|
||||
import com.djrapitops.plan.delivery.domain.DateMap;
|
||||
import com.djrapitops.plan.delivery.domain.datatransfer.InputFilterDto;
|
||||
import com.djrapitops.plan.delivery.domain.datatransfer.InputQueryDto;
|
||||
import com.djrapitops.plan.delivery.domain.datatransfer.ViewDto;
|
||||
import com.djrapitops.plan.delivery.formatting.Formatter;
|
||||
import com.djrapitops.plan.delivery.formatting.Formatters;
|
||||
import com.djrapitops.plan.delivery.rendering.json.PlayersTableJSONCreator;
|
||||
@ -27,9 +30,11 @@ import com.djrapitops.plan.delivery.web.resolver.Response;
|
||||
import com.djrapitops.plan.delivery.web.resolver.exception.BadRequestException;
|
||||
import com.djrapitops.plan.delivery.web.resolver.request.Request;
|
||||
import com.djrapitops.plan.delivery.web.resolver.request.WebUser;
|
||||
import com.djrapitops.plan.delivery.webserver.RequestBodyConverter;
|
||||
import com.djrapitops.plan.delivery.webserver.cache.JSONStorage;
|
||||
import com.djrapitops.plan.extension.implementation.storage.queries.ExtensionQueryResultTableDataQuery;
|
||||
import com.djrapitops.plan.identification.ServerInfo;
|
||||
import com.djrapitops.plan.identification.ServerUUID;
|
||||
import com.djrapitops.plan.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.settings.config.paths.DisplaySettings;
|
||||
import com.djrapitops.plan.settings.config.paths.TimeSettings;
|
||||
@ -39,7 +44,6 @@ import com.djrapitops.plan.storage.database.Database;
|
||||
import com.djrapitops.plan.storage.database.queries.analysis.NetworkActivityIndexQueries;
|
||||
import com.djrapitops.plan.storage.database.queries.filter.Filter;
|
||||
import com.djrapitops.plan.storage.database.queries.filter.QueryFilters;
|
||||
import com.djrapitops.plan.storage.database.queries.filter.SpecifiedFilterInformation;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.GeoInfoQueries;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.SessionQueries;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.playertable.QueryTablePlayersQuery;
|
||||
@ -52,7 +56,6 @@ import javax.inject.Singleton;
|
||||
import java.io.IOException;
|
||||
import java.net.URLDecoder;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
@Singleton
|
||||
@ -67,6 +70,7 @@ public class QueryJSONResolver implements Resolver {
|
||||
private final GraphJSONCreator graphJSONCreator;
|
||||
private final Locale locale;
|
||||
private final Formatters formatters;
|
||||
private final Gson gson;
|
||||
|
||||
@Inject
|
||||
public QueryJSONResolver(
|
||||
@ -76,7 +80,8 @@ public class QueryJSONResolver implements Resolver {
|
||||
ServerInfo serverInfo, JSONStorage jsonStorage,
|
||||
GraphJSONCreator graphJSONCreator,
|
||||
Locale locale,
|
||||
Formatters formatters
|
||||
Formatters formatters,
|
||||
Gson gson
|
||||
) {
|
||||
this.filters = filters;
|
||||
this.config = config;
|
||||
@ -86,6 +91,7 @@ public class QueryJSONResolver implements Resolver {
|
||||
this.graphJSONCreator = graphJSONCreator;
|
||||
this.locale = locale;
|
||||
this.formatters = formatters;
|
||||
this.gson = gson;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -103,17 +109,33 @@ public class QueryJSONResolver implements Resolver {
|
||||
Optional<Response> cachedResult = checkForCachedResult(request);
|
||||
if (cachedResult.isPresent()) return cachedResult.get();
|
||||
|
||||
String q = request.getQuery().get("q").orElseThrow(() -> new BadRequestException("'q' parameter not set (expecting json array)"));
|
||||
String view = request.getQuery().get("view").orElseThrow(() -> new BadRequestException("'view' parameter not set (expecting json object {afterDate, afterTime, beforeDate, beforeTime})"));
|
||||
InputQueryDto inputQuery = parseInputQuery(request);
|
||||
List<InputFilterDto> queries = inputQuery.getFilters();
|
||||
|
||||
try {
|
||||
String query = URLDecoder.decode(q, "UTF-8");
|
||||
List<SpecifiedFilterInformation> queries = SpecifiedFilterInformation.parse(query);
|
||||
Filter.Result result = filters.apply(queries);
|
||||
List<Filter.ResultPath> resultPath = result.getInverseResultPath();
|
||||
Collections.reverse(resultPath);
|
||||
|
||||
return buildAndStoreResponse(view, result, resultPath);
|
||||
return buildAndStoreResponse(inputQuery.getView(), result, resultPath);
|
||||
}
|
||||
|
||||
private InputQueryDto parseInputQuery(Request request) {
|
||||
if (request.getRequestBody().length == 0) {
|
||||
return parseInputQueryFromQueryParams(request);
|
||||
} else {
|
||||
return RequestBodyConverter.bodyJson(request, gson, InputQueryDto.class);
|
||||
}
|
||||
}
|
||||
|
||||
private InputQueryDto parseInputQueryFromQueryParams(Request request) {
|
||||
String q = request.getQuery().get("q").orElseThrow(() -> new BadRequestException("'q' parameter not set (expecting json array)"));
|
||||
try {
|
||||
String query = URLDecoder.decode(q, "UTF-8");
|
||||
List<InputFilterDto> queryFilters = InputFilterDto.parse(query, gson);
|
||||
ViewDto view = request.getQuery().get("view")
|
||||
.map(viewJson -> gson.fromJson(viewJson, ViewDto.class))
|
||||
.orElseThrow(() -> new BadRequestException("'view' parameter not set (expecting json object {afterDate, afterTime, beforeDate, beforeTime})"));
|
||||
return new InputQueryDto(view, queryFilters);
|
||||
} catch (IOException e) {
|
||||
throw new BadRequestException("Failed to decode json: '" + q + "', " + e.getMessage());
|
||||
}
|
||||
@ -132,12 +154,12 @@ public class QueryJSONResolver implements Resolver {
|
||||
}
|
||||
}
|
||||
|
||||
private Response buildAndStoreResponse(String view, Filter.Result result, List<Filter.ResultPath> resultPath) {
|
||||
private Response buildAndStoreResponse(ViewDto view, Filter.Result result, List<Filter.ResultPath> resultPath) {
|
||||
try {
|
||||
long timestamp = System.currentTimeMillis();
|
||||
Map<String, Object> json = Maps.builder(String.class, Object.class)
|
||||
.put("path", resultPath)
|
||||
.put("view", new Gson().fromJson(view, FiltersJSONResolver.ViewJSON.class))
|
||||
.put("view", view)
|
||||
.put("timestamp", timestamp)
|
||||
.build();
|
||||
if (!result.isEmpty()) {
|
||||
@ -155,23 +177,22 @@ public class QueryJSONResolver implements Resolver {
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Object> getDataFor(Set<UUID> playerUUIDs, String view) throws ParseException {
|
||||
FiltersJSONResolver.ViewJSON viewJSON = new Gson().fromJson(view, FiltersJSONResolver.ViewJSON.class);
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy kk:mm");
|
||||
long after = dateFormat.parse(viewJSON.afterDate + " " + viewJSON.afterTime).getTime();
|
||||
long before = dateFormat.parse(viewJSON.beforeDate + " " + viewJSON.beforeTime).getTime();
|
||||
private Map<String, Object> getDataFor(Set<UUID> playerUUIDs, ViewDto view) throws ParseException {
|
||||
long after = view.getAfterEpochMs();
|
||||
long before = view.getBeforeEpochMs();
|
||||
List<ServerUUID> serverUUIDs = view.getServerUUIDs();
|
||||
|
||||
return Maps.builder(String.class, Object.class)
|
||||
.put("players", getPlayersTableData(playerUUIDs, after, before))
|
||||
.put("activity", getActivityGraphData(playerUUIDs, after, before))
|
||||
.put("players", getPlayersTableData(playerUUIDs, serverUUIDs, after, before))
|
||||
.put("activity", getActivityGraphData(playerUUIDs, serverUUIDs, after, before))
|
||||
.put("geolocation", getGeolocationData(playerUUIDs))
|
||||
.put("sessions", getSessionSummaryData(playerUUIDs, after, before))
|
||||
.put("sessions", getSessionSummaryData(playerUUIDs, serverUUIDs, after, before))
|
||||
.build();
|
||||
}
|
||||
|
||||
private Map<String, String> getSessionSummaryData(Set<UUID> playerUUIDs, long after, long before) {
|
||||
private Map<String, String> getSessionSummaryData(Set<UUID> playerUUIDs, List<ServerUUID> serverUUIDs, long after, long before) {
|
||||
Database database = dbSystem.getDatabase();
|
||||
Map<String, Long> summary = database.query(SessionQueries.summaryOfPlayers(playerUUIDs, after, before));
|
||||
Map<String, Long> summary = database.query(SessionQueries.summaryOfPlayers(playerUUIDs, serverUUIDs, after, before));
|
||||
Map<String, String> formattedSummary = new HashMap<>();
|
||||
Formatter<Long> timeAmount = formatters.timeAmount();
|
||||
for (Map.Entry<String, Long> entry : summary.entrySet()) {
|
||||
@ -189,7 +210,7 @@ public class QueryJSONResolver implements Resolver {
|
||||
);
|
||||
}
|
||||
|
||||
private Map<String, Object> getActivityGraphData(Set<UUID> playerUUIDs, long after, long before) {
|
||||
private Map<String, Object> getActivityGraphData(Set<UUID> playerUUIDs, List<ServerUUID> serverUUIDs, long after, long before) {
|
||||
Database database = dbSystem.getDatabase();
|
||||
Long threshold = config.get(TimeSettings.ACTIVE_PLAY_THRESHOLD);
|
||||
|
||||
@ -198,16 +219,16 @@ public class QueryJSONResolver implements Resolver {
|
||||
|
||||
DateMap<Map<String, Integer>> activityData = new DateMap<>();
|
||||
for (long time = before; time >= stopDate; time -= TimeAmount.WEEK.toMillis(1L)) {
|
||||
activityData.put(time, database.query(NetworkActivityIndexQueries.fetchActivityIndexGroupingsOn(time, threshold, playerUUIDs)));
|
||||
activityData.put(time, database.query(NetworkActivityIndexQueries.fetchActivityIndexGroupingsOn(time, threshold, playerUUIDs, serverUUIDs)));
|
||||
}
|
||||
|
||||
return graphJSONCreator.createActivityGraphJSON(activityData);
|
||||
}
|
||||
|
||||
private Map<String, Object> getPlayersTableData(Set<UUID> playerUUIDs, long after, long before) {
|
||||
private Map<String, Object> getPlayersTableData(Set<UUID> playerUUIDs, List<ServerUUID> serverUUIDs, long after, long before) {
|
||||
Database database = dbSystem.getDatabase();
|
||||
return new PlayersTableJSONCreator(
|
||||
database.query(new QueryTablePlayersQuery(playerUUIDs, after, before, config.get(TimeSettings.ACTIVE_PLAY_THRESHOLD))),
|
||||
database.query(new QueryTablePlayersQuery(playerUUIDs, serverUUIDs, after, before, config.get(TimeSettings.ACTIVE_PLAY_THRESHOLD))),
|
||||
database.query(new ExtensionQueryResultTableDataQuery(serverInfo.getServerUUID(), playerUUIDs)),
|
||||
config.get(DisplaySettings.OPEN_PLAYER_LINKS_IN_NEW_TAB),
|
||||
formatters, locale
|
||||
|
@ -57,4 +57,8 @@ public interface FiltersModule {
|
||||
@IntoSet
|
||||
Filter filter8(PluginBooleanGroupFilter filter);
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
Filter filter9(PlayedOnServerFilter filter);
|
||||
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ import com.djrapitops.plan.settings.locale.LocaleSystem;
|
||||
import com.djrapitops.plan.storage.file.JarResource;
|
||||
import com.djrapitops.plan.utilities.logging.ErrorLogger;
|
||||
import com.djrapitops.plan.utilities.logging.PluginErrorLogger;
|
||||
import com.google.gson.Gson;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import dagger.multibindings.ElementsIntoSet;
|
||||
@ -49,6 +50,12 @@ import java.util.function.Predicate;
|
||||
@Module
|
||||
public class SystemObjectProvidingModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
Gson provideGson() {
|
||||
return new Gson();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ElementsIntoSet
|
||||
Set<Importer> emptyImporterSet() {
|
||||
|
@ -17,6 +17,7 @@
|
||||
package com.djrapitops.plan.storage.database.queries.analysis;
|
||||
|
||||
import com.djrapitops.plan.delivery.domain.mutators.ActivityIndex;
|
||||
import com.djrapitops.plan.identification.ServerUUID;
|
||||
import com.djrapitops.plan.storage.database.queries.Query;
|
||||
import com.djrapitops.plan.storage.database.queries.QueryStatement;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.SessionsTable;
|
||||
@ -74,6 +75,10 @@ public class NetworkActivityIndexQueries {
|
||||
}
|
||||
|
||||
public static String selectActivityIndexSQL() {
|
||||
return selectActivityIndexSQL(Collections.emptyList());
|
||||
}
|
||||
|
||||
public static String selectActivityIndexSQL(Collection<ServerUUID> onServers) {
|
||||
String selectActivePlaytimeSQL = SELECT +
|
||||
"ux." + UsersTable.USER_UUID + ",COALESCE(active_playtime,0) AS active_playtime" +
|
||||
FROM + UsersTable.TABLE_NAME + " ux" +
|
||||
@ -82,6 +87,7 @@ public class NetworkActivityIndexQueries {
|
||||
FROM + SessionsTable.TABLE_NAME +
|
||||
WHERE + SessionsTable.SESSION_END + ">=?" +
|
||||
AND + SessionsTable.SESSION_START + "<=?" +
|
||||
(onServers.isEmpty() ? "" : AND + SessionsTable.SERVER_UUID + " IN ('" + new TextStringBuilder().appendWithSeparators(onServers, "','") + "')") +
|
||||
GROUP_BY + SessionsTable.USER_UUID +
|
||||
") sx on sx.uuid=ux.uuid";
|
||||
|
||||
@ -163,8 +169,8 @@ public class NetworkActivityIndexQueries {
|
||||
};
|
||||
}
|
||||
|
||||
public static Query<Map<String, Integer>> fetchActivityIndexGroupingsOn(long date, long threshold, Collection<UUID> playerUUIDs) {
|
||||
String selectActivityIndex = selectActivityIndexSQL();
|
||||
public static Query<Map<String, Integer>> fetchActivityIndexGroupingsOn(long date, long threshold, Collection<UUID> playerUUIDs, List<ServerUUID> serverUUIDs) {
|
||||
String selectActivityIndex = selectActivityIndexSQL(serverUUIDs);
|
||||
|
||||
String selectIndexes = SELECT + "activity_index" +
|
||||
FROM + UsersTable.TABLE_NAME + " u" +
|
||||
|
@ -16,6 +16,8 @@
|
||||
*/
|
||||
package com.djrapitops.plan.storage.database.queries.filter;
|
||||
|
||||
import com.djrapitops.plan.delivery.domain.datatransfer.InputFilterDto;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
@ -40,9 +42,9 @@ public interface Filter {
|
||||
* @return Set of UUIDs this filter applies to
|
||||
* @throws IllegalArgumentException If the arguments are not valid.
|
||||
*/
|
||||
Set<UUID> getMatchingUUIDs(SpecifiedFilterInformation query);
|
||||
Set<UUID> getMatchingUUIDs(InputFilterDto query);
|
||||
|
||||
default Result apply(SpecifiedFilterInformation query) {
|
||||
default Result apply(InputFilterDto query) {
|
||||
try {
|
||||
return new Result(null, getKind(), getMatchingUUIDs(query));
|
||||
} catch (CompleteSetException allMatch) {
|
||||
@ -64,7 +66,7 @@ public interface Filter {
|
||||
this.currentUUIDs = currentUUIDs;
|
||||
}
|
||||
|
||||
public Result apply(Filter filter, SpecifiedFilterInformation query) {
|
||||
public Result apply(Filter filter, InputFilterDto query) {
|
||||
try {
|
||||
Set<UUID> got = filter.getMatchingUUIDs(query);
|
||||
currentUUIDs.retainAll(got);
|
||||
|
@ -16,6 +16,7 @@
|
||||
*/
|
||||
package com.djrapitops.plan.storage.database.queries.filter;
|
||||
|
||||
import com.djrapitops.plan.delivery.domain.datatransfer.InputFilterDto;
|
||||
import com.djrapitops.plan.delivery.web.resolver.exception.BadRequestException;
|
||||
import com.djrapitops.plan.storage.database.DBSystem;
|
||||
import com.djrapitops.plan.storage.database.queries.filter.filters.AllPlayersFilter;
|
||||
@ -81,25 +82,25 @@ public class QueryFilters {
|
||||
* @return the result object or null if none of the filterQueries could be applied.
|
||||
* @throws BadRequestException If the request kind is not supported or if filter was given bad options.
|
||||
*/
|
||||
public Filter.Result apply(List<SpecifiedFilterInformation> filterQueries) {
|
||||
public Filter.Result apply(List<InputFilterDto> filterQueries) {
|
||||
prepareFilters();
|
||||
Filter.Result current = null;
|
||||
if (filterQueries.isEmpty()) return allPlayersFilter.apply(null);
|
||||
for (SpecifiedFilterInformation specifiedFilterInformation : filterQueries) {
|
||||
current = apply(current, specifiedFilterInformation);
|
||||
for (InputFilterDto inputFilterDto : filterQueries) {
|
||||
current = apply(current, inputFilterDto);
|
||||
if (current != null && current.isEmpty()) break;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
private Filter.Result apply(Filter.Result current, SpecifiedFilterInformation specifiedFilterInformation) {
|
||||
String kind = specifiedFilterInformation.getKind();
|
||||
private Filter.Result apply(Filter.Result current, InputFilterDto inputFilterDto) {
|
||||
String kind = inputFilterDto.getKind();
|
||||
Filter filter = getFilter(kind).orElseThrow(() -> new BadRequestException("Filter kind not supported: '" + kind + "'"));
|
||||
|
||||
return getResult(current, filter, specifiedFilterInformation);
|
||||
return getResult(current, filter, inputFilterDto);
|
||||
}
|
||||
|
||||
private Filter.Result getResult(Filter.Result current, Filter filter, SpecifiedFilterInformation query) {
|
||||
private Filter.Result getResult(Filter.Result current, Filter filter, InputFilterDto query) {
|
||||
try {
|
||||
return current == null ? filter.apply(query) : current.apply(filter, query);
|
||||
} catch (IllegalArgumentException badOptions) {
|
||||
|
@ -16,6 +16,7 @@
|
||||
*/
|
||||
package com.djrapitops.plan.storage.database.queries.filter.filters;
|
||||
|
||||
import com.djrapitops.plan.delivery.domain.datatransfer.InputFilterDto;
|
||||
import com.djrapitops.plan.delivery.domain.mutators.ActivityIndex;
|
||||
import com.djrapitops.plan.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.settings.config.paths.TimeSettings;
|
||||
@ -23,7 +24,6 @@ import com.djrapitops.plan.settings.locale.Locale;
|
||||
import com.djrapitops.plan.storage.database.DBSystem;
|
||||
import com.djrapitops.plan.storage.database.queries.analysis.NetworkActivityIndexQueries;
|
||||
import com.djrapitops.plan.storage.database.queries.filter.CompleteSetException;
|
||||
import com.djrapitops.plan.storage.database.queries.filter.SpecifiedFilterInformation;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
@ -63,7 +63,7 @@ public class ActivityIndexFilter extends MultiOptionFilter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> getMatchingUUIDs(SpecifiedFilterInformation query) {
|
||||
public Set<UUID> getMatchingUUIDs(InputFilterDto query) {
|
||||
List<String> selected = getSelected(query);
|
||||
String[] options = getOptionsArray();
|
||||
|
||||
|
@ -16,9 +16,9 @@
|
||||
*/
|
||||
package com.djrapitops.plan.storage.database.queries.filter.filters;
|
||||
|
||||
import com.djrapitops.plan.delivery.domain.datatransfer.InputFilterDto;
|
||||
import com.djrapitops.plan.storage.database.DBSystem;
|
||||
import com.djrapitops.plan.storage.database.queries.filter.Filter;
|
||||
import com.djrapitops.plan.storage.database.queries.filter.SpecifiedFilterInformation;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.UserIdentifierQueries;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@ -52,7 +52,7 @@ public class AllPlayersFilter implements Filter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> getMatchingUUIDs(SpecifiedFilterInformation query) {
|
||||
public Set<UUID> getMatchingUUIDs(InputFilterDto query) {
|
||||
return dbSystem.getDatabase().query(UserIdentifierQueries.fetchAllPlayerUUIDs());
|
||||
}
|
||||
}
|
||||
|
@ -16,11 +16,11 @@
|
||||
*/
|
||||
package com.djrapitops.plan.storage.database.queries.filter.filters;
|
||||
|
||||
import com.djrapitops.plan.delivery.domain.datatransfer.InputFilterDto;
|
||||
import com.djrapitops.plan.settings.locale.Locale;
|
||||
import com.djrapitops.plan.settings.locale.lang.FilterLang;
|
||||
import com.djrapitops.plan.storage.database.DBSystem;
|
||||
import com.djrapitops.plan.storage.database.queries.filter.CompleteSetException;
|
||||
import com.djrapitops.plan.storage.database.queries.filter.SpecifiedFilterInformation;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.UserInfoQueries;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@ -57,7 +57,7 @@ public class BannedFilter extends MultiOptionFilter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> getMatchingUUIDs(SpecifiedFilterInformation query) {
|
||||
public Set<UUID> getMatchingUUIDs(InputFilterDto query) {
|
||||
List<String> selected = getSelected(query);
|
||||
Set<UUID> uuids = new HashSet<>();
|
||||
String[] options = getOptionsArray();
|
||||
|
@ -16,10 +16,10 @@
|
||||
*/
|
||||
package com.djrapitops.plan.storage.database.queries.filter.filters;
|
||||
|
||||
import com.djrapitops.plan.delivery.domain.datatransfer.InputFilterDto;
|
||||
import com.djrapitops.plan.delivery.web.resolver.exception.BadRequestException;
|
||||
import com.djrapitops.plan.storage.database.DBSystem;
|
||||
import com.djrapitops.plan.storage.database.queries.filter.Filter;
|
||||
import com.djrapitops.plan.storage.database.queries.filter.SpecifiedFilterInformation;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.BaseUserQueries;
|
||||
import com.djrapitops.plan.utilities.java.Maps;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@ -61,15 +61,15 @@ public abstract class DateRangeFilter implements Filter {
|
||||
.build();
|
||||
}
|
||||
|
||||
protected long getAfter(SpecifiedFilterInformation query) {
|
||||
protected long getAfter(InputFilterDto query) {
|
||||
return getTime(query, "afterDate", "afterTime");
|
||||
}
|
||||
|
||||
protected long getBefore(SpecifiedFilterInformation query) {
|
||||
protected long getBefore(InputFilterDto query) {
|
||||
return getTime(query, "beforeDate", "beforeTime");
|
||||
}
|
||||
|
||||
private long getTime(SpecifiedFilterInformation query, String dateKey, String timeKey) {
|
||||
private long getTime(InputFilterDto query, String dateKey, String timeKey) {
|
||||
String date = query.get(dateKey).orElseThrow(() -> new BadRequestException("'" + dateKey + "' not specified in parameters for " + getKind()));
|
||||
String time = query.get(timeKey).orElseThrow(() -> new BadRequestException("'" + timeKey + "' not specified in parameters for " + getKind()));
|
||||
|
||||
|
@ -16,8 +16,8 @@
|
||||
*/
|
||||
package com.djrapitops.plan.storage.database.queries.filter.filters;
|
||||
|
||||
import com.djrapitops.plan.delivery.domain.datatransfer.InputFilterDto;
|
||||
import com.djrapitops.plan.storage.database.DBSystem;
|
||||
import com.djrapitops.plan.storage.database.queries.filter.SpecifiedFilterInformation;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.GeoInfoQueries;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@ -47,7 +47,7 @@ public class GeolocationsFilter extends MultiOptionFilter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> getMatchingUUIDs(SpecifiedFilterInformation query) {
|
||||
public Set<UUID> getMatchingUUIDs(InputFilterDto query) {
|
||||
return dbSystem.getDatabase().query(GeoInfoQueries.uuidsOfPlayersWithGeolocations(getSelected(query)));
|
||||
}
|
||||
}
|
||||
|
@ -16,8 +16,8 @@
|
||||
*/
|
||||
package com.djrapitops.plan.storage.database.queries.filter.filters;
|
||||
|
||||
import com.djrapitops.plan.delivery.domain.datatransfer.InputFilterDto;
|
||||
import com.djrapitops.plan.storage.database.DBSystem;
|
||||
import com.djrapitops.plan.storage.database.queries.filter.SpecifiedFilterInformation;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.UserInfoQueries;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@ -47,7 +47,7 @@ public class JoinAddressFilter extends MultiOptionFilter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> getMatchingUUIDs(SpecifiedFilterInformation query) {
|
||||
public Set<UUID> getMatchingUUIDs(InputFilterDto query) {
|
||||
return dbSystem.getDatabase().query(UserInfoQueries.uuidsOfPlayersWithJoinAddresses(getSelected(query)));
|
||||
}
|
||||
}
|
||||
|
@ -16,9 +16,9 @@
|
||||
*/
|
||||
package com.djrapitops.plan.storage.database.queries.filter.filters;
|
||||
|
||||
import com.djrapitops.plan.delivery.domain.datatransfer.InputFilterDto;
|
||||
import com.djrapitops.plan.storage.database.queries.filter.CompleteSetException;
|
||||
import com.djrapitops.plan.storage.database.queries.filter.Filter;
|
||||
import com.djrapitops.plan.storage.database.queries.filter.SpecifiedFilterInformation;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
@ -31,7 +31,7 @@ public abstract class MultiOptionFilter implements Filter {
|
||||
return new String[]{"selected"};
|
||||
}
|
||||
|
||||
protected List<String> getSelected(SpecifiedFilterInformation query) {
|
||||
protected List<String> getSelected(InputFilterDto query) {
|
||||
String selectedJSON = query.get("selected").orElseThrow(IllegalArgumentException::new);
|
||||
List<String> selected = new Gson().fromJson(selectedJSON, new TypeToken<List<String>>() {}.getType());
|
||||
if (selected.isEmpty()) throw new CompleteSetException();
|
||||
|
@ -16,11 +16,11 @@
|
||||
*/
|
||||
package com.djrapitops.plan.storage.database.queries.filter.filters;
|
||||
|
||||
import com.djrapitops.plan.delivery.domain.datatransfer.InputFilterDto;
|
||||
import com.djrapitops.plan.settings.locale.Locale;
|
||||
import com.djrapitops.plan.settings.locale.lang.FilterLang;
|
||||
import com.djrapitops.plan.storage.database.DBSystem;
|
||||
import com.djrapitops.plan.storage.database.queries.filter.CompleteSetException;
|
||||
import com.djrapitops.plan.storage.database.queries.filter.SpecifiedFilterInformation;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.UserInfoQueries;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@ -57,7 +57,7 @@ public class OperatorsFilter extends MultiOptionFilter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> getMatchingUUIDs(SpecifiedFilterInformation query) {
|
||||
public Set<UUID> getMatchingUUIDs(InputFilterDto query) {
|
||||
List<String> selected = getSelected(query);
|
||||
Set<UUID> uuids = new HashSet<>();
|
||||
String[] options = getOptionsArray();
|
||||
|
@ -16,14 +16,16 @@
|
||||
*/
|
||||
package com.djrapitops.plan.storage.database.queries.filter.filters;
|
||||
|
||||
import com.djrapitops.plan.delivery.domain.datatransfer.InputFilterDto;
|
||||
import com.djrapitops.plan.identification.ServerUUID;
|
||||
import com.djrapitops.plan.storage.database.DBSystem;
|
||||
import com.djrapitops.plan.storage.database.queries.filter.SpecifiedFilterInformation;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.ServerQueries;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.SessionQueries;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
|
||||
@Singleton
|
||||
public class PlayedBetweenDateRangeFilter extends DateRangeFilter {
|
||||
@ -42,9 +44,18 @@ public class PlayedBetweenDateRangeFilter extends DateRangeFilter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> getMatchingUUIDs(SpecifiedFilterInformation query) {
|
||||
public Set<UUID> getMatchingUUIDs(InputFilterDto query) {
|
||||
long after = getAfter(query);
|
||||
long before = getBefore(query);
|
||||
return dbSystem.getDatabase().query(SessionQueries.uuidsOfPlayedBetween(after, before));
|
||||
List<String> serverNames = getServerNames(query);
|
||||
List<ServerUUID> serverUUIDs = serverNames.isEmpty() ? Collections.emptyList() : dbSystem.getDatabase().query(ServerQueries.fetchServersMatchingIdentifiers(serverNames));
|
||||
return dbSystem.getDatabase().query(SessionQueries.uuidsOfPlayedBetween(after, before, serverUUIDs));
|
||||
}
|
||||
|
||||
private List<String> getServerNames(InputFilterDto query) {
|
||||
return query.get("servers")
|
||||
.map(serversList -> new Gson().fromJson(serversList, String[].class))
|
||||
.map(Arrays::asList)
|
||||
.orElseGet(Collections::emptyList);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.storage.database.queries.filter.filters;
|
||||
|
||||
import com.djrapitops.plan.delivery.domain.datatransfer.InputFilterDto;
|
||||
import com.djrapitops.plan.identification.ServerUUID;
|
||||
import com.djrapitops.plan.storage.database.DBSystem;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.ServerQueries;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.UserInfoQueries;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.*;
|
||||
|
||||
@Singleton
|
||||
public class PlayedOnServerFilter extends MultiOptionFilter {
|
||||
|
||||
private final DBSystem dbSystem;
|
||||
|
||||
@Inject
|
||||
public PlayedOnServerFilter(DBSystem dbSystem) {
|
||||
this.dbSystem = dbSystem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKind() {
|
||||
return "playedOnServer";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getOptions() {
|
||||
return Collections.singletonMap("options", getSelectionOptions());
|
||||
}
|
||||
|
||||
private List<String> getSelectionOptions() {
|
||||
return dbSystem.getDatabase().query(ServerQueries.fetchGameServerNames());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> getMatchingUUIDs(InputFilterDto query) {
|
||||
List<String> serverNames = getSelected(query);
|
||||
List<ServerUUID> serverUUIDs = serverNames.isEmpty() ? Collections.emptyList() : dbSystem.getDatabase().query(ServerQueries.fetchServersMatchingIdentifiers(serverNames));
|
||||
|
||||
return dbSystem.getDatabase().query(UserInfoQueries.uuidsOfRegisteredBetween(0, System.currentTimeMillis(), serverUUIDs));
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@
|
||||
*/
|
||||
package com.djrapitops.plan.storage.database.queries.filter.filters;
|
||||
|
||||
import com.djrapitops.plan.delivery.domain.datatransfer.InputFilterDto;
|
||||
import com.djrapitops.plan.identification.Server;
|
||||
import com.djrapitops.plan.identification.ServerUUID;
|
||||
import com.djrapitops.plan.storage.database.DBSystem;
|
||||
@ -23,7 +24,6 @@ import com.djrapitops.plan.storage.database.Database;
|
||||
import com.djrapitops.plan.storage.database.queries.Query;
|
||||
import com.djrapitops.plan.storage.database.queries.QueryAllStatement;
|
||||
import com.djrapitops.plan.storage.database.queries.QueryStatement;
|
||||
import com.djrapitops.plan.storage.database.queries.filter.SpecifiedFilterInformation;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.ServerQueries;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.ExtensionPlayerValueTable;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.ExtensionPluginTable;
|
||||
@ -164,7 +164,7 @@ public class PluginBooleanGroupFilter extends MultiOptionFilter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> getMatchingUUIDs(SpecifiedFilterInformation query) {
|
||||
public Set<UUID> getMatchingUUIDs(InputFilterDto query) {
|
||||
Map<PluginBooleanOption, SelectedBoolean> selectedBooleanOptions = new HashMap<>();
|
||||
for (String selected : getSelected(query)) {
|
||||
String[] optionAndBoolean = StringUtils.split(selected, ":", 2);
|
||||
|
@ -16,6 +16,7 @@
|
||||
*/
|
||||
package com.djrapitops.plan.storage.database.queries.filter.filters;
|
||||
|
||||
import com.djrapitops.plan.delivery.domain.datatransfer.InputFilterDto;
|
||||
import com.djrapitops.plan.extension.implementation.providers.ProviderIdentifier;
|
||||
import com.djrapitops.plan.extension.implementation.storage.queries.ExtensionUUIDsInGroupQuery;
|
||||
import com.djrapitops.plan.identification.Server;
|
||||
@ -23,7 +24,6 @@ import com.djrapitops.plan.identification.ServerInfo;
|
||||
import com.djrapitops.plan.identification.ServerUUID;
|
||||
import com.djrapitops.plan.storage.database.DBSystem;
|
||||
import com.djrapitops.plan.storage.database.queries.QueryAllStatement;
|
||||
import com.djrapitops.plan.storage.database.queries.filter.SpecifiedFilterInformation;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.ExtensionGroupsTable;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.ExtensionPluginTable;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.ExtensionProviderTable;
|
||||
@ -67,7 +67,7 @@ public class PluginGroupsFilter extends MultiOptionFilter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> getMatchingUUIDs(SpecifiedFilterInformation query) {
|
||||
public Set<UUID> getMatchingUUIDs(InputFilterDto query) {
|
||||
return dbSystem.getDatabase().query(
|
||||
new ExtensionUUIDsInGroupQuery(identifier.getPluginName(), identifier.getProviderName(), identifier.getServerUUID(), getSelected(query))
|
||||
);
|
||||
|
@ -16,14 +16,17 @@
|
||||
*/
|
||||
package com.djrapitops.plan.storage.database.queries.filter.filters;
|
||||
|
||||
import com.djrapitops.plan.delivery.domain.datatransfer.InputFilterDto;
|
||||
import com.djrapitops.plan.identification.ServerUUID;
|
||||
import com.djrapitops.plan.storage.database.DBSystem;
|
||||
import com.djrapitops.plan.storage.database.queries.filter.SpecifiedFilterInformation;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.BaseUserQueries;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.ServerQueries;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.UserInfoQueries;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
|
||||
@Singleton
|
||||
public class RegisteredBetweenDateRangeFilter extends DateRangeFilter {
|
||||
@ -42,9 +45,21 @@ public class RegisteredBetweenDateRangeFilter extends DateRangeFilter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> getMatchingUUIDs(SpecifiedFilterInformation query) {
|
||||
public Set<UUID> getMatchingUUIDs(InputFilterDto query) {
|
||||
long after = getAfter(query);
|
||||
long before = getBefore(query);
|
||||
return dbSystem.getDatabase().query(BaseUserQueries.uuidsOfRegisteredBetween(after, before));
|
||||
List<String> serverNames = getServerNames(query);
|
||||
List<ServerUUID> serverUUIDs = serverNames.isEmpty() ? Collections.emptyList() : dbSystem.getDatabase().query(ServerQueries.fetchServersMatchingIdentifiers(serverNames));
|
||||
return dbSystem.getDatabase().query(
|
||||
serverUUIDs.isEmpty() ? BaseUserQueries.uuidsOfRegisteredBetween(after, before)
|
||||
: UserInfoQueries.uuidsOfRegisteredBetween(after, before, serverUUIDs)
|
||||
);
|
||||
}
|
||||
|
||||
private List<String> getServerNames(InputFilterDto query) {
|
||||
return query.get("servers")
|
||||
.map(serversList -> new Gson().fromJson(serversList, String[].class))
|
||||
.map(Arrays::asList)
|
||||
.orElseGet(Collections::emptyList);
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.djrapitops.plan.storage.database.sql.building.Sql.*;
|
||||
|
||||
@ -172,6 +173,24 @@ public class ServerQueries {
|
||||
};
|
||||
}
|
||||
|
||||
public static Query<List<String>> fetchGameServerNames() {
|
||||
String sql = Select.from(ServerTable.TABLE_NAME,
|
||||
ServerTable.SERVER_ID, ServerTable.SERVER_UUID, ServerTable.NAME)
|
||||
.where(ServerTable.PROXY + "=0")
|
||||
.toString();
|
||||
|
||||
return new QueryAllStatement<List<String>>(sql) {
|
||||
@Override
|
||||
public List<String> processResults(ResultSet set) throws SQLException {
|
||||
List<String> names = new ArrayList<>();
|
||||
while (set.next()) {
|
||||
names.add(Server.getIdentifiableName(set.getString(ServerTable.NAME), set.getInt(ServerTable.SERVER_ID)));
|
||||
}
|
||||
return names;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Query<Map<ServerUUID, String>> fetchServerNames() {
|
||||
String sql = Select.from(ServerTable.TABLE_NAME,
|
||||
ServerTable.SERVER_ID, ServerTable.SERVER_UUID, ServerTable.NAME)
|
||||
@ -263,4 +282,14 @@ public class ServerQueries {
|
||||
public static Query<Map<String, ServerUUID>> fetchServerNamesToUUIDs() {
|
||||
return db -> Maps.reverse(db.query(fetchServerNames()));
|
||||
}
|
||||
|
||||
public static Query<List<ServerUUID>> fetchServersMatchingIdentifiers(List<String> serverNames) {
|
||||
return db -> {
|
||||
Map<String, ServerUUID> nameToUUIDMap = db.query(ServerQueries.fetchServerNamesToUUIDs());
|
||||
return serverNames.stream()
|
||||
.map(nameToUUIDMap::get)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
};
|
||||
}
|
||||
}
|
@ -846,11 +846,12 @@ public class SessionQueries {
|
||||
};
|
||||
}
|
||||
|
||||
public static Query<Set<UUID>> uuidsOfPlayedBetween(long after, long before) {
|
||||
public static Query<Set<UUID>> uuidsOfPlayedBetween(long after, long before, List<ServerUUID> serverUUIDs) {
|
||||
String sql = SELECT + DISTINCT + SessionsTable.USER_UUID +
|
||||
FROM + SessionsTable.TABLE_NAME +
|
||||
WHERE + SessionsTable.SESSION_END + ">=?" +
|
||||
AND + SessionsTable.SESSION_START + "<=?";
|
||||
AND + SessionsTable.SESSION_START + "<=?" +
|
||||
(serverUUIDs.isEmpty() ? "" : AND + SessionsTable.SERVER_UUID + " IN ('" + new TextStringBuilder().appendWithSeparators(serverUUIDs, "','") + "')");
|
||||
return new QueryStatement<Set<UUID>>(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
@ -869,7 +870,7 @@ public class SessionQueries {
|
||||
};
|
||||
}
|
||||
|
||||
public static Query<Map<String, Long>> summaryOfPlayers(Set<UUID> playerUUIDs, long after, long before) {
|
||||
public static Query<Map<String, Long>> summaryOfPlayers(Set<UUID> playerUUIDs, List<ServerUUID> serverUUIDs, long after, long before) {
|
||||
String selectAggregates = SELECT +
|
||||
"SUM(" + SessionsTable.SESSION_END + '-' + SessionsTable.SESSION_START + ") as playtime," +
|
||||
"SUM(" + SessionsTable.SESSION_END + '-' + SessionsTable.SESSION_START + '-' + SessionsTable.AFK_TIME + ") as active_playtime," +
|
||||
@ -878,7 +879,8 @@ public class SessionQueries {
|
||||
WHERE + SessionsTable.SESSION_START + ">?" +
|
||||
AND + SessionsTable.SESSION_END + "<?" +
|
||||
AND + SessionsTable.USER_UUID + " IN ('" +
|
||||
new TextStringBuilder().appendWithSeparators(playerUUIDs, "','").build() + "')";
|
||||
new TextStringBuilder().appendWithSeparators(playerUUIDs, "','").build() + "')" +
|
||||
(serverUUIDs.isEmpty() ? "" : AND + SessionsTable.SERVER_UUID + " IN ('" + new TextStringBuilder().appendWithSeparators(serverUUIDs, "','") + "')");
|
||||
|
||||
return new QueryStatement<Map<String, Long>>(selectAggregates) {
|
||||
@Override
|
||||
|
@ -22,6 +22,7 @@ import com.djrapitops.plan.storage.database.queries.Query;
|
||||
import com.djrapitops.plan.storage.database.queries.QueryAllStatement;
|
||||
import com.djrapitops.plan.storage.database.queries.QueryStatement;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.UserInfoTable;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.UsersTable;
|
||||
import com.djrapitops.plan.utilities.java.Lists;
|
||||
import org.apache.commons.text.TextStringBuilder;
|
||||
|
||||
@ -338,4 +339,28 @@ public class UserInfoQueries {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Query<Set<UUID>> uuidsOfRegisteredBetween(long after, long before, List<ServerUUID> serverUUIDs) {
|
||||
String sql = SELECT + DISTINCT + UserInfoTable.USER_UUID +
|
||||
FROM + UserInfoTable.TABLE_NAME +
|
||||
WHERE + UserInfoTable.REGISTERED + ">=?" +
|
||||
AND + UserInfoTable.REGISTERED + "<=?" +
|
||||
AND + UserInfoTable.SERVER_UUID + " IN ('" + new TextStringBuilder().appendWithSeparators(serverUUIDs, "','") + "')";
|
||||
return new QueryStatement<Set<UUID>>(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setLong(1, after);
|
||||
statement.setLong(2, before);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> processResults(ResultSet set) throws SQLException {
|
||||
Set<UUID> uuids = new HashSet<>();
|
||||
while (set.next()) {
|
||||
uuids.add(UUID.fromString(set.getString(UsersTable.USER_UUID)));
|
||||
}
|
||||
return uuids;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@ package com.djrapitops.plan.storage.database.queries.objects.playertable;
|
||||
|
||||
import com.djrapitops.plan.delivery.domain.TablePlayer;
|
||||
import com.djrapitops.plan.delivery.domain.mutators.ActivityIndex;
|
||||
import com.djrapitops.plan.identification.ServerUUID;
|
||||
import com.djrapitops.plan.storage.database.SQLDB;
|
||||
import com.djrapitops.plan.storage.database.queries.Query;
|
||||
import com.djrapitops.plan.storage.database.queries.QueryStatement;
|
||||
@ -46,6 +47,7 @@ import static com.djrapitops.plan.storage.database.sql.building.Sql.*;
|
||||
public class QueryTablePlayersQuery implements Query<List<TablePlayer>> {
|
||||
|
||||
private final Collection<UUID> playerUUIDs;
|
||||
private final List<ServerUUID> serverUUIDs;
|
||||
private final long afterDate;
|
||||
private final long beforeDate;
|
||||
private final long activeMsThreshold;
|
||||
@ -54,12 +56,14 @@ public class QueryTablePlayersQuery implements Query<List<TablePlayer>> {
|
||||
* Create a new query.
|
||||
*
|
||||
* @param playerUUIDs UUIDs of the players in the query
|
||||
* @param beforeDate View data before this epoch ms
|
||||
* @param serverUUIDs View data for these Server UUIDs
|
||||
* @param afterDate View data after this epoch ms
|
||||
* @param beforeDate View data before this epoch ms
|
||||
* @param activeMsThreshold Playtime threshold for Activity Index calculation
|
||||
*/
|
||||
public QueryTablePlayersQuery(Collection<UUID> playerUUIDs, long afterDate, long beforeDate, long activeMsThreshold) {
|
||||
public QueryTablePlayersQuery(Collection<UUID> playerUUIDs, List<ServerUUID> serverUUIDs, long afterDate, long beforeDate, long activeMsThreshold) {
|
||||
this.playerUUIDs = playerUUIDs;
|
||||
this.serverUUIDs = serverUUIDs;
|
||||
this.afterDate = afterDate;
|
||||
this.beforeDate = beforeDate;
|
||||
this.activeMsThreshold = activeMsThreshold;
|
||||
@ -95,12 +99,14 @@ public class QueryTablePlayersQuery implements Query<List<TablePlayer>> {
|
||||
AND + "s." + SessionsTable.SESSION_END + "<=?" +
|
||||
AND + "s." + SessionsTable.USER_UUID +
|
||||
uuidsInSet +
|
||||
(serverUUIDs.isEmpty() ? "" : AND + "s." + SessionsTable.SERVER_UUID + " IN ('" + new TextStringBuilder().appendWithSeparators(serverUUIDs, "','") + "')") +
|
||||
GROUP_BY + "s." + SessionsTable.USER_UUID;
|
||||
|
||||
String selectBanned = SELECT + DISTINCT + "ub." + UserInfoTable.USER_UUID +
|
||||
FROM + UserInfoTable.TABLE_NAME + " ub" +
|
||||
WHERE + UserInfoTable.BANNED + "=?" +
|
||||
AND + UserInfoTable.USER_UUID + uuidsInSet;
|
||||
AND + UserInfoTable.USER_UUID + uuidsInSet +
|
||||
(serverUUIDs.isEmpty() ? "" : AND + UserInfoTable.SERVER_UUID + " IN ('" + new TextStringBuilder().appendWithSeparators(serverUUIDs, "','") + "')");
|
||||
|
||||
String selectBaseUsers = SELECT +
|
||||
"u." + UsersTable.USER_UUID + ',' +
|
||||
|
@ -869,6 +869,30 @@ div#navSrvContainer::-webkit-scrollbar-thumb {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn.bg-plan:hover,
|
||||
.btn.bg-pink:hover,
|
||||
.btn.bg-red:hover,
|
||||
.btn.bg-purple:hover,
|
||||
.btn.bg-deep-purple:hover,
|
||||
.btn.bg-indigo:hover,
|
||||
.btn.bg-light-blue:hover,
|
||||
.btn.bg-black:hover,
|
||||
.btn.bg-blue:hover,
|
||||
.btn.bg-cyan:hover,
|
||||
.btn.bg-teal:hover,
|
||||
.btn.bg-green:hover,
|
||||
.btn.bg-light-green:hover,
|
||||
.btn.bg-lime:hover,
|
||||
.btn.bg-yellow:hover,
|
||||
.btn.bg-amber:hover,
|
||||
.btn.bg-orange:hover,
|
||||
.btn.bg-deep-orange:hover,
|
||||
.btn.bg-brown:hover,
|
||||
.btn.bg-grey:hover,
|
||||
.btn.bg-blue-grey:hover {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.bg-night, body.theme-night .fc-toolbar-chunk .btn.btn-primary {
|
||||
background-color: #44475a;
|
||||
color: #eee8d5;
|
||||
|
@ -209,6 +209,12 @@ class RegisteredBetweenFilter extends BetweenDateFilter {
|
||||
}
|
||||
}
|
||||
|
||||
class PlayedOnServerFilter extends MultipleChoiceFilter {
|
||||
constructor(id, options) {
|
||||
super(id, "playedOnServer", "have played on at least one of", options);
|
||||
}
|
||||
}
|
||||
|
||||
function createFilter(filter, id) {
|
||||
if (filter.kind.startsWith("pluginGroups-")) {
|
||||
return new PluginGroupsFilter(id, filter.kind, filter.options);
|
||||
@ -230,6 +236,8 @@ function createFilter(filter, id) {
|
||||
return new RegisteredBetweenFilter(id, filter.options);
|
||||
case "pluginsBooleanGroups":
|
||||
return new PluginBooleanGroupsFilter(id, filter.options);
|
||||
case "playedOnServer":
|
||||
return new PlayedOnServerFilter(id, filter.options);
|
||||
default:
|
||||
throw new Error("Unsupported filter kind: '" + filter.kind + "'");
|
||||
}
|
||||
@ -258,6 +266,8 @@ function getReadableFilterName(filter) {
|
||||
return "Registered between";
|
||||
case "pluginsBooleanGroups":
|
||||
return "Has plugin boolean value";
|
||||
case "playedOnServer":
|
||||
return "Has played on one of servers";
|
||||
default:
|
||||
return filter.kind;
|
||||
}
|
||||
|
@ -6,7 +6,8 @@ const queryState = {
|
||||
afterDate: null,
|
||||
afterTime: null,
|
||||
beforeDate: null,
|
||||
beforeTime: null
|
||||
beforeTime: null,
|
||||
servers: []
|
||||
},
|
||||
invalidFormFields: {
|
||||
ids: [],
|
||||
@ -34,6 +35,8 @@ const queryState = {
|
||||
|
||||
let timestamp = undefined;
|
||||
|
||||
let serverMap = {};
|
||||
|
||||
function loadView(json) {
|
||||
queryState.view = json.view;
|
||||
|
||||
@ -42,11 +45,36 @@ function loadView(json) {
|
||||
document.getElementById('viewToDateField').setAttribute('placeholder', json.view.beforeDate);
|
||||
document.getElementById('viewToTimeField').setAttribute('placeholder', json.view.beforeTime);
|
||||
|
||||
// Load server selector or hide it
|
||||
if (json.view.servers.length >= 2) {
|
||||
let options = ``;
|
||||
for (let server of json.view.servers) {
|
||||
if (server.proxy) continue;
|
||||
serverMap[server.serverUUID] = server;
|
||||
options += `<option data-plan-server-uuid="${server.serverUUID}">${server.serverName}</option>`
|
||||
}
|
||||
const serverSelector = document.getElementById("server-selector");
|
||||
serverSelector.innerHTML = options;
|
||||
|
||||
serverSelector.addEventListener('click', () => {
|
||||
queryState.view.servers = [];
|
||||
if (serverSelector.selectedOptions.length !== serverSelector.options.length) {
|
||||
for (const option of serverSelector.selectedOptions) {
|
||||
queryState.view.servers.push(serverMap[option.getAttribute('data-plan-server-uuid')]);
|
||||
}
|
||||
}
|
||||
document.getElementById("serverDropdown").innerText = queryState.view.servers.length
|
||||
? `using data of ${queryState.view.servers.length} server(s)`
|
||||
: "using data of all servers"
|
||||
})
|
||||
} else {
|
||||
document.getElementById("serverDropdown").classList.add("hidden");
|
||||
}
|
||||
|
||||
const playersOnlineSeries = {
|
||||
name: 'Players Online', type: 'areaspline', tooltip: {valueDecimals: 0},
|
||||
data: json.viewPoints, color: '#9E9E9E', yAxis: 0
|
||||
}
|
||||
|
||||
graphs.push(Highcharts.stockChart('viewChart', {
|
||||
rangeSelector: {
|
||||
selected: 3,
|
||||
@ -424,7 +452,8 @@ function displayDataResultScreen(resultCount, view) {
|
||||
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
|
||||
<h6 class="m-0 fw-bold col-black" title=" ${afterDate} ${afterTime} - ${beforeDate} ${beforeTime}"><i
|
||||
class="fas fa-fw fa-users col-black"></i>
|
||||
View: ${afterDate} - ${beforeDate}</h6>
|
||||
View: ${afterDate} - ${beforeDate},
|
||||
${view.servers.length ? "using data of servers: " + view.servers.map(server => server.serverName).join(', ') : "using data of all servers"}</h6>
|
||||
</div>
|
||||
<table class="table table-bordered table-striped table-hover player-table" style="width: 100%">
|
||||
<tr>
|
||||
|
@ -141,6 +141,21 @@
|
||||
</div>
|
||||
<div class="chart-area" id="viewChart"><span class="loader"></span></div>
|
||||
|
||||
<div>
|
||||
<button aria-expanded="false" aria-haspopup="true" class="btn dropdown-toggle"
|
||||
data-bs-target="#server-dropdown" data-bs-toggle="collapse"
|
||||
id="serverDropdown" type="button">using data of all servers
|
||||
</button>
|
||||
<div aria-labelledby="serverDropdown" class="collapse"
|
||||
id="server-dropdown">
|
||||
<select class="form-control" id="server-selector" multiple>
|
||||
<option selected>Proxy server</option>
|
||||
<option>Server 1</option>
|
||||
<option>Skyblock</option>
|
||||
<option>Server 3</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
<div id="filters"></div>
|
||||
|
@ -22,6 +22,7 @@ import com.djrapitops.plan.settings.locale.Locale;
|
||||
import com.djrapitops.plan.settings.locale.LocaleSystem;
|
||||
import com.djrapitops.plan.storage.file.JarResource;
|
||||
import com.djrapitops.plan.utilities.logging.ErrorLogger;
|
||||
import com.google.gson.Gson;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import utilities.TestErrorLogger;
|
||||
@ -37,6 +38,12 @@ import java.util.function.Predicate;
|
||||
@Module
|
||||
public class TestSystemObjectProvidingModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
Gson provideGson() {
|
||||
return new Gson();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
Locale provideLocale(LocaleSystem localeSystem) {
|
||||
|
Loading…
Reference in New Issue
Block a user