mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2024-06-26 14:44:45 +02:00
Store join addresses separately and link to plan_sessions table for time data.
Affects issues: - #2362
This commit is contained in:
parent
a97489ecd2
commit
52b8afe6cb
|
@ -25,6 +25,7 @@ import com.djrapitops.plan.extension.ExtensionSvc;
|
|||
import com.djrapitops.plan.gathering.cache.NicknameCache;
|
||||
import com.djrapitops.plan.gathering.cache.SessionCache;
|
||||
import com.djrapitops.plan.gathering.domain.ActiveSession;
|
||||
import com.djrapitops.plan.gathering.domain.event.JoinAddress;
|
||||
import com.djrapitops.plan.gathering.geolocation.GeolocationCache;
|
||||
import com.djrapitops.plan.gathering.listeners.Status;
|
||||
import com.djrapitops.plan.identification.ServerInfo;
|
||||
|
@ -114,7 +115,9 @@ public class PlayerOnlineListener implements Listener {
|
|||
boolean banned = result == PlayerLoginEvent.Result.KICK_BANNED;
|
||||
String joinAddress = event.getHostname();
|
||||
if (!joinAddress.isEmpty()) {
|
||||
joinAddresses.put(playerUUID, joinAddress.substring(0, joinAddress.lastIndexOf(':')));
|
||||
joinAddress = joinAddress.substring(0, joinAddress.lastIndexOf(':'));
|
||||
joinAddresses.put(playerUUID, joinAddress);
|
||||
dbSystem.getDatabase().executeTransaction(new StoreJoinAddressTransaction(joinAddress));
|
||||
}
|
||||
dbSystem.getDatabase().executeTransaction(new BanStatusTransaction(playerUUID, serverUUID, () -> banned));
|
||||
} catch (Exception e) {
|
||||
|
@ -166,7 +169,7 @@ public class PlayerOnlineListener implements Listener {
|
|||
BukkitAFKListener.afkTracker.performedAction(playerUUID, time);
|
||||
|
||||
String world = player.getWorld().getName();
|
||||
String gm = Optional.ofNullable(player.getGameMode()).map(gameMode -> gameMode.name()).orElse("Unknown");
|
||||
String gm = Optional.ofNullable(player.getGameMode()).map(Enum::name).orElse("Unknown");
|
||||
|
||||
Database database = dbSystem.getDatabase();
|
||||
database.executeTransaction(new WorldNameStoreTransaction(serverUUID, world));
|
||||
|
@ -192,8 +195,10 @@ public class PlayerOnlineListener implements Listener {
|
|||
ActiveSession session = new ActiveSession(playerUUID, serverUUID, time, world, gm);
|
||||
session.getExtraData().put(PlayerName.class, new PlayerName(playerName));
|
||||
session.getExtraData().put(ServerName.class, new ServerName(serverInfo.getServer().getIdentifiableName()));
|
||||
session.getExtraData().put(JoinAddress.class, new JoinAddress(getHostName));
|
||||
sessionCache.cacheSession(playerUUID, session)
|
||||
.ifPresent(previousSession -> database.executeTransaction(new SessionEndTransaction(previousSession)));
|
||||
.map(SessionEndTransaction::new)
|
||||
.ifPresent(database::executeTransaction);
|
||||
|
||||
database.executeTransaction(new NicknameStoreTransaction(
|
||||
playerUUID, new Nickname(displayName, time, serverUUID),
|
||||
|
|
|
@ -48,7 +48,6 @@ public class PerServerContainer extends HashMap<ServerUUID, DataContainer> {
|
|||
putToContainerOfServer(serverUUID, PerServerKeys.REGISTERED, userInfo.getRegistered());
|
||||
putToContainerOfServer(serverUUID, PerServerKeys.BANNED, userInfo.isBanned());
|
||||
putToContainerOfServer(serverUUID, PerServerKeys.OPERATOR, userInfo.isOperator());
|
||||
putToContainerOfServer(serverUUID, PerServerKeys.JOIN_ADDRESS, userInfo.getJoinAddress());
|
||||
}
|
||||
|
||||
public void putUserInfo(Collection<UserInfo> userInformation) {
|
||||
|
|
|
@ -27,6 +27,7 @@ import com.djrapitops.plan.delivery.rendering.html.Html;
|
|||
import com.djrapitops.plan.delivery.rendering.json.graphs.Graphs;
|
||||
import com.djrapitops.plan.delivery.rendering.json.graphs.pie.WorldPie;
|
||||
import com.djrapitops.plan.gathering.domain.*;
|
||||
import com.djrapitops.plan.gathering.domain.event.JoinAddress;
|
||||
import com.djrapitops.plan.identification.ServerUUID;
|
||||
import com.djrapitops.plan.settings.config.WorldAliasSettings;
|
||||
import com.djrapitops.plan.utilities.analysis.Median;
|
||||
|
@ -289,6 +290,8 @@ public class SessionsMutator {
|
|||
WorldPie worldPie = graphs.pie().worldPie(session.getExtraData(WorldTimes.class).orElseGet(WorldTimes::new));
|
||||
sessionMap.put("world_series", worldPie.getSlices());
|
||||
sessionMap.put("gm_series", worldPie.toHighChartsDrillDownMaps());
|
||||
sessionMap.put("join_address", session.getExtraData(JoinAddress.class)
|
||||
.map(JoinAddress::getAddress).orElse("-"));
|
||||
|
||||
session.getExtraData(AveragePing.class).ifPresent(averagePing ->
|
||||
sessionMap.put("avg_ping", formatters.decimals().apply(averagePing.getValue()) + " ms")
|
||||
|
|
|
@ -50,6 +50,7 @@ import com.djrapitops.plan.storage.database.queries.analysis.ActivityIndexQuerie
|
|||
import com.djrapitops.plan.storage.database.queries.analysis.NetworkActivityIndexQueries;
|
||||
import com.djrapitops.plan.storage.database.queries.analysis.PlayerCountQueries;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.*;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.JoinAddressTable;
|
||||
import com.djrapitops.plan.utilities.java.Lists;
|
||||
import com.djrapitops.plan.utilities.java.Maps;
|
||||
import net.playeranalytics.plugin.scheduling.TimeAmount;
|
||||
|
@ -123,7 +124,7 @@ public class GraphJSONCreator {
|
|||
}
|
||||
|
||||
public Map<String, Object> optimizedPerformanceGraphJSON(ServerUUID serverUUID, URIQuery query) {
|
||||
long after = getAfter(query); // TODO Implement if performance issues become apparent.
|
||||
// long after = getAfter(query); // TODO Implement if performance issues become apparent.
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
long twoMonthsAgo = now - TimeUnit.DAYS.toMillis(60);
|
||||
|
@ -438,7 +439,7 @@ public class GraphJSONCreator {
|
|||
|
||||
public Map<String, Object> playerHostnamePieJSONAsMap() {
|
||||
String[] pieColors = theme.getPieColors(ThemeVal.GRAPH_WORLD_PIE);
|
||||
Map<String, Integer> joinAddresses = dbSystem.getDatabase().query(UserInfoQueries.joinAddresses());
|
||||
Map<String, Integer> joinAddresses = dbSystem.getDatabase().query(JoinAddressQueries.latestJoinAddresses());
|
||||
|
||||
translateUnknown(joinAddresses);
|
||||
|
||||
|
@ -450,7 +451,7 @@ public class GraphJSONCreator {
|
|||
|
||||
public Map<String, Object> playerHostnamePieJSONAsMap(ServerUUID serverUUID) {
|
||||
String[] pieColors = theme.getPieColors(ThemeVal.GRAPH_WORLD_PIE);
|
||||
Map<String, Integer> joinAddresses = dbSystem.getDatabase().query(UserInfoQueries.joinAddresses(serverUUID));
|
||||
Map<String, Integer> joinAddresses = dbSystem.getDatabase().query(JoinAddressQueries.latestJoinAddresses(serverUUID));
|
||||
|
||||
translateUnknown(joinAddresses);
|
||||
|
||||
|
@ -461,9 +462,9 @@ public class GraphJSONCreator {
|
|||
}
|
||||
|
||||
public void translateUnknown(Map<String, Integer> joinAddresses) {
|
||||
Integer unknown = joinAddresses.get("unknown");
|
||||
Integer unknown = joinAddresses.get(JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP);
|
||||
if (unknown != null) {
|
||||
joinAddresses.remove("unknown");
|
||||
joinAddresses.remove(JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP);
|
||||
joinAddresses.put(locale.getString(GenericLang.UNKNOWN).toLowerCase(), unknown);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -151,6 +151,7 @@ public class DBOpException extends IllegalStateException implements ExceptionWit
|
|||
public boolean isUserIdConstraintViolation() {
|
||||
return context != null
|
||||
&& context.getRelated().contains(DBOpException.CONSTRAINT_VIOLATION)
|
||||
&& getMessage().contains("user_id");
|
||||
&& getCause() != null
|
||||
&& getCause().getMessage().contains("user_id");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,9 @@ public class DataMap {
|
|||
return Optional.ofNullable(ofType.cast(data.get(ofType.getName())));
|
||||
}
|
||||
|
||||
public void remove(Class<?> ofType) {
|
||||
data.remove(ofType.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
package com.djrapitops.plan.gathering.domain;
|
||||
|
||||
import com.djrapitops.plan.delivery.domain.DateHolder;
|
||||
import com.djrapitops.plan.gathering.domain.event.JoinAddress;
|
||||
import com.djrapitops.plan.identification.ServerUUID;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.JoinAddressTable;
|
||||
import com.google.gson.Gson;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
|
@ -47,7 +49,7 @@ public class FinishedSession implements DateHolder {
|
|||
this.start = start;
|
||||
this.end = end;
|
||||
this.afkTime = afkTime;
|
||||
this.extraData = extraData;
|
||||
this.extraData = extraData != null ? extraData : new DataMap();
|
||||
}
|
||||
|
||||
public UUID getPlayerUUID() {
|
||||
|
@ -113,50 +115,6 @@ public class FinishedSession implements DateHolder {
|
|||
return getStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
FinishedSession that = (FinishedSession) o;
|
||||
return start == that.start && end == that.end &&
|
||||
afkTime == that.afkTime &&
|
||||
Objects.equals(playerUUID, that.playerUUID) &&
|
||||
Objects.equals(serverUUID, that.serverUUID) &&
|
||||
Objects.equals(getExtraData(WorldTimes.class), that.getExtraData(WorldTimes.class)) &&
|
||||
Objects.equals(getExtraData(PlayerKills.class), that.getExtraData(PlayerKills.class)) &&
|
||||
Objects.equals(getExtraData(MobKillCounter.class), that.getExtraData(MobKillCounter.class)) &&
|
||||
Objects.equals(getExtraData(DeathCounter.class), that.getExtraData(DeathCounter.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(playerUUID, serverUUID, start, end, afkTime, extraData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FinishedSession{" +
|
||||
"playerUUID=" + playerUUID +
|
||||
", serverUUID=" + serverUUID +
|
||||
", start=" + start +
|
||||
", end=" + end +
|
||||
", afkTime=" + afkTime +
|
||||
", extraData=" + extraData +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static class Id {
|
||||
private final int value;
|
||||
|
||||
public Id(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int get() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize csv format of the session.
|
||||
*
|
||||
|
@ -182,9 +140,43 @@ public class FinishedSession implements DateHolder {
|
|||
extraData.put(PlayerKills.class, gson.fromJson(asArray[6], PlayerKills.class));
|
||||
extraData.put(MobKillCounter.class, gson.fromJson(asArray[7], MobKillCounter.class));
|
||||
extraData.put(DeathCounter.class, gson.fromJson(asArray[8], DeathCounter.class));
|
||||
extraData.put(JoinAddress.class, new JoinAddress(asArray[9]));
|
||||
return Optional.of(new FinishedSession(playerUUID, serverUUID, start, end, afkTime, extraData));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(playerUUID, serverUUID, start, end, afkTime, extraData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FinishedSession{" +
|
||||
"playerUUID=" + playerUUID +
|
||||
", serverUUID=" + serverUUID +
|
||||
", start=" + start +
|
||||
", end=" + end +
|
||||
", afkTime=" + afkTime +
|
||||
", extraData=" + extraData +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
FinishedSession that = (FinishedSession) o;
|
||||
return start == that.start && end == that.end &&
|
||||
afkTime == that.afkTime &&
|
||||
Objects.equals(playerUUID, that.playerUUID) &&
|
||||
Objects.equals(serverUUID, that.serverUUID) &&
|
||||
Objects.equals(getExtraData(WorldTimes.class), that.getExtraData(WorldTimes.class)) &&
|
||||
Objects.equals(getExtraData(PlayerKills.class), that.getExtraData(PlayerKills.class)) &&
|
||||
Objects.equals(getExtraData(MobKillCounter.class), that.getExtraData(MobKillCounter.class)) &&
|
||||
Objects.equals(getExtraData(DeathCounter.class), that.getExtraData(DeathCounter.class)) &&
|
||||
Objects.equals(getExtraData(JoinAddress.class), that.getExtraData(JoinAddress.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize into csv format.
|
||||
*
|
||||
|
@ -199,6 +191,19 @@ public class FinishedSession implements DateHolder {
|
|||
getExtraData(WorldTimes.class).orElseGet(WorldTimes::new).toJson() + ';' +
|
||||
getExtraData(PlayerKills.class).orElseGet(PlayerKills::new).toJson() + ';' +
|
||||
getExtraData(MobKillCounter.class).orElseGet(MobKillCounter::new).toJson() + ';' +
|
||||
getExtraData(DeathCounter.class).orElseGet(DeathCounter::new).toJson();
|
||||
getExtraData(DeathCounter.class).orElseGet(DeathCounter::new).toJson() + ';' +
|
||||
getExtraData(JoinAddress.class).orElseGet(() -> new JoinAddress(JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP)).getAddress();
|
||||
}
|
||||
|
||||
public static class Id {
|
||||
private final int value;
|
||||
|
||||
public Id(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int get() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,6 +55,10 @@ public class UserInfo {
|
|||
return serverUUID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Join address is now stored in {@link FinishedSession#getExtraData()}, this method may become unreliable in the future.
|
||||
*/
|
||||
@Deprecated
|
||||
public String getJoinAddress() {
|
||||
return joinAddress;
|
||||
}
|
||||
|
|
|
@ -16,21 +16,41 @@
|
|||
*/
|
||||
package com.djrapitops.plan.gathering.domain.event;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class JoinAddress {
|
||||
private final String address;
|
||||
private final Supplier<String> address;
|
||||
|
||||
public JoinAddress(String address) {
|
||||
this(() -> address);
|
||||
}
|
||||
|
||||
public JoinAddress(Supplier<String> address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
return address.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "JoinAddress{" +
|
||||
"address='" + address + '\'' +
|
||||
"address='" + address.get() + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
JoinAddress that = (JoinAddress) o;
|
||||
return Objects.equals(getAddress(), that.getAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getAddress());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,9 +76,7 @@ public class DataPipelineModule {
|
|||
service.pull(ActiveSession.class, uuid)
|
||||
.map(ActiveSession::getExtraData)
|
||||
.flatMap(extra -> extra.get(PlayerKills.class)))
|
||||
.registerSink(UUID.class, MobKill.class, (uuid, kill) -> {
|
||||
service.pull(MobKillCounter.class, uuid).ifPresent(Counter::add);
|
||||
})
|
||||
.registerSink(UUID.class, MobKill.class, (uuid, kill) -> service.pull(MobKillCounter.class, uuid).ifPresent(Counter::add))
|
||||
.registerSink(UUID.class, PlayerKill.class, (uuid, kill) -> {
|
||||
service.pull(PlayerKills.class, kill.getKiller().getUuid()).ifPresent(playerKills -> playerKills.add(kill));
|
||||
service.pull(DeathCounter.class, kill.getVictim().getUuid()).ifPresent(Counter::add);
|
||||
|
@ -91,7 +89,7 @@ public class DataPipelineModule {
|
|||
DataService.Pipeline playerLeaveToSession(SessionCache sessionCache) {
|
||||
return service -> service
|
||||
.registerOptionalMapper(UUID.class, PlayerLeave.class, FinishedSession.class, sessionCache::endSession)
|
||||
.registerDatabaseSink(UUID.class, FinishedSession.class, SessionEndTransaction::new);
|
||||
.registerDatabaseSink(UUID.class, FinishedSession.class, (playerUUID, session) -> new SessionEndTransaction(session));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -225,7 +225,8 @@ public abstract class SQLDB extends AbstractDatabase {
|
|||
new SessionsOptimizationPatch(),
|
||||
new UserInfoHostnameAllowNullPatch(),
|
||||
new RegisterDateMinimizationPatch(),
|
||||
new UsersTableNameLengthPatch()
|
||||
new UsersTableNameLengthPatch(),
|
||||
new SessionJoinAddressPatch()
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ package com.djrapitops.plan.storage.database.queries;
|
|||
|
||||
import com.djrapitops.plan.delivery.domain.Nickname;
|
||||
import com.djrapitops.plan.gathering.domain.*;
|
||||
import com.djrapitops.plan.gathering.domain.event.JoinAddress;
|
||||
import com.djrapitops.plan.identification.ServerUUID;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.*;
|
||||
import com.djrapitops.plan.storage.database.transactions.ExecBatchStatement;
|
||||
|
@ -68,6 +69,8 @@ public class DataStoreQueries {
|
|||
statement.setInt(5, session.getMobKillCount());
|
||||
statement.setLong(6, session.getAfkTime());
|
||||
statement.setString(7, session.getServerUUID().toString());
|
||||
statement.setString(8, session.getExtraData(JoinAddress.class)
|
||||
.map(JoinAddress::getAddress).orElse(JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -19,9 +19,12 @@ package com.djrapitops.plan.storage.database.queries;
|
|||
import com.djrapitops.plan.delivery.domain.Nickname;
|
||||
import com.djrapitops.plan.delivery.domain.World;
|
||||
import com.djrapitops.plan.delivery.domain.auth.User;
|
||||
import com.djrapitops.plan.exceptions.database.DBOpException;
|
||||
import com.djrapitops.plan.gathering.domain.*;
|
||||
import com.djrapitops.plan.gathering.domain.event.JoinAddress;
|
||||
import com.djrapitops.plan.identification.Server;
|
||||
import com.djrapitops.plan.identification.ServerUUID;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.JoinAddressQueries;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.WorldTimesQueries;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.*;
|
||||
import com.djrapitops.plan.storage.database.transactions.ExecBatchStatement;
|
||||
|
@ -285,6 +288,8 @@ public class LargeStoreQueries {
|
|||
statement.setInt(5, session.getMobKillCount());
|
||||
statement.setLong(6, session.getAfkTime());
|
||||
statement.setString(7, session.getServerUUID().toString());
|
||||
statement.setString(8, session.getExtraData(JoinAddress.class)
|
||||
.map(JoinAddress::getAddress).orElse(JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP));
|
||||
statement.addBatch();
|
||||
}
|
||||
}
|
||||
|
@ -294,6 +299,8 @@ public class LargeStoreQueries {
|
|||
public static Executable storeAllSessionsWithKillAndWorldData(Collection<FinishedSession> sessions) {
|
||||
return connection -> {
|
||||
Set<World> existingWorlds = WorldTimesQueries.fetchWorlds().executeWithConnection(connection);
|
||||
List<String> existingJoinAddresses = JoinAddressQueries.allJoinAddresses().executeWithConnection(connection);
|
||||
storeAllJoinAddresses(sessions, existingJoinAddresses).execute(connection);
|
||||
storeAllWorldNames(sessions, existingWorlds).execute(connection);
|
||||
storeAllSessionsWithoutKillOrWorldData(sessions).execute(connection);
|
||||
storeSessionKillData(sessions).execute(connection);
|
||||
|
@ -301,16 +308,41 @@ public class LargeStoreQueries {
|
|||
};
|
||||
}
|
||||
|
||||
private static Executable storeAllJoinAddresses(Collection<FinishedSession> sessions, List<String> existingJoinAddresses) {
|
||||
return new ExecBatchStatement(JoinAddressTable.INSERT_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) {
|
||||
sessions.stream()
|
||||
.map(FinishedSession::getExtraData)
|
||||
.map(extraData -> extraData.get(JoinAddress.class))
|
||||
.filter(Optional::isPresent)
|
||||
.map(Optional::get)
|
||||
.map(JoinAddress::getAddress)
|
||||
.map(String::toLowerCase)
|
||||
.filter(address -> !existingJoinAddresses.contains(address))
|
||||
.distinct()
|
||||
.forEach(address -> {
|
||||
try {
|
||||
statement.setString(1, address);
|
||||
statement.addBatch();
|
||||
} catch (SQLException e) {
|
||||
throw DBOpException.forCause(JoinAddressTable.INSERT_STATEMENT, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static Executable storeAllWorldNames(Collection<FinishedSession> sessions, Set<World> existingWorlds) {
|
||||
Set<World> worlds = sessions.stream().flatMap(session -> {
|
||||
ServerUUID serverUUID = session.getServerUUID();
|
||||
return session.getExtraData(WorldTimes.class)
|
||||
.map(WorldTimes::getWorldTimes)
|
||||
.map(Map::keySet)
|
||||
.orElseGet(Collections::emptySet)
|
||||
.stream()
|
||||
.map(worldName -> new World(worldName, serverUUID));
|
||||
}).filter(world -> !existingWorlds.contains(world))
|
||||
ServerUUID serverUUID = session.getServerUUID();
|
||||
return session.getExtraData(WorldTimes.class)
|
||||
.map(WorldTimes::getWorldTimes)
|
||||
.map(Map::keySet)
|
||||
.orElseGet(Collections::emptySet)
|
||||
.stream()
|
||||
.map(worldName -> new World(worldName, serverUUID));
|
||||
}).filter(world -> !existingWorlds.contains(world))
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (worlds.isEmpty()) return Executable.empty();
|
||||
|
|
|
@ -23,6 +23,7 @@ import com.djrapitops.plan.delivery.domain.keys.Key;
|
|||
import com.djrapitops.plan.delivery.domain.keys.PerServerKeys;
|
||||
import com.djrapitops.plan.gathering.domain.FinishedSession;
|
||||
import com.djrapitops.plan.gathering.domain.UserInfo;
|
||||
import com.djrapitops.plan.gathering.domain.event.JoinAddress;
|
||||
import com.djrapitops.plan.identification.ServerUUID;
|
||||
import com.djrapitops.plan.storage.database.SQLDB;
|
||||
import com.djrapitops.plan.storage.database.queries.PerServerAggregateQueries;
|
||||
|
@ -64,6 +65,12 @@ public class PerServerContainerQuery implements Query<PerServerContainer> {
|
|||
for (Map.Entry<ServerUUID, List<FinishedSession>> entry : sessions.entrySet()) {
|
||||
ServerUUID serverUUID = entry.getKey();
|
||||
List<FinishedSession> serverSessions = entry.getValue();
|
||||
if (!serverSessions.isEmpty()) {
|
||||
serverSessions.get(0).getExtraData().get(JoinAddress.class).map(JoinAddress::getAddress)
|
||||
.ifPresent(address ->
|
||||
perServerContainer.putToContainerOfServer(serverUUID, PerServerKeys.JOIN_ADDRESS, address)
|
||||
);
|
||||
}
|
||||
|
||||
DataContainer serverContainer = perServerContainer.getOrDefault(serverUUID, new SupplierDataContainer());
|
||||
serverContainer.putRawData(PerServerKeys.SESSIONS, serverSessions);
|
||||
|
|
|
@ -18,7 +18,7 @@ package com.djrapitops.plan.storage.database.queries.filter.filters;
|
|||
|
||||
import com.djrapitops.plan.delivery.domain.datatransfer.InputFilterDto;
|
||||
import com.djrapitops.plan.storage.database.DBSystem;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.UserInfoQueries;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.JoinAddressQueries;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
@ -46,11 +46,11 @@ public class JoinAddressFilter extends MultiOptionFilter {
|
|||
}
|
||||
|
||||
private List<String> getSelectionOptions() {
|
||||
return dbSystem.getDatabase().query(UserInfoQueries.uniqueJoinAddresses());
|
||||
return dbSystem.getDatabase().query(JoinAddressQueries.uniqueJoinAddresses());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Integer> getMatchingUserIds(InputFilterDto query) {
|
||||
return dbSystem.getDatabase().query(UserInfoQueries.userIdsOfPlayersWithJoinAddresses(getSelected(query)));
|
||||
return dbSystem.getDatabase().query(JoinAddressQueries.userIdsOfPlayersWithJoinAddresses(getSelected(query)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* 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.objects;
|
||||
|
||||
import com.djrapitops.plan.identification.ServerUUID;
|
||||
import com.djrapitops.plan.storage.database.queries.Query;
|
||||
import com.djrapitops.plan.storage.database.queries.QueryAllStatement;
|
||||
import com.djrapitops.plan.storage.database.queries.QueryStatement;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.JoinAddressTable;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.ServerTable;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.SessionsTable;
|
||||
import org.apache.commons.text.TextStringBuilder;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
|
||||
import static com.djrapitops.plan.storage.database.sql.building.Sql.*;
|
||||
|
||||
public class JoinAddressQueries {
|
||||
|
||||
private JoinAddressQueries() {
|
||||
/* Static method class */
|
||||
}
|
||||
|
||||
public static Query<Map<String, Integer>> latestJoinAddresses() {
|
||||
String selectLatestJoinAddresses = SELECT +
|
||||
"COUNT(1) as total," +
|
||||
JoinAddressTable.JOIN_ADDRESS +
|
||||
FROM + SessionsTable.TABLE_NAME + " a" +
|
||||
LEFT_JOIN + SessionsTable.TABLE_NAME + " b on a." + SessionsTable.ID + "<b." + SessionsTable.ID +
|
||||
AND + "a." + SessionsTable.USER_ID + "=b." + SessionsTable.USER_ID +
|
||||
INNER_JOIN + JoinAddressTable.TABLE_NAME + " j on j." + JoinAddressTable.ID + "=a." + SessionsTable.JOIN_ADDRESS_ID +
|
||||
WHERE + "b." + SessionsTable.ID + IS_NULL +
|
||||
GROUP_BY + JoinAddressTable.JOIN_ADDRESS +
|
||||
ORDER_BY + JoinAddressTable.JOIN_ADDRESS + " ASC";
|
||||
|
||||
return new QueryAllStatement<Map<String, Integer>>(selectLatestJoinAddresses, 100) {
|
||||
@Override
|
||||
public Map<String, Integer> processResults(ResultSet set) throws SQLException {
|
||||
Map<String, Integer> joinAddresses = new TreeMap<>();
|
||||
while (set.next()) {
|
||||
joinAddresses.put(set.getString(JoinAddressTable.JOIN_ADDRESS), set.getInt("total"));
|
||||
}
|
||||
return joinAddresses;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Query<Map<String, Integer>> latestJoinAddresses(ServerUUID serverUUID) {
|
||||
String selectLatestJoinAddresses = SELECT +
|
||||
"COUNT(1) as total," +
|
||||
JoinAddressTable.JOIN_ADDRESS +
|
||||
FROM + SessionsTable.TABLE_NAME + " a" +
|
||||
LEFT_JOIN + SessionsTable.TABLE_NAME + " b on a." + SessionsTable.ID + "<b." + SessionsTable.ID +
|
||||
AND + "a." + SessionsTable.USER_ID + "=b." + SessionsTable.USER_ID +
|
||||
AND + "a." + SessionsTable.SERVER_ID + "=b." + SessionsTable.SERVER_ID +
|
||||
INNER_JOIN + JoinAddressTable.TABLE_NAME + " j on j." + JoinAddressTable.ID + "=a." + SessionsTable.JOIN_ADDRESS_ID +
|
||||
WHERE + "b." + SessionsTable.ID + IS_NULL +
|
||||
AND + "a." + SessionsTable.SERVER_ID + "=" + ServerTable.SELECT_SERVER_ID +
|
||||
GROUP_BY + JoinAddressTable.JOIN_ADDRESS +
|
||||
ORDER_BY + JoinAddressTable.JOIN_ADDRESS + " ASC";
|
||||
|
||||
return new QueryStatement<Map<String, Integer>>(selectLatestJoinAddresses, 100) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, serverUUID.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Integer> processResults(ResultSet set) throws SQLException {
|
||||
Map<String, Integer> joinAddresses = new TreeMap<>();
|
||||
while (set.next()) {
|
||||
joinAddresses.put(set.getString(JoinAddressTable.JOIN_ADDRESS), set.getInt("total"));
|
||||
}
|
||||
return joinAddresses;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static QueryStatement<List<String>> allJoinAddresses() {
|
||||
String sql = SELECT + JoinAddressTable.JOIN_ADDRESS +
|
||||
FROM + JoinAddressTable.TABLE_NAME +
|
||||
ORDER_BY + JoinAddressTable.JOIN_ADDRESS + " ASC";
|
||||
return new QueryAllStatement<List<String>>(sql, 100) {
|
||||
@Override
|
||||
public List<String> processResults(ResultSet set) throws SQLException {
|
||||
List<String> joinAddresses = new ArrayList<>();
|
||||
while (set.next()) joinAddresses.add(set.getString(JoinAddressTable.JOIN_ADDRESS));
|
||||
return joinAddresses;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Query<List<String>> uniqueJoinAddresses() {
|
||||
return db -> {
|
||||
List<String> addresses = db.query(allJoinAddresses());
|
||||
if (!addresses.contains(JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP)) {
|
||||
addresses.add(JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP);
|
||||
}
|
||||
return addresses;
|
||||
};
|
||||
}
|
||||
|
||||
public static Query<Set<Integer>> userIdsOfPlayersWithJoinAddresses(List<String> joinAddresses) {
|
||||
String sql = SELECT + DISTINCT + SessionsTable.USER_ID +
|
||||
FROM + JoinAddressTable.TABLE_NAME + " j" +
|
||||
INNER_JOIN + SessionsTable.TABLE_NAME + " s on s." + SessionsTable.JOIN_ADDRESS_ID + "=j." + JoinAddressTable.ID +
|
||||
WHERE + JoinAddressTable.JOIN_ADDRESS + " IN (" +
|
||||
new TextStringBuilder().appendWithSeparators(joinAddresses.stream().map(item -> '?').iterator(), ",") +
|
||||
')'; // Don't append addresses directly, SQL injection hazard
|
||||
|
||||
return new QueryStatement<Set<Integer>>(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
for (int i = 0; i < joinAddresses.size(); i++) {
|
||||
statement.setString(i + 1, joinAddresses.get(i).toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Integer> processResults(ResultSet set) throws SQLException {
|
||||
return UserInfoQueries.extractUserIds(set, SessionsTable.USER_ID);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -22,6 +22,7 @@ import com.djrapitops.plan.delivery.domain.ServerIdentifier;
|
|||
import com.djrapitops.plan.delivery.domain.ServerName;
|
||||
import com.djrapitops.plan.delivery.domain.mutators.SessionsMutator;
|
||||
import com.djrapitops.plan.gathering.domain.*;
|
||||
import com.djrapitops.plan.gathering.domain.event.JoinAddress;
|
||||
import com.djrapitops.plan.identification.Server;
|
||||
import com.djrapitops.plan.identification.ServerUUID;
|
||||
import com.djrapitops.plan.storage.database.queries.Query;
|
||||
|
@ -70,6 +71,7 @@ public class SessionQueries {
|
|||
WorldTimesTable.ADVENTURE + ',' +
|
||||
WorldTimesTable.SPECTATOR + ',' +
|
||||
WorldTable.NAME + ',' +
|
||||
"j." + JoinAddressTable.JOIN_ADDRESS + " as join_address," +
|
||||
KillsTable.KILLER_UUID + ',' +
|
||||
KillsTable.VICTIM_UUID + ',' +
|
||||
"v." + UsersTable.USER_NAME + " as victim_name, " +
|
||||
|
@ -77,6 +79,7 @@ public class SessionQueries {
|
|||
KillsTable.DATE + ',' +
|
||||
KillsTable.WEAPON +
|
||||
FROM + SessionsTable.TABLE_NAME + " s" +
|
||||
INNER_JOIN + JoinAddressTable.TABLE_NAME + " j on s." + SessionsTable.JOIN_ADDRESS_ID + "=j." + JoinAddressTable.ID +
|
||||
INNER_JOIN + UsersTable.TABLE_NAME + " u on u." + UsersTable.ID + "=s." + SessionsTable.USER_ID +
|
||||
INNER_JOIN + ServerTable.TABLE_NAME + " server on server." + ServerTable.ID + "=s." + SessionsTable.SERVER_ID +
|
||||
LEFT_JOIN + UserInfoTable.TABLE_NAME + " u_info on (u_info." + UserInfoTable.USER_ID + "=s." + SessionsTable.USER_ID + AND + "u_info." + UserInfoTable.SERVER_ID + "=s." + SessionsTable.SERVER_ID + ')' +
|
||||
|
@ -114,7 +117,7 @@ public class SessionQueries {
|
|||
String sql = SELECT_SESSIONS_STATEMENT +
|
||||
WHERE + "s." + SessionsTable.USER_ID + "=" + UsersTable.SELECT_USER_ID +
|
||||
ORDER_BY_SESSION_START_DESC;
|
||||
return new QueryStatement<Map<ServerUUID, List<FinishedSession>>>(sql, 50000) {
|
||||
return new QueryStatement<Map<ServerUUID, List<FinishedSession>>>(sql, 1000) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, playerUUID.toString());
|
||||
|
@ -159,6 +162,7 @@ public class SessionQueries {
|
|||
extraData.put(FinishedSession.Id.class, new FinishedSession.Id(set.getInt(SessionsTable.ID)));
|
||||
extraData.put(MobKillCounter.class, new MobKillCounter(set.getInt(SessionsTable.MOB_KILLS)));
|
||||
extraData.put(DeathCounter.class, new DeathCounter(set.getInt(SessionsTable.DEATHS)));
|
||||
extraData.put(JoinAddress.class, new JoinAddress(set.getString("join_address")));
|
||||
|
||||
Optional<WorldTimes> existingWorldTimes = extraData.get(WorldTimes.class);
|
||||
Optional<PlayerKills> existingPlayerKills = extraData.get(PlayerKills.class);
|
||||
|
|
|
@ -158,82 +158,6 @@ public class UserInfoQueries {
|
|||
};
|
||||
}
|
||||
|
||||
public static Query<Map<String, Integer>> joinAddresses() {
|
||||
String sql = SELECT +
|
||||
"COUNT(1) as total," +
|
||||
"LOWER(COALESCE(" + UserInfoTable.JOIN_ADDRESS + ", ?)) as address" +
|
||||
FROM + '(' +
|
||||
SELECT + DISTINCT +
|
||||
UserInfoTable.USER_ID + ',' +
|
||||
UserInfoTable.JOIN_ADDRESS +
|
||||
FROM + UserInfoTable.TABLE_NAME +
|
||||
") q1" +
|
||||
GROUP_BY + "address" +
|
||||
ORDER_BY + "address ASC";
|
||||
|
||||
return new QueryStatement<Map<String, Integer>>(sql, 100) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, "Unknown");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Integer> processResults(ResultSet set) throws SQLException {
|
||||
Map<String, Integer> joinAddresses = new TreeMap<>();
|
||||
while (set.next()) {
|
||||
joinAddresses.put(set.getString("address"), set.getInt("total"));
|
||||
}
|
||||
return joinAddresses;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Query<Map<String, Integer>> joinAddresses(ServerUUID serverUUID) {
|
||||
String sql = SELECT +
|
||||
"COUNT(1) as total," +
|
||||
"LOWER(COALESCE(" + UserInfoTable.JOIN_ADDRESS + ", ?)) as address" +
|
||||
FROM + UserInfoTable.TABLE_NAME +
|
||||
WHERE + UserInfoTable.SERVER_ID + "=" + ServerTable.SELECT_SERVER_ID +
|
||||
GROUP_BY + "address" +
|
||||
ORDER_BY + "address ASC";
|
||||
|
||||
return new QueryStatement<Map<String, Integer>>(sql, 100) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, "Unknown");
|
||||
statement.setString(2, serverUUID.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Integer> processResults(ResultSet set) throws SQLException {
|
||||
Map<String, Integer> joinAddresses = new TreeMap<>();
|
||||
while (set.next()) {
|
||||
joinAddresses.put(set.getString("address"), set.getInt("total"));
|
||||
}
|
||||
return joinAddresses;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Query<List<String>> uniqueJoinAddresses() {
|
||||
String sql = SELECT + DISTINCT + "LOWER(COALESCE(" + UserInfoTable.JOIN_ADDRESS + ", ?)) as address" +
|
||||
FROM + UserInfoTable.TABLE_NAME +
|
||||
ORDER_BY + "address ASC";
|
||||
return new QueryStatement<List<String>>(sql, 100) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, "unknown");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> processResults(ResultSet set) throws SQLException {
|
||||
List<String> joinAddresses = new ArrayList<>();
|
||||
while (set.next()) joinAddresses.add(set.getString("address"));
|
||||
return joinAddresses;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Query<Set<Integer>> userIdsOfOperators() {
|
||||
return getUserIdsForBooleanGroup(UserInfoTable.OP, true);
|
||||
}
|
||||
|
@ -257,9 +181,13 @@ public class UserInfoQueries {
|
|||
}
|
||||
|
||||
public static Set<Integer> extractUserIds(ResultSet set) throws SQLException {
|
||||
return extractUserIds(set, UsersTable.ID);
|
||||
}
|
||||
|
||||
public static Set<Integer> extractUserIds(ResultSet set, String column) throws SQLException {
|
||||
Set<Integer> userIds = new HashSet<>();
|
||||
while (set.next()) {
|
||||
userIds.add(set.getInt(UsersTable.ID));
|
||||
userIds.add(set.getInt(column));
|
||||
}
|
||||
return userIds;
|
||||
}
|
||||
|
@ -276,35 +204,6 @@ public class UserInfoQueries {
|
|||
return getUserIdsForBooleanGroup(UserInfoTable.BANNED, false);
|
||||
}
|
||||
|
||||
public static Query<Set<Integer>> userIdsOfPlayersWithJoinAddresses(List<String> joinAddresses) {
|
||||
String selectLowercaseJoinAddresses = SELECT +
|
||||
"u." + UsersTable.ID + ',' +
|
||||
"LOWER(COALESCE(" + UserInfoTable.JOIN_ADDRESS + ", ?)) as address" +
|
||||
FROM + UserInfoTable.TABLE_NAME +
|
||||
INNER_JOIN + UsersTable.TABLE_NAME + " u on u." + UsersTable.ID + '=' + UserInfoTable.TABLE_NAME + '.' + UserInfoTable.USER_ID;
|
||||
String sql = SELECT + DISTINCT + UsersTable.ID +
|
||||
FROM + '(' + selectLowercaseJoinAddresses + ") q1" +
|
||||
WHERE + "address IN (" +
|
||||
new TextStringBuilder().appendWithSeparators(joinAddresses.stream().map(item -> '?').iterator(), ",") +
|
||||
')'; // Don't append addresses directly, SQL injection hazard
|
||||
|
||||
return new QueryStatement<Set<Integer>>(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, "unknown");
|
||||
for (int i = 1; i <= joinAddresses.size(); i++) {
|
||||
String address = joinAddresses.get(i - 1);
|
||||
statement.setString(i + 1, address);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Integer> processResults(ResultSet set) throws SQLException {
|
||||
return extractUserIds(set);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Query<Set<Integer>> userIdsOfRegisteredBetween(long after, long before, List<ServerUUID> serverUUIDs) {
|
||||
String selectServerIds = SELECT + ServerTable.ID +
|
||||
FROM + ServerTable.TABLE_NAME +
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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.sql.tables;
|
||||
|
||||
import com.djrapitops.plan.storage.database.DBType;
|
||||
import com.djrapitops.plan.storage.database.sql.building.CreateTableBuilder;
|
||||
import com.djrapitops.plan.storage.database.sql.building.Sql;
|
||||
|
||||
import static com.djrapitops.plan.storage.database.sql.building.Sql.*;
|
||||
|
||||
public class JoinAddressTable {
|
||||
|
||||
public static final String TABLE_NAME = "plan_join_address";
|
||||
public static final String ID = "id";
|
||||
public static final String JOIN_ADDRESS = "join_address";
|
||||
public static final String SELECT_ID = '(' + SELECT + ID + FROM + TABLE_NAME + WHERE + JOIN_ADDRESS + "=LOWER(?))";
|
||||
public static final String INSERT_STATEMENT = "INSERT INTO " + TABLE_NAME +
|
||||
" (" + JOIN_ADDRESS + ") VALUES (LOWER(?))";
|
||||
public static final String DEFAULT_VALUE_FOR_LOOKUP = "unknown";
|
||||
|
||||
private JoinAddressTable() {}
|
||||
|
||||
public static String createTableSQL(DBType dbType) {
|
||||
return CreateTableBuilder.create(TABLE_NAME, dbType)
|
||||
.column(ID, Sql.INT).primaryKey()
|
||||
.column(JOIN_ADDRESS, Sql.varchar(255)).unique()
|
||||
.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -32,6 +32,7 @@ import static com.djrapitops.plan.storage.database.sql.building.Sql.*;
|
|||
* {@link Version10Patch}
|
||||
* {@link SessionAFKTimePatch}
|
||||
* {@link SessionsOptimizationPatch}
|
||||
* {@link com.djrapitops.plan.storage.database.transactions.patches.SessionJoinAddressPatch}
|
||||
*
|
||||
* @author AuroraLS3
|
||||
*/
|
||||
|
@ -47,6 +48,7 @@ public class SessionsTable {
|
|||
public static final String MOB_KILLS = "mob_kills";
|
||||
public static final String DEATHS = "deaths";
|
||||
public static final String AFK_TIME = "afk_time";
|
||||
public static final String JOIN_ADDRESS_ID = "join_address_id";
|
||||
|
||||
public static final String INSERT_STATEMENT = "INSERT INTO " + TABLE_NAME + " ("
|
||||
+ USER_ID + ','
|
||||
|
@ -55,8 +57,9 @@ public class SessionsTable {
|
|||
+ DEATHS + ','
|
||||
+ MOB_KILLS + ','
|
||||
+ AFK_TIME + ','
|
||||
+ SERVER_ID
|
||||
+ ") VALUES (" + UsersTable.SELECT_USER_ID + ", ?, ?, ?, ?, ?, " + ServerTable.SELECT_SERVER_ID + ")";
|
||||
+ SERVER_ID + ','
|
||||
+ JOIN_ADDRESS_ID
|
||||
+ ") VALUES (" + UsersTable.SELECT_USER_ID + ", ?, ?, ?, ?, ?, " + ServerTable.SELECT_SERVER_ID + ", " + JoinAddressTable.SELECT_ID + ")";
|
||||
|
||||
public static final String SELECT_SESSION_ID_STATEMENT = "(SELECT " + TABLE_NAME + '.' + ID + FROM + TABLE_NAME +
|
||||
WHERE + TABLE_NAME + '.' + USER_ID + "=" + UsersTable.SELECT_USER_ID +
|
||||
|
@ -78,6 +81,7 @@ public class SessionsTable {
|
|||
.column(MOB_KILLS, Sql.INT).notNull()
|
||||
.column(DEATHS, Sql.INT).notNull()
|
||||
.column(AFK_TIME, Sql.LONG).notNull()
|
||||
.column(JOIN_ADDRESS_ID, INT).notNull().defaultValue("1") // References JoinAddressTable.ID, but no foreign key to allow null values.
|
||||
.foreignKey(USER_ID, UsersTable.TABLE_NAME, UsersTable.ID)
|
||||
.foreignKey(SERVER_ID, ServerTable.TABLE_NAME, ServerTable.ID)
|
||||
.toString();
|
||||
|
|
|
@ -42,6 +42,10 @@ public class UserInfoTable {
|
|||
public static final String REGISTERED = "registered";
|
||||
public static final String OP = "opped";
|
||||
public static final String BANNED = "banned";
|
||||
/**
|
||||
* @deprecated Join address is now stored in {@link JoinAddressTable}, this column may become unreliable in the future.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String JOIN_ADDRESS = "join_address";
|
||||
|
||||
public static final String INSERT_STATEMENT = "INSERT INTO " + TABLE_NAME + " (" +
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package com.djrapitops.plan.storage.database.transactions.commands;
|
||||
|
||||
import com.djrapitops.plan.storage.database.sql.tables.*;
|
||||
import com.djrapitops.plan.storage.database.transactions.events.StoreJoinAddressTransaction;
|
||||
import com.djrapitops.plan.storage.database.transactions.patches.Patch;
|
||||
|
||||
/**
|
||||
|
@ -39,6 +40,7 @@ public class RemoveEverythingTransaction extends Patch {
|
|||
clearTable(KillsTable.TABLE_NAME);
|
||||
clearTable(WorldTimesTable.TABLE_NAME);
|
||||
clearTable(SessionsTable.TABLE_NAME);
|
||||
clearTable(JoinAddressTable.TABLE_NAME);
|
||||
clearTable(WorldTable.TABLE_NAME);
|
||||
clearTable(PingTable.TABLE_NAME);
|
||||
clearTable(UserInfoTable.TABLE_NAME);
|
||||
|
@ -57,6 +59,8 @@ public class RemoveEverythingTransaction extends Patch {
|
|||
clearTable(ExtensionTabTable.TABLE_NAME);
|
||||
clearTable(ExtensionPluginTable.TABLE_NAME);
|
||||
clearTable(ExtensionIconTable.TABLE_NAME);
|
||||
|
||||
executeOther(new StoreJoinAddressTransaction(JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP));
|
||||
}
|
||||
|
||||
private void clearTable(String tableName) {
|
||||
|
|
|
@ -18,6 +18,7 @@ package com.djrapitops.plan.storage.database.transactions.events;
|
|||
|
||||
import com.djrapitops.plan.exceptions.database.DBOpException;
|
||||
import com.djrapitops.plan.gathering.domain.FinishedSession;
|
||||
import com.djrapitops.plan.gathering.domain.event.JoinAddress;
|
||||
import com.djrapitops.plan.storage.database.queries.DataStoreQueries;
|
||||
import com.djrapitops.plan.storage.database.transactions.Transaction;
|
||||
|
||||
|
@ -32,10 +33,6 @@ public class SessionEndTransaction extends Transaction {
|
|||
|
||||
private final FinishedSession session;
|
||||
|
||||
public SessionEndTransaction(UUID playerUUID, FinishedSession session) {
|
||||
this(session);
|
||||
}
|
||||
|
||||
public SessionEndTransaction(FinishedSession session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
@ -43,19 +40,36 @@ public class SessionEndTransaction extends Transaction {
|
|||
@Override
|
||||
protected void performOperations() {
|
||||
try {
|
||||
execute(DataStoreQueries.storeSession(session));
|
||||
storeSession();
|
||||
} catch (DBOpException failed) {
|
||||
if (failed.isUserIdConstraintViolation()) {
|
||||
retry();
|
||||
retry(failed);
|
||||
} else {
|
||||
throw failed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void retry() {
|
||||
UUID playerUUID = session.getPlayerUUID();
|
||||
executeOther(new PlayerRegisterTransaction(playerUUID, System::currentTimeMillis, playerUUID.toString()));
|
||||
private void storeSession() {
|
||||
storeJoinAddressIfPresent();
|
||||
execute(DataStoreQueries.storeSession(session));
|
||||
}
|
||||
|
||||
private void storeJoinAddressIfPresent() {
|
||||
session.getExtraData(JoinAddress.class)
|
||||
.map(JoinAddress::getAddress)
|
||||
.map(StoreJoinAddressTransaction::new)
|
||||
.ifPresent(this::executeOther);
|
||||
}
|
||||
|
||||
private void retry(DBOpException failed) {
|
||||
try {
|
||||
UUID playerUUID = session.getPlayerUUID();
|
||||
executeOther(new PlayerRegisterTransaction(playerUUID, System::currentTimeMillis, playerUUID.toString()));
|
||||
storeSession();
|
||||
} catch (DBOpException anotherFail) {
|
||||
anotherFail.addSuppressed(failed);
|
||||
throw anotherFail;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* 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.transactions.events;
|
||||
|
||||
import com.djrapitops.plan.delivery.domain.container.CachingSupplier;
|
||||
import com.djrapitops.plan.storage.database.queries.HasMoreThanZeroQueryStatement;
|
||||
import com.djrapitops.plan.storage.database.queries.Query;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.JoinAddressTable;
|
||||
import com.djrapitops.plan.storage.database.transactions.ExecStatement;
|
||||
import com.djrapitops.plan.storage.database.transactions.Transaction;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static com.djrapitops.plan.storage.database.sql.building.Sql.*;
|
||||
|
||||
public class StoreJoinAddressTransaction extends Transaction {
|
||||
|
||||
private final Supplier<String> joinAddress;
|
||||
|
||||
public StoreJoinAddressTransaction(String joinAddress) {
|
||||
this(() -> joinAddress);
|
||||
}
|
||||
|
||||
public StoreJoinAddressTransaction(Supplier<String> joinAddress) {
|
||||
this.joinAddress = new CachingSupplier<>(joinAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldBeExecuted() {
|
||||
return !query(hasAddressAlready());
|
||||
}
|
||||
|
||||
private Query<Boolean> hasAddressAlready() {
|
||||
String sql = SELECT + "COUNT(*) as c" +
|
||||
FROM + JoinAddressTable.TABLE_NAME +
|
||||
WHERE + JoinAddressTable.JOIN_ADDRESS + "=?";
|
||||
return new HasMoreThanZeroQueryStatement(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
String address = joinAddress.get();
|
||||
statement.setString(1, address.toLowerCase());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performOperations() {
|
||||
execute(new ExecStatement(JoinAddressTable.INSERT_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, joinAddress.get().toLowerCase());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -63,6 +63,9 @@ public class CreateIndexTransaction extends Transaction {
|
|||
createIndex(TPSTable.TABLE_NAME, "plan_tps_date_index",
|
||||
TPSTable.DATE
|
||||
);
|
||||
|
||||
createIndex(SessionsTable.TABLE_NAME, "plan_session_join_address_index",
|
||||
SessionsTable.JOIN_ADDRESS_ID);
|
||||
}
|
||||
|
||||
private void createIndex(String tableName, String indexName, String... indexedColumns) {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package com.djrapitops.plan.storage.database.transactions.init;
|
||||
|
||||
import com.djrapitops.plan.storage.database.sql.tables.*;
|
||||
import com.djrapitops.plan.storage.database.transactions.events.StoreJoinAddressTransaction;
|
||||
|
||||
/**
|
||||
* Transaction that creates the table schema of Plan database.
|
||||
|
@ -36,6 +37,8 @@ public class CreateTablesTransaction extends OperationCriticalTransaction {
|
|||
execute(UserInfoTable.createTableSQL(dbType));
|
||||
execute(GeoInfoTable.createTableSQL(dbType));
|
||||
execute(NicknamesTable.createTableSQL(dbType));
|
||||
execute(JoinAddressTable.createTableSQL(dbType));
|
||||
executeOther(new StoreJoinAddressTransaction(JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP));
|
||||
execute(SessionsTable.createTableSQL(dbType));
|
||||
execute(KillsTable.createTableSQL(dbType));
|
||||
execute(PingTable.createTableSQL(dbType));
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* 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.transactions.patches;
|
||||
|
||||
import com.djrapitops.plan.storage.database.queries.Query;
|
||||
import com.djrapitops.plan.storage.database.queries.QueryAllStatement;
|
||||
import com.djrapitops.plan.storage.database.queries.QueryStatement;
|
||||
import com.djrapitops.plan.storage.database.sql.building.Sql;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.JoinAddressTable;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.SessionsTable;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.UserInfoTable;
|
||||
import com.djrapitops.plan.storage.database.transactions.ExecBatchStatement;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import static com.djrapitops.plan.storage.database.sql.building.Sql.*;
|
||||
|
||||
/**
|
||||
* Adds join_address_id to plan_sessions, and populates latest session rows with value from plan_user_info.
|
||||
*
|
||||
* @author AuroraLS3
|
||||
*/
|
||||
public class SessionJoinAddressPatch extends Patch {
|
||||
|
||||
public static Query<List<String>> uniqueJoinAddressesOld() {
|
||||
String sql = SELECT + DISTINCT + "LOWER(COALESCE(" + UserInfoTable.JOIN_ADDRESS + ", ?)) as address" +
|
||||
FROM + UserInfoTable.TABLE_NAME +
|
||||
ORDER_BY + "address ASC";
|
||||
return new QueryStatement<List<String>>(sql, 100) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> processResults(ResultSet set) throws SQLException {
|
||||
List<String> joinAddresses = new ArrayList<>();
|
||||
while (set.next()) joinAddresses.add(set.getString("address"));
|
||||
return joinAddresses;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasBeenApplied() {
|
||||
return hasColumn(SessionsTable.TABLE_NAME, SessionsTable.JOIN_ADDRESS_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyPatch() {
|
||||
Integer defaultAddressId = getDefaultAddressId();
|
||||
addColumn(SessionsTable.TABLE_NAME, SessionsTable.JOIN_ADDRESS_ID + ' ' + Sql.INT + " DEFAULT " + defaultAddressId);
|
||||
|
||||
populateAddresses();
|
||||
populateLatestSessions();
|
||||
}
|
||||
|
||||
private Integer getDefaultAddressId() {
|
||||
return query(new QueryStatement<Integer>(SELECT + ID +
|
||||
FROM + JoinAddressTable.TABLE_NAME +
|
||||
WHERE + JoinAddressTable.JOIN_ADDRESS + "=LOWER(?)") {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer processResults(ResultSet set) throws SQLException {
|
||||
return set.next() ? set.getInt(JoinAddressTable.ID) : 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void populateAddresses() {
|
||||
List<String> joinAddresses = query(uniqueJoinAddressesOld());
|
||||
joinAddresses.remove(JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP);
|
||||
execute(new ExecBatchStatement(JoinAddressTable.INSERT_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
for (String joinAddress : joinAddresses) {
|
||||
statement.setString(1, joinAddress.toLowerCase());
|
||||
statement.addBatch();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void populateLatestSessions() {
|
||||
String sql = SELECT +
|
||||
"MAX(s." + SessionsTable.ID + ") as session_id," +
|
||||
"j." + JoinAddressTable.ID + " as join_address_id" +
|
||||
FROM + UserInfoTable.TABLE_NAME + " u" +
|
||||
INNER_JOIN + SessionsTable.TABLE_NAME + " s on s." + SessionsTable.USER_ID + "=u." + UserInfoTable.USER_ID +
|
||||
AND + "s." + SessionsTable.SERVER_ID + "=u." + UserInfoTable.SERVER_ID +
|
||||
INNER_JOIN + JoinAddressTable.TABLE_NAME + " j on j." + JoinAddressTable.JOIN_ADDRESS + "=u." + UserInfoTable.JOIN_ADDRESS +
|
||||
GROUP_BY + "u." + UserInfoTable.USER_ID + ",u." + UserInfoTable.SERVER_ID;
|
||||
|
||||
Map<Integer, Integer> joinAddressIdsBySessionId = query(new QueryAllStatement<Map<Integer, Integer>>(sql) {
|
||||
@Override
|
||||
public Map<Integer, Integer> processResults(ResultSet set) throws SQLException {
|
||||
Map<Integer, Integer> joinAddressBySessionId = new TreeMap<>();
|
||||
while (set.next()) {
|
||||
joinAddressBySessionId.put(
|
||||
set.getInt("session_id"),
|
||||
set.getInt("join_address_id")
|
||||
);
|
||||
}
|
||||
return joinAddressBySessionId;
|
||||
}
|
||||
});
|
||||
|
||||
String updateSql = "UPDATE " + SessionsTable.TABLE_NAME + " SET " + SessionsTable.JOIN_ADDRESS_ID + "=?" +
|
||||
WHERE + SessionsTable.ID + "=?";
|
||||
|
||||
execute(new ExecBatchStatement(updateSql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
for (Map.Entry<Integer, Integer> sessionIdAndJoinAddressId : joinAddressIdsBySessionId.entrySet()) {
|
||||
Integer sessionId = sessionIdAndJoinAddressId.getKey();
|
||||
Integer joinAddressId = sessionIdAndJoinAddressId.getValue();
|
||||
statement.setInt(1, joinAddressId);
|
||||
statement.setInt(2, sessionId);
|
||||
statement.addBatch();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -30,7 +30,10 @@ import com.djrapitops.plan.query.QuerySvc;
|
|||
import com.djrapitops.plan.settings.config.Config;
|
||||
import com.djrapitops.plan.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.settings.locale.Locale;
|
||||
import com.djrapitops.plan.storage.database.queries.*;
|
||||
import com.djrapitops.plan.storage.database.queries.PlayerFetchQueries;
|
||||
import com.djrapitops.plan.storage.database.queries.Query;
|
||||
import com.djrapitops.plan.storage.database.queries.QueryAllStatement;
|
||||
import com.djrapitops.plan.storage.database.queries.ServerAggregateQueries;
|
||||
import com.djrapitops.plan.storage.database.queries.containers.ContainerFetchQueries;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.*;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.playertable.NetworkTablePlayersQuery;
|
||||
|
@ -101,7 +104,7 @@ public interface DatabaseTest extends DatabaseTestPreparer {
|
|||
|
||||
FinishedSession session = RandomData.randomSession(serverUUID(), worlds, playerUUID, player2UUID);
|
||||
|
||||
execute(DataStoreQueries.storeSession(session));
|
||||
db().executeTransaction(new SessionEndTransaction(session));
|
||||
db().executeTransaction(new NicknameStoreTransaction(playerUUID, new Nickname("TestNick", RandomData.randomTime(), serverUUID()), (uuid, name) -> false /* Not cached */));
|
||||
db().executeTransaction(new GeoInfoStoreTransaction(playerUUID, new GeoInfo("TestLoc", RandomData.randomTime())));
|
||||
|
||||
|
@ -131,7 +134,7 @@ public interface DatabaseTest extends DatabaseTestPreparer {
|
|||
|
||||
long sessionStart = System.currentTimeMillis();
|
||||
ActiveSession session = new ActiveSession(playerUUID, serverUUID(), sessionStart, worlds[0], "SURVIVAL");
|
||||
execute(DataStoreQueries.storeSession(session.toFinishedSession(sessionStart + 22345L)));
|
||||
db().executeTransaction(new SessionEndTransaction(session.toFinishedSession(sessionStart + 22345L)));
|
||||
|
||||
TestPluginLogger logger = new TestPluginLogger();
|
||||
new DBCleanTask(
|
||||
|
@ -154,7 +157,7 @@ public interface DatabaseTest extends DatabaseTestPreparer {
|
|||
saveUserTwo();
|
||||
saveTwoWorlds();
|
||||
FinishedSession session = RandomData.randomSession(serverUUID(), worlds, playerUUID, player2UUID);
|
||||
execute(DataStoreQueries.storeSession(session));
|
||||
db().executeTransaction(new SessionEndTransaction(session));
|
||||
db().executeTransaction(new NicknameStoreTransaction(playerUUID, RandomData.randomNickname(serverUUID()), (uuid, name) -> false /* Not cached */));
|
||||
saveGeoInfo(playerUUID, new GeoInfo("TestLoc", RandomData.randomTime()));
|
||||
assertTrue(db().query(PlayerFetchQueries.isPlayerRegistered(playerUUID)));
|
||||
|
|
|
@ -28,6 +28,7 @@ import com.djrapitops.plan.storage.database.queries.objects.playertable.ServerTa
|
|||
import com.djrapitops.plan.storage.database.sql.tables.SessionsTable;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.UsersTable;
|
||||
import com.djrapitops.plan.storage.database.transactions.events.PlayerServerRegisterTransaction;
|
||||
import com.djrapitops.plan.storage.database.transactions.events.SessionEndTransaction;
|
||||
import com.djrapitops.plan.storage.database.transactions.events.WorldNameStoreTransaction;
|
||||
import org.junit.jupiter.api.RepeatedTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -59,7 +60,7 @@ public interface ActivityIndexQueriesTest extends DatabaseTestPreparer {
|
|||
}
|
||||
|
||||
for (FinishedSession session : RandomData.randomSessions(serverUUID(), worlds, playerUUID, player2UUID)) {
|
||||
if (save.test(session)) execute(DataStoreQueries.storeSession(session));
|
||||
if (save.test(session)) db().executeTransaction(new SessionEndTransaction(session));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ public interface DatabaseBackupTest extends DatabaseTestPreparer {
|
|||
TestConstants.PLAYER_TWO_NAME, serverUUID(), TestConstants.GET_PLAYER_HOSTNAME));
|
||||
|
||||
FinishedSession session = RandomData.randomSession(serverUUID(), worlds, playerUUID, player2UUID);
|
||||
execute(DataStoreQueries.storeSession(session));
|
||||
db().executeTransaction(new SessionEndTransaction(session));
|
||||
|
||||
db().executeTransaction(
|
||||
new NicknameStoreTransaction(playerUUID, RandomData.randomNickname(serverUUID()), (uuid, name) -> false /* Not cached */)
|
||||
|
|
|
@ -38,6 +38,7 @@ import com.djrapitops.plan.identification.ServerUUID;
|
|||
import com.djrapitops.plan.storage.database.DatabaseTestPreparer;
|
||||
import com.djrapitops.plan.storage.database.transactions.commands.RemoveEverythingTransaction;
|
||||
import com.djrapitops.plan.storage.database.transactions.events.PlayerRegisterTransaction;
|
||||
import com.djrapitops.plan.storage.database.transactions.events.SessionEndTransaction;
|
||||
import com.djrapitops.plan.storage.database.transactions.events.WorldNameStoreTransaction;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -121,7 +122,7 @@ public interface ExtensionsDatabaseTest extends DatabaseTestPreparer {
|
|||
// Store a session to check against issue https://github.com/plan-player-analytics/Plan/issues/1039
|
||||
ActiveSession session = new ActiveSession(playerUUID, serverUUID(), 32345L, worlds[0], "SURVIVAL");
|
||||
session.getExtraData().put(WorldTimes.class, RandomData.randomWorldTimes(worlds));
|
||||
execute(DataStoreQueries.storeSession(session.toFinishedSession(42345L)));
|
||||
db().executeTransaction(new SessionEndTransaction(session.toFinishedSession(42345L)));
|
||||
|
||||
Map<UUID, ExtensionTabData> result = db().query(new ExtensionServerTableDataQuery(serverUUID(), 50));
|
||||
assertEquals(1, result.size());
|
||||
|
|
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import com.djrapitops.plan.gathering.domain.FinishedSession;
|
||||
import com.djrapitops.plan.gathering.domain.event.JoinAddress;
|
||||
import com.djrapitops.plan.storage.database.DatabaseTestPreparer;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.BaseUserQueries;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.JoinAddressQueries;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.JoinAddressTable;
|
||||
import com.djrapitops.plan.storage.database.transactions.commands.RemoveEverythingTransaction;
|
||||
import com.djrapitops.plan.storage.database.transactions.events.PlayerRegisterTransaction;
|
||||
import com.djrapitops.plan.storage.database.transactions.events.SessionEndTransaction;
|
||||
import com.djrapitops.plan.storage.database.transactions.events.StoreJoinAddressTransaction;
|
||||
import com.djrapitops.plan.storage.database.transactions.events.WorldNameStoreTransaction;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import utilities.RandomData;
|
||||
import utilities.TestConstants;
|
||||
import utilities.TestData;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public interface JoinAddressQueriesTest extends DatabaseTestPreparer {
|
||||
|
||||
@Test
|
||||
default void removeEverythingRemovesJoinAddresses() {
|
||||
String joinAddress = TestConstants.GET_PLAYER_HOSTNAME.get();
|
||||
executeTransactions(new StoreJoinAddressTransaction(joinAddress));
|
||||
|
||||
List<String> expected = List.of(joinAddress, JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP);
|
||||
List<String> result = db().query(JoinAddressQueries.uniqueJoinAddresses());
|
||||
assertEquals(expected, result);
|
||||
|
||||
executeTransactions(new RemoveEverythingTransaction());
|
||||
|
||||
expected = List.of(JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP);
|
||||
result = db().query(JoinAddressQueries.uniqueJoinAddresses());
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
default void unknownJoinAddressIsStoredInDatabaseDuringCreation() {
|
||||
List<String> expected = List.of(JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP);
|
||||
List<String> result = db().query(JoinAddressQueries.allJoinAddresses());
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
default void joinAddressCanBeUnknown() {
|
||||
db().executeTransaction(new WorldNameStoreTransaction(serverUUID(), worlds[0]));
|
||||
db().executeTransaction(new WorldNameStoreTransaction(serverUUID(), worlds[1]));
|
||||
db().executeTransaction(new PlayerRegisterTransaction(playerUUID, System::currentTimeMillis, TestConstants.PLAYER_ONE_NAME));
|
||||
|
||||
FinishedSession session = RandomData.randomSession(serverUUID(), worlds, playerUUID, player2UUID);
|
||||
session.getExtraData().remove(JoinAddress.class);
|
||||
db().executeTransaction(new SessionEndTransaction(session));
|
||||
|
||||
Set<Integer> expected = Set.of(db().query(BaseUserQueries.fetchUserId(playerUUID)));
|
||||
Set<Integer> result = db().query(JoinAddressQueries.userIdsOfPlayersWithJoinAddresses(List.of(JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP)));
|
||||
|
||||
assertEquals(expected, result);
|
||||
|
||||
Map<String, Integer> expectedAddressCounts = Map.of(JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP, 1);
|
||||
Map<String, Integer> resultAddressCounts = db().query(JoinAddressQueries.latestJoinAddresses());
|
||||
|
||||
assertEquals(expectedAddressCounts, resultAddressCounts);
|
||||
}
|
||||
|
||||
@Test
|
||||
default void latestJoinAddressIsUpdatedUponSecondSession() {
|
||||
joinAddressCanBeUnknown();
|
||||
|
||||
FinishedSession session = RandomData.randomSession(serverUUID(), worlds, playerUUID, player2UUID);
|
||||
String expectedAddress = TestConstants.GET_PLAYER_HOSTNAME.get();
|
||||
session.getExtraData().put(JoinAddress.class, new JoinAddress(expectedAddress));
|
||||
db().executeTransaction(new SessionEndTransaction(session));
|
||||
|
||||
Map<String, Integer> expected = Map.of(expectedAddress, 1);
|
||||
Map<String, Integer> result = db().query(JoinAddressQueries.latestJoinAddresses());
|
||||
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
default void joinAddressUpdateIsUniquePerServer() {
|
||||
joinAddressCanBeUnknown();
|
||||
|
||||
db().executeTransaction(TestData.storeServers());
|
||||
|
||||
db().executeTransaction(new WorldNameStoreTransaction(TestConstants.SERVER_TWO_UUID, worlds[0]));
|
||||
db().executeTransaction(new WorldNameStoreTransaction(TestConstants.SERVER_TWO_UUID, worlds[1]));
|
||||
FinishedSession session = RandomData.randomSession(TestConstants.SERVER_TWO_UUID, worlds, playerUUID, player2UUID);
|
||||
String expectedAddress = TestConstants.GET_PLAYER_HOSTNAME.get();
|
||||
session.getExtraData().put(JoinAddress.class, new JoinAddress(expectedAddress));
|
||||
db().executeTransaction(new SessionEndTransaction(session));
|
||||
|
||||
Map<String, Integer> expected1 = Map.of(JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP, 1);
|
||||
Map<String, Integer> result1 = db().query(JoinAddressQueries.latestJoinAddresses(serverUUID()));
|
||||
|
||||
assertEquals(expected1, result1);
|
||||
|
||||
Map<String, Integer> expected2 = Map.of(expectedAddress, 1);
|
||||
Map<String, Integer> result2 = db().query(JoinAddressQueries.latestJoinAddresses(TestConstants.SERVER_TWO_UUID));
|
||||
|
||||
assertEquals(expected2, result2);
|
||||
}
|
||||
|
||||
@Test
|
||||
default void joinAddressQueryHasNoNullValues() {
|
||||
joinAddressCanBeUnknown();
|
||||
|
||||
Map<String, Integer> expected = Collections.singletonMap(JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP, 1);
|
||||
Map<String, Integer> result = db().query(JoinAddressQueries.latestJoinAddresses());
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
default void serverJoinAddressQueryHasNoNullValues() {
|
||||
joinAddressCanBeUnknown();
|
||||
|
||||
Map<String, Integer> expected = Collections.singletonMap(JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP, 1);
|
||||
Map<String, Integer> result = db().query(JoinAddressQueries.latestJoinAddresses(serverUUID()));
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
default void joinAddressQueryHasDistinctPlayers() {
|
||||
joinAddressCanBeUnknown();
|
||||
|
||||
db().executeTransaction(TestData.storeServers());
|
||||
|
||||
FinishedSession session = RandomData.randomSession(serverUUID(), worlds, player2UUID, playerUUID);
|
||||
String expectedAddress = TestConstants.GET_PLAYER_HOSTNAME.get();
|
||||
session.getExtraData().put(JoinAddress.class, new JoinAddress(expectedAddress));
|
||||
db().executeTransaction(new SessionEndTransaction(session));
|
||||
|
||||
Map<String, Integer> expected = Map.of(JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP, 1, expectedAddress, 1);
|
||||
Map<String, Integer> result = db().query(JoinAddressQueries.latestJoinAddresses());
|
||||
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
default void joinAddressFilterOptionsAreFetched() {
|
||||
executeTransactions(
|
||||
new StoreJoinAddressTransaction(TestConstants.GET_PLAYER_HOSTNAME.get())
|
||||
);
|
||||
|
||||
List<String> expected = List.of(TestConstants.GET_PLAYER_HOSTNAME.get().toLowerCase(), JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP);
|
||||
List<String> result = db().query(JoinAddressQueries.uniqueJoinAddresses());
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
default void joinAddressFilterOptionsAreFetchedWhenThereAreMultiple() {
|
||||
executeTransactions(
|
||||
new StoreJoinAddressTransaction(TestConstants.GET_PLAYER_HOSTNAME.get()),
|
||||
new StoreJoinAddressTransaction(TestConstants.GET_PLAYER_HOSTNAME.get() + "_a"),
|
||||
new StoreJoinAddressTransaction(TestConstants.GET_PLAYER_HOSTNAME.get() + "_b")
|
||||
);
|
||||
|
||||
List<String> expected = Arrays.asList(
|
||||
TestConstants.GET_PLAYER_HOSTNAME.get().toLowerCase(),
|
||||
TestConstants.GET_PLAYER_HOSTNAME.get().toLowerCase() + "_a",
|
||||
TestConstants.GET_PLAYER_HOSTNAME.get().toLowerCase() + "_b",
|
||||
JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP
|
||||
);
|
||||
List<String> result = db().query(JoinAddressQueries.uniqueJoinAddresses());
|
||||
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
default void joinAddressFilterUUIDsAreFetched() {
|
||||
latestJoinAddressIsUpdatedUponSecondSession();
|
||||
|
||||
Set<Integer> expected = Set.of(db().query(BaseUserQueries.fetchUserId(playerUUID)));
|
||||
Set<Integer> result = db().query(JoinAddressQueries.userIdsOfPlayersWithJoinAddresses(
|
||||
List.of(TestConstants.GET_PLAYER_HOSTNAME.get().toLowerCase()))
|
||||
);
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
default void joinAddressFilterUUIDsAreFetchedWhenUnknown() {
|
||||
joinAddressCanBeUnknown();
|
||||
|
||||
Set<Integer> expected = Set.of(db().query(BaseUserQueries.fetchUserId(playerUUID)));
|
||||
Set<Integer> result = db().query(JoinAddressQueries.userIdsOfPlayersWithJoinAddresses(
|
||||
List.of(JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP))
|
||||
);
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
}
|
|
@ -31,6 +31,7 @@ public interface QueriesTestAggregate extends
|
|||
TPSQueriesTest,
|
||||
UserInfoQueriesTest,
|
||||
WebUserQueriesTest,
|
||||
FilterQueryTest {
|
||||
FilterQueryTest,
|
||||
JoinAddressQueriesTest {
|
||||
/* Collects all query tests together so its easier to implement database tests */
|
||||
}
|
||||
|
|
|
@ -141,7 +141,7 @@ public interface SessionQueriesTest extends DatabaseTestPreparer {
|
|||
long expectedLength = session.getLength();
|
||||
long sessionEnd = session.getEnd();
|
||||
|
||||
execute(DataStoreQueries.storeSession(session));
|
||||
db().executeTransaction(new SessionEndTransaction(session));
|
||||
|
||||
forcePersistenceCheck();
|
||||
|
||||
|
@ -170,7 +170,7 @@ public interface SessionQueriesTest extends DatabaseTestPreparer {
|
|||
default void sessionsAreStoredWithAllData() {
|
||||
prepareForSessionSave();
|
||||
FinishedSession session = RandomData.randomSession(serverUUID(), worlds, playerUUID, player2UUID);
|
||||
execute(DataStoreQueries.storeSession(session));
|
||||
db().executeTransaction(new SessionEndTransaction(session));
|
||||
|
||||
forcePersistenceCheck();
|
||||
|
||||
|
@ -187,7 +187,7 @@ public interface SessionQueriesTest extends DatabaseTestPreparer {
|
|||
default void mostRecentSessionsCanBeQueried() {
|
||||
prepareForSessionSave();
|
||||
FinishedSession session = RandomData.randomSession(serverUUID(), worlds, playerUUID, player2UUID);
|
||||
execute(DataStoreQueries.storeSession(session));
|
||||
db().executeTransaction(new SessionEndTransaction(session));
|
||||
|
||||
List<FinishedSession> expected = Collections.singletonList(session);
|
||||
List<FinishedSession> result = db().query(SessionQueries.fetchLatestSessionsOfServer(serverUUID(), 1));
|
||||
|
@ -294,7 +294,7 @@ public interface SessionQueriesTest extends DatabaseTestPreparer {
|
|||
prepareForSessionSave();
|
||||
|
||||
FinishedSession session = RandomData.randomSession(serverUUID(), worlds, playerUUID, player2UUID);
|
||||
execute(DataStoreQueries.storeSession(session));
|
||||
db().executeTransaction(new SessionEndTransaction(session));
|
||||
|
||||
forcePersistenceCheck();
|
||||
|
||||
|
@ -310,7 +310,7 @@ public interface SessionQueriesTest extends DatabaseTestPreparer {
|
|||
FinishedSession session = RandomData.randomSession(serverUUID(), worlds, playerUUID, player2UUID);
|
||||
List<PlayerKill> expected = session.getExtraData(PlayerKills.class).map(PlayerKills::asList)
|
||||
.orElseThrow(AssertionError::new);
|
||||
execute(DataStoreQueries.storeSession(session));
|
||||
db().executeTransaction(new SessionEndTransaction(session));
|
||||
|
||||
forcePersistenceCheck();
|
||||
|
||||
|
@ -330,7 +330,7 @@ public interface SessionQueriesTest extends DatabaseTestPreparer {
|
|||
|
||||
FinishedSession session = RandomData.randomSession(serverUUID(), worlds, playerUUID, player2UUID);
|
||||
WorldTimes expected = session.getExtraData(WorldTimes.class).orElseThrow(AssertionError::new);
|
||||
execute(DataStoreQueries.storeSession(session));
|
||||
db().executeTransaction(new SessionEndTransaction(session));
|
||||
|
||||
// Fetch the session
|
||||
Map<ServerUUID, List<FinishedSession>> sessions = db().query(SessionQueries.fetchSessionsOfPlayer(playerUUID));
|
||||
|
@ -377,8 +377,8 @@ public interface SessionQueriesTest extends DatabaseTestPreparer {
|
|||
prepareForSessionSave();
|
||||
List<FinishedSession> player1Sessions = RandomData.randomSessions(serverUUID(), worlds, playerUUID, player2UUID);
|
||||
List<FinishedSession> player2Sessions = RandomData.randomSessions(serverUUID(), worlds, player2UUID, playerUUID);
|
||||
player1Sessions.forEach(session -> execute(DataStoreQueries.storeSession(session)));
|
||||
player2Sessions.forEach(session -> execute(DataStoreQueries.storeSession(session)));
|
||||
player1Sessions.forEach(session -> db().executeTransaction(new SessionEndTransaction(session)));
|
||||
player2Sessions.forEach(session -> db().executeTransaction(new SessionEndTransaction(session)));
|
||||
|
||||
long playtimeThreshold = RandomData.randomLong(TimeUnit.HOURS.toMillis(1L), TimeUnit.DAYS.toMillis(2L));
|
||||
|
||||
|
@ -397,8 +397,8 @@ public interface SessionQueriesTest extends DatabaseTestPreparer {
|
|||
prepareForSessionSave();
|
||||
List<FinishedSession> player1Sessions = RandomData.randomSessions(serverUUID(), worlds, playerUUID, player2UUID);
|
||||
List<FinishedSession> player2Sessions = RandomData.randomSessions(serverUUID(), worlds, player2UUID, playerUUID);
|
||||
player1Sessions.forEach(session -> execute(DataStoreQueries.storeSession(session)));
|
||||
player2Sessions.forEach(session -> execute(DataStoreQueries.storeSession(session)));
|
||||
player1Sessions.forEach(session -> db().executeTransaction(new SessionEndTransaction(session)));
|
||||
player2Sessions.forEach(session -> db().executeTransaction(new SessionEndTransaction(session)));
|
||||
|
||||
long time = System.currentTimeMillis();
|
||||
long playtimeThreshold = RandomData.randomLong(TimeUnit.HOURS.toMillis(1L), TimeUnit.DAYS.toMillis(2L));
|
||||
|
@ -433,14 +433,14 @@ public interface SessionQueriesTest extends DatabaseTestPreparer {
|
|||
default void serverPreferencePieValuesAreCorrect() {
|
||||
prepareForSessionSave();
|
||||
List<FinishedSession> server1Sessions = RandomData.randomSessions(serverUUID(), worlds, playerUUID, player2UUID);
|
||||
server1Sessions.forEach(session -> execute(DataStoreQueries.storeSession(session)));
|
||||
server1Sessions.forEach(session -> db().executeTransaction(new SessionEndTransaction(session)));
|
||||
|
||||
ServerUUID serverTwoUuid = TestConstants.SERVER_TWO_UUID;
|
||||
executeTransactions(new StoreServerInformationTransaction(new Server(serverTwoUuid, TestConstants.SERVER_TWO_NAME, "", TestConstants.VERSION)));
|
||||
db().executeTransaction(new WorldNameStoreTransaction(serverTwoUuid, worlds[0]));
|
||||
db().executeTransaction(new WorldNameStoreTransaction(serverTwoUuid, worlds[1]));
|
||||
List<FinishedSession> server2Sessions = RandomData.randomSessions(serverTwoUuid, worlds, playerUUID, player2UUID);
|
||||
server2Sessions.forEach(session -> execute(DataStoreQueries.storeSession(session)));
|
||||
server2Sessions.forEach(session -> db().executeTransaction(new SessionEndTransaction(session)));
|
||||
|
||||
Map<String, Long> expected = Maps.builder(String.class, Long.class)
|
||||
.put(TestConstants.SERVER_NAME, new SessionsMutator(server1Sessions).toPlaytime())
|
||||
|
|
|
@ -18,12 +18,10 @@ package com.djrapitops.plan.storage.database.queries;
|
|||
|
||||
import com.djrapitops.plan.gathering.domain.BaseUser;
|
||||
import com.djrapitops.plan.gathering.domain.UserInfo;
|
||||
import com.djrapitops.plan.identification.Server;
|
||||
import com.djrapitops.plan.storage.database.DatabaseTestPreparer;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.BaseUserQueries;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.UserIdentifierQueries;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.UserInfoQueries;
|
||||
import com.djrapitops.plan.storage.database.transactions.StoreServerInformationTransaction;
|
||||
import com.djrapitops.plan.storage.database.transactions.Transaction;
|
||||
import com.djrapitops.plan.storage.database.transactions.commands.RemoveEverythingTransaction;
|
||||
import com.djrapitops.plan.storage.database.transactions.events.*;
|
||||
|
@ -51,45 +49,6 @@ public interface UserInfoQueriesTest extends DatabaseTestPreparer {
|
|||
assertEquals(expected, userInfo);
|
||||
}
|
||||
|
||||
@Test
|
||||
default void joinAddressCanBeNull() {
|
||||
assertFalse(db().query(BaseUserQueries.fetchBaseUserOfPlayer(playerUUID)).isPresent());
|
||||
db().executeTransaction(new PlayerServerRegisterTransaction(playerUUID, () -> TestConstants.REGISTER_TIME, TestConstants.PLAYER_ONE_NAME, serverUUID(), () -> null));
|
||||
|
||||
Set<UserInfo> userInfo = db().query(UserInfoQueries.fetchUserInformationOfUser(playerUUID));
|
||||
Set<UserInfo> expected = Collections.singleton(new UserInfo(playerUUID, serverUUID(), TestConstants.REGISTER_TIME, false, null, false));
|
||||
|
||||
assertEquals(expected, userInfo);
|
||||
}
|
||||
|
||||
@Test
|
||||
default void joinAddressIsUpdatedUponSecondLogin() {
|
||||
assertFalse(db().query(BaseUserQueries.fetchBaseUserOfPlayer(playerUUID)).isPresent());
|
||||
db().executeTransaction(new PlayerServerRegisterTransaction(playerUUID, () -> TestConstants.REGISTER_TIME, TestConstants.PLAYER_ONE_NAME, serverUUID(), () -> null));
|
||||
db().executeTransaction(new PlayerServerRegisterTransaction(playerUUID, () -> TestConstants.REGISTER_TIME, TestConstants.PLAYER_ONE_NAME, serverUUID(), TestConstants.GET_PLAYER_HOSTNAME));
|
||||
|
||||
Set<UserInfo> userInfo = db().query(UserInfoQueries.fetchUserInformationOfUser(playerUUID));
|
||||
Set<UserInfo> expected = Collections.singleton(new UserInfo(playerUUID, serverUUID(), TestConstants.REGISTER_TIME, false, TestConstants.GET_PLAYER_HOSTNAME.get(), false));
|
||||
|
||||
assertEquals(expected, userInfo);
|
||||
}
|
||||
|
||||
@Test
|
||||
default void joinAddressUpdateIsUniquePerServer() {
|
||||
db().executeTransaction(new PlayerServerRegisterTransaction(playerUUID, () -> TestConstants.REGISTER_TIME, TestConstants.PLAYER_ONE_NAME, serverUUID(), () -> null));
|
||||
db().executeTransaction(new PlayerServerRegisterTransaction(playerUUID, () -> TestConstants.REGISTER_TIME, TestConstants.PLAYER_ONE_NAME, serverUUID(), TestConstants.GET_PLAYER_HOSTNAME));
|
||||
|
||||
db().executeTransaction(new StoreServerInformationTransaction(new Server(TestConstants.SERVER_TWO_UUID, TestConstants.SERVER_TWO_NAME, "", TestConstants.VERSION)));
|
||||
db().executeTransaction(new PlayerServerRegisterTransaction(playerUUID, () -> TestConstants.REGISTER_TIME, TestConstants.PLAYER_ONE_NAME, TestConstants.SERVER_TWO_UUID, () -> "example.join.address"));
|
||||
|
||||
Set<UserInfo> userInfo = db().query(UserInfoQueries.fetchUserInformationOfUser(playerUUID));
|
||||
Set<UserInfo> expected = new HashSet<>(Arrays.asList(
|
||||
new UserInfo(playerUUID, serverUUID(), TestConstants.REGISTER_TIME, false, TestConstants.GET_PLAYER_HOSTNAME.get(), false),
|
||||
new UserInfo(playerUUID, TestConstants.SERVER_TWO_UUID, TestConstants.REGISTER_TIME, false, "example.join.address", false)
|
||||
));
|
||||
|
||||
assertEquals(expected, userInfo);
|
||||
}
|
||||
|
||||
@Test
|
||||
default void userInfoTableUpdatesBanStatus() {
|
||||
|
@ -267,81 +226,4 @@ public interface UserInfoQueriesTest extends DatabaseTestPreparer {
|
|||
default void noMinimumRegisterDateIsFetchedWithNoData() {
|
||||
assertFalse(db().query(BaseUserQueries.minimumRegisterDate()).isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
default void joinAddressQueryHasNoNullValues() {
|
||||
joinAddressCanBeNull();
|
||||
|
||||
Map<String, Integer> expected = Collections.singletonMap("unknown", 1);
|
||||
Map<String, Integer> result = db().query(UserInfoQueries.joinAddresses());
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
default void serverJoinAddressQueryHasNoNullValues() {
|
||||
joinAddressCanBeNull();
|
||||
|
||||
Map<String, Integer> expected = Collections.singletonMap("unknown", 1);
|
||||
Map<String, Integer> result = db().query(UserInfoQueries.joinAddresses(serverUUID()));
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
default void joinAddressQueryHasDistinctPlayers() {
|
||||
db().executeTransaction(new StoreServerInformationTransaction(new Server(TestConstants.SERVER_TWO_UUID, TestConstants.SERVER_TWO_NAME, "", TestConstants.VERSION)));
|
||||
db().executeTransaction(new PlayerServerRegisterTransaction(playerUUID, () -> TestConstants.REGISTER_TIME, TestConstants.PLAYER_ONE_NAME, serverUUID(), TestConstants.GET_PLAYER_HOSTNAME));
|
||||
db().executeTransaction(new PlayerServerRegisterTransaction(playerUUID, () -> TestConstants.REGISTER_TIME, TestConstants.PLAYER_ONE_NAME, TestConstants.SERVER_TWO_UUID, TestConstants.GET_PLAYER_HOSTNAME));
|
||||
|
||||
Map<String, Integer> expected = Collections.singletonMap(TestConstants.GET_PLAYER_HOSTNAME.get(), 1);
|
||||
Map<String, Integer> result = db().query(UserInfoQueries.joinAddresses());
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
default void joinAddressFilterOptionsAreFetched() {
|
||||
joinAddressIsUpdatedUponSecondLogin();
|
||||
|
||||
List<String> expected = Collections.singletonList(TestConstants.GET_PLAYER_HOSTNAME.get().toLowerCase());
|
||||
List<String> result = db().query(UserInfoQueries.uniqueJoinAddresses());
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
default void joinAddressFilterOptionsAreFetchedWhenThereAreMultiple() {
|
||||
joinAddressIsUpdatedUponSecondLogin();
|
||||
db().executeTransaction(new StoreServerInformationTransaction(new Server(TestConstants.SERVER_TWO_UUID, TestConstants.SERVER_TWO_NAME, "", TestConstants.VERSION)));
|
||||
|
||||
db().executeTransaction(new PlayerServerRegisterTransaction(playerUUID, () -> TestConstants.REGISTER_TIME, TestConstants.PLAYER_ONE_NAME, serverUUID(), () -> TestConstants.GET_PLAYER_HOSTNAME.get() + "_b"));
|
||||
db().executeTransaction(new PlayerServerRegisterTransaction(player2UUID, () -> TestConstants.REGISTER_TIME, TestConstants.PLAYER_ONE_NAME, TestConstants.SERVER_TWO_UUID, () -> TestConstants.GET_PLAYER_HOSTNAME.get() + "_a"));
|
||||
|
||||
List<String> expected = Arrays.asList(
|
||||
TestConstants.GET_PLAYER_HOSTNAME.get().toLowerCase() + "_a",
|
||||
TestConstants.GET_PLAYER_HOSTNAME.get().toLowerCase() + "_b"
|
||||
);
|
||||
List<String> result = db().query(UserInfoQueries.uniqueJoinAddresses());
|
||||
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
default void joinAddressFilterUUIDsAreFetched() {
|
||||
joinAddressIsUpdatedUponSecondLogin();
|
||||
|
||||
Set<Integer> expected = Set.of(db().query(BaseUserQueries.fetchUserId(playerUUID)));
|
||||
Set<Integer> result = db().query(UserInfoQueries.userIdsOfPlayersWithJoinAddresses(
|
||||
Collections.singletonList(TestConstants.GET_PLAYER_HOSTNAME.get().toLowerCase()))
|
||||
);
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
default void joinAddressFilterUUIDsAreFetchedWhenUnknown() {
|
||||
joinAddressCanBeNull();
|
||||
|
||||
Set<Integer> expected = Set.of(db().query(BaseUserQueries.fetchUserId(playerUUID)));
|
||||
Set<Integer> result = db().query(UserInfoQueries.userIdsOfPlayersWithJoinAddresses(
|
||||
Collections.singletonList("unknown"))
|
||||
);
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,8 @@ package com.djrapitops.plan.storage.database.queries.analysis;
|
|||
|
||||
import com.djrapitops.plan.gathering.domain.FinishedSession;
|
||||
import com.djrapitops.plan.storage.database.DatabaseTestPreparer;
|
||||
import com.djrapitops.plan.storage.database.queries.DataStoreQueries;
|
||||
import com.djrapitops.plan.storage.database.transactions.events.PlayerServerRegisterTransaction;
|
||||
import com.djrapitops.plan.storage.database.transactions.events.SessionEndTransaction;
|
||||
import com.djrapitops.plan.storage.database.transactions.events.WorldNameStoreTransaction;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import utilities.RandomData;
|
||||
|
@ -37,7 +37,7 @@ public interface TopListQueriesTest extends DatabaseTestPreparer {
|
|||
db().executeTransaction(new PlayerServerRegisterTransaction(player2UUID, RandomData::randomTime,
|
||||
TestConstants.PLAYER_TWO_NAME, serverUUID(), TestConstants.GET_PLAYER_HOSTNAME));
|
||||
FinishedSession session = RandomData.randomSession(serverUUID(), worlds, playerUUID, player2UUID);
|
||||
execute(DataStoreQueries.storeSession(session));
|
||||
db().executeTransaction(new SessionEndTransaction(session));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -20,6 +20,7 @@ import com.djrapitops.plan.delivery.domain.DateObj;
|
|||
import com.djrapitops.plan.delivery.domain.Nickname;
|
||||
import com.djrapitops.plan.delivery.rendering.json.graphs.line.Point;
|
||||
import com.djrapitops.plan.gathering.domain.*;
|
||||
import com.djrapitops.plan.gathering.domain.event.JoinAddress;
|
||||
import com.djrapitops.plan.identification.ServerUUID;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.KillsTable;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
|
@ -28,6 +29,8 @@ import java.util.*;
|
|||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class RandomData {
|
||||
|
||||
|
@ -37,6 +40,9 @@ public class RandomData {
|
|||
|
||||
private static final Random r = new Random();
|
||||
|
||||
private static final int JOIN_ADDRESS_COUNT = 50;
|
||||
private static final List<JoinAddress> JOIN_ADDRESSES = generateJoinAddresses(JOIN_ADDRESS_COUNT);
|
||||
|
||||
public static int randomInt(int rangeStart, int rangeEnd) {
|
||||
return ThreadLocalRandom.current().nextInt(rangeStart, rangeEnd);
|
||||
}
|
||||
|
@ -117,6 +123,7 @@ public class RandomData {
|
|||
}
|
||||
extraData.put(MobKillCounter.class, new MobKillCounter());
|
||||
extraData.put(DeathCounter.class, new DeathCounter());
|
||||
extraData.put(JoinAddress.class, JOIN_ADDRESSES.get(randomInt(0, JOIN_ADDRESS_COUNT)));
|
||||
return new FinishedSession(
|
||||
uuids[0], serverUUID,
|
||||
start, end, RandomData.randomLong(0, end - start),
|
||||
|
@ -197,4 +204,10 @@ public class RandomData {
|
|||
public static double randomDouble() {
|
||||
return ThreadLocalRandom.current().nextDouble();
|
||||
}
|
||||
|
||||
public static List<JoinAddress> generateJoinAddresses(int n) {
|
||||
return IntStream.range(0, n).mapToObj(i -> "join_address_" + i)
|
||||
.map(JoinAddress::new)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import com.djrapitops.plan.extension.ExtensionSvc;
|
|||
import com.djrapitops.plan.gathering.cache.NicknameCache;
|
||||
import com.djrapitops.plan.gathering.cache.SessionCache;
|
||||
import com.djrapitops.plan.gathering.domain.ActiveSession;
|
||||
import com.djrapitops.plan.gathering.domain.event.JoinAddress;
|
||||
import com.djrapitops.plan.gathering.geolocation.GeolocationCache;
|
||||
import com.djrapitops.plan.identification.ServerInfo;
|
||||
import com.djrapitops.plan.identification.ServerUUID;
|
||||
|
@ -139,7 +140,9 @@ public class PlayerOnlineListener implements FabricListener {
|
|||
ServerUUID serverUUID = serverInfo.getServerUUID();
|
||||
String joinAddress = address.toString();
|
||||
if (!joinAddress.isEmpty()) {
|
||||
joinAddresses.put(playerUUID, joinAddress.substring(0, joinAddress.lastIndexOf(':')));
|
||||
joinAddress = joinAddress.substring(0, joinAddress.lastIndexOf(':'));
|
||||
joinAddresses.put(playerUUID, joinAddress);
|
||||
dbSystem.getDatabase().executeTransaction(new StoreJoinAddressTransaction(joinAddress));
|
||||
}
|
||||
dbSystem.getDatabase().executeTransaction(new BanStatusTransaction(playerUUID, serverUUID, () -> banned));
|
||||
} catch (Exception e) {
|
||||
|
@ -201,6 +204,7 @@ public class PlayerOnlineListener implements FabricListener {
|
|||
ActiveSession session = new ActiveSession(playerUUID, serverUUID, time, world, gm);
|
||||
session.getExtraData().put(PlayerName.class, new PlayerName(playerName));
|
||||
session.getExtraData().put(ServerName.class, new ServerName(serverInfo.getServer().getIdentifiableName()));
|
||||
session.getExtraData().put(JoinAddress.class, new JoinAddress(getHostName));
|
||||
sessionCache.cacheSession(playerUUID, session)
|
||||
.ifPresent(previousSession -> database.executeTransaction(new SessionEndTransaction(previousSession)));
|
||||
|
||||
|
|
|
@ -184,7 +184,8 @@ public class PlayerOnlineListener implements Listener {
|
|||
session.getExtraData().put(PlayerName.class, new PlayerName(playerName));
|
||||
session.getExtraData().put(ServerName.class, new ServerName(serverInfo.getServer().getIdentifiableName()));
|
||||
sessionCache.cacheSession(playerUUID, session)
|
||||
.ifPresent(previousSession -> database.executeTransaction(new SessionEndTransaction(previousSession)));
|
||||
.map(SessionEndTransaction::new)
|
||||
.ifPresent(database::executeTransaction);
|
||||
|
||||
database.executeTransaction(new NicknameStoreTransaction(
|
||||
playerUUID, new Nickname(displayName, time, serverUUID),
|
||||
|
|
|
@ -25,6 +25,7 @@ import com.djrapitops.plan.extension.ExtensionSvc;
|
|||
import com.djrapitops.plan.gathering.cache.NicknameCache;
|
||||
import com.djrapitops.plan.gathering.cache.SessionCache;
|
||||
import com.djrapitops.plan.gathering.domain.ActiveSession;
|
||||
import com.djrapitops.plan.gathering.domain.event.JoinAddress;
|
||||
import com.djrapitops.plan.gathering.geolocation.GeolocationCache;
|
||||
import com.djrapitops.plan.gathering.listeners.Status;
|
||||
import com.djrapitops.plan.identification.ServerInfo;
|
||||
|
@ -179,12 +180,15 @@ public class PlayerOnlineListener {
|
|||
new GeoInfoStoreTransaction(playerUUID, address, time, geolocationCache::getCountry)
|
||||
);
|
||||
}
|
||||
database.executeTransaction(new StoreJoinAddressTransaction(getHostName));
|
||||
|
||||
ActiveSession session = new ActiveSession(playerUUID, serverUUID, time, world, gm);
|
||||
session.getExtraData().put(PlayerName.class, new PlayerName(playerName));
|
||||
session.getExtraData().put(ServerName.class, new ServerName(serverInfo.getServer().getIdentifiableName()));
|
||||
session.getExtraData().put(JoinAddress.class, new JoinAddress(getHostName));
|
||||
sessionCache.cacheSession(playerUUID, session)
|
||||
.ifPresent(previousSession -> database.executeTransaction(new SessionEndTransaction(previousSession)));
|
||||
.map(SessionEndTransaction::new)
|
||||
.ifPresent(database::executeTransaction);
|
||||
|
||||
database.executeTransaction(new NicknameStoreTransaction(
|
||||
playerUUID, new Nickname(displayName, time, serverUUID),
|
||||
|
|
Loading…
Reference in New Issue
Block a user