mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2025-03-10 13:49:17 +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
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
* 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.Gson;
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
@ -27,18 +28,18 @@ import java.util.*;
|
|||||||
*
|
*
|
||||||
* @author AuroraLS3
|
* @author AuroraLS3
|
||||||
*/
|
*/
|
||||||
public class SpecifiedFilterInformation {
|
public class InputFilterDto {
|
||||||
|
|
||||||
private final String kind;
|
private final String kind;
|
||||||
private final Map<String, String> parameters;
|
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.kind = kind;
|
||||||
this.parameters = parameters;
|
this.parameters = parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<SpecifiedFilterInformation> parse(String json) throws IOException {
|
public static List<InputFilterDto> parse(String json, Gson gson) throws IOException {
|
||||||
return new Gson().getAdapter(new TypeToken<List<SpecifiedFilterInformation>>() {}).fromJson(json);
|
return gson.getAdapter(new TypeToken<List<InputFilterDto>>() {}).fromJson(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getKind() {
|
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;
|
package com.djrapitops.plan.delivery.rendering.json;
|
||||||
|
|
||||||
import com.djrapitops.plan.delivery.domain.DateObj;
|
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.PlayerKillMutator;
|
||||||
import com.djrapitops.plan.delivery.domain.mutators.SessionsMutator;
|
import com.djrapitops.plan.delivery.domain.mutators.SessionsMutator;
|
||||||
import com.djrapitops.plan.delivery.domain.mutators.TPSMutator;
|
import com.djrapitops.plan.delivery.domain.mutators.TPSMutator;
|
||||||
@ -266,16 +267,10 @@ public class JSONFactory {
|
|||||||
return tableEntries;
|
return tableEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Object> listServers() {
|
public Map<String, List<ServerDto>> listServers() {
|
||||||
Collection<Server> servers = dbSystem.getDatabase().query(ServerQueries.fetchPlanServerInformationCollection());
|
Collection<Server> servers = dbSystem.getDatabase().query(ServerQueries.fetchPlanServerInformationCollection());
|
||||||
return Maps.builder(String.class, Object.class)
|
return Collections.singletonMap("servers", servers.stream()
|
||||||
.put("servers", servers.stream()
|
.map(ServerDto::fromServer)
|
||||||
.map(server -> Maps.builder(String.class, Object.class)
|
.collect(Collectors.toList()));
|
||||||
.put("serverUUID", server.getUuid().toString())
|
|
||||||
.put("serverName", server.getIdentifiableName())
|
|
||||||
.put("proxy", server.isProxy())
|
|
||||||
.build())
|
|
||||||
.collect(Collectors.toList()))
|
|
||||||
.build();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -89,6 +89,7 @@ public class WebAssetVersionCheckTask extends TaskSystem.Task {
|
|||||||
if (!outdated.isEmpty()) {
|
if (!outdated.isEmpty()) {
|
||||||
logger.warn("You have customized files which are out of date due to recent updates!");
|
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("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) {
|
for (AssetInfo asset : outdated) {
|
||||||
logger.warn(String.format("- %s was modified %s, but the plugin contains a version from %s",
|
logger.warn(String.format("- %s was modified %s, but the plugin contains a version from %s",
|
||||||
|
@ -18,26 +18,38 @@ package com.djrapitops.plan.delivery.webserver;
|
|||||||
|
|
||||||
import com.djrapitops.plan.delivery.web.resolver.request.Request;
|
import com.djrapitops.plan.delivery.web.resolver.request.Request;
|
||||||
import com.djrapitops.plan.delivery.web.resolver.request.URIQuery;
|
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 {
|
public class RequestBodyConverter {
|
||||||
|
|
||||||
private RequestBodyConverter() {
|
private RequestBodyConverter() {
|
||||||
/* Static utility class */
|
/* Static utility class */
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the body of a request as an url-encoded form.
|
* Get the body of a request as an url-encoded form.
|
||||||
*
|
*
|
||||||
* @return {@link URIQuery}.
|
* @return {@link URIQuery}.
|
||||||
*/
|
*/
|
||||||
public static URIQuery formBody(Request request) {
|
public static URIQuery formBody(Request request) {
|
||||||
if (
|
if (
|
||||||
"POST".equalsIgnoreCase(request.getMethod()) &&
|
"POST".equalsIgnoreCase(request.getMethod()) &&
|
||||||
"application/x-www-form-urlencoded".equalsIgnoreCase(request.getHeader("Content-type").orElse(""))
|
"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 {
|
} else {
|
||||||
return new URIQuery("");
|
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;
|
package com.djrapitops.plan.delivery.webserver.resolver.json;
|
||||||
|
|
||||||
import com.djrapitops.plan.delivery.domain.DateObj;
|
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.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.Graphs;
|
||||||
import com.djrapitops.plan.delivery.rendering.json.graphs.line.LineGraph;
|
import com.djrapitops.plan.delivery.rendering.json.graphs.line.LineGraph;
|
||||||
import com.djrapitops.plan.delivery.rendering.json.graphs.line.Point;
|
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.java.Lists;
|
||||||
import com.djrapitops.plan.utilities.logging.ErrorContext;
|
import com.djrapitops.plan.utilities.logging.ErrorContext;
|
||||||
import com.djrapitops.plan.utilities.logging.ErrorLogger;
|
import com.djrapitops.plan.utilities.logging.ErrorLogger;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
@ -50,6 +51,7 @@ public class FiltersJSONResolver implements Resolver {
|
|||||||
private final ServerInfo serverInfo;
|
private final ServerInfo serverInfo;
|
||||||
private final DBSystem dbSystem;
|
private final DBSystem dbSystem;
|
||||||
private final QueryFilters filters;
|
private final QueryFilters filters;
|
||||||
|
private final JSONFactory jsonFactory;
|
||||||
private final Graphs graphs;
|
private final Graphs graphs;
|
||||||
private final Formatters formatters;
|
private final Formatters formatters;
|
||||||
private final ErrorLogger errorLogger;
|
private final ErrorLogger errorLogger;
|
||||||
@ -59,6 +61,7 @@ public class FiltersJSONResolver implements Resolver {
|
|||||||
ServerInfo serverInfo,
|
ServerInfo serverInfo,
|
||||||
DBSystem dbSystem,
|
DBSystem dbSystem,
|
||||||
QueryFilters filters,
|
QueryFilters filters,
|
||||||
|
JSONFactory jsonFactory,
|
||||||
Graphs graphs,
|
Graphs graphs,
|
||||||
Formatters formatters,
|
Formatters formatters,
|
||||||
ErrorLogger errorLogger
|
ErrorLogger errorLogger
|
||||||
@ -66,6 +69,7 @@ public class FiltersJSONResolver implements Resolver {
|
|||||||
this.serverInfo = serverInfo;
|
this.serverInfo = serverInfo;
|
||||||
this.dbSystem = dbSystem;
|
this.dbSystem = dbSystem;
|
||||||
this.filters = filters;
|
this.filters = filters;
|
||||||
|
this.jsonFactory = jsonFactory;
|
||||||
this.graphs = graphs;
|
this.graphs = graphs;
|
||||||
this.formatters = formatters;
|
this.formatters = formatters;
|
||||||
this.errorLogger = errorLogger;
|
this.errorLogger = errorLogger;
|
||||||
@ -85,9 +89,9 @@ public class FiltersJSONResolver implements Resolver {
|
|||||||
private Response getResponse() {
|
private Response getResponse() {
|
||||||
return Response.builder()
|
return Response.builder()
|
||||||
.setMimeType(MimeType.JSON)
|
.setMimeType(MimeType.JSON)
|
||||||
.setJSONContent(new FilterResponseJSON(
|
.setJSONContent(new FilterResponseDto(
|
||||||
filters.getFilters(),
|
filters.getFilters(),
|
||||||
new ViewJSON(formatters),
|
new ViewDto(formatters, jsonFactory.listServers().get("servers")),
|
||||||
fetchViewGraphPoints()
|
fetchViewGraphPoints()
|
||||||
)).build();
|
)).build();
|
||||||
}
|
}
|
||||||
@ -111,17 +115,17 @@ public class FiltersJSONResolver implements Resolver {
|
|||||||
/**
|
/**
|
||||||
* JSON serialization class.
|
* JSON serialization class.
|
||||||
*/
|
*/
|
||||||
class FilterResponseJSON {
|
class FilterResponseDto {
|
||||||
final List<FilterJSON> filters;
|
final List<FilterDto> filters;
|
||||||
final ViewJSON view;
|
final ViewDto view;
|
||||||
final List<Double[]> viewPoints;
|
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.viewPoints = viewPoints;
|
||||||
this.filters = new ArrayList<>();
|
this.filters = new ArrayList<>();
|
||||||
for (Map.Entry<String, Filter> entry : filtersByKind.entrySet()) {
|
for (Map.Entry<String, Filter> entry : filtersByKind.entrySet()) {
|
||||||
try {
|
try {
|
||||||
filters.add(new FilterJSON(entry.getKey(), entry.getValue()));
|
filters.add(new FilterDto(entry.getKey(), entry.getValue()));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
errorLogger.error(e, ErrorContext.builder()
|
errorLogger.error(e, ErrorContext.builder()
|
||||||
.whatToDo("Report this, filter '" + entry.getKey() + "' has implementation error.")
|
.whatToDo("Report this, filter '" + entry.getKey() + "' has implementation error.")
|
||||||
@ -133,63 +137,4 @@ public class FiltersJSONResolver implements Resolver {
|
|||||||
this.view = view;
|
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<Long> timeAmount;
|
||||||
private final Formatter<Double> percentage;
|
private final Formatter<Double> percentage;
|
||||||
private final Formatter<Double> byteSize;
|
private final Formatter<Double> byteSize;
|
||||||
|
private final Gson gson;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public NetworkPerformanceJSONResolver(
|
public NetworkPerformanceJSONResolver(
|
||||||
PlanConfig config,
|
PlanConfig config,
|
||||||
Locale locale,
|
Locale locale,
|
||||||
DBSystem dbSystem,
|
DBSystem dbSystem,
|
||||||
Formatters formatters
|
Formatters formatters,
|
||||||
|
Gson gson
|
||||||
) {
|
) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.locale = locale;
|
this.locale = locale;
|
||||||
@ -73,6 +75,7 @@ public class NetworkPerformanceJSONResolver implements Resolver {
|
|||||||
percentage = formatters.percentage();
|
percentage = formatters.percentage();
|
||||||
timeAmount = formatters.timeAmount();
|
timeAmount = formatters.timeAmount();
|
||||||
byteSize = formatters.byteSize();
|
byteSize = formatters.byteSize();
|
||||||
|
this.gson = gson;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -93,7 +96,7 @@ public class NetworkPerformanceJSONResolver implements Resolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private List<UUID> getUUIDList(String jsonString) {
|
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) {
|
public Map<String, Object> createJSONAsMap(Collection<ServerUUID> serverUUIDs) {
|
||||||
|
@ -17,6 +17,9 @@
|
|||||||
package com.djrapitops.plan.delivery.webserver.resolver.json;
|
package com.djrapitops.plan.delivery.webserver.resolver.json;
|
||||||
|
|
||||||
import com.djrapitops.plan.delivery.domain.DateMap;
|
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.Formatter;
|
||||||
import com.djrapitops.plan.delivery.formatting.Formatters;
|
import com.djrapitops.plan.delivery.formatting.Formatters;
|
||||||
import com.djrapitops.plan.delivery.rendering.json.PlayersTableJSONCreator;
|
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.exception.BadRequestException;
|
||||||
import com.djrapitops.plan.delivery.web.resolver.request.Request;
|
import com.djrapitops.plan.delivery.web.resolver.request.Request;
|
||||||
import com.djrapitops.plan.delivery.web.resolver.request.WebUser;
|
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.delivery.webserver.cache.JSONStorage;
|
||||||
import com.djrapitops.plan.extension.implementation.storage.queries.ExtensionQueryResultTableDataQuery;
|
import com.djrapitops.plan.extension.implementation.storage.queries.ExtensionQueryResultTableDataQuery;
|
||||||
import com.djrapitops.plan.identification.ServerInfo;
|
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.PlanConfig;
|
||||||
import com.djrapitops.plan.settings.config.paths.DisplaySettings;
|
import com.djrapitops.plan.settings.config.paths.DisplaySettings;
|
||||||
import com.djrapitops.plan.settings.config.paths.TimeSettings;
|
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.analysis.NetworkActivityIndexQueries;
|
||||||
import com.djrapitops.plan.storage.database.queries.filter.Filter;
|
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.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.GeoInfoQueries;
|
||||||
import com.djrapitops.plan.storage.database.queries.objects.SessionQueries;
|
import com.djrapitops.plan.storage.database.queries.objects.SessionQueries;
|
||||||
import com.djrapitops.plan.storage.database.queries.objects.playertable.QueryTablePlayersQuery;
|
import com.djrapitops.plan.storage.database.queries.objects.playertable.QueryTablePlayersQuery;
|
||||||
@ -52,7 +56,6 @@ import javax.inject.Singleton;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@ -67,6 +70,7 @@ public class QueryJSONResolver implements Resolver {
|
|||||||
private final GraphJSONCreator graphJSONCreator;
|
private final GraphJSONCreator graphJSONCreator;
|
||||||
private final Locale locale;
|
private final Locale locale;
|
||||||
private final Formatters formatters;
|
private final Formatters formatters;
|
||||||
|
private final Gson gson;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public QueryJSONResolver(
|
public QueryJSONResolver(
|
||||||
@ -76,7 +80,8 @@ public class QueryJSONResolver implements Resolver {
|
|||||||
ServerInfo serverInfo, JSONStorage jsonStorage,
|
ServerInfo serverInfo, JSONStorage jsonStorage,
|
||||||
GraphJSONCreator graphJSONCreator,
|
GraphJSONCreator graphJSONCreator,
|
||||||
Locale locale,
|
Locale locale,
|
||||||
Formatters formatters
|
Formatters formatters,
|
||||||
|
Gson gson
|
||||||
) {
|
) {
|
||||||
this.filters = filters;
|
this.filters = filters;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
@ -86,6 +91,7 @@ public class QueryJSONResolver implements Resolver {
|
|||||||
this.graphJSONCreator = graphJSONCreator;
|
this.graphJSONCreator = graphJSONCreator;
|
||||||
this.locale = locale;
|
this.locale = locale;
|
||||||
this.formatters = formatters;
|
this.formatters = formatters;
|
||||||
|
this.gson = gson;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -103,17 +109,33 @@ public class QueryJSONResolver implements Resolver {
|
|||||||
Optional<Response> cachedResult = checkForCachedResult(request);
|
Optional<Response> cachedResult = checkForCachedResult(request);
|
||||||
if (cachedResult.isPresent()) return cachedResult.get();
|
if (cachedResult.isPresent()) return cachedResult.get();
|
||||||
|
|
||||||
String q = request.getQuery().get("q").orElseThrow(() -> new BadRequestException("'q' parameter not set (expecting json array)"));
|
InputQueryDto inputQuery = parseInputQuery(request);
|
||||||
String view = request.getQuery().get("view").orElseThrow(() -> new BadRequestException("'view' parameter not set (expecting json object {afterDate, afterTime, beforeDate, beforeTime})"));
|
List<InputFilterDto> queries = inputQuery.getFilters();
|
||||||
|
|
||||||
|
Filter.Result result = filters.apply(queries);
|
||||||
|
List<Filter.ResultPath> resultPath = result.getInverseResultPath();
|
||||||
|
Collections.reverse(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 {
|
try {
|
||||||
String query = URLDecoder.decode(q, "UTF-8");
|
String query = URLDecoder.decode(q, "UTF-8");
|
||||||
List<SpecifiedFilterInformation> queries = SpecifiedFilterInformation.parse(query);
|
List<InputFilterDto> queryFilters = InputFilterDto.parse(query, gson);
|
||||||
Filter.Result result = filters.apply(queries);
|
ViewDto view = request.getQuery().get("view")
|
||||||
List<Filter.ResultPath> resultPath = result.getInverseResultPath();
|
.map(viewJson -> gson.fromJson(viewJson, ViewDto.class))
|
||||||
Collections.reverse(resultPath);
|
.orElseThrow(() -> new BadRequestException("'view' parameter not set (expecting json object {afterDate, afterTime, beforeDate, beforeTime})"));
|
||||||
|
return new InputQueryDto(view, queryFilters);
|
||||||
return buildAndStoreResponse(view, result, resultPath);
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new BadRequestException("Failed to decode json: '" + q + "', " + e.getMessage());
|
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 {
|
try {
|
||||||
long timestamp = System.currentTimeMillis();
|
long timestamp = System.currentTimeMillis();
|
||||||
Map<String, Object> json = Maps.builder(String.class, Object.class)
|
Map<String, Object> json = Maps.builder(String.class, Object.class)
|
||||||
.put("path", resultPath)
|
.put("path", resultPath)
|
||||||
.put("view", new Gson().fromJson(view, FiltersJSONResolver.ViewJSON.class))
|
.put("view", view)
|
||||||
.put("timestamp", timestamp)
|
.put("timestamp", timestamp)
|
||||||
.build();
|
.build();
|
||||||
if (!result.isEmpty()) {
|
if (!result.isEmpty()) {
|
||||||
@ -155,23 +177,22 @@ public class QueryJSONResolver implements Resolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, Object> getDataFor(Set<UUID> playerUUIDs, String view) throws ParseException {
|
private Map<String, Object> getDataFor(Set<UUID> playerUUIDs, ViewDto view) throws ParseException {
|
||||||
FiltersJSONResolver.ViewJSON viewJSON = new Gson().fromJson(view, FiltersJSONResolver.ViewJSON.class);
|
long after = view.getAfterEpochMs();
|
||||||
SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy kk:mm");
|
long before = view.getBeforeEpochMs();
|
||||||
long after = dateFormat.parse(viewJSON.afterDate + " " + viewJSON.afterTime).getTime();
|
List<ServerUUID> serverUUIDs = view.getServerUUIDs();
|
||||||
long before = dateFormat.parse(viewJSON.beforeDate + " " + viewJSON.beforeTime).getTime();
|
|
||||||
|
|
||||||
return Maps.builder(String.class, Object.class)
|
return Maps.builder(String.class, Object.class)
|
||||||
.put("players", getPlayersTableData(playerUUIDs, after, before))
|
.put("players", getPlayersTableData(playerUUIDs, serverUUIDs, after, before))
|
||||||
.put("activity", getActivityGraphData(playerUUIDs, after, before))
|
.put("activity", getActivityGraphData(playerUUIDs, serverUUIDs, after, before))
|
||||||
.put("geolocation", getGeolocationData(playerUUIDs))
|
.put("geolocation", getGeolocationData(playerUUIDs))
|
||||||
.put("sessions", getSessionSummaryData(playerUUIDs, after, before))
|
.put("sessions", getSessionSummaryData(playerUUIDs, serverUUIDs, after, before))
|
||||||
.build();
|
.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();
|
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<>();
|
Map<String, String> formattedSummary = new HashMap<>();
|
||||||
Formatter<Long> timeAmount = formatters.timeAmount();
|
Formatter<Long> timeAmount = formatters.timeAmount();
|
||||||
for (Map.Entry<String, Long> entry : summary.entrySet()) {
|
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();
|
Database database = dbSystem.getDatabase();
|
||||||
Long threshold = config.get(TimeSettings.ACTIVE_PLAY_THRESHOLD);
|
Long threshold = config.get(TimeSettings.ACTIVE_PLAY_THRESHOLD);
|
||||||
|
|
||||||
@ -198,16 +219,16 @@ public class QueryJSONResolver implements Resolver {
|
|||||||
|
|
||||||
DateMap<Map<String, Integer>> activityData = new DateMap<>();
|
DateMap<Map<String, Integer>> activityData = new DateMap<>();
|
||||||
for (long time = before; time >= stopDate; time -= TimeAmount.WEEK.toMillis(1L)) {
|
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);
|
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();
|
Database database = dbSystem.getDatabase();
|
||||||
return new PlayersTableJSONCreator(
|
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)),
|
database.query(new ExtensionQueryResultTableDataQuery(serverInfo.getServerUUID(), playerUUIDs)),
|
||||||
config.get(DisplaySettings.OPEN_PLAYER_LINKS_IN_NEW_TAB),
|
config.get(DisplaySettings.OPEN_PLAYER_LINKS_IN_NEW_TAB),
|
||||||
formatters, locale
|
formatters, locale
|
||||||
|
@ -57,4 +57,8 @@ public interface FiltersModule {
|
|||||||
@IntoSet
|
@IntoSet
|
||||||
Filter filter8(PluginBooleanGroupFilter filter);
|
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.storage.file.JarResource;
|
||||||
import com.djrapitops.plan.utilities.logging.ErrorLogger;
|
import com.djrapitops.plan.utilities.logging.ErrorLogger;
|
||||||
import com.djrapitops.plan.utilities.logging.PluginErrorLogger;
|
import com.djrapitops.plan.utilities.logging.PluginErrorLogger;
|
||||||
|
import com.google.gson.Gson;
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
import dagger.multibindings.ElementsIntoSet;
|
import dagger.multibindings.ElementsIntoSet;
|
||||||
@ -49,6 +50,12 @@ import java.util.function.Predicate;
|
|||||||
@Module
|
@Module
|
||||||
public class SystemObjectProvidingModule {
|
public class SystemObjectProvidingModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
Gson provideGson() {
|
||||||
|
return new Gson();
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@ElementsIntoSet
|
@ElementsIntoSet
|
||||||
Set<Importer> emptyImporterSet() {
|
Set<Importer> emptyImporterSet() {
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package com.djrapitops.plan.storage.database.queries.analysis;
|
package com.djrapitops.plan.storage.database.queries.analysis;
|
||||||
|
|
||||||
import com.djrapitops.plan.delivery.domain.mutators.ActivityIndex;
|
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.Query;
|
||||||
import com.djrapitops.plan.storage.database.queries.QueryStatement;
|
import com.djrapitops.plan.storage.database.queries.QueryStatement;
|
||||||
import com.djrapitops.plan.storage.database.sql.tables.SessionsTable;
|
import com.djrapitops.plan.storage.database.sql.tables.SessionsTable;
|
||||||
@ -74,6 +75,10 @@ public class NetworkActivityIndexQueries {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String selectActivityIndexSQL() {
|
public static String selectActivityIndexSQL() {
|
||||||
|
return selectActivityIndexSQL(Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String selectActivityIndexSQL(Collection<ServerUUID> onServers) {
|
||||||
String selectActivePlaytimeSQL = SELECT +
|
String selectActivePlaytimeSQL = SELECT +
|
||||||
"ux." + UsersTable.USER_UUID + ",COALESCE(active_playtime,0) AS active_playtime" +
|
"ux." + UsersTable.USER_UUID + ",COALESCE(active_playtime,0) AS active_playtime" +
|
||||||
FROM + UsersTable.TABLE_NAME + " ux" +
|
FROM + UsersTable.TABLE_NAME + " ux" +
|
||||||
@ -82,6 +87,7 @@ public class NetworkActivityIndexQueries {
|
|||||||
FROM + SessionsTable.TABLE_NAME +
|
FROM + SessionsTable.TABLE_NAME +
|
||||||
WHERE + SessionsTable.SESSION_END + ">=?" +
|
WHERE + SessionsTable.SESSION_END + ">=?" +
|
||||||
AND + SessionsTable.SESSION_START + "<=?" +
|
AND + SessionsTable.SESSION_START + "<=?" +
|
||||||
|
(onServers.isEmpty() ? "" : AND + SessionsTable.SERVER_UUID + " IN ('" + new TextStringBuilder().appendWithSeparators(onServers, "','") + "')") +
|
||||||
GROUP_BY + SessionsTable.USER_UUID +
|
GROUP_BY + SessionsTable.USER_UUID +
|
||||||
") sx on sx.uuid=ux.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) {
|
public static Query<Map<String, Integer>> fetchActivityIndexGroupingsOn(long date, long threshold, Collection<UUID> playerUUIDs, List<ServerUUID> serverUUIDs) {
|
||||||
String selectActivityIndex = selectActivityIndexSQL();
|
String selectActivityIndex = selectActivityIndexSQL(serverUUIDs);
|
||||||
|
|
||||||
String selectIndexes = SELECT + "activity_index" +
|
String selectIndexes = SELECT + "activity_index" +
|
||||||
FROM + UsersTable.TABLE_NAME + " u" +
|
FROM + UsersTable.TABLE_NAME + " u" +
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.djrapitops.plan.storage.database.queries.filter;
|
package com.djrapitops.plan.storage.database.queries.filter;
|
||||||
|
|
||||||
|
import com.djrapitops.plan.delivery.domain.datatransfer.InputFilterDto;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,9 +42,9 @@ public interface Filter {
|
|||||||
* @return Set of UUIDs this filter applies to
|
* @return Set of UUIDs this filter applies to
|
||||||
* @throws IllegalArgumentException If the arguments are not valid.
|
* @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 {
|
try {
|
||||||
return new Result(null, getKind(), getMatchingUUIDs(query));
|
return new Result(null, getKind(), getMatchingUUIDs(query));
|
||||||
} catch (CompleteSetException allMatch) {
|
} catch (CompleteSetException allMatch) {
|
||||||
@ -64,7 +66,7 @@ public interface Filter {
|
|||||||
this.currentUUIDs = currentUUIDs;
|
this.currentUUIDs = currentUUIDs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result apply(Filter filter, SpecifiedFilterInformation query) {
|
public Result apply(Filter filter, InputFilterDto query) {
|
||||||
try {
|
try {
|
||||||
Set<UUID> got = filter.getMatchingUUIDs(query);
|
Set<UUID> got = filter.getMatchingUUIDs(query);
|
||||||
currentUUIDs.retainAll(got);
|
currentUUIDs.retainAll(got);
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.djrapitops.plan.storage.database.queries.filter;
|
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.delivery.web.resolver.exception.BadRequestException;
|
||||||
import com.djrapitops.plan.storage.database.DBSystem;
|
import com.djrapitops.plan.storage.database.DBSystem;
|
||||||
import com.djrapitops.plan.storage.database.queries.filter.filters.AllPlayersFilter;
|
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.
|
* @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.
|
* @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();
|
prepareFilters();
|
||||||
Filter.Result current = null;
|
Filter.Result current = null;
|
||||||
if (filterQueries.isEmpty()) return allPlayersFilter.apply(null);
|
if (filterQueries.isEmpty()) return allPlayersFilter.apply(null);
|
||||||
for (SpecifiedFilterInformation specifiedFilterInformation : filterQueries) {
|
for (InputFilterDto inputFilterDto : filterQueries) {
|
||||||
current = apply(current, specifiedFilterInformation);
|
current = apply(current, inputFilterDto);
|
||||||
if (current != null && current.isEmpty()) break;
|
if (current != null && current.isEmpty()) break;
|
||||||
}
|
}
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Filter.Result apply(Filter.Result current, SpecifiedFilterInformation specifiedFilterInformation) {
|
private Filter.Result apply(Filter.Result current, InputFilterDto inputFilterDto) {
|
||||||
String kind = specifiedFilterInformation.getKind();
|
String kind = inputFilterDto.getKind();
|
||||||
Filter filter = getFilter(kind).orElseThrow(() -> new BadRequestException("Filter kind not supported: '" + kind + "'"));
|
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 {
|
try {
|
||||||
return current == null ? filter.apply(query) : current.apply(filter, query);
|
return current == null ? filter.apply(query) : current.apply(filter, query);
|
||||||
} catch (IllegalArgumentException badOptions) {
|
} catch (IllegalArgumentException badOptions) {
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.djrapitops.plan.storage.database.queries.filter.filters;
|
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.delivery.domain.mutators.ActivityIndex;
|
||||||
import com.djrapitops.plan.settings.config.PlanConfig;
|
import com.djrapitops.plan.settings.config.PlanConfig;
|
||||||
import com.djrapitops.plan.settings.config.paths.TimeSettings;
|
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.DBSystem;
|
||||||
import com.djrapitops.plan.storage.database.queries.analysis.NetworkActivityIndexQueries;
|
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.CompleteSetException;
|
||||||
import com.djrapitops.plan.storage.database.queries.filter.SpecifiedFilterInformation;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
@ -63,7 +63,7 @@ public class ActivityIndexFilter extends MultiOptionFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<UUID> getMatchingUUIDs(SpecifiedFilterInformation query) {
|
public Set<UUID> getMatchingUUIDs(InputFilterDto query) {
|
||||||
List<String> selected = getSelected(query);
|
List<String> selected = getSelected(query);
|
||||||
String[] options = getOptionsArray();
|
String[] options = getOptionsArray();
|
||||||
|
|
||||||
|
@ -16,9 +16,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.djrapitops.plan.storage.database.queries.filter.filters;
|
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.DBSystem;
|
||||||
import com.djrapitops.plan.storage.database.queries.filter.Filter;
|
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 com.djrapitops.plan.storage.database.queries.objects.UserIdentifierQueries;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@ -52,7 +52,7 @@ public class AllPlayersFilter implements Filter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<UUID> getMatchingUUIDs(SpecifiedFilterInformation query) {
|
public Set<UUID> getMatchingUUIDs(InputFilterDto query) {
|
||||||
return dbSystem.getDatabase().query(UserIdentifierQueries.fetchAllPlayerUUIDs());
|
return dbSystem.getDatabase().query(UserIdentifierQueries.fetchAllPlayerUUIDs());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,11 +16,11 @@
|
|||||||
*/
|
*/
|
||||||
package com.djrapitops.plan.storage.database.queries.filter.filters;
|
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.Locale;
|
||||||
import com.djrapitops.plan.settings.locale.lang.FilterLang;
|
import com.djrapitops.plan.settings.locale.lang.FilterLang;
|
||||||
import com.djrapitops.plan.storage.database.DBSystem;
|
import com.djrapitops.plan.storage.database.DBSystem;
|
||||||
import com.djrapitops.plan.storage.database.queries.filter.CompleteSetException;
|
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 com.djrapitops.plan.storage.database.queries.objects.UserInfoQueries;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@ -57,7 +57,7 @@ public class BannedFilter extends MultiOptionFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<UUID> getMatchingUUIDs(SpecifiedFilterInformation query) {
|
public Set<UUID> getMatchingUUIDs(InputFilterDto query) {
|
||||||
List<String> selected = getSelected(query);
|
List<String> selected = getSelected(query);
|
||||||
Set<UUID> uuids = new HashSet<>();
|
Set<UUID> uuids = new HashSet<>();
|
||||||
String[] options = getOptionsArray();
|
String[] options = getOptionsArray();
|
||||||
|
@ -16,10 +16,10 @@
|
|||||||
*/
|
*/
|
||||||
package com.djrapitops.plan.storage.database.queries.filter.filters;
|
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.delivery.web.resolver.exception.BadRequestException;
|
||||||
import com.djrapitops.plan.storage.database.DBSystem;
|
import com.djrapitops.plan.storage.database.DBSystem;
|
||||||
import com.djrapitops.plan.storage.database.queries.filter.Filter;
|
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.storage.database.queries.objects.BaseUserQueries;
|
||||||
import com.djrapitops.plan.utilities.java.Maps;
|
import com.djrapitops.plan.utilities.java.Maps;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
@ -61,15 +61,15 @@ public abstract class DateRangeFilter implements Filter {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected long getAfter(SpecifiedFilterInformation query) {
|
protected long getAfter(InputFilterDto query) {
|
||||||
return getTime(query, "afterDate", "afterTime");
|
return getTime(query, "afterDate", "afterTime");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected long getBefore(SpecifiedFilterInformation query) {
|
protected long getBefore(InputFilterDto query) {
|
||||||
return getTime(query, "beforeDate", "beforeTime");
|
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 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()));
|
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;
|
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.DBSystem;
|
||||||
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.GeoInfoQueries;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@ -47,7 +47,7 @@ public class GeolocationsFilter extends MultiOptionFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<UUID> getMatchingUUIDs(SpecifiedFilterInformation query) {
|
public Set<UUID> getMatchingUUIDs(InputFilterDto query) {
|
||||||
return dbSystem.getDatabase().query(GeoInfoQueries.uuidsOfPlayersWithGeolocations(getSelected(query)));
|
return dbSystem.getDatabase().query(GeoInfoQueries.uuidsOfPlayersWithGeolocations(getSelected(query)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.djrapitops.plan.storage.database.queries.filter.filters;
|
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.DBSystem;
|
||||||
import com.djrapitops.plan.storage.database.queries.filter.SpecifiedFilterInformation;
|
|
||||||
import com.djrapitops.plan.storage.database.queries.objects.UserInfoQueries;
|
import com.djrapitops.plan.storage.database.queries.objects.UserInfoQueries;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@ -47,7 +47,7 @@ public class JoinAddressFilter extends MultiOptionFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<UUID> getMatchingUUIDs(SpecifiedFilterInformation query) {
|
public Set<UUID> getMatchingUUIDs(InputFilterDto query) {
|
||||||
return dbSystem.getDatabase().query(UserInfoQueries.uuidsOfPlayersWithJoinAddresses(getSelected(query)));
|
return dbSystem.getDatabase().query(UserInfoQueries.uuidsOfPlayersWithJoinAddresses(getSelected(query)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.djrapitops.plan.storage.database.queries.filter.filters;
|
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.CompleteSetException;
|
||||||
import com.djrapitops.plan.storage.database.queries.filter.Filter;
|
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.Gson;
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ public abstract class MultiOptionFilter implements Filter {
|
|||||||
return new String[]{"selected"};
|
return new String[]{"selected"};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<String> getSelected(SpecifiedFilterInformation query) {
|
protected List<String> getSelected(InputFilterDto query) {
|
||||||
String selectedJSON = query.get("selected").orElseThrow(IllegalArgumentException::new);
|
String selectedJSON = query.get("selected").orElseThrow(IllegalArgumentException::new);
|
||||||
List<String> selected = new Gson().fromJson(selectedJSON, new TypeToken<List<String>>() {}.getType());
|
List<String> selected = new Gson().fromJson(selectedJSON, new TypeToken<List<String>>() {}.getType());
|
||||||
if (selected.isEmpty()) throw new CompleteSetException();
|
if (selected.isEmpty()) throw new CompleteSetException();
|
||||||
|
@ -16,11 +16,11 @@
|
|||||||
*/
|
*/
|
||||||
package com.djrapitops.plan.storage.database.queries.filter.filters;
|
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.Locale;
|
||||||
import com.djrapitops.plan.settings.locale.lang.FilterLang;
|
import com.djrapitops.plan.settings.locale.lang.FilterLang;
|
||||||
import com.djrapitops.plan.storage.database.DBSystem;
|
import com.djrapitops.plan.storage.database.DBSystem;
|
||||||
import com.djrapitops.plan.storage.database.queries.filter.CompleteSetException;
|
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 com.djrapitops.plan.storage.database.queries.objects.UserInfoQueries;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@ -57,7 +57,7 @@ public class OperatorsFilter extends MultiOptionFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<UUID> getMatchingUUIDs(SpecifiedFilterInformation query) {
|
public Set<UUID> getMatchingUUIDs(InputFilterDto query) {
|
||||||
List<String> selected = getSelected(query);
|
List<String> selected = getSelected(query);
|
||||||
Set<UUID> uuids = new HashSet<>();
|
Set<UUID> uuids = new HashSet<>();
|
||||||
String[] options = getOptionsArray();
|
String[] options = getOptionsArray();
|
||||||
|
@ -16,14 +16,16 @@
|
|||||||
*/
|
*/
|
||||||
package com.djrapitops.plan.storage.database.queries.filter.filters;
|
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.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.djrapitops.plan.storage.database.queries.objects.SessionQueries;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
import java.util.Set;
|
import java.util.*;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class PlayedBetweenDateRangeFilter extends DateRangeFilter {
|
public class PlayedBetweenDateRangeFilter extends DateRangeFilter {
|
||||||
@ -42,9 +44,18 @@ public class PlayedBetweenDateRangeFilter extends DateRangeFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<UUID> getMatchingUUIDs(SpecifiedFilterInformation query) {
|
public Set<UUID> getMatchingUUIDs(InputFilterDto query) {
|
||||||
long after = getAfter(query);
|
long after = getAfter(query);
|
||||||
long before = getBefore(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;
|
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.Server;
|
||||||
import com.djrapitops.plan.identification.ServerUUID;
|
import com.djrapitops.plan.identification.ServerUUID;
|
||||||
import com.djrapitops.plan.storage.database.DBSystem;
|
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.Query;
|
||||||
import com.djrapitops.plan.storage.database.queries.QueryAllStatement;
|
import com.djrapitops.plan.storage.database.queries.QueryAllStatement;
|
||||||
import com.djrapitops.plan.storage.database.queries.QueryStatement;
|
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.queries.objects.ServerQueries;
|
||||||
import com.djrapitops.plan.storage.database.sql.tables.ExtensionPlayerValueTable;
|
import com.djrapitops.plan.storage.database.sql.tables.ExtensionPlayerValueTable;
|
||||||
import com.djrapitops.plan.storage.database.sql.tables.ExtensionPluginTable;
|
import com.djrapitops.plan.storage.database.sql.tables.ExtensionPluginTable;
|
||||||
@ -164,7 +164,7 @@ public class PluginBooleanGroupFilter extends MultiOptionFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<UUID> getMatchingUUIDs(SpecifiedFilterInformation query) {
|
public Set<UUID> getMatchingUUIDs(InputFilterDto query) {
|
||||||
Map<PluginBooleanOption, SelectedBoolean> selectedBooleanOptions = new HashMap<>();
|
Map<PluginBooleanOption, SelectedBoolean> selectedBooleanOptions = new HashMap<>();
|
||||||
for (String selected : getSelected(query)) {
|
for (String selected : getSelected(query)) {
|
||||||
String[] optionAndBoolean = StringUtils.split(selected, ":", 2);
|
String[] optionAndBoolean = StringUtils.split(selected, ":", 2);
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.djrapitops.plan.storage.database.queries.filter.filters;
|
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.providers.ProviderIdentifier;
|
||||||
import com.djrapitops.plan.extension.implementation.storage.queries.ExtensionUUIDsInGroupQuery;
|
import com.djrapitops.plan.extension.implementation.storage.queries.ExtensionUUIDsInGroupQuery;
|
||||||
import com.djrapitops.plan.identification.Server;
|
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.identification.ServerUUID;
|
||||||
import com.djrapitops.plan.storage.database.DBSystem;
|
import com.djrapitops.plan.storage.database.DBSystem;
|
||||||
import com.djrapitops.plan.storage.database.queries.QueryAllStatement;
|
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.ExtensionGroupsTable;
|
||||||
import com.djrapitops.plan.storage.database.sql.tables.ExtensionPluginTable;
|
import com.djrapitops.plan.storage.database.sql.tables.ExtensionPluginTable;
|
||||||
import com.djrapitops.plan.storage.database.sql.tables.ExtensionProviderTable;
|
import com.djrapitops.plan.storage.database.sql.tables.ExtensionProviderTable;
|
||||||
@ -67,7 +67,7 @@ public class PluginGroupsFilter extends MultiOptionFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<UUID> getMatchingUUIDs(SpecifiedFilterInformation query) {
|
public Set<UUID> getMatchingUUIDs(InputFilterDto query) {
|
||||||
return dbSystem.getDatabase().query(
|
return dbSystem.getDatabase().query(
|
||||||
new ExtensionUUIDsInGroupQuery(identifier.getPluginName(), identifier.getProviderName(), identifier.getServerUUID(), getSelected(query))
|
new ExtensionUUIDsInGroupQuery(identifier.getPluginName(), identifier.getProviderName(), identifier.getServerUUID(), getSelected(query))
|
||||||
);
|
);
|
||||||
|
@ -16,14 +16,17 @@
|
|||||||
*/
|
*/
|
||||||
package com.djrapitops.plan.storage.database.queries.filter.filters;
|
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.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.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.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
import java.util.Set;
|
import java.util.*;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class RegisteredBetweenDateRangeFilter extends DateRangeFilter {
|
public class RegisteredBetweenDateRangeFilter extends DateRangeFilter {
|
||||||
@ -42,9 +45,21 @@ public class RegisteredBetweenDateRangeFilter extends DateRangeFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<UUID> getMatchingUUIDs(SpecifiedFilterInformation query) {
|
public Set<UUID> getMatchingUUIDs(InputFilterDto query) {
|
||||||
long after = getAfter(query);
|
long after = getAfter(query);
|
||||||
long before = getBefore(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.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static com.djrapitops.plan.storage.database.sql.building.Sql.*;
|
import static com.djrapitops.plan.storage.database.sql.building.Sql.*;
|
||||||
|
|
||||||
@ -172,9 +173,27 @@ 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() {
|
public static Query<Map<ServerUUID, String>> fetchServerNames() {
|
||||||
String sql = Select.from(ServerTable.TABLE_NAME,
|
String sql = Select.from(ServerTable.TABLE_NAME,
|
||||||
ServerTable.SERVER_ID, ServerTable.SERVER_UUID, ServerTable.NAME)
|
ServerTable.SERVER_ID, ServerTable.SERVER_UUID, ServerTable.NAME)
|
||||||
.toString();
|
.toString();
|
||||||
|
|
||||||
return new QueryAllStatement<Map<ServerUUID, String>>(sql) {
|
return new QueryAllStatement<Map<ServerUUID, String>>(sql) {
|
||||||
@ -263,4 +282,14 @@ public class ServerQueries {
|
|||||||
public static Query<Map<String, ServerUUID>> fetchServerNamesToUUIDs() {
|
public static Query<Map<String, ServerUUID>> fetchServerNamesToUUIDs() {
|
||||||
return db -> Maps.reverse(db.query(fetchServerNames()));
|
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 +
|
String sql = SELECT + DISTINCT + SessionsTable.USER_UUID +
|
||||||
FROM + SessionsTable.TABLE_NAME +
|
FROM + SessionsTable.TABLE_NAME +
|
||||||
WHERE + SessionsTable.SESSION_END + ">=?" +
|
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) {
|
return new QueryStatement<Set<UUID>>(sql) {
|
||||||
@Override
|
@Override
|
||||||
public void prepare(PreparedStatement statement) throws SQLException {
|
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 +
|
String selectAggregates = SELECT +
|
||||||
"SUM(" + SessionsTable.SESSION_END + '-' + SessionsTable.SESSION_START + ") as playtime," +
|
"SUM(" + SessionsTable.SESSION_END + '-' + SessionsTable.SESSION_START + ") as playtime," +
|
||||||
"SUM(" + SessionsTable.SESSION_END + '-' + SessionsTable.SESSION_START + '-' + SessionsTable.AFK_TIME + ") as active_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 + ">?" +
|
WHERE + SessionsTable.SESSION_START + ">?" +
|
||||||
AND + SessionsTable.SESSION_END + "<?" +
|
AND + SessionsTable.SESSION_END + "<?" +
|
||||||
AND + SessionsTable.USER_UUID + " IN ('" +
|
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) {
|
return new QueryStatement<Map<String, Long>>(selectAggregates) {
|
||||||
@Override
|
@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.QueryAllStatement;
|
||||||
import com.djrapitops.plan.storage.database.queries.QueryStatement;
|
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.UserInfoTable;
|
||||||
|
import com.djrapitops.plan.storage.database.sql.tables.UsersTable;
|
||||||
import com.djrapitops.plan.utilities.java.Lists;
|
import com.djrapitops.plan.utilities.java.Lists;
|
||||||
import org.apache.commons.text.TextStringBuilder;
|
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.TablePlayer;
|
||||||
import com.djrapitops.plan.delivery.domain.mutators.ActivityIndex;
|
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.SQLDB;
|
||||||
import com.djrapitops.plan.storage.database.queries.Query;
|
import com.djrapitops.plan.storage.database.queries.Query;
|
||||||
import com.djrapitops.plan.storage.database.queries.QueryStatement;
|
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>> {
|
public class QueryTablePlayersQuery implements Query<List<TablePlayer>> {
|
||||||
|
|
||||||
private final Collection<UUID> playerUUIDs;
|
private final Collection<UUID> playerUUIDs;
|
||||||
|
private final List<ServerUUID> serverUUIDs;
|
||||||
private final long afterDate;
|
private final long afterDate;
|
||||||
private final long beforeDate;
|
private final long beforeDate;
|
||||||
private final long activeMsThreshold;
|
private final long activeMsThreshold;
|
||||||
@ -54,12 +56,14 @@ public class QueryTablePlayersQuery implements Query<List<TablePlayer>> {
|
|||||||
* Create a new query.
|
* Create a new query.
|
||||||
*
|
*
|
||||||
* @param playerUUIDs UUIDs of the players in the 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 afterDate View data after this epoch ms
|
||||||
|
* @param beforeDate View data before this epoch ms
|
||||||
* @param activeMsThreshold Playtime threshold for Activity Index calculation
|
* @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.playerUUIDs = playerUUIDs;
|
||||||
|
this.serverUUIDs = serverUUIDs;
|
||||||
this.afterDate = afterDate;
|
this.afterDate = afterDate;
|
||||||
this.beforeDate = beforeDate;
|
this.beforeDate = beforeDate;
|
||||||
this.activeMsThreshold = activeMsThreshold;
|
this.activeMsThreshold = activeMsThreshold;
|
||||||
@ -95,12 +99,14 @@ public class QueryTablePlayersQuery implements Query<List<TablePlayer>> {
|
|||||||
AND + "s." + SessionsTable.SESSION_END + "<=?" +
|
AND + "s." + SessionsTable.SESSION_END + "<=?" +
|
||||||
AND + "s." + SessionsTable.USER_UUID +
|
AND + "s." + SessionsTable.USER_UUID +
|
||||||
uuidsInSet +
|
uuidsInSet +
|
||||||
|
(serverUUIDs.isEmpty() ? "" : AND + "s." + SessionsTable.SERVER_UUID + " IN ('" + new TextStringBuilder().appendWithSeparators(serverUUIDs, "','") + "')") +
|
||||||
GROUP_BY + "s." + SessionsTable.USER_UUID;
|
GROUP_BY + "s." + SessionsTable.USER_UUID;
|
||||||
|
|
||||||
String selectBanned = SELECT + DISTINCT + "ub." + UserInfoTable.USER_UUID +
|
String selectBanned = SELECT + DISTINCT + "ub." + UserInfoTable.USER_UUID +
|
||||||
FROM + UserInfoTable.TABLE_NAME + " ub" +
|
FROM + UserInfoTable.TABLE_NAME + " ub" +
|
||||||
WHERE + UserInfoTable.BANNED + "=?" +
|
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 +
|
String selectBaseUsers = SELECT +
|
||||||
"u." + UsersTable.USER_UUID + ',' +
|
"u." + UsersTable.USER_UUID + ',' +
|
||||||
|
@ -869,6 +869,30 @@ div#navSrvContainer::-webkit-scrollbar-thumb {
|
|||||||
color: #fff;
|
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 {
|
.bg-night, body.theme-night .fc-toolbar-chunk .btn.btn-primary {
|
||||||
background-color: #44475a;
|
background-color: #44475a;
|
||||||
color: #eee8d5;
|
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) {
|
function createFilter(filter, id) {
|
||||||
if (filter.kind.startsWith("pluginGroups-")) {
|
if (filter.kind.startsWith("pluginGroups-")) {
|
||||||
return new PluginGroupsFilter(id, filter.kind, filter.options);
|
return new PluginGroupsFilter(id, filter.kind, filter.options);
|
||||||
@ -230,6 +236,8 @@ function createFilter(filter, id) {
|
|||||||
return new RegisteredBetweenFilter(id, filter.options);
|
return new RegisteredBetweenFilter(id, filter.options);
|
||||||
case "pluginsBooleanGroups":
|
case "pluginsBooleanGroups":
|
||||||
return new PluginBooleanGroupsFilter(id, filter.options);
|
return new PluginBooleanGroupsFilter(id, filter.options);
|
||||||
|
case "playedOnServer":
|
||||||
|
return new PlayedOnServerFilter(id, filter.options);
|
||||||
default:
|
default:
|
||||||
throw new Error("Unsupported filter kind: '" + filter.kind + "'");
|
throw new Error("Unsupported filter kind: '" + filter.kind + "'");
|
||||||
}
|
}
|
||||||
@ -258,6 +266,8 @@ function getReadableFilterName(filter) {
|
|||||||
return "Registered between";
|
return "Registered between";
|
||||||
case "pluginsBooleanGroups":
|
case "pluginsBooleanGroups":
|
||||||
return "Has plugin boolean value";
|
return "Has plugin boolean value";
|
||||||
|
case "playedOnServer":
|
||||||
|
return "Has played on one of servers";
|
||||||
default:
|
default:
|
||||||
return filter.kind;
|
return filter.kind;
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,8 @@ const queryState = {
|
|||||||
afterDate: null,
|
afterDate: null,
|
||||||
afterTime: null,
|
afterTime: null,
|
||||||
beforeDate: null,
|
beforeDate: null,
|
||||||
beforeTime: null
|
beforeTime: null,
|
||||||
|
servers: []
|
||||||
},
|
},
|
||||||
invalidFormFields: {
|
invalidFormFields: {
|
||||||
ids: [],
|
ids: [],
|
||||||
@ -34,6 +35,8 @@ const queryState = {
|
|||||||
|
|
||||||
let timestamp = undefined;
|
let timestamp = undefined;
|
||||||
|
|
||||||
|
let serverMap = {};
|
||||||
|
|
||||||
function loadView(json) {
|
function loadView(json) {
|
||||||
queryState.view = json.view;
|
queryState.view = json.view;
|
||||||
|
|
||||||
@ -42,11 +45,36 @@ function loadView(json) {
|
|||||||
document.getElementById('viewToDateField').setAttribute('placeholder', json.view.beforeDate);
|
document.getElementById('viewToDateField').setAttribute('placeholder', json.view.beforeDate);
|
||||||
document.getElementById('viewToTimeField').setAttribute('placeholder', json.view.beforeTime);
|
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 = {
|
const playersOnlineSeries = {
|
||||||
name: 'Players Online', type: 'areaspline', tooltip: {valueDecimals: 0},
|
name: 'Players Online', type: 'areaspline', tooltip: {valueDecimals: 0},
|
||||||
data: json.viewPoints, color: '#9E9E9E', yAxis: 0
|
data: json.viewPoints, color: '#9E9E9E', yAxis: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
graphs.push(Highcharts.stockChart('viewChart', {
|
graphs.push(Highcharts.stockChart('viewChart', {
|
||||||
rangeSelector: {
|
rangeSelector: {
|
||||||
selected: 3,
|
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">
|
<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
|
<h6 class="m-0 fw-bold col-black" title=" ${afterDate} ${afterTime} - ${beforeDate} ${beforeTime}"><i
|
||||||
class="fas fa-fw fa-users col-black"></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>
|
</div>
|
||||||
<table class="table table-bordered table-striped table-hover player-table" style="width: 100%">
|
<table class="table table-bordered table-striped table-hover player-table" style="width: 100%">
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -141,6 +141,21 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="chart-area" id="viewChart"><span class="loader"></span></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>
|
<hr>
|
||||||
|
|
||||||
<div id="filters"></div>
|
<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.settings.locale.LocaleSystem;
|
||||||
import com.djrapitops.plan.storage.file.JarResource;
|
import com.djrapitops.plan.storage.file.JarResource;
|
||||||
import com.djrapitops.plan.utilities.logging.ErrorLogger;
|
import com.djrapitops.plan.utilities.logging.ErrorLogger;
|
||||||
|
import com.google.gson.Gson;
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
import utilities.TestErrorLogger;
|
import utilities.TestErrorLogger;
|
||||||
@ -37,6 +38,12 @@ import java.util.function.Predicate;
|
|||||||
@Module
|
@Module
|
||||||
public class TestSystemObjectProvidingModule {
|
public class TestSystemObjectProvidingModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
Gson provideGson() {
|
||||||
|
return new Gson();
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
Locale provideLocale(LocaleSystem localeSystem) {
|
Locale provideLocale(LocaleSystem localeSystem) {
|
||||||
|
Loading…
Reference in New Issue
Block a user