[Merge] Version 4.7.2 (#960)

This commit is contained in:
Risto Lahtela 2019-03-10 14:13:24 +02:00 committed by GitHub
commit e6576a281b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 651 additions and 117 deletions

View File

@ -12,7 +12,7 @@ allprojects {
wrapper.gradleVersion = "5.0"
group "com.djrapitops"
version "4.7.1"
version "4.7.2"
test {
// useJUnitPlatform()
@ -107,8 +107,8 @@ subprojects {
testCompile "org.junit.platform:junit-platform-runner:1.4.0" // JUnit 4 runner for JUnit 5 tests
testCompile "org.junit.vintage:junit-vintage-engine:5.4.0" // JUnit 4 compatibility for JUnit 5
testCompile "org.junit.jupiter:junit-jupiter-params:5.4.0" // JUnit 5, parameterized tests
testCompile "org.mockito:mockito-core:2.24.5" // Mockito Core
testCompile "org.mockito:mockito-junit-jupiter:2.24.5" // Mockito JUnit 5 Extension
testCompile "org.mockito:mockito-core:2.25.0" // Mockito Core
testCompile "org.mockito:mockito-junit-jupiter:2.25.0" // Mockito JUnit 5 Extension
testCompile "org.seleniumhq.selenium:selenium-java:3.141.59" // Selenium (Browser tests)
testCompile "com.jayway.awaitility:awaitility:1.7.0" // Awaitility (Concurrent wait conditions)

View File

@ -59,7 +59,7 @@ public class BungeeServerInfo extends ServerInfo {
}
@Override
public Server loadServerInfo() throws EnableException {
public void loadServerInfo() throws EnableException {
checkIfDefaultIP();
try {
@ -76,7 +76,6 @@ public class BungeeServerInfo extends ServerInfo {
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return server;
}
private void updateServerInfo(Database db) {

View File

@ -51,6 +51,7 @@ public class ManageCommand extends TreeCmdNode {
ManageSetupCommand setupCommand,
ManageConDebugCommand conDebugCommand,
ManageImportCommand importCommand,
ManageExportCommand exportCommand,
ManageDisableCommand disableCommand,
ManageUninstalledCommand uninstalledCommand
) {
@ -72,6 +73,7 @@ public class ManageCommand extends TreeCmdNode {
setupCommand,
conDebugCommand,
importCommand,
exportCommand,
disableCommand,
uninstalledCommand
};

View File

@ -0,0 +1,157 @@
/*
* 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.command.commands.manage;
import com.djrapitops.plan.db.Database;
import com.djrapitops.plan.db.access.queries.objects.UserIdentifierQueries;
import com.djrapitops.plan.system.database.DBSystem;
import com.djrapitops.plan.system.export.HtmlExport;
import com.djrapitops.plan.system.export.JSONExport;
import com.djrapitops.plan.system.info.server.ServerInfo;
import com.djrapitops.plan.system.locale.Locale;
import com.djrapitops.plan.system.locale.lang.CmdHelpLang;
import com.djrapitops.plan.system.locale.lang.CommandLang;
import com.djrapitops.plan.system.locale.lang.DeepHelpLang;
import com.djrapitops.plan.system.locale.lang.ManageLang;
import com.djrapitops.plan.system.processing.Processing;
import com.djrapitops.plan.system.settings.Permissions;
import com.djrapitops.plan.system.settings.config.PlanConfig;
import com.djrapitops.plan.system.settings.paths.ExportSettings;
import com.djrapitops.plugin.command.ColorScheme;
import com.djrapitops.plugin.command.CommandNode;
import com.djrapitops.plugin.command.CommandType;
import com.djrapitops.plugin.command.Sender;
import com.djrapitops.plugin.utilities.Verify;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.Arrays;
import java.util.Map;
import java.util.UUID;
import java.util.function.Consumer;
/**
* This manage SubCommand is used to import data from 3rd party plugins.
*
* @author Rsl1122
*/
@Singleton
public class ManageExportCommand extends CommandNode {
private final Locale locale;
private final ColorScheme colorScheme;
private final PlanConfig config;
private final DBSystem dbSystem;
private final ServerInfo serverInfo;
private final HtmlExport htmlExport;
private final JSONExport jsonExport;
private final Processing processing;
@Inject
public ManageExportCommand(
Locale locale,
ColorScheme colorScheme,
PlanConfig config,
DBSystem dbSystem,
ServerInfo serverInfo,
Processing processing,
HtmlExport htmlExport,
JSONExport jsonExport
) {
super("export", Permissions.MANAGE.getPermission(), CommandType.CONSOLE);
this.locale = locale;
this.colorScheme = colorScheme;
this.config = config;
this.dbSystem = dbSystem;
this.serverInfo = serverInfo;
this.htmlExport = htmlExport;
this.jsonExport = jsonExport;
this.processing = processing;
setArguments("<export_kind>/list");
setShortHelp(locale.getString(CmdHelpLang.MANAGE_EXPORT));
setInDepthHelp(locale.getArray(DeepHelpLang.MANAGE_EXPORT));
}
@Override
public void onCommand(Sender sender, String commandLabel, String[] args) {
Verify.isTrue(args.length >= 1,
() -> new IllegalArgumentException(locale.getString(CommandLang.FAIL_REQ_ARGS, "1+", Arrays.toString(this.getArguments()))));
String exportArg = args[0];
if ("list".equals(exportArg)) {
sender.sendMessage("> " + colorScheme.getMainColor() + "players, server_json");
return;
}
Database.State dbState = dbSystem.getDatabase().getState();
if (dbState != Database.State.OPEN) {
sender.sendMessage(locale.getString(CommandLang.FAIL_DATABASE_NOT_OPEN, dbState.name()));
return;
}
getExportFunction(exportArg).accept(sender);
}
private Consumer<Sender> getExportFunction(String exportArg) {
switch (exportArg) {
case "players":
return this::exportPlayers;
case "server_json":
return this::exportServerJSON;
default:
return sender -> sender.sendMessage(locale.getString(ManageLang.FAIL_EXPORTER_NOT_FOUND, exportArg));
}
}
private void exportServerJSON(Sender sender) {
sender.sendMessage(locale.getString(ManageLang.PROGRESS_START));
processing.submitNonCritical(() -> {
jsonExport.exportServerJSON(serverInfo.getServerUUID());
sender.sendMessage(locale.getString(ManageLang.PROGRESS_SUCCESS));
});
}
private void exportPlayers(Sender sender) {
sender.sendMessage(locale.getString(ManageLang.PROGRESS_START));
if (config.get(ExportSettings.PLAYERS_PAGE)) {
processing.submitNonCritical(htmlExport::exportPlayersPage);
}
Boolean exportPlayerJSON = config.get(ExportSettings.PLAYER_JSON);
Boolean exportPlayerHTML = config.get(ExportSettings.PLAYER_PAGES);
processing.submitNonCritical(() -> {
Map<UUID, String> players = dbSystem.getDatabase().query(UserIdentifierQueries.fetchAllPlayerNames());
int size = players.size();
int i = 1;
for (Map.Entry<UUID, String> entry : players.entrySet()) {
if (exportPlayerJSON) {
jsonExport.exportPlayerJSON(entry.getKey());
}
if (exportPlayerHTML) {
htmlExport.exportPlayerPage(entry.getKey(), entry.getValue());
}
i++;
if (i % 1000 == 0) {
sender.sendMessage(i + " / " + size + " processed..");
}
}
sender.sendMessage(locale.getString(ManageLang.PROGRESS_SUCCESS));
});
}
}

View File

@ -66,14 +66,21 @@ public class BaseUser {
if (this == o) return true;
if (!(o instanceof BaseUser)) return false;
BaseUser baseUser = (BaseUser) o;
return registered == baseUser.registered &&
timesKicked == baseUser.timesKicked &&
uuid.equals(baseUser.uuid) &&
name.equals(baseUser.name);
return uuid.equals(baseUser.uuid) && name.equals(baseUser.name);
}
@Override
public int hashCode() {
return Objects.hash(uuid, name, registered, timesKicked);
return Objects.hash(uuid, name);
}
@Override
public String toString() {
return "BaseUser{" +
uuid +
", '" + name + '\'' +
", +" + registered +
", kick:" + timesKicked +
'}';
}
}

View File

@ -21,7 +21,10 @@ import com.djrapitops.plan.data.store.keys.SessionKeys;
import com.djrapitops.plan.data.store.objects.DateHolder;
import com.djrapitops.plan.data.time.WorldTimes;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
/**
* DataContainer for information about a player's play session.
@ -91,7 +94,7 @@ public class Session extends DynamicDataContainer implements DateHolder {
*/
public Session(int id, UUID uuid, UUID serverUUID, long sessionStart, long sessionEnd, int mobKills, int deaths, long afkTime) {
this.sessionStart = sessionStart;
worldTimes = new WorldTimes(new HashMap<>());
worldTimes = new WorldTimes();
playerKills = new ArrayList<>();
this.mobKills = mobKills;

View File

@ -363,7 +363,7 @@ public class AnalysisContainer extends DynamicDataContainer {
private void addGraphSuppliers() {
Key<WorldPie> worldPie = new Key<>(WorldPie.class, "WORLD_PIE");
putCachingSupplier(worldPie, () -> graphs.pie().worldPie(
serverContainer.getValue(ServerKeys.WORLD_TIMES).orElse(new WorldTimes(new HashMap<>()))
serverContainer.getValue(ServerKeys.WORLD_TIMES).orElse(new WorldTimes())
));
putSupplier(AnalysisKeys.WORLD_PIE_SERIES, () -> getUnsafe(worldPie).toHighChartsSeries());
putSupplier(AnalysisKeys.GM_PIE_SERIES, () -> getUnsafe(worldPie).toHighChartsDrilldown());

View File

@ -46,13 +46,13 @@ public class PerServerMutator {
public List<Session> flatMapSessions() {
return data.values().stream()
.filter(container -> container.supports(PerServerKeys.SESSIONS))
.map(container -> container.getUnsafe(PerServerKeys.SESSIONS))
.map(container -> container.getValue(PerServerKeys.SESSIONS).orElse(Collections.emptyList()))
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
public WorldTimes flatMapWorldTimes() {
WorldTimes total = new WorldTimes(new HashMap<>());
WorldTimes total = new WorldTimes();
for (DataContainer container : data.values()) {
if (container.supports(PerServerKeys.WORLD_TIMES)) {
@ -68,7 +68,7 @@ public class PerServerMutator {
Map<UUID, WorldTimes> timesMap = new HashMap<>();
for (Map.Entry<UUID, DataContainer> entry : data.entrySet()) {
DataContainer container = entry.getValue();
timesMap.put(entry.getKey(), container.getValue(PerServerKeys.WORLD_TIMES).orElse(new WorldTimes(new HashMap<>())));
timesMap.put(entry.getKey(), container.getValue(PerServerKeys.WORLD_TIMES).orElse(new WorldTimes()));
}
return timesMap;
}

View File

@ -75,7 +75,7 @@ public class SessionsMutator {
}
public WorldTimes toTotalWorldTimes() {
WorldTimes total = new WorldTimes(new HashMap<>());
WorldTimes total = new WorldTimes();
for (Session session : sessions) {
session.getValue(SessionKeys.WORLD_TIMES).ifPresent(total::add);

View File

@ -54,6 +54,10 @@ public class WorldTimes {
this.times = times;
}
public WorldTimes() {
this(new HashMap<>());
}
private void addWorld(String worldName, String gameMode, long changeTime) {
if (worldName == null || gameMode == null) return;
times.put(worldName, new GMTimes(gameMode, changeTime));

View File

@ -103,9 +103,9 @@ public class DataStoreQueries {
statement.setString(1, session.getUnsafe(SessionKeys.UUID).toString());
statement.setLong(2, session.getUnsafe(SessionKeys.START));
statement.setLong(3, session.getUnsafe(SessionKeys.END));
statement.setInt(4, session.getUnsafe(SessionKeys.DEATH_COUNT));
statement.setInt(5, session.getUnsafe(SessionKeys.MOB_KILL_COUNT));
statement.setLong(6, session.getUnsafe(SessionKeys.AFK_TIME));
statement.setInt(4, session.getValue(SessionKeys.DEATH_COUNT).orElse(0));
statement.setInt(5, session.getValue(SessionKeys.MOB_KILL_COUNT).orElse(0));
statement.setLong(6, session.getValue(SessionKeys.AFK_TIME).orElse(0L));
statement.setString(7, session.getUnsafe(SessionKeys.SERVER_UUID).toString());
}
};

View File

@ -341,9 +341,9 @@ public class LargeStoreQueries {
statement.setString(1, session.getUnsafe(SessionKeys.UUID).toString());
statement.setLong(2, session.getUnsafe(SessionKeys.START));
statement.setLong(3, session.getUnsafe(SessionKeys.END));
statement.setInt(4, session.getUnsafe(SessionKeys.DEATH_COUNT));
statement.setInt(5, session.getUnsafe(SessionKeys.MOB_KILL_COUNT));
statement.setLong(6, session.getUnsafe(SessionKeys.AFK_TIME));
statement.setInt(4, session.getValue(SessionKeys.DEATH_COUNT).orElse(0));
statement.setInt(5, session.getValue(SessionKeys.MOB_KILL_COUNT).orElse(0));
statement.setLong(6, session.getValue(SessionKeys.AFK_TIME).orElse(0L));
statement.setString(7, session.getUnsafe(SessionKeys.SERVER_UUID).toString());
statement.addBatch();
}

View File

@ -63,7 +63,7 @@ public class PerServerContainerQuery implements Query<PerServerContainer> {
// After-values that can be calculated without database.
for (DataContainer serverContainer : perServerContainer.values()) {
serverContainer.putSupplier(PerServerKeys.MOB_DEATH_COUNT, () ->
serverContainer.getUnsafe(PerServerKeys.DEATH_COUNT) - serverContainer.getUnsafe(PerServerKeys.PLAYER_DEATH_COUNT)
serverContainer.getValue(PerServerKeys.DEATH_COUNT).orElse(0) - serverContainer.getValue(PerServerKeys.PLAYER_DEATH_COUNT).orElse(0)
);
}

View File

@ -19,6 +19,7 @@ package com.djrapitops.plan.db.access.queries.containers;
import com.djrapitops.plan.data.container.BaseUser;
import com.djrapitops.plan.data.container.Session;
import com.djrapitops.plan.data.store.Key;
import com.djrapitops.plan.data.store.containers.PerServerContainer;
import com.djrapitops.plan.data.store.containers.PlayerContainer;
import com.djrapitops.plan.data.store.keys.PlayerKeys;
import com.djrapitops.plan.data.store.keys.SessionKeys;
@ -29,7 +30,7 @@ import com.djrapitops.plan.db.SQLDB;
import com.djrapitops.plan.db.access.Query;
import com.djrapitops.plan.db.access.queries.objects.*;
import java.util.HashMap;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
@ -64,11 +65,11 @@ public class PlayerContainerQuery implements Query<PlayerContainer> {
container.putCachingSupplier(PlayerKeys.NICKNAMES, () -> db.query(NicknameQueries.fetchNicknameDataOfPlayer(uuid)));
container.putCachingSupplier(PlayerKeys.PER_SERVER, () -> db.query(new PerServerContainerQuery(uuid)));
container.putSupplier(PlayerKeys.BANNED, () -> new PerServerMutator(container.getUnsafe(PlayerKeys.PER_SERVER)).isBanned());
container.putSupplier(PlayerKeys.OPERATOR, () -> new PerServerMutator(container.getUnsafe(PlayerKeys.PER_SERVER)).isOperator());
container.putSupplier(PlayerKeys.BANNED, () -> new PerServerMutator(container.getValue(PlayerKeys.PER_SERVER).orElse(new PerServerContainer())).isBanned());
container.putSupplier(PlayerKeys.OPERATOR, () -> new PerServerMutator(container.getValue(PlayerKeys.PER_SERVER).orElse(new PerServerContainer())).isOperator());
container.putCachingSupplier(PlayerKeys.SESSIONS, () -> {
List<Session> sessions = new PerServerMutator(container.getUnsafe(PlayerKeys.PER_SERVER)).flatMapSessions();
List<Session> sessions = new PerServerMutator(container.getValue(PlayerKeys.PER_SERVER).orElse(new PerServerContainer())).flatMapSessions();
container.getValue(PlayerKeys.ACTIVE_SESSION).ifPresent(sessions::add);
return sessions;
}
@ -77,7 +78,7 @@ public class PlayerContainerQuery implements Query<PlayerContainer> {
{
WorldTimes worldTimes = db.query(WorldTimesQueries.fetchPlayerTotalWorldTimes(uuid));
container.getValue(PlayerKeys.ACTIVE_SESSION).ifPresent(session -> worldTimes.add(
session.getValue(SessionKeys.WORLD_TIMES).orElse(new WorldTimes(new HashMap<>())))
session.getValue(SessionKeys.WORLD_TIMES).orElse(new WorldTimes()))
);
return worldTimes;
});
@ -86,7 +87,7 @@ public class PlayerContainerQuery implements Query<PlayerContainer> {
container.putSupplier(PlayerKeys.PLAYER_KILLS, () -> SessionsMutator.forContainer(container).toPlayerKillList());
container.putSupplier(PlayerKeys.PLAYER_DEATHS, () -> SessionsMutator.forContainer(container).toPlayerDeathList());
container.putSupplier(PlayerKeys.PLAYER_KILL_COUNT, () -> container.getUnsafe(PlayerKeys.PLAYER_KILLS).size());
container.putSupplier(PlayerKeys.PLAYER_KILL_COUNT, () -> container.getValue(PlayerKeys.PLAYER_KILLS).map(Collection::size).orElse(0));
container.putSupplier(PlayerKeys.MOB_KILL_COUNT, () -> SessionsMutator.forContainer(container).toMobKillCount());
container.putSupplier(PlayerKeys.DEATH_COUNT, () -> SessionsMutator.forContainer(container).toDeathCount());

View File

@ -30,6 +30,7 @@ import com.djrapitops.plan.db.access.queries.objects.WorldTimesQueries;
import com.djrapitops.plan.system.cache.SessionCache;
import com.djrapitops.plan.system.info.server.Server;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
@ -65,7 +66,7 @@ public class ServerContainerQuery implements Query<ServerContainer> {
container.putRawData(ServerKeys.SERVER_UUID, serverUUID);
container.putRawData(ServerKeys.NAME, serverInfo.get().getName());
container.putCachingSupplier(ServerKeys.PLAYERS, () -> db.query(new ServerPlayerContainersQuery(serverUUID)));
container.putSupplier(ServerKeys.PLAYER_COUNT, () -> container.getUnsafe(ServerKeys.PLAYERS).size());
container.putSupplier(ServerKeys.PLAYER_COUNT, () -> container.getValue(ServerKeys.PLAYERS).map(Collection::size).orElse(0));
container.putCachingSupplier(ServerKeys.TPS, () -> db.query(TPSQueries.fetchTPSDataOfServer(serverUUID)));
container.putCachingSupplier(ServerKeys.PING, () -> PlayersMutator.forContainer(container).pings());

View File

@ -103,7 +103,7 @@ public class ServerPlayerContainersQuery implements Query<List<PlayerContainer>>
WorldTimes worldTimes = new PerServerMutator(container.getUnsafe(PlayerKeys.PER_SERVER)).flatMapWorldTimes();
container.getValue(PlayerKeys.ACTIVE_SESSION)
.ifPresent(session -> worldTimes.add(
session.getValue(SessionKeys.WORLD_TIMES).orElse(new WorldTimes(new HashMap<>())))
session.getValue(SessionKeys.WORLD_TIMES).orElse(new WorldTimes()))
);
return worldTimes;
});

View File

@ -27,7 +27,10 @@ import com.djrapitops.plan.db.sql.tables.UsersTable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import java.util.Collection;
import java.util.HashSet;
import java.util.Optional;
import java.util.UUID;
/**
* Queries for {@link BaseUser} objects.
@ -126,8 +129,8 @@ public class BaseUserQueries {
}
@Override
public List<BaseUser> processResults(ResultSet set) throws SQLException {
List<BaseUser> users = new ArrayList<>();
public Collection<BaseUser> processResults(ResultSet set) throws SQLException {
Collection<BaseUser> users = new HashSet<>();
while (set.next()) {
UUID playerUUID = UUID.fromString(set.getString(UsersTable.USER_UUID));
String name = set.getString(UsersTable.USER_NAME);

View File

@ -214,7 +214,7 @@ public class SessionQueries {
set.getLong(SessionsTable.AFK_TIME)
));
WorldTimes worldTimes = session.getUnsafe(SessionKeys.WORLD_TIMES);
WorldTimes worldTimes = session.getValue(SessionKeys.WORLD_TIMES).orElse(new WorldTimes());
String worldName = set.getString(WorldTable.NAME);
if (!worldTimes.contains(worldName)) {

View File

@ -75,7 +75,7 @@ public class WorldTimesQueries {
public WorldTimes processResults(ResultSet set) throws SQLException {
String[] gms = GMTimes.getGMKeyArray();
WorldTimes worldTimes = new WorldTimes(new HashMap<>());
WorldTimes worldTimes = new WorldTimes();
while (set.next()) {
String worldName = set.getString(worldColumn);
@ -110,7 +110,7 @@ public class WorldTimesQueries {
public WorldTimes processResults(ResultSet set) throws SQLException {
String[] gms = GMTimes.getGMKeyArray();
WorldTimes worldTimes = new WorldTimes(new HashMap<>());
WorldTimes worldTimes = new WorldTimes();
while (set.next()) {
String worldName = set.getString(worldColumn);
@ -149,7 +149,7 @@ public class WorldTimesQueries {
Map<UUID, WorldTimes> worldTimesMap = new HashMap<>();
while (set.next()) {
UUID serverUUID = UUID.fromString(set.getString(WorldTimesTable.SERVER_UUID));
WorldTimes worldTimes = worldTimesMap.getOrDefault(serverUUID, new WorldTimes(new HashMap<>()));
WorldTimes worldTimes = worldTimesMap.getOrDefault(serverUUID, new WorldTimes());
String worldName = set.getString(worldColumn);
GMTimes gmTimes = extractGMTimes(set, gms);

View File

@ -33,6 +33,7 @@ import com.djrapitops.plan.system.settings.paths.ExportSettings;
import com.djrapitops.plan.system.settings.theme.Theme;
import com.djrapitops.plan.system.settings.theme.ThemeVal;
import com.djrapitops.plan.utilities.file.FileUtil;
import com.djrapitops.plan.utilities.html.pages.InspectPage;
import com.djrapitops.plan.utilities.html.pages.PageFactory;
import com.djrapitops.plugin.api.Check;
import com.djrapitops.plugin.logging.L;
@ -107,7 +108,21 @@ public class HtmlExport extends SpecificExport {
});
}
public void exportPlayer(UUID playerUUID) {
public void exportPlayerPage(UUID playerUUID) {
Optional<String> name = dbSystem.getDatabase().query(UserIdentifierQueries.fetchPlayerNameOf(playerUUID));
exportPlayerPage(playerUUID, name.orElse("Unknown"));
}
public void exportPlayerPage(UUID playerUUID, String playerName) {
InspectPage playerPage = pageFactory.inspectPage(playerUUID);
try {
exportPlayerPage(playerName, playerPage.toHtml());
} catch (ParseException | IOException e) {
errorHandler.log(L.ERROR, this.getClass(), e);
}
}
public void exportCachedPlayerPage(UUID playerUUID) {
if (Check.isBukkitAvailable() && connectionSystem.isServerAvailable()) {
return;
}

View File

@ -32,6 +32,7 @@ import javax.inject.Inject;
import javax.inject.Singleton;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.UUID;
@ -77,7 +78,7 @@ public class JSONExport extends SpecificExport {
try {
File htmlLocation = getPlayerFolder();
htmlLocation.mkdirs();
File exportFile = new File(htmlLocation, playerName.replace(" ", "%20").replace(".", "%2E") + ".json");
File exportFile = new File(htmlLocation, URLEncoder.encode(playerName, "UTF-8") + ".json");
export(exportFile, Collections.singletonList(json));
} catch (IOException e) {
@ -94,7 +95,7 @@ public class JSONExport extends SpecificExport {
try {
File htmlLocation = getServerFolder();
htmlLocation.mkdirs();
File exportFile = new File(htmlLocation, serverName.replace(" ", "%20").replace(".", "%2E") + ".json");
File exportFile = new File(htmlLocation, URLEncoder.encode(serverName, "UTF-8") + ".json");
export(exportFile, Collections.singletonList(json));
} catch (IOException e) {

View File

@ -25,6 +25,7 @@ import com.djrapitops.plugin.api.Check;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
@ -89,20 +90,24 @@ public abstract class SpecificExport {
return player;
}
protected void exportAvailablePlayerPage(UUID uuid, String name) throws IOException {
Response response = ResponseCache.loadResponse(PageId.PLAYER.of(uuid));
protected void exportPlayerPage(String playerName, String html) throws IOException {
List<String> lines = Arrays.asList(html.split("\n"));
File htmlLocation = new File(getPlayerFolder(), URLEncoder.encode(playerName, "UTF-8").replace(".", "%2E"));
htmlLocation.mkdirs();
File exportFile = new File(htmlLocation, "index.html");
export(exportFile, lines);
}
protected void exportAvailablePlayerPage(UUID playerUUID, String name) throws IOException {
Response response = ResponseCache.loadResponse(PageId.PLAYER.of(playerUUID));
if (response == null) {
return;
}
String html = response.getContent().replace("../", "../../");
List<String> lines = Arrays.asList(html.split("\n"));
File htmlLocation = new File(getPlayerFolder(), name.replace(" ", "%20").replace(".", "%2E"));
htmlLocation.mkdirs();
File exportFile = new File(htmlLocation, "index.html");
export(exportFile, lines);
exportPlayerPage(name, html);
}
protected void exportAvailableServerPage(UUID serverUUID, String serverName) throws IOException {
@ -123,7 +128,7 @@ public abstract class SpecificExport {
if (serverUUID.equals(serverInfo.getServerUUID())) {
htmlLocation = new File(getFolder(), "network");
} else {
htmlLocation = new File(getServerFolder(), serverName.replace(" ", "%20").replace(".", "%2E"));
htmlLocation = new File(getServerFolder(), URLEncoder.encode(serverName, "UTF-8").replace(".", "%2E"));
html = html.replace("../", "../../");
}
} else {

View File

@ -105,13 +105,13 @@ public class CacheInspectPageRequest extends InfoRequestWithVariables implements
return DefaultResponses.SUCCESS.get();
}
private void cache(UUID uuid, String html) {
ResponseCache.cacheResponse(PageId.PLAYER.of(uuid), () -> new InspectPageResponse(uuid, html));
private void cache(UUID playerUUID, String html) {
ResponseCache.cacheResponse(PageId.PLAYER.of(playerUUID), () -> new InspectPageResponse(playerUUID, html));
if (config.get(ExportSettings.PLAYER_PAGES)) {
processing.submitNonCritical(() -> htmlExport.exportPlayer(uuid));
processing.submitNonCritical(() -> htmlExport.exportCachedPlayerPage(playerUUID));
}
if (config.get(ExportSettings.PLAYER_JSON)) {
processing.submitNonCritical(() -> jsonExport.exportPlayerJSON(uuid));
processing.submitNonCritical(() -> jsonExport.exportPlayerJSON(playerUUID));
}
}

View File

@ -53,11 +53,11 @@ public abstract class ServerInfo implements SubSystem {
@Override
public void enable() throws EnableException {
server = loadServerInfo();
loadServerInfo();
Verify.nullCheck(server, () -> new EnableException("Server information did not load!"));
}
protected abstract Server loadServerInfo() throws EnableException;
protected abstract void loadServerInfo() throws EnableException;
@Override
public void disable() {

View File

@ -23,9 +23,12 @@ import com.djrapitops.plan.db.access.queries.objects.ServerQueries;
import com.djrapitops.plan.db.access.transactions.StoreServerInformationTransaction;
import com.djrapitops.plan.system.database.DBSystem;
import com.djrapitops.plan.system.info.server.properties.ServerProperties;
import com.djrapitops.plan.system.processing.Processing;
import com.djrapitops.plan.system.settings.config.PlanConfig;
import com.djrapitops.plan.system.settings.paths.PluginSettings;
import com.djrapitops.plan.system.webserver.WebServer;
import com.djrapitops.plugin.logging.L;
import com.djrapitops.plugin.logging.error.ErrorHandler;
import dagger.Lazy;
import javax.inject.Inject;
@ -45,24 +48,31 @@ import java.util.concurrent.ExecutionException;
@Singleton
public class ServerServerInfo extends ServerInfo {
private final Lazy<WebServer> webServer;
private final ServerInfoFile serverInfoFile;
private final PlanConfig config;
private ServerInfoFile serverInfoFile;
private DBSystem dbSystem;
private final Processing processing;
private final DBSystem dbSystem;
private final Lazy<WebServer> webServer;
private final ErrorHandler errorHandler;
@Inject
public ServerServerInfo(
ServerProperties serverProperties,
ServerInfoFile serverInfoFile,
Processing processing,
PlanConfig config,
DBSystem dbSystem,
Lazy<WebServer> webServer,
PlanConfig config
ErrorHandler errorHandler
) {
super(serverProperties);
this.serverInfoFile = serverInfoFile;
this.processing = processing;
this.dbSystem = dbSystem;
this.webServer = webServer;
this.config = config;
this.errorHandler = errorHandler;
}
@Override
@ -76,10 +86,15 @@ public class ServerServerInfo extends ServerInfo {
}
@Override
protected Server loadServerInfo() throws EnableException {
protected void loadServerInfo() throws EnableException {
Optional<UUID> serverUUID = serverInfoFile.getUUID();
try {
return serverUUID.isPresent() ? updateDbInfo(serverUUID.get()) : registerServer();
if (serverUUID.isPresent()) {
server = createServerObject(serverUUID.get());
processing.submitNonCritical(() -> updateDbInfo(serverUUID.get()));
} else {
server = registerServer();
}
} catch (DBOpException e) {
String causeMsg = e.getMessage();
throw new EnableException("Failed to read Server information from Database: " + causeMsg, e);
@ -87,34 +102,38 @@ public class ServerServerInfo extends ServerInfo {
throw new EnableException("Failed to read ServerInfoFile.yml", e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null; // This line is not reached due to the thread interrupt.
} catch (Exception e) {
throw new EnableException("Failed to perform a database transaction to store the server information", e);
}
}
private Server updateDbInfo(UUID serverUUID) throws Exception {
Database db = dbSystem.getDatabase();
private void updateDbInfo(UUID serverUUID) {
try {
Database db = dbSystem.getDatabase();
Optional<Server> foundServer = db.query(ServerQueries.fetchServerMatchingIdentifier(serverUUID));
if (!foundServer.isPresent()) {
return registerServer(serverUUID);
Optional<Server> foundServer = db.query(ServerQueries.fetchServerMatchingIdentifier(serverUUID));
if (!foundServer.isPresent()) {
server = registerServer(serverUUID);
return;
}
server = foundServer.get();
// Update information
String name = config.get(PluginSettings.SERVER_NAME).replaceAll("[^a-zA-Z0-9_\\s]", "_");
server.setName("plan".equalsIgnoreCase(name) ? "Server " + server.getId() : name);
String webAddress = webServer.get().getAccessAddress();
server.setWebAddress(webAddress);
int maxPlayers = serverProperties.getMaxPlayers();
server.setMaxPlayers(maxPlayers);
// Save
db.executeTransaction(new StoreServerInformationTransaction(server));
} catch (InterruptedException | ExecutionException | IOException e) {
errorHandler.log(L.CRITICAL, this.getClass(), e);
}
Server server = foundServer.get();
// Update information
String name = config.get(PluginSettings.SERVER_NAME).replaceAll("[^a-zA-Z0-9_\\s]", "_");
server.setName("plan".equalsIgnoreCase(name) ? "Server " + server.getId() : name);
String webAddress = webServer.get().getAccessAddress();
server.setWebAddress(webAddress);
int maxPlayers = serverProperties.getMaxPlayers();
server.setMaxPlayers(maxPlayers);
// Save
db.executeTransaction(new StoreServerInformationTransaction(server));
return server;
}
private Server registerServer() throws Exception {
@ -124,11 +143,7 @@ public class ServerServerInfo extends ServerInfo {
private Server registerServer(UUID serverUUID) throws ExecutionException, InterruptedException, IOException {
Database db = dbSystem.getDatabase();
// Create the server object
String webAddress = webServer.get().getAccessAddress();
String name = config.get(PluginSettings.SERVER_NAME).replaceAll("[^a-zA-Z0-9_\\s]", "_");
int maxPlayers = serverProperties.getMaxPlayers();
Server server = new Server(-1, serverUUID, name, webAddress, maxPlayers);
Server server = createServerObject(serverUUID);
// Save
db.executeTransaction(new StoreServerInformationTransaction(server))
@ -142,4 +157,11 @@ public class ServerServerInfo extends ServerInfo {
serverInfoFile.saveServerUUID(serverUUID);
return server;
}
private Server createServerObject(UUID serverUUID) {
String webAddress = webServer.get().getAccessAddress();
String name = config.get(PluginSettings.SERVER_NAME).replaceAll("[^a-zA-Z0-9_\\s]", "_");
int maxPlayers = serverProperties.getMaxPlayers();
return new Server(-1, serverUUID, name, webAddress, maxPlayers);
}
}

View File

@ -48,6 +48,7 @@ public enum CmdHelpLang implements Lang {
MANAGE_CLEAR("Command Help - /plan manage clear", "Clear a Database"),
MANAGE_CON("Command Help - /plan manage con", "Debug Server-Bungee connections"),
MANAGE_IMPORT("Command Help - /plan manage import", "Import data from elsewhere"),
MANAGE_EXPORT("Command Help - /plan manage export", "Trigger export manually"),
MANAGE_DISABLE("Command Help - /plan manage disable", "Disable a feature temporarily"),
MANAGE_SETUP("Command Help - /plan manage setup", "Set-up Server-Bungee connection"),

View File

@ -41,6 +41,7 @@ public enum DeepHelpLang implements Lang {
MANAGE_CON("In Depth Help - /plan manage con ?", "> §2Connection Debug Subcommand\\ Used to debug connections in the network.\\ Sends a request to each server in the database."),
MANAGE_DISABLE("In Depth Help - /plan manage disable ?", "> §2Disable Subcommand\\ Can disable parts of the plugin until next reload.\\ Accepted arguments:\\ §2kickcount §fDisables kick counts in case /kickall is used on shutdown macro."),
MANAGE_IMPORT("In Depth Help - /plan manage import ?", "> §2Import Subcommand\\ Import data from other sources.\\ Accepted Arguments:\\ §2offline §fBukkit player data, only register date and name."),
MANAGE_EXPORT("In Depth Help - /plan manage export ?", "> §2Export Subcommand\\ Trigger export to result folders.\\ Accepted Arguments:\\ §2list §fList possible arguments.\\ §2players §fExport /players, /player pages + /player/raw json depending on config values.\\ §2server_json §fExport /server/raw JSON if enabled in config."),
MANAGE_MOVE("In Depth Help - /plan manage move ?", "> §2Move Subcommand\\ Move data from SQLite to MySQL or other way around.\\ Target database is cleared before transfer."),
MANAGE_REMOVE("In Depth Help - /plan manage remove ?", "> §2Remove Subcommand\\ Remove player's data from the active database."),
MANAGE_RESTORE("In Depth Help - /plan manage restore ?", "> §2Restore Subcommand\\ Restore a previous backup SQLite database (.db file)\\ You can also restore database.db from another server to MySQL.\\ Target database is cleared before transfer."),

View File

@ -45,6 +45,7 @@ public enum ManageLang implements Lang {
FAIL_INCORRECT_DB("Manage - Fail Incorrect Database", "> §c'${0}' is not a supported database."),
FAIL_FILE_NOT_FOUND("Manage - Fail File not found", "> §cNo File found at ${0}"),
FAIL_IMPORTER_NOT_FOUND("Manage - Fail No Importer", "§eImporter '${0}' doesn't exist"),
FAIL_EXPORTER_NOT_FOUND("Manage - Fail No Exporter", "§eExporter '${0}' doesn't exist"),
NO_SERVER("Manage - Fail No Server", "No server found with given parameters."),
UNINSTALLING_SAME_SERVER("Manage - Fail Same server", "Can not mark this server as uninstalled (You are on it)");

View File

@ -16,8 +16,11 @@
*/
package com.djrapitops.plan.system.processing.processors.info;
import com.djrapitops.plan.system.export.HtmlExport;
import com.djrapitops.plan.system.export.JSONExport;
import com.djrapitops.plan.system.info.InfoSystem;
import com.djrapitops.plan.system.info.connection.WebExceptionLogger;
import com.djrapitops.plan.system.settings.config.PlanConfig;
import com.djrapitops.plugin.command.Sender;
import dagger.Lazy;
@ -34,14 +37,23 @@ import java.util.function.BiConsumer;
@Singleton
public class InfoProcessors {
private final Lazy<PlanConfig> config;
private final Lazy<HtmlExport> htmlExport;
private final Lazy<JSONExport> jsonExport;
private final Lazy<InfoSystem> infoSystem;
private final Lazy<WebExceptionLogger> webExceptionLogger;
@Inject
public InfoProcessors(
Lazy<PlanConfig> config,
Lazy<HtmlExport> htmlExport,
Lazy<JSONExport> jsonExport,
Lazy<InfoSystem> infoSystem,
Lazy<WebExceptionLogger> webExceptionLogger
) {
this.config = config;
this.htmlExport = htmlExport;
this.jsonExport = jsonExport;
this.infoSystem = infoSystem;
this.webExceptionLogger = webExceptionLogger;
}
@ -58,6 +70,6 @@ public class InfoProcessors {
}
public PlayerPageUpdateProcessor playerPageUpdateProcessor(UUID uuid) {
return new PlayerPageUpdateProcessor(uuid);
return new PlayerPageUpdateProcessor(uuid, config.get(), htmlExport.get(), jsonExport.get());
}
}

View File

@ -16,6 +16,10 @@
*/
package com.djrapitops.plan.system.processing.processors.info;
import com.djrapitops.plan.system.export.HtmlExport;
import com.djrapitops.plan.system.export.JSONExport;
import com.djrapitops.plan.system.settings.config.PlanConfig;
import com.djrapitops.plan.system.settings.paths.ExportSettings;
import com.djrapitops.plan.system.webserver.cache.PageId;
import com.djrapitops.plan.system.webserver.cache.ResponseCache;
@ -23,16 +27,35 @@ import java.util.UUID;
public class PlayerPageUpdateProcessor implements Runnable {
private final UUID uuid;
private final UUID playerUUID;
private final PlanConfig config;
private final HtmlExport htmlExport;
private final JSONExport jsonExport;
PlayerPageUpdateProcessor(
UUID uuid
UUID playerUUID,
PlanConfig config,
HtmlExport htmlExport,
JSONExport jsonExport
) {
this.uuid = uuid;
this.playerUUID = playerUUID;
this.config = config;
this.htmlExport = htmlExport;
this.jsonExport = jsonExport;
}
@Override
public void run() {
ResponseCache.clearResponse(PageId.PLAYER.of(uuid));
ResponseCache.clearResponse(PageId.PLAYER.of(playerUUID));
if (config.get(ExportSettings.EXPORT_ON_ONLINE_STATUS_CHANGE)) {
if (config.get(ExportSettings.PLAYER_JSON)) {
jsonExport.exportPlayerJSON(playerUUID);
}
if (config.get(ExportSettings.PLAYER_PAGES)) {
htmlExport.exportPlayerPage(playerUUID);
}
}
}
}

View File

@ -165,7 +165,7 @@ public class WorldAliasSettings {
if (!session.supports(SessionKeys.WORLD_TIMES)) {
return "No World Time Data";
}
WorldTimes worldTimes = session.getUnsafe(SessionKeys.WORLD_TIMES);
WorldTimes worldTimes = session.getValue(SessionKeys.WORLD_TIMES).orElse(new WorldTimes());
if (!session.supports(SessionKeys.END)) {
return "Current: " + aliases.getOrDefault(worldTimes.getCurrentWorld(), "Unknown");
}

View File

@ -35,6 +35,7 @@ public class ExportSettings {
public static final Setting<Boolean> PLAYERS_PAGE = new BooleanSetting("Export.Parts.Players_page");
public static final Setting<Boolean> SERVER_PAGE = new BooleanSetting("Export.Parts.Server_page");
public static final Setting<Boolean> SERVER_JSON = new BooleanSetting("Export.Parts.Server_JSON");
public static final Setting<Boolean> EXPORT_ON_ONLINE_STATUS_CHANGE = new BooleanSetting("Export.Export_player_on_login_and_logout");
private ExportSettings() {
/* static variable class */

View File

@ -118,7 +118,7 @@ public class PlayerCalendar {
.orElse(System.currentTimeMillis()))
.append("}");
for (PlayerKill kill : session.getUnsafe(SessionKeys.PLAYER_KILLS)) {
for (PlayerKill kill : session.getPlayerKills()) {
long time = kill.getDate();
series.append(",{title: 'Killed: ").append(kill.getVictim())

View File

@ -110,7 +110,7 @@ public class PunchCard implements HighChart {
private List<Long> getSessionStarts(Collection<Session> data) {
return data.stream()
.filter(Objects::nonNull)
.map(s -> s.getUnsafe(SessionKeys.START))
.map(session -> session.getUnsafe(SessionKeys.START))
.sorted()
.collect(Collectors.toList());
}

View File

@ -223,7 +223,7 @@ public class InspectPage implements Page {
sessionsAndPlaytime(replacer, sessionsMutator, daySessionsMutator, weekSessionsMutator, monthSessionsMutator);
String punchCardData = graphs.special().punchCard(allSessions).toHighChartsSeries();
WorldTimes worldTimes = player.getValue(PlayerKeys.WORLD_TIMES).orElse(new WorldTimes(new HashMap<>()));
WorldTimes worldTimes = player.getValue(PlayerKeys.WORLD_TIMES).orElse(new WorldTimes());
WorldPie worldPie = graphs.pie().worldPie(worldTimes);

View File

@ -25,6 +25,7 @@ import com.djrapitops.plan.utilities.comparators.SessionStartComparator;
import com.djrapitops.plan.utilities.formatting.Formatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
@ -85,7 +86,7 @@ public class RecentLoginList {
String name = player.getUnsafe(PlayerKeys.NAME);
long registerDate = player.getValue(PlayerKeys.REGISTERED).orElse(0L);
List<Session> sessions = player.getUnsafe(PlayerKeys.SESSIONS);
List<Session> sessions = player.getValue(PlayerKeys.SESSIONS).orElse(Collections.emptyList());
if (sessions.isEmpty()) {
continue;
}

View File

@ -33,7 +33,6 @@ import com.djrapitops.plan.utilities.html.icon.Icon;
import com.djrapitops.plan.utilities.html.icon.Icons;
import com.djrapitops.plugin.utilities.Format;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
@ -92,7 +91,7 @@ public class ServerAccordion extends Accordion {
UUID serverUUID = entry.getKey();
DataContainer container = entry.getValue();
String serverName = serverNames.getOrDefault(serverUUID, "Unknown");
WorldTimes worldTimes = container.getValue(PerServerKeys.WORLD_TIMES).orElse(new WorldTimes(new HashMap<>()));
WorldTimes worldTimes = container.getValue(PerServerKeys.WORLD_TIMES).orElse(new WorldTimes());
SessionsMutator sessionsMutator = SessionsMutator.forContainer(container);
boolean banned = container.getValue(PerServerKeys.BANNED).orElse(false);

View File

@ -33,7 +33,10 @@ import com.djrapitops.plan.utilities.html.graphs.pie.WorldPie;
import com.djrapitops.plan.utilities.html.icon.Icons;
import com.djrapitops.plan.utilities.html.tables.HtmlTables;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Supplier;
/**
@ -119,7 +122,7 @@ public class SessionAccordion extends Accordion {
String playerName = playerNames.getOrDefault(session.getValue(SessionKeys.UUID).orElse(null), "Unknown");
String sessionStart = yearFormatter.apply(session);
WorldTimes worldTimes = session.getValue(SessionKeys.WORLD_TIMES).orElse(new WorldTimes(new HashMap<>()));
WorldTimes worldTimes = session.getValue(SessionKeys.WORLD_TIMES).orElse(new WorldTimes());
WorldPie worldPie = graphs.pie().worldPie(worldTimes);
String longestWorldPlayed = worldAliasSettings.getLongestWorldPlayed(session);
@ -191,7 +194,7 @@ public class SessionAccordion extends Accordion {
String serverName = serverNames.getOrDefault(session.getValue(SessionKeys.SERVER_UUID).orElse(null), "Unknown");
String sessionStart = yearFormatter.apply(session);
WorldTimes worldTimes = session.getValue(SessionKeys.WORLD_TIMES).orElse(new WorldTimes(new HashMap<>()));
WorldTimes worldTimes = session.getValue(SessionKeys.WORLD_TIMES).orElse(new WorldTimes());
WorldPie worldPie = graphs.pie().worldPie(worldTimes);
String longestWorldPlayed = worldAliasSettings.getLongestWorldPlayed(session);

View File

@ -1,7 +1,7 @@
name: Plan
author: Rsl1122
main: com.djrapitops.plan.PlanBungee
version: 4.7.1
version: 4.7.2
softdepend:
- AdvancedBan
- LiteBans

View File

@ -161,6 +161,7 @@ Export:
Players_page: false
Server_page: false
Server_JSON: false
Export_player_on_login_and_logout: false
# -----------------------------------------------------
# These settings affect Plugin data integration.
# If a plugin is causing issues the integration can be disabled by setting Plugin_name.Enabled: false

View File

@ -174,6 +174,8 @@ Export:
Players_page: false
Server_page: false
Server_JSON: false
# All player pages/JSON can be exported by using /plan m export players
Export_player_on_login_and_logout: false
# -----------------------------------------------------
# These settings affect Plugin data integration.
# If a plugin is causing issues the integration can be disabled by setting Plugin_name.Enabled: false

View File

@ -1,7 +1,7 @@
name: Plan
author: Rsl1122
main: com.djrapitops.plan.Plan
version: 4.7.1
version: 4.7.2
softdepend:
- EssentialsX
- Towny

View File

@ -32,7 +32,9 @@ import com.djrapitops.plan.data.time.WorldTimes;
import com.djrapitops.plan.db.access.Executable;
import com.djrapitops.plan.db.access.Query;
import com.djrapitops.plan.db.access.queries.*;
import com.djrapitops.plan.db.access.queries.containers.AllPlayerContainersQuery;
import com.djrapitops.plan.db.access.queries.containers.ContainerFetchQueries;
import com.djrapitops.plan.db.access.queries.containers.ServerPlayerContainersQuery;
import com.djrapitops.plan.db.access.queries.objects.*;
import com.djrapitops.plan.db.access.transactions.BackupCopyTransaction;
import com.djrapitops.plan.db.access.transactions.StoreConfigTransaction;
@ -60,10 +62,7 @@ import org.junit.rules.TemporaryFolder;
import org.junit.rules.Timeout;
import rules.ComponentMocker;
import rules.PluginComponentMocker;
import utilities.FieldFetcher;
import utilities.OptionalAssert;
import utilities.RandomData;
import utilities.TestConstants;
import utilities.*;
import java.io.File;
import java.lang.management.ManagementFactory;
@ -749,7 +748,7 @@ public abstract class CommonDBTest {
@Test
public void emptyServerWorldTimesIsEmpty() {
WorldTimes worldTimesOfServer = db.query(WorldTimesQueries.fetchServerTotalWorldTimes(serverUUID));
assertEquals(new WorldTimes(new HashMap<>()), worldTimesOfServer);
assertEquals(new WorldTimes(), worldTimesOfServer);
}
@Test
@ -1015,4 +1014,83 @@ public abstract class CommonDBTest {
Map<UUID, Integer> result = db.query(ServerAggregateQueries.serverUserCounts());
assertEquals(expected, result);
}
private void executeTransactions(Transaction... transactions) {
for (Transaction transaction : transactions) {
db.executeTransaction(transaction);
}
}
@Test
public void baseUsersQueryDoesNotReturnDuplicatePlayers() {
db.executeTransaction(TestData.storeServers());
executeTransactions(TestData.storePlayerOneData());
executeTransactions(TestData.storePlayerTwoData());
Collection<BaseUser> expected = new HashSet<>(Arrays.asList(TestData.getPlayerBaseUser(), TestData.getPlayer2BaseUser()));
Collection<BaseUser> result = db.query(BaseUserQueries.fetchServerBaseUsers(TestConstants.SERVER_UUID));
assertEquals(expected, result);
result = db.query(BaseUserQueries.fetchServerBaseUsers(TestConstants.SERVER_TWO_UUID));
assertEquals(expected, result);
}
@Test
public void serverPlayerContainersQueryDoesNotReturnDuplicatePlayers() {
db.executeTransaction(TestData.storeServers());
executeTransactions(TestData.storePlayerOneData());
executeTransactions(TestData.storePlayerTwoData());
List<UUID> expected = Arrays.asList(playerUUID, player2UUID);
Collections.sort(expected);
Collection<UUID> result = db.query(new ServerPlayerContainersQuery(TestConstants.SERVER_UUID))
.stream().map(player -> player.getUnsafe(PlayerKeys.UUID))
.sorted()
.collect(Collectors.toList());
assertEquals(expected, result);
}
@Test
public void allPlayerContainersQueryDoesNotReturnDuplicatePlayers() {
db.executeTransaction(TestData.storeServers());
executeTransactions(TestData.storePlayerOneData());
executeTransactions(TestData.storePlayerTwoData());
List<UUID> expected = Arrays.asList(playerUUID, player2UUID);
Collections.sort(expected);
Collection<UUID> result = db.query(new AllPlayerContainersQuery())
.stream().map(player -> player.getUnsafe(PlayerKeys.UUID))
.sorted()
.collect(Collectors.toList());
assertEquals(expected, result);
}
// This test is against issue https://github.com/Rsl1122/Plan-PlayerAnalytics/issues/956
@Test
public void analysisContainerPlayerNamesAreCollectedFromBaseUsersCorrectly() {
db.executeTransaction(TestData.storeServers());
executeTransactions(TestData.storePlayerOneData());
executeTransactions(TestData.storePlayerTwoData());
BaseUser playerBaseUser = TestData.getPlayerBaseUser();
BaseUser player2BaseUser = TestData.getPlayer2BaseUser();
AnalysisContainer.Factory factory = constructAnalysisContainerFactory();
AnalysisContainer analysisContainer = factory.forServerContainer(
db.query(ContainerFetchQueries.fetchServerContainer(TestConstants.SERVER_UUID))
);
Map<UUID, String> expected = new HashMap<>();
expected.put(playerBaseUser.getUuid(), playerBaseUser.getName());
expected.put(player2BaseUser.getUuid(), player2BaseUser.getName());
Map<UUID, String> result = analysisContainer.getValue(AnalysisKeys.PLAYER_NAMES).orElseThrow(AssertionError::new);
assertEquals(expected, result);
}
}

View File

@ -26,10 +26,12 @@ import java.util.UUID;
public class TestConstants {
public static final UUID SERVER_UUID = UUID.fromString("e4ec2edd-e0ed-3c58-a87d-8a9021899479");
public static final UUID SERVER_TWO_UUID = UUID.fromString("c4ec2edd-e0ed-3c58-a87d-8a9024791899");
public static final UUID PLAYER_ONE_UUID = UUID.fromString("45b0dfdb-f71d-4cf3-8c21-27c9d4c651db");
public static final UUID PLAYER_TWO_UUID = UUID.fromString("ec94a954-1fa1-445b-b09b-9b698519af80");
public static final String PLAYER_ONE_NAME = "Test_Player_one";
public static final String PLAYER_TWO_NAME = "Test_Player_two";
public static final String WORLD_ONE_NAME = "World One";

View File

@ -0,0 +1,190 @@
/*
* 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 utilities;
import com.djrapitops.plan.data.container.BaseUser;
import com.djrapitops.plan.data.container.GeoInfo;
import com.djrapitops.plan.data.container.PlayerKill;
import com.djrapitops.plan.data.container.Session;
import com.djrapitops.plan.data.time.GMTimes;
import com.djrapitops.plan.db.access.transactions.StoreServerInformationTransaction;
import com.djrapitops.plan.db.access.transactions.Transaction;
import com.djrapitops.plan.db.access.transactions.events.*;
import com.djrapitops.plan.system.info.server.Server;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Class for saving test data to a database.
*
* @author Rsl1122
*/
public class TestData {
private static UUID playerUUID = TestConstants.PLAYER_ONE_UUID;
private static UUID player2UUID = TestConstants.PLAYER_TWO_UUID;
private static UUID serverUUID = TestConstants.SERVER_UUID;
private static UUID server2UUID = TestConstants.SERVER_TWO_UUID;
private static String playerName = TestConstants.PLAYER_ONE_NAME;
private static String player2Name = TestConstants.PLAYER_TWO_NAME;
private static String[] serverWorldNames = new String[]{
TestConstants.WORLD_ONE_NAME, "World Two", "world"
};
private static String[] server2WorldNames = new String[]{
"Foo", "Bar", "Z"
};
private static long playerFirstJoin = 1234500L;
private static long playerSecondJoin = 234000L;
private static List<Session> playerSessions = createSessionsForPlayer(playerUUID);
private static List<Session> player2Sessions = createSessionsForPlayer(player2UUID);
private static List<GeoInfo> playerGeoInfo = createGeoInfoForPlayer();
private static List<GeoInfo> createGeoInfoForPlayer() {
List<GeoInfo> geoInfos = new ArrayList<>();
try {
geoInfos.add(new GeoInfo(InetAddress.getByName("1.2.3.4"), "Not Known", playerFirstJoin));
geoInfos.add(new GeoInfo(InetAddress.getByName("43b9:416b:3cb2:649d:ebaf:872:d89a:343d"), "Not Known", playerFirstJoin));
geoInfos.add(new GeoInfo(InetAddress.getByName("127.0.0.1"), "Local Machine", playerFirstJoin));
geoInfos.add(new GeoInfo(InetAddress.getByName("181.103.227.78"), "Argentina", playerFirstJoin));
} catch (UnknownHostException | NoSuchAlgorithmException e) {
Logger.getGlobal().log(Level.WARNING, e, () -> "Failed to create GeoInfo");
}
return geoInfos;
}
private static List<Session> createSessionsForPlayer(UUID uuid) {
List<Session> sessions = new ArrayList<>();
String[] gms = GMTimes.getGMKeyArray();
Session sessionOne = new Session(uuid, serverUUID, playerFirstJoin, serverWorldNames[0], gms[0]);
UUID otherUUID = uuid.equals(playerUUID) ? player2UUID : playerUUID;
sessionOne.playerKilled(new PlayerKill(otherUUID, "Iron Sword", 1234750L));
sessionOne.playerKilled(new PlayerKill(otherUUID, "Gold Sword", 1234800L));
sessionOne.endSession(1235000L); // Length 500ms
sessions.add(sessionOne);
Session sessionTwo = new Session(uuid, server2UUID, playerSecondJoin, server2WorldNames[0], gms[1]);
sessionTwo.changeState(server2WorldNames[1], gms[0], 334000L); // Length 100s
sessionTwo.endSession(434000L); // Length 200s
sessions.add(sessionTwo);
return sessions;
}
public static Transaction storeServers() {
return new Transaction() {
@Override
protected void performOperations() {
executeOther(new StoreServerInformationTransaction(new Server(-1, serverUUID, "Server 1", "", 20)));
executeOther(new StoreServerInformationTransaction(new Server(-1, server2UUID, "Server 2", "", 50)));
for (String worldName : serverWorldNames) {
executeOther(new WorldNameStoreTransaction(serverUUID, worldName));
}
for (String worldName : server2WorldNames) {
executeOther(new WorldNameStoreTransaction(server2UUID, worldName));
}
}
};
}
public static Transaction[] storePlayerOneData() {
return new Transaction[]{
new PlayerRegisterTransaction(playerUUID, () -> playerFirstJoin, playerName),
new Transaction() {
@Override
protected void performOperations() {
executeOther(new PlayerServerRegisterTransaction(playerUUID, () -> playerFirstJoin, playerName, serverUUID));
executeOther(new PlayerServerRegisterTransaction(playerUUID, () -> playerSecondJoin, playerName, server2UUID));
for (GeoInfo geoInfo : playerGeoInfo) {
executeOther(new GeoInfoStoreTransaction(playerUUID, geoInfo));
}
for (Session session : playerSessions) {
executeOther(new SessionEndTransaction(session));
}
}
}
};
}
public static Transaction[] storePlayerTwoData() {
return new Transaction[]{
new PlayerRegisterTransaction(player2UUID, () -> playerFirstJoin, player2Name),
new Transaction() {
@Override
protected void performOperations() {
executeOther(new PlayerServerRegisterTransaction(player2UUID, () -> playerFirstJoin, player2Name, serverUUID));
executeOther(new PlayerServerRegisterTransaction(player2UUID, () -> playerSecondJoin, player2Name, server2UUID));
for (GeoInfo geoInfo : playerGeoInfo) {
executeOther(new GeoInfoStoreTransaction(player2UUID, geoInfo));
}
for (Session session : player2Sessions) {
executeOther(new SessionEndTransaction(session));
}
}
}
};
}
public static String[] getServerWorldNames() {
return serverWorldNames;
}
public static String[] getServer2WorldNames() {
return server2WorldNames;
}
public static List<Session> getPlayerSessions() {
return playerSessions;
}
public static List<Session> getPlayer2Sessions() {
return player2Sessions;
}
public static List<GeoInfo> getPlayerGeoInfo() {
return playerGeoInfo;
}
public static BaseUser getPlayerBaseUser() {
return new BaseUser(playerUUID, playerName, playerFirstJoin, 0);
}
public static BaseUser getPlayer2BaseUser() {
return new BaseUser(player2UUID, player2Name, playerFirstJoin, 0);
}
}

View File

@ -42,7 +42,7 @@ import java.io.InputStream;
@Plugin(
id = "plan",
name = "Plan",
version = "4.7.1",
version = "4.7.2",
description = "Player Analytics Plugin by Rsl1122",
authors = {"Rsl1122"},
dependencies = {

View File

@ -46,7 +46,7 @@ import java.nio.file.Path;
@Plugin(
id = "plan",
name = "Plan",
version = "4.7.1",
version = "4.7.2",
description = "Player Analytics Plugin by Rsl1122",
authors = {"Rsl1122"}
)

View File

@ -59,7 +59,7 @@ public class VelocityServerInfo extends ServerInfo {
}
@Override
public Server loadServerInfo() throws EnableException {
public void loadServerInfo() throws EnableException {
checkIfDefaultIP();
try {
@ -76,7 +76,6 @@ public class VelocityServerInfo extends ServerInfo {
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return server;
}
private void updateServerInfo(Database db) {

View File

@ -180,7 +180,7 @@
<dependency>
<groupId>io.github.nucleuspowered</groupId>
<artifactId>nucleus-api</artifactId>
<version>1.9.0-S7.1</version>
<version>1.9.1-S7.1</version>
<scope>provided</scope>
</dependency>
<dependency> <!-- Maven Central -->