Whitelist bounce gathering (#3511)
* Store bounced whitelist logins * Add allowlist bounce endpoint * Restore locale file indent from master branch * Add UI for allowlist * Update locale * Fix sonar detected bug and implement database tests Affects issues: - Close #2233
This commit is contained in:
parent
24e6af2d03
commit
8116063e62
|
@ -28,6 +28,7 @@ import com.djrapitops.plan.identification.ServerUUID;
|
||||||
import com.djrapitops.plan.storage.database.DBSystem;
|
import com.djrapitops.plan.storage.database.DBSystem;
|
||||||
import com.djrapitops.plan.storage.database.transactions.events.BanStatusTransaction;
|
import com.djrapitops.plan.storage.database.transactions.events.BanStatusTransaction;
|
||||||
import com.djrapitops.plan.storage.database.transactions.events.KickStoreTransaction;
|
import com.djrapitops.plan.storage.database.transactions.events.KickStoreTransaction;
|
||||||
|
import com.djrapitops.plan.storage.database.transactions.events.StoreAllowlistBounceTransaction;
|
||||||
import com.djrapitops.plan.utilities.logging.ErrorContext;
|
import com.djrapitops.plan.utilities.logging.ErrorContext;
|
||||||
import com.djrapitops.plan.utilities.logging.ErrorLogger;
|
import com.djrapitops.plan.utilities.logging.ErrorLogger;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
|
@ -82,6 +83,11 @@ public class PlayerOnlineListener implements Listener {
|
||||||
UUID playerUUID = event.getPlayer().getUniqueId();
|
UUID playerUUID = event.getPlayer().getUniqueId();
|
||||||
ServerUUID serverUUID = serverInfo.getServerUUID();
|
ServerUUID serverUUID = serverInfo.getServerUUID();
|
||||||
boolean banned = PlayerLoginEvent.Result.KICK_BANNED == event.getResult();
|
boolean banned = PlayerLoginEvent.Result.KICK_BANNED == event.getResult();
|
||||||
|
boolean notWhitelisted = PlayerLoginEvent.Result.KICK_WHITELIST == event.getResult();
|
||||||
|
|
||||||
|
if (notWhitelisted) {
|
||||||
|
dbSystem.getDatabase().executeTransaction(new StoreAllowlistBounceTransaction(playerUUID, event.getPlayer().getName(), serverUUID, System.currentTimeMillis()));
|
||||||
|
}
|
||||||
|
|
||||||
String address = event.getHostname();
|
String address = event.getHostname();
|
||||||
if (!address.isEmpty()) {
|
if (!address.isEmpty()) {
|
||||||
|
|
|
@ -93,6 +93,7 @@ public enum WebPermission implements Supplier<String>, Lang {
|
||||||
PAGE_SERVER_PERFORMANCE_OVERVIEW("See Performance numbers"),
|
PAGE_SERVER_PERFORMANCE_OVERVIEW("See Performance numbers"),
|
||||||
PAGE_SERVER_PLUGIN_HISTORY("See Plugin History"),
|
PAGE_SERVER_PLUGIN_HISTORY("See Plugin History"),
|
||||||
PAGE_SERVER_PLUGINS("See Plugins -tabs of servers"),
|
PAGE_SERVER_PLUGINS("See Plugins -tabs of servers"),
|
||||||
|
PAGE_SERVER_ALLOWLIST_BOUNCE("See list of Game allowlist bounces"),
|
||||||
|
|
||||||
PAGE_PLAYER("See all of player page"),
|
PAGE_PLAYER("See all of player page"),
|
||||||
PAGE_PLAYER_OVERVIEW("See Player Overview -tab"),
|
PAGE_PLAYER_OVERVIEW("See Player Overview -tab"),
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Player Analytics (Plan).
|
||||||
|
*
|
||||||
|
* Plan is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Plan is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package com.djrapitops.plan.delivery.domain.datatransfer;
|
||||||
|
|
||||||
|
import com.djrapitops.plan.utilities.dev.Untrusted;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an event where player bounced off the whitelist.
|
||||||
|
*
|
||||||
|
* @author AuroraLS3
|
||||||
|
*/
|
||||||
|
public class AllowlistBounce {
|
||||||
|
|
||||||
|
private final UUID playerUUID;
|
||||||
|
@Untrusted
|
||||||
|
private final String playerName;
|
||||||
|
private final int count;
|
||||||
|
private final long lastTime;
|
||||||
|
|
||||||
|
public AllowlistBounce(UUID playerUUID, String playerName, int count, long lastTime) {
|
||||||
|
this.playerUUID = playerUUID;
|
||||||
|
this.playerName = playerName;
|
||||||
|
this.count = count;
|
||||||
|
this.lastTime = lastTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getPlayerUUID() {
|
||||||
|
return playerUUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPlayerName() {
|
||||||
|
return playerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCount() {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLastTime() {
|
||||||
|
return lastTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
AllowlistBounce bounce = (AllowlistBounce) o;
|
||||||
|
return getCount() == bounce.getCount() && getLastTime() == bounce.getLastTime() && Objects.equals(getPlayerUUID(), bounce.getPlayerUUID()) && Objects.equals(getPlayerName(), bounce.getPlayerName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(getPlayerUUID(), getPlayerName(), getCount(), getLastTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "AllowlistBounce{" +
|
||||||
|
"playerUUID=" + playerUUID +
|
||||||
|
", playerName='" + playerName + '\'' +
|
||||||
|
", count=" + count +
|
||||||
|
", lastTime=" + lastTime +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
|
@ -57,6 +57,7 @@ public enum DataID {
|
||||||
JOIN_ADDRESSES_BY_DAY,
|
JOIN_ADDRESSES_BY_DAY,
|
||||||
PLAYER_RETENTION,
|
PLAYER_RETENTION,
|
||||||
PLAYER_JOIN_ADDRESSES,
|
PLAYER_JOIN_ADDRESSES,
|
||||||
|
PLAYER_ALLOWLIST_BOUNCES,
|
||||||
;
|
;
|
||||||
|
|
||||||
public String of(ServerUUID serverUUID) {
|
public String of(ServerUUID serverUUID) {
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Player Analytics (Plan).
|
||||||
|
*
|
||||||
|
* Plan is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Plan is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package com.djrapitops.plan.delivery.webserver.resolver.json;
|
||||||
|
|
||||||
|
import com.djrapitops.plan.delivery.domain.auth.WebPermission;
|
||||||
|
import com.djrapitops.plan.delivery.formatting.Formatter;
|
||||||
|
import com.djrapitops.plan.delivery.web.resolver.MimeType;
|
||||||
|
import com.djrapitops.plan.delivery.web.resolver.Response;
|
||||||
|
import com.djrapitops.plan.delivery.web.resolver.request.Request;
|
||||||
|
import com.djrapitops.plan.delivery.web.resolver.request.WebUser;
|
||||||
|
import com.djrapitops.plan.delivery.webserver.cache.AsyncJSONResolverService;
|
||||||
|
import com.djrapitops.plan.delivery.webserver.cache.DataID;
|
||||||
|
import com.djrapitops.plan.delivery.webserver.cache.JSONStorage;
|
||||||
|
import com.djrapitops.plan.identification.Identifiers;
|
||||||
|
import com.djrapitops.plan.identification.ServerUUID;
|
||||||
|
import com.djrapitops.plan.storage.database.DBSystem;
|
||||||
|
import com.djrapitops.plan.storage.database.Database;
|
||||||
|
import com.djrapitops.plan.storage.database.queries.objects.AllowlistQueries;
|
||||||
|
import com.djrapitops.plan.storage.database.queries.objects.SessionQueries;
|
||||||
|
import com.djrapitops.plan.utilities.dev.Untrusted;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Content;
|
||||||
|
import io.swagger.v3.oas.annotations.media.ExampleObject;
|
||||||
|
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||||
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
|
import jakarta.ws.rs.GET;
|
||||||
|
import jakarta.ws.rs.Path;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response resolver to get game allowlist bounces.
|
||||||
|
*
|
||||||
|
* @author AuroraLS3
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
@Path("/v1/gameAllowlistBounces")
|
||||||
|
public class AllowlistJSONResolver extends JSONResolver {
|
||||||
|
|
||||||
|
private final DBSystem dbSystem;
|
||||||
|
private final Identifiers identifiers;
|
||||||
|
private final AsyncJSONResolverService jsonResolverService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public AllowlistJSONResolver(DBSystem dbSystem, Identifiers identifiers, AsyncJSONResolverService jsonResolverService) {
|
||||||
|
this.dbSystem = dbSystem;
|
||||||
|
this.identifiers = identifiers;
|
||||||
|
this.jsonResolverService = jsonResolverService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Formatter<Long> getHttpLastModifiedFormatter() {return jsonResolverService.getHttpLastModifiedFormatter();}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canAccess(@Untrusted Request request) {
|
||||||
|
WebUser user = request.getUser().orElse(new WebUser(""));
|
||||||
|
|
||||||
|
return user.hasPermission(WebPermission.PAGE_SERVER_ALLOWLIST_BOUNCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Operation(
|
||||||
|
description = "Get allowlist bounce data for server",
|
||||||
|
responses = {
|
||||||
|
@ApiResponse(responseCode = "200", content = @Content(mediaType = MimeType.JSON)),
|
||||||
|
@ApiResponse(responseCode = "400", description = "If 'server' parameter is not an existing server")
|
||||||
|
},
|
||||||
|
parameters = @Parameter(in = ParameterIn.QUERY, name = "server", description = "Server identifier to get data for (optional)", examples = {
|
||||||
|
@ExampleObject("Server 1"),
|
||||||
|
@ExampleObject("1"),
|
||||||
|
@ExampleObject("1fb39d2a-eb82-4868-b245-1fad17d823b3"),
|
||||||
|
}),
|
||||||
|
requestBody = @RequestBody(content = @Content(examples = @ExampleObject()))
|
||||||
|
)
|
||||||
|
@Override
|
||||||
|
public Optional<Response> resolve(@Untrusted Request request) {
|
||||||
|
return Optional.of(getResponse(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Response getResponse(@Untrusted Request request) {
|
||||||
|
JSONStorage.StoredJSON result = getStoredJSON(request);
|
||||||
|
return getCachedOrNewResponse(request, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private JSONStorage.StoredJSON getStoredJSON(Request request) {
|
||||||
|
Optional<Long> timestamp = Identifiers.getTimestamp(request);
|
||||||
|
|
||||||
|
ServerUUID serverUUID = identifiers.getServerUUID(request);
|
||||||
|
Database database = dbSystem.getDatabase();
|
||||||
|
return jsonResolverService.resolve(timestamp, DataID.PLAYER_ALLOWLIST_BOUNCES, serverUUID,
|
||||||
|
theUUID -> Map.of(
|
||||||
|
"allowlist_bounces", database.query(AllowlistQueries.getBounces(serverUUID)),
|
||||||
|
"last_seen_by_uuid", database.query(SessionQueries.lastSeen(serverUUID))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -90,6 +90,7 @@ public class RootJSONResolver {
|
||||||
RetentionJSONResolver retentionJSONResolver,
|
RetentionJSONResolver retentionJSONResolver,
|
||||||
PlayerJoinAddressJSONResolver playerJoinAddressJSONResolver,
|
PlayerJoinAddressJSONResolver playerJoinAddressJSONResolver,
|
||||||
PluginHistoryJSONResolver pluginHistoryJSONResolver,
|
PluginHistoryJSONResolver pluginHistoryJSONResolver,
|
||||||
|
AllowlistJSONResolver allowlistJSONResolver,
|
||||||
|
|
||||||
PreferencesJSONResolver preferencesJSONResolver,
|
PreferencesJSONResolver preferencesJSONResolver,
|
||||||
StorePreferencesJSONResolver storePreferencesJSONResolver,
|
StorePreferencesJSONResolver storePreferencesJSONResolver,
|
||||||
|
@ -129,7 +130,8 @@ public class RootJSONResolver {
|
||||||
.add("extensionData", extensionJSONResolver)
|
.add("extensionData", extensionJSONResolver)
|
||||||
.add("retention", retentionJSONResolver)
|
.add("retention", retentionJSONResolver)
|
||||||
.add("joinAddresses", playerJoinAddressJSONResolver)
|
.add("joinAddresses", playerJoinAddressJSONResolver)
|
||||||
.add("preferences", preferencesJSONResolver);
|
.add("preferences", preferencesJSONResolver)
|
||||||
|
.add("gameAllowlistBounces", allowlistJSONResolver);
|
||||||
|
|
||||||
this.webServer = webServer;
|
this.webServer = webServer;
|
||||||
// These endpoints require authentication to be enabled.
|
// These endpoints require authentication to be enabled.
|
||||||
|
|
|
@ -285,6 +285,15 @@ public enum HtmlLang implements Lang {
|
||||||
LABEL_TABLE_SHOW_PER_PAGE("html.label.table.showPerPage", "Show per page"),
|
LABEL_TABLE_SHOW_PER_PAGE("html.label.table.showPerPage", "Show per page"),
|
||||||
LABEL_EXPORT("html.label.export", "Export"),
|
LABEL_EXPORT("html.label.export", "Export"),
|
||||||
|
|
||||||
|
LABEL_ALLOWLIST("html.label.allowlist", "Allowlist"),
|
||||||
|
LABEL_ALLOWLIST_BOUNCES("html.label.allowlistBounces", "Allowlist Bounces"),
|
||||||
|
LABEL_ATTEMPTS("html.label.attempts", "Attempts"),
|
||||||
|
LABEL_LAST_KNOWN_ATTEMPT("html.label.lastKnownAttempt", "Last Known Attempt"),
|
||||||
|
LABEL_PREVIOUS_ATTEMPT("html.label.lastBlocked", "Last Blocked"),
|
||||||
|
LABEL_LAST_ALLOWED_LOGIN("html.label.lastAllowed", "Last Allowed"),
|
||||||
|
LABEL_BLOCKED("html.label.blocked", "Blocked"),
|
||||||
|
LABEL_ALLOWED("html.label.allowed", "Allowed"),
|
||||||
|
|
||||||
LOGIN_LOGIN("html.login.login", "Login"),
|
LOGIN_LOGIN("html.login.login", "Login"),
|
||||||
LOGIN_LOGOUT("html.login.logout", "Logout"),
|
LOGIN_LOGOUT("html.login.logout", "Logout"),
|
||||||
LOGIN_USERNAME("html.login.username", "Username"),
|
LOGIN_USERNAME("html.login.username", "Username"),
|
||||||
|
|
|
@ -147,6 +147,10 @@ public abstract class SQLDB extends AbstractDatabase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ThreadLocal<StackTraceElement[]> getTransactionOrigin() {
|
||||||
|
return TRANSACTION_ORIGIN;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() {
|
public void init() {
|
||||||
List<Runnable> unfinishedTransactions = forceCloseTransactionExecutor();
|
List<Runnable> unfinishedTransactions = forceCloseTransactionExecutor();
|
||||||
|
@ -187,22 +191,6 @@ public abstract class SQLDB extends AbstractDatabase {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<Runnable> forceCloseTransactionExecutor() {
|
|
||||||
if (transactionExecutor == null || transactionExecutor.isShutdown() || transactionExecutor.isTerminated()) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
List<Runnable> unfinished = transactionExecutor.shutdownNow();
|
|
||||||
int unfinishedCount = unfinished.size();
|
|
||||||
if (unfinishedCount > 0) {
|
|
||||||
logger.warn(unfinishedCount + " unfinished database transactions were not executed.");
|
|
||||||
}
|
|
||||||
return unfinished;
|
|
||||||
} finally {
|
|
||||||
logger.info(locale.getString(PluginLang.DISABLED_WAITING_TRANSACTIONS_COMPLETE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Patch[] patches() {
|
Patch[] patches() {
|
||||||
return new Patch[]{
|
return new Patch[]{
|
||||||
new Version10Patch(),
|
new Version10Patch(),
|
||||||
|
@ -313,6 +301,22 @@ public abstract class SQLDB extends AbstractDatabase {
|
||||||
*/
|
*/
|
||||||
public abstract void setupDataSource();
|
public abstract void setupDataSource();
|
||||||
|
|
||||||
|
protected List<Runnable> forceCloseTransactionExecutor() {
|
||||||
|
if (transactionExecutor == null || transactionExecutor.isShutdown() || transactionExecutor.isTerminated()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
List<Runnable> unfinished = transactionExecutor.shutdownNow();
|
||||||
|
int unfinishedCount = unfinished.size();
|
||||||
|
if (unfinishedCount > 0) {
|
||||||
|
logger.warn(unfinishedCount + " unfinished database transactions were not executed.");
|
||||||
|
}
|
||||||
|
return unfinished;
|
||||||
|
} finally {
|
||||||
|
logger.info(locale.getString(PluginLang.DISABLED_WAITING_TRANSACTIONS_COMPLETE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
// SQLiteDB Overrides this, so any additions to this should also be reflected there.
|
// SQLiteDB Overrides this, so any additions to this should also be reflected there.
|
||||||
|
@ -326,13 +330,6 @@ public abstract class SQLDB extends AbstractDatabase {
|
||||||
setState(State.CLOSED);
|
setState(State.CLOSED);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void unloadDriverClassloader() {
|
|
||||||
// Unloading class loader using close() causes issues when reloading.
|
|
||||||
// It is better to leak this memory than crash the plugin on reload.
|
|
||||||
|
|
||||||
driverClassLoader = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract Connection getConnection() throws SQLException;
|
public abstract Connection getConnection() throws SQLException;
|
||||||
|
|
||||||
public abstract void returnToPool(Connection connection);
|
public abstract void returnToPool(Connection connection);
|
||||||
|
@ -346,8 +343,11 @@ public abstract class SQLDB extends AbstractDatabase {
|
||||||
return accessLock.performDatabaseOperation(() -> query.executeQuery(this), transaction);
|
return accessLock.performDatabaseOperation(() -> query.executeQuery(this), transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ThreadLocal<StackTraceElement[]> getTransactionOrigin() {
|
protected void unloadDriverClassloader() {
|
||||||
return TRANSACTION_ORIGIN;
|
// Unloading class loader using close() causes issues when reloading.
|
||||||
|
// It is better to leak this memory than crash the plugin on reload.
|
||||||
|
|
||||||
|
driverClassLoader = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* 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.delivery.domain.datatransfer.AllowlistBounce;
|
||||||
|
import com.djrapitops.plan.identification.ServerUUID;
|
||||||
|
import com.djrapitops.plan.storage.database.queries.Query;
|
||||||
|
import com.djrapitops.plan.storage.database.sql.tables.AllowlistBounceTable;
|
||||||
|
import com.djrapitops.plan.storage.database.sql.tables.ServerTable;
|
||||||
|
import org.intellij.lang.annotations.Language;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static com.djrapitops.plan.storage.database.sql.building.Sql.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query against {@link AllowlistBounceTable}.
|
||||||
|
*
|
||||||
|
* @author AuroraLS3
|
||||||
|
*/
|
||||||
|
public class AllowlistQueries {
|
||||||
|
|
||||||
|
private AllowlistQueries() {
|
||||||
|
/* Static method class */
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Query<List<AllowlistBounce>> getBounces(ServerUUID serverUUID) {
|
||||||
|
@Language("SQL") String sql = SELECT +
|
||||||
|
AllowlistBounceTable.UUID + ',' +
|
||||||
|
AllowlistBounceTable.USER_NAME + ',' +
|
||||||
|
AllowlistBounceTable.TIMES + ',' +
|
||||||
|
AllowlistBounceTable.LAST_BOUNCE +
|
||||||
|
FROM + AllowlistBounceTable.TABLE_NAME +
|
||||||
|
WHERE + AllowlistBounceTable.SERVER_ID + "=" + ServerTable.SELECT_SERVER_ID;
|
||||||
|
return db -> db.queryList(sql, AllowlistQueries::extract, serverUUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AllowlistBounce extract(ResultSet set) throws SQLException {
|
||||||
|
return new AllowlistBounce(
|
||||||
|
UUID.fromString(set.getString(AllowlistBounceTable.UUID)),
|
||||||
|
set.getString(AllowlistBounceTable.USER_NAME),
|
||||||
|
set.getInt(AllowlistBounceTable.TIMES),
|
||||||
|
set.getLong(AllowlistBounceTable.LAST_BOUNCE)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1014,4 +1014,16 @@ public class SessionQueries {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Query<Map<UUID, Long>> lastSeen(ServerUUID serverUUID) {
|
||||||
|
String sql = SELECT + UsersTable.USER_UUID + ", MAX(" + SessionsTable.SESSION_END + ") as last_seen" +
|
||||||
|
FROM + SessionsTable.TABLE_NAME + " s" +
|
||||||
|
INNER_JOIN + UsersTable.TABLE_NAME + " u ON u." + UsersTable.ID + "=s." + SessionsTable.USER_ID +
|
||||||
|
WHERE + SessionsTable.SERVER_ID + "=" + ServerTable.SELECT_SERVER_ID +
|
||||||
|
GROUP_BY + UsersTable.USER_UUID;
|
||||||
|
return db -> db.queryMap(sql, (set, to) -> to.put(
|
||||||
|
UUID.fromString(set.getString(UsersTable.USER_UUID)),
|
||||||
|
set.getLong("last_seen")
|
||||||
|
), serverUUID);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
* 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 org.intellij.lang.annotations.Language;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents plan_allowlist_bounce table.
|
||||||
|
*
|
||||||
|
* @author AuroraLS3
|
||||||
|
*/
|
||||||
|
public class AllowlistBounceTable {
|
||||||
|
|
||||||
|
public static final String TABLE_NAME = "plan_allowlist_bounce";
|
||||||
|
|
||||||
|
public static final String ID = "id";
|
||||||
|
public static final String UUID = "uuid";
|
||||||
|
public static final String USER_NAME = "name";
|
||||||
|
public static final String SERVER_ID = "server_id";
|
||||||
|
public static final String TIMES = "times";
|
||||||
|
public static final String LAST_BOUNCE = "last_bounce";
|
||||||
|
|
||||||
|
@Language("SQL")
|
||||||
|
public static final String INSERT_STATEMENT = "INSERT INTO " + TABLE_NAME + " (" +
|
||||||
|
UUID + ',' +
|
||||||
|
USER_NAME + ',' +
|
||||||
|
SERVER_ID + ',' +
|
||||||
|
TIMES + ',' +
|
||||||
|
LAST_BOUNCE +
|
||||||
|
") VALUES (?,?," + ServerTable.SELECT_SERVER_ID + ",?,?)";
|
||||||
|
|
||||||
|
@Language("SQL")
|
||||||
|
public static final String INCREMENT_TIMES_STATEMENT = "UPDATE " + TABLE_NAME +
|
||||||
|
" SET " + TIMES + "=" + TIMES + "+1, " + LAST_BOUNCE + "=?" +
|
||||||
|
" WHERE " + UUID + "=?" +
|
||||||
|
" AND " + SERVER_ID + "=" + ServerTable.SELECT_SERVER_ID;
|
||||||
|
|
||||||
|
private AllowlistBounceTable() {
|
||||||
|
/* Static information class */
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String createTableSQL(DBType dbType) {
|
||||||
|
return CreateTableBuilder.create(TABLE_NAME, dbType)
|
||||||
|
.column(ID, Sql.INT).primaryKey()
|
||||||
|
.column(UUID, Sql.varchar(36)).notNull().unique()
|
||||||
|
.column(USER_NAME, Sql.varchar(36)).notNull()
|
||||||
|
.column(SERVER_ID, Sql.INT).notNull()
|
||||||
|
.column(TIMES, Sql.INT).notNull().defaultValue("0")
|
||||||
|
.column(LAST_BOUNCE, Sql.LONG).notNull()
|
||||||
|
.foreignKey(SERVER_ID, ServerTable.TABLE_NAME, ServerTable.ID)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,6 +24,7 @@ import com.djrapitops.plan.storage.database.sql.building.Insert;
|
||||||
import com.djrapitops.plan.storage.database.sql.building.Sql;
|
import com.djrapitops.plan.storage.database.sql.building.Sql;
|
||||||
import com.djrapitops.plan.storage.database.sql.building.Update;
|
import com.djrapitops.plan.storage.database.sql.building.Update;
|
||||||
import org.apache.commons.text.TextStringBuilder;
|
import org.apache.commons.text.TextStringBuilder;
|
||||||
|
import org.intellij.lang.annotations.Language;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
@ -61,6 +62,7 @@ public class ServerTable {
|
||||||
.where(SERVER_UUID + "=?")
|
.where(SERVER_UUID + "=?")
|
||||||
.toString();
|
.toString();
|
||||||
|
|
||||||
|
@Language("SQL")
|
||||||
public static final String SELECT_SERVER_ID =
|
public static final String SELECT_SERVER_ID =
|
||||||
'(' + SELECT + TABLE_NAME + '.' + ID +
|
'(' + SELECT + TABLE_NAME + '.' + ID +
|
||||||
FROM + TABLE_NAME +
|
FROM + TABLE_NAME +
|
||||||
|
|
|
@ -43,6 +43,7 @@ public class RemoveEverythingTransaction extends Patch {
|
||||||
clearTable(WorldTimesTable.TABLE_NAME);
|
clearTable(WorldTimesTable.TABLE_NAME);
|
||||||
clearTable(SessionsTable.TABLE_NAME);
|
clearTable(SessionsTable.TABLE_NAME);
|
||||||
clearTable(JoinAddressTable.TABLE_NAME);
|
clearTable(JoinAddressTable.TABLE_NAME);
|
||||||
|
clearTable(AllowlistBounceTable.TABLE_NAME);
|
||||||
clearTable(WorldTable.TABLE_NAME);
|
clearTable(WorldTable.TABLE_NAME);
|
||||||
clearTable(PingTable.TABLE_NAME);
|
clearTable(PingTable.TABLE_NAME);
|
||||||
clearTable(UserInfoTable.TABLE_NAME);
|
clearTable(UserInfoTable.TABLE_NAME);
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* 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.identification.ServerUUID;
|
||||||
|
import com.djrapitops.plan.storage.database.sql.tables.AllowlistBounceTable;
|
||||||
|
import com.djrapitops.plan.storage.database.transactions.ExecStatement;
|
||||||
|
import com.djrapitops.plan.storage.database.transactions.Transaction;
|
||||||
|
import com.djrapitops.plan.utilities.dev.Untrusted;
|
||||||
|
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores a bounced allowlist login.
|
||||||
|
*
|
||||||
|
* @author AuroraLS3
|
||||||
|
*/
|
||||||
|
public class StoreAllowlistBounceTransaction extends Transaction {
|
||||||
|
|
||||||
|
private final UUID playerUUID;
|
||||||
|
@Untrusted
|
||||||
|
private final String playerName;
|
||||||
|
private final ServerUUID serverUUID;
|
||||||
|
private final long time;
|
||||||
|
|
||||||
|
public StoreAllowlistBounceTransaction(UUID playerUUID, @Untrusted String playerName, ServerUUID serverUUID, long time) {
|
||||||
|
this.playerUUID = playerUUID;
|
||||||
|
this.playerName = playerName;
|
||||||
|
this.serverUUID = serverUUID;
|
||||||
|
this.time = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void performOperations() {
|
||||||
|
boolean updated = execute(new ExecStatement(AllowlistBounceTable.INCREMENT_TIMES_STATEMENT) {
|
||||||
|
@Override
|
||||||
|
public void prepare(PreparedStatement statement) throws SQLException {
|
||||||
|
statement.setLong(1, time);
|
||||||
|
statement.setString(2, playerUUID.toString());
|
||||||
|
statement.setString(3, serverUUID.toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!updated) {
|
||||||
|
execute(new ExecStatement(AllowlistBounceTable.INSERT_STATEMENT) {
|
||||||
|
@Override
|
||||||
|
public void prepare(PreparedStatement statement) throws SQLException {
|
||||||
|
statement.setString(1, playerUUID.toString());
|
||||||
|
statement.setString(2, playerName);
|
||||||
|
statement.setString(3, serverUUID.toString());
|
||||||
|
statement.setInt(4, 1);
|
||||||
|
statement.setLong(5, time);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -59,6 +59,7 @@ public class CreateTablesTransaction extends OperationCriticalTransaction {
|
||||||
executeOther(new SecurityTableIdPatch());
|
executeOther(new SecurityTableIdPatch());
|
||||||
execute(WebUserPreferencesTable.createTableSQL(dbType));
|
execute(WebUserPreferencesTable.createTableSQL(dbType));
|
||||||
execute(PluginVersionTable.createTableSQL(dbType));
|
execute(PluginVersionTable.createTableSQL(dbType));
|
||||||
|
execute(AllowlistBounceTable.createTableSQL(dbType));
|
||||||
|
|
||||||
// DataExtension tables
|
// DataExtension tables
|
||||||
execute(ExtensionIconTable.createTableSQL(dbType));
|
execute(ExtensionIconTable.createTableSQL(dbType));
|
||||||
|
|
|
@ -294,9 +294,13 @@ html:
|
||||||
afkTime: "挂机时间"
|
afkTime: "挂机时间"
|
||||||
all: "全部"
|
all: "全部"
|
||||||
allTime: "所有时间"
|
allTime: "所有时间"
|
||||||
|
allowed: "Allowed"
|
||||||
|
allowlist: "Allowlist"
|
||||||
|
allowlistBounces: "Allowlist Bounces"
|
||||||
alphabetical: "按字母顺序"
|
alphabetical: "按字母顺序"
|
||||||
apply: "应用"
|
apply: "应用"
|
||||||
asNumbers: "数据"
|
asNumbers: "数据"
|
||||||
|
attempts: "Attempts"
|
||||||
average: "平均"
|
average: "平均"
|
||||||
averageActivePlaytime: "平均活跃时间"
|
averageActivePlaytime: "平均活跃时间"
|
||||||
averageAfkTime: "平均挂机时间"
|
averageAfkTime: "平均挂机时间"
|
||||||
|
@ -317,6 +321,7 @@ html:
|
||||||
banned: "已被封禁"
|
banned: "已被封禁"
|
||||||
bestPeak: "历史最高峰值"
|
bestPeak: "历史最高峰值"
|
||||||
bestPing: "最低延迟"
|
bestPing: "最低延迟"
|
||||||
|
blocked: "Blocked"
|
||||||
calendar: " 日历"
|
calendar: " 日历"
|
||||||
comparing7days: "对比 7 天的情况"
|
comparing7days: "对比 7 天的情况"
|
||||||
connectionInfo: "连接信息"
|
connectionInfo: "连接信息"
|
||||||
|
@ -430,7 +435,10 @@ html:
|
||||||
last24hours: "过去 24 小时"
|
last24hours: "过去 24 小时"
|
||||||
last30days: "过去 30 天"
|
last30days: "过去 30 天"
|
||||||
last7days: "过去 7 天"
|
last7days: "过去 7 天"
|
||||||
|
lastAllowed: "Last Allowed"
|
||||||
|
lastBlocked: "Last Blocked"
|
||||||
lastConnected: "最后连接时间"
|
lastConnected: "最后连接时间"
|
||||||
|
lastKnownAttempt: "Last Known Attempt"
|
||||||
lastPeak: "上次在线峰值"
|
lastPeak: "上次在线峰值"
|
||||||
lastSeen: "最后在线时间"
|
lastSeen: "最后在线时间"
|
||||||
latestJoinAddresses: "上一次加入地址"
|
latestJoinAddresses: "上一次加入地址"
|
||||||
|
@ -686,6 +694,7 @@ html:
|
||||||
page_player_sessions: "查看玩家会话 - 选项卡"
|
page_player_sessions: "查看玩家会话 - 选项卡"
|
||||||
page_player_versus: "查看PvP和PvE - 选项卡"
|
page_player_versus: "查看PvP和PvE - 选项卡"
|
||||||
page_server: "查看所有服务器页面"
|
page_server: "查看所有服务器页面"
|
||||||
|
page_server_allowlist_bounce: "See list of Game allowlist bounces"
|
||||||
page_server_geolocations: "查看服务器地理位置 - 选项卡"
|
page_server_geolocations: "查看服务器地理位置 - 选项卡"
|
||||||
page_server_geolocations_map: "查看服务器地理位置地图"
|
page_server_geolocations_map: "查看服务器地理位置地图"
|
||||||
page_server_geolocations_ping_per_country: "查看按国家划分的延迟表"
|
page_server_geolocations_ping_per_country: "查看按国家划分的延迟表"
|
||||||
|
|
|
@ -294,9 +294,13 @@ html:
|
||||||
afkTime: "AFK čas"
|
afkTime: "AFK čas"
|
||||||
all: "Vše"
|
all: "Vše"
|
||||||
allTime: "Celkově"
|
allTime: "Celkově"
|
||||||
|
allowed: "Allowed"
|
||||||
|
allowlist: "Allowlist"
|
||||||
|
allowlistBounces: "Allowlist Bounces"
|
||||||
alphabetical: "Abecední řazení"
|
alphabetical: "Abecední řazení"
|
||||||
apply: "Apply"
|
apply: "Apply"
|
||||||
asNumbers: "statistiky"
|
asNumbers: "statistiky"
|
||||||
|
attempts: "Attempts"
|
||||||
average: "Průměrná délka prvního připojení"
|
average: "Průměrná délka prvního připojení"
|
||||||
averageActivePlaytime: "Průměrná herní aktivita"
|
averageActivePlaytime: "Průměrná herní aktivita"
|
||||||
averageAfkTime: "Průměrný AFK čas"
|
averageAfkTime: "Průměrný AFK čas"
|
||||||
|
@ -317,6 +321,7 @@ html:
|
||||||
banned: "Zabanován"
|
banned: "Zabanován"
|
||||||
bestPeak: "Nejvíce hráčů"
|
bestPeak: "Nejvíce hráčů"
|
||||||
bestPing: "Nejlepší ping"
|
bestPing: "Nejlepší ping"
|
||||||
|
blocked: "Blocked"
|
||||||
calendar: " Kalendář"
|
calendar: " Kalendář"
|
||||||
comparing7days: "Srovnání posledních 7 dní"
|
comparing7days: "Srovnání posledních 7 dní"
|
||||||
connectionInfo: "Informace o připojení"
|
connectionInfo: "Informace o připojení"
|
||||||
|
@ -430,7 +435,10 @@ html:
|
||||||
last24hours: "Posledních 24 hodin"
|
last24hours: "Posledních 24 hodin"
|
||||||
last30days: "Posledních 30 dní"
|
last30days: "Posledních 30 dní"
|
||||||
last7days: "Posledních 7 dní"
|
last7days: "Posledních 7 dní"
|
||||||
|
lastAllowed: "Last Allowed"
|
||||||
|
lastBlocked: "Last Blocked"
|
||||||
lastConnected: "Poslední připojení"
|
lastConnected: "Poslední připojení"
|
||||||
|
lastKnownAttempt: "Last Known Attempt"
|
||||||
lastPeak: "Naposledy nejvíce hráčů"
|
lastPeak: "Naposledy nejvíce hráčů"
|
||||||
lastSeen: "Naposledy viděn"
|
lastSeen: "Naposledy viděn"
|
||||||
latestJoinAddresses: "Poslední adresy pro připojení"
|
latestJoinAddresses: "Poslední adresy pro připojení"
|
||||||
|
@ -686,6 +694,7 @@ html:
|
||||||
page_player_sessions: "See Player Sessions -tab"
|
page_player_sessions: "See Player Sessions -tab"
|
||||||
page_player_versus: "See PvP & PvE -tab"
|
page_player_versus: "See PvP & PvE -tab"
|
||||||
page_server: "See all of server page"
|
page_server: "See all of server page"
|
||||||
|
page_server_allowlist_bounce: "See list of Game allowlist bounces"
|
||||||
page_server_geolocations: "See Geolocations tab"
|
page_server_geolocations: "See Geolocations tab"
|
||||||
page_server_geolocations_map: "See Geolocations Map"
|
page_server_geolocations_map: "See Geolocations Map"
|
||||||
page_server_geolocations_ping_per_country: "See Ping Per Country table"
|
page_server_geolocations_ping_per_country: "See Ping Per Country table"
|
||||||
|
|
|
@ -294,9 +294,13 @@ html:
|
||||||
afkTime: "AFK Zeit"
|
afkTime: "AFK Zeit"
|
||||||
all: "Gesamt"
|
all: "Gesamt"
|
||||||
allTime: "Gesamte zeit"
|
allTime: "Gesamte zeit"
|
||||||
|
allowed: "Allowed"
|
||||||
|
allowlist: "Allowlist"
|
||||||
|
allowlistBounces: "Allowlist Bounces"
|
||||||
alphabetical: "Alphabetical"
|
alphabetical: "Alphabetical"
|
||||||
apply: "Apply"
|
apply: "Apply"
|
||||||
asNumbers: "als Zahlen"
|
asNumbers: "als Zahlen"
|
||||||
|
attempts: "Attempts"
|
||||||
average: "Average first session length"
|
average: "Average first session length"
|
||||||
averageActivePlaytime: "Durchschnittliche aktive Spielzeit"
|
averageActivePlaytime: "Durchschnittliche aktive Spielzeit"
|
||||||
averageAfkTime: "Durchschnittliche AFK Zeit"
|
averageAfkTime: "Durchschnittliche AFK Zeit"
|
||||||
|
@ -317,6 +321,7 @@ html:
|
||||||
banned: "Gebannt"
|
banned: "Gebannt"
|
||||||
bestPeak: "Rekord"
|
bestPeak: "Rekord"
|
||||||
bestPing: "Bester Ping"
|
bestPing: "Bester Ping"
|
||||||
|
blocked: "Blocked"
|
||||||
calendar: " Kalender"
|
calendar: " Kalender"
|
||||||
comparing7days: "Vergleiche 7 Tage"
|
comparing7days: "Vergleiche 7 Tage"
|
||||||
connectionInfo: "Verbindungsinformationen"
|
connectionInfo: "Verbindungsinformationen"
|
||||||
|
@ -430,7 +435,10 @@ html:
|
||||||
last24hours: "Letzte 24 Stunden"
|
last24hours: "Letzte 24 Stunden"
|
||||||
last30days: "Letzte 30 Tage"
|
last30days: "Letzte 30 Tage"
|
||||||
last7days: "Letzte 7 Tage"
|
last7days: "Letzte 7 Tage"
|
||||||
|
lastAllowed: "Last Allowed"
|
||||||
|
lastBlocked: "Last Blocked"
|
||||||
lastConnected: "Letzte Verbindung"
|
lastConnected: "Letzte Verbindung"
|
||||||
|
lastKnownAttempt: "Last Known Attempt"
|
||||||
lastPeak: "Letzter Höchststand"
|
lastPeak: "Letzter Höchststand"
|
||||||
lastSeen: "Zuletzt gesehen"
|
lastSeen: "Zuletzt gesehen"
|
||||||
latestJoinAddresses: "Latest Join Addresses"
|
latestJoinAddresses: "Latest Join Addresses"
|
||||||
|
@ -686,6 +694,7 @@ html:
|
||||||
page_player_sessions: "See Player Sessions -tab"
|
page_player_sessions: "See Player Sessions -tab"
|
||||||
page_player_versus: "See PvP & PvE -tab"
|
page_player_versus: "See PvP & PvE -tab"
|
||||||
page_server: "See all of server page"
|
page_server: "See all of server page"
|
||||||
|
page_server_allowlist_bounce: "See list of Game allowlist bounces"
|
||||||
page_server_geolocations: "See Geolocations tab"
|
page_server_geolocations: "See Geolocations tab"
|
||||||
page_server_geolocations_map: "See Geolocations Map"
|
page_server_geolocations_map: "See Geolocations Map"
|
||||||
page_server_geolocations_ping_per_country: "See Ping Per Country table"
|
page_server_geolocations_ping_per_country: "See Ping Per Country table"
|
||||||
|
|
|
@ -294,9 +294,13 @@ html:
|
||||||
afkTime: "AFK Time"
|
afkTime: "AFK Time"
|
||||||
all: "All"
|
all: "All"
|
||||||
allTime: "All Time"
|
allTime: "All Time"
|
||||||
|
allowed: "Allowed"
|
||||||
|
allowlist: "Allowlist"
|
||||||
|
allowlistBounces: "Allowlist Bounces"
|
||||||
alphabetical: "Alphabetical"
|
alphabetical: "Alphabetical"
|
||||||
apply: "Apply"
|
apply: "Apply"
|
||||||
asNumbers: "as Numbers"
|
asNumbers: "as Numbers"
|
||||||
|
attempts: "Attempts"
|
||||||
average: "Average first session length"
|
average: "Average first session length"
|
||||||
averageActivePlaytime: "Average Active Playtime"
|
averageActivePlaytime: "Average Active Playtime"
|
||||||
averageAfkTime: "Average AFK Time"
|
averageAfkTime: "Average AFK Time"
|
||||||
|
@ -317,6 +321,7 @@ html:
|
||||||
banned: "Banned"
|
banned: "Banned"
|
||||||
bestPeak: "All Time Peak"
|
bestPeak: "All Time Peak"
|
||||||
bestPing: "Best Ping"
|
bestPing: "Best Ping"
|
||||||
|
blocked: "Blocked"
|
||||||
calendar: " Calendar"
|
calendar: " Calendar"
|
||||||
comparing7days: "Comparing 7 days"
|
comparing7days: "Comparing 7 days"
|
||||||
connectionInfo: "Connection Information"
|
connectionInfo: "Connection Information"
|
||||||
|
@ -430,7 +435,10 @@ html:
|
||||||
last24hours: "Last 24 hours"
|
last24hours: "Last 24 hours"
|
||||||
last30days: "Last 30 days"
|
last30days: "Last 30 days"
|
||||||
last7days: "Last 7 days"
|
last7days: "Last 7 days"
|
||||||
|
lastAllowed: "Last Allowed"
|
||||||
|
lastBlocked: "Last Blocked"
|
||||||
lastConnected: "Last Connected"
|
lastConnected: "Last Connected"
|
||||||
|
lastKnownAttempt: "Last Known Attempt"
|
||||||
lastPeak: "Last Peak"
|
lastPeak: "Last Peak"
|
||||||
lastSeen: "Last Seen"
|
lastSeen: "Last Seen"
|
||||||
latestJoinAddresses: "Latest Join Addresses"
|
latestJoinAddresses: "Latest Join Addresses"
|
||||||
|
@ -686,6 +694,7 @@ html:
|
||||||
page_player_sessions: "See Player Sessions -tab"
|
page_player_sessions: "See Player Sessions -tab"
|
||||||
page_player_versus: "See PvP & PvE -tab"
|
page_player_versus: "See PvP & PvE -tab"
|
||||||
page_server: "See all of server page"
|
page_server: "See all of server page"
|
||||||
|
page_server_allowlist_bounce: "See list of Game allowlist bounces"
|
||||||
page_server_geolocations: "See Geolocations tab"
|
page_server_geolocations: "See Geolocations tab"
|
||||||
page_server_geolocations_map: "See Geolocations Map"
|
page_server_geolocations_map: "See Geolocations Map"
|
||||||
page_server_geolocations_ping_per_country: "See Ping Per Country table"
|
page_server_geolocations_ping_per_country: "See Ping Per Country table"
|
||||||
|
|
|
@ -294,9 +294,13 @@ html:
|
||||||
afkTime: "Tiempo AFK"
|
afkTime: "Tiempo AFK"
|
||||||
all: "Todo"
|
all: "Todo"
|
||||||
allTime: "Todo el tiempo"
|
allTime: "Todo el tiempo"
|
||||||
|
allowed: "Allowed"
|
||||||
|
allowlist: "Allowlist"
|
||||||
|
allowlistBounces: "Allowlist Bounces"
|
||||||
alphabetical: "Alphabetical"
|
alphabetical: "Alphabetical"
|
||||||
apply: "Apply"
|
apply: "Apply"
|
||||||
asNumbers: "como números"
|
asNumbers: "como números"
|
||||||
|
attempts: "Attempts"
|
||||||
average: "Average first session length"
|
average: "Average first session length"
|
||||||
averageActivePlaytime: "Tiempo de juego activo promedio"
|
averageActivePlaytime: "Tiempo de juego activo promedio"
|
||||||
averageAfkTime: "Tiempo AFK promedio"
|
averageAfkTime: "Tiempo AFK promedio"
|
||||||
|
@ -317,6 +321,7 @@ html:
|
||||||
banned: "Baneado"
|
banned: "Baneado"
|
||||||
bestPeak: "Mejor pico"
|
bestPeak: "Mejor pico"
|
||||||
bestPing: "Mejor Ping"
|
bestPing: "Mejor Ping"
|
||||||
|
blocked: "Blocked"
|
||||||
calendar: " Calendario"
|
calendar: " Calendario"
|
||||||
comparing7days: "Comparando 7 dias"
|
comparing7days: "Comparando 7 dias"
|
||||||
connectionInfo: "Información de conexión"
|
connectionInfo: "Información de conexión"
|
||||||
|
@ -430,7 +435,10 @@ html:
|
||||||
last24hours: "Últimas 24 horas"
|
last24hours: "Últimas 24 horas"
|
||||||
last30days: "Últimos 30 dias"
|
last30days: "Últimos 30 dias"
|
||||||
last7days: "Últimos 7 días"
|
last7days: "Últimos 7 días"
|
||||||
|
lastAllowed: "Last Allowed"
|
||||||
|
lastBlocked: "Last Blocked"
|
||||||
lastConnected: "Última vez conectado"
|
lastConnected: "Última vez conectado"
|
||||||
|
lastKnownAttempt: "Last Known Attempt"
|
||||||
lastPeak: "Último pico"
|
lastPeak: "Último pico"
|
||||||
lastSeen: "Última vez visto"
|
lastSeen: "Última vez visto"
|
||||||
latestJoinAddresses: "Latest Join Addresses"
|
latestJoinAddresses: "Latest Join Addresses"
|
||||||
|
@ -686,6 +694,7 @@ html:
|
||||||
page_player_sessions: "See Player Sessions -tab"
|
page_player_sessions: "See Player Sessions -tab"
|
||||||
page_player_versus: "See PvP & PvE -tab"
|
page_player_versus: "See PvP & PvE -tab"
|
||||||
page_server: "See all of server page"
|
page_server: "See all of server page"
|
||||||
|
page_server_allowlist_bounce: "See list of Game allowlist bounces"
|
||||||
page_server_geolocations: "See Geolocations tab"
|
page_server_geolocations: "See Geolocations tab"
|
||||||
page_server_geolocations_map: "See Geolocations Map"
|
page_server_geolocations_map: "See Geolocations Map"
|
||||||
page_server_geolocations_ping_per_country: "See Ping Per Country table"
|
page_server_geolocations_ping_per_country: "See Ping Per Country table"
|
||||||
|
|
|
@ -294,9 +294,13 @@ html:
|
||||||
afkTime: "Aika AFK:ina"
|
afkTime: "Aika AFK:ina"
|
||||||
all: "Kaikki"
|
all: "Kaikki"
|
||||||
allTime: "Kaikkien aikojen"
|
allTime: "Kaikkien aikojen"
|
||||||
|
allowed: "Allowed"
|
||||||
|
allowlist: "Allowlist"
|
||||||
|
allowlistBounces: "Allowlist Bounces"
|
||||||
alphabetical: "Aakkosjärjestys"
|
alphabetical: "Aakkosjärjestys"
|
||||||
apply: "Käytä"
|
apply: "Käytä"
|
||||||
asNumbers: "Numeroina"
|
asNumbers: "Numeroina"
|
||||||
|
attempts: "Attempts"
|
||||||
average: "Keskimäräinen"
|
average: "Keskimäräinen"
|
||||||
averageActivePlaytime: "Keskimäräinen Aktiivinen peliaika"
|
averageActivePlaytime: "Keskimäräinen Aktiivinen peliaika"
|
||||||
averageAfkTime: "Keskimäräinen AFK aika"
|
averageAfkTime: "Keskimäräinen AFK aika"
|
||||||
|
@ -317,6 +321,7 @@ html:
|
||||||
banned: "Pannassa"
|
banned: "Pannassa"
|
||||||
bestPeak: "Paras Huippu"
|
bestPeak: "Paras Huippu"
|
||||||
bestPing: "Paras Vasteaika"
|
bestPing: "Paras Vasteaika"
|
||||||
|
blocked: "Blocked"
|
||||||
calendar: " Kalenteri"
|
calendar: " Kalenteri"
|
||||||
comparing7days: "Verrataan 7 päivää"
|
comparing7days: "Verrataan 7 päivää"
|
||||||
connectionInfo: "Yhteyksien tiedot"
|
connectionInfo: "Yhteyksien tiedot"
|
||||||
|
@ -430,7 +435,10 @@ html:
|
||||||
last24hours: "Viimeiset 24 tuntia"
|
last24hours: "Viimeiset 24 tuntia"
|
||||||
last30days: "Viimeiset 30 päivää"
|
last30days: "Viimeiset 30 päivää"
|
||||||
last7days: "Viimeiset 7 päivää"
|
last7days: "Viimeiset 7 päivää"
|
||||||
|
lastAllowed: "Last Allowed"
|
||||||
|
lastBlocked: "Last Blocked"
|
||||||
lastConnected: "Viimeisin yhteys"
|
lastConnected: "Viimeisin yhteys"
|
||||||
|
lastKnownAttempt: "Last Known Attempt"
|
||||||
lastPeak: "Viimeisin huippu"
|
lastPeak: "Viimeisin huippu"
|
||||||
lastSeen: "Nähty Viimeksi"
|
lastSeen: "Nähty Viimeksi"
|
||||||
latestJoinAddresses: "Viimeisimmät Liittymisosoitteet"
|
latestJoinAddresses: "Viimeisimmät Liittymisosoitteet"
|
||||||
|
@ -686,6 +694,7 @@ html:
|
||||||
page_player_sessions: "Näkee Pelaajan Istunnot osion"
|
page_player_sessions: "Näkee Pelaajan Istunnot osion"
|
||||||
page_player_versus: "Näkee PvP & PvE osion"
|
page_player_versus: "Näkee PvP & PvE osion"
|
||||||
page_server: "Näkee koko palvelin sivun"
|
page_server: "Näkee koko palvelin sivun"
|
||||||
|
page_server_allowlist_bounce: "See list of Game allowlist bounces"
|
||||||
page_server_geolocations: "Näkee Geolokaatio osion"
|
page_server_geolocations: "Näkee Geolokaatio osion"
|
||||||
page_server_geolocations_map: "Näkee Geolokaatio kartan"
|
page_server_geolocations_map: "Näkee Geolokaatio kartan"
|
||||||
page_server_geolocations_ping_per_country: "Näkee Viive per Maa -taulun"
|
page_server_geolocations_ping_per_country: "Näkee Viive per Maa -taulun"
|
||||||
|
|
|
@ -294,9 +294,13 @@ html:
|
||||||
afkTime: "Temps AFK"
|
afkTime: "Temps AFK"
|
||||||
all: "Tout"
|
all: "Tout"
|
||||||
allTime: "Tout le Temps"
|
allTime: "Tout le Temps"
|
||||||
|
allowed: "Allowed"
|
||||||
|
allowlist: "Allowlist"
|
||||||
|
allowlistBounces: "Allowlist Bounces"
|
||||||
alphabetical: "Alphabetical"
|
alphabetical: "Alphabetical"
|
||||||
apply: "Apply"
|
apply: "Apply"
|
||||||
asNumbers: "en Chiffres"
|
asNumbers: "en Chiffres"
|
||||||
|
attempts: "Attempts"
|
||||||
average: "Average first session length"
|
average: "Average first session length"
|
||||||
averageActivePlaytime: "Temps Actif moyen"
|
averageActivePlaytime: "Temps Actif moyen"
|
||||||
averageAfkTime: "Temps AFK moyen"
|
averageAfkTime: "Temps AFK moyen"
|
||||||
|
@ -317,6 +321,7 @@ html:
|
||||||
banned: "Banni(e)"
|
banned: "Banni(e)"
|
||||||
bestPeak: "Pic maximal de Joueurs en Ligne"
|
bestPeak: "Pic maximal de Joueurs en Ligne"
|
||||||
bestPing: "Meilleure Latence"
|
bestPing: "Meilleure Latence"
|
||||||
|
blocked: "Blocked"
|
||||||
calendar: " Calendrier"
|
calendar: " Calendrier"
|
||||||
comparing7days: "Comparaison des 7 derniers Jours"
|
comparing7days: "Comparaison des 7 derniers Jours"
|
||||||
connectionInfo: "Renseignements sur la Connexion"
|
connectionInfo: "Renseignements sur la Connexion"
|
||||||
|
@ -430,7 +435,10 @@ html:
|
||||||
last24hours: "24 Dernières heures"
|
last24hours: "24 Dernières heures"
|
||||||
last30days: "30 Derniers jours"
|
last30days: "30 Derniers jours"
|
||||||
last7days: "7 Derniers jours"
|
last7days: "7 Derniers jours"
|
||||||
|
lastAllowed: "Last Allowed"
|
||||||
|
lastBlocked: "Last Blocked"
|
||||||
lastConnected: "Dernier Connecté"
|
lastConnected: "Dernier Connecté"
|
||||||
|
lastKnownAttempt: "Last Known Attempt"
|
||||||
lastPeak: "Dernier pic de Joueurs en Ligne"
|
lastPeak: "Dernier pic de Joueurs en Ligne"
|
||||||
lastSeen: "Dernière Connexion"
|
lastSeen: "Dernière Connexion"
|
||||||
latestJoinAddresses: "Latest Join Addresses"
|
latestJoinAddresses: "Latest Join Addresses"
|
||||||
|
@ -686,6 +694,7 @@ html:
|
||||||
page_player_sessions: "See Player Sessions -tab"
|
page_player_sessions: "See Player Sessions -tab"
|
||||||
page_player_versus: "See PvP & PvE -tab"
|
page_player_versus: "See PvP & PvE -tab"
|
||||||
page_server: "See all of server page"
|
page_server: "See all of server page"
|
||||||
|
page_server_allowlist_bounce: "See list of Game allowlist bounces"
|
||||||
page_server_geolocations: "See Geolocations tab"
|
page_server_geolocations: "See Geolocations tab"
|
||||||
page_server_geolocations_map: "See Geolocations Map"
|
page_server_geolocations_map: "See Geolocations Map"
|
||||||
page_server_geolocations_ping_per_country: "See Ping Per Country table"
|
page_server_geolocations_ping_per_country: "See Ping Per Country table"
|
||||||
|
|
|
@ -294,9 +294,13 @@ html:
|
||||||
afkTime: "Tempo AFK"
|
afkTime: "Tempo AFK"
|
||||||
all: "Tutto"
|
all: "Tutto"
|
||||||
allTime: "Tutto il Tempo"
|
allTime: "Tutto il Tempo"
|
||||||
|
allowed: "Allowed"
|
||||||
|
allowlist: "Allowlist"
|
||||||
|
allowlistBounces: "Allowlist Bounces"
|
||||||
alphabetical: "Alphabetical"
|
alphabetical: "Alphabetical"
|
||||||
apply: "Apply"
|
apply: "Apply"
|
||||||
asNumbers: "Statistiche"
|
asNumbers: "Statistiche"
|
||||||
|
attempts: "Attempts"
|
||||||
average: "Average first session length"
|
average: "Average first session length"
|
||||||
averageActivePlaytime: "Average Active Playtime"
|
averageActivePlaytime: "Average Active Playtime"
|
||||||
averageAfkTime: "Average AFK Time"
|
averageAfkTime: "Average AFK Time"
|
||||||
|
@ -317,6 +321,7 @@ html:
|
||||||
banned: "Bannato"
|
banned: "Bannato"
|
||||||
bestPeak: "Record Migliore"
|
bestPeak: "Record Migliore"
|
||||||
bestPing: "Ping Migliore"
|
bestPing: "Ping Migliore"
|
||||||
|
blocked: "Blocked"
|
||||||
calendar: " Calendario"
|
calendar: " Calendario"
|
||||||
comparing7days: "Comparazione di 7 giorni"
|
comparing7days: "Comparazione di 7 giorni"
|
||||||
connectionInfo: "Informazioni sulla Connessione"
|
connectionInfo: "Informazioni sulla Connessione"
|
||||||
|
@ -430,7 +435,10 @@ html:
|
||||||
last24hours: "Ultime 24 ore"
|
last24hours: "Ultime 24 ore"
|
||||||
last30days: "Ultimi 30 giorni"
|
last30days: "Ultimi 30 giorni"
|
||||||
last7days: "Ultimi 7 giorni"
|
last7days: "Ultimi 7 giorni"
|
||||||
|
lastAllowed: "Last Allowed"
|
||||||
|
lastBlocked: "Last Blocked"
|
||||||
lastConnected: "Ultima connessione"
|
lastConnected: "Ultima connessione"
|
||||||
|
lastKnownAttempt: "Last Known Attempt"
|
||||||
lastPeak: "Record Settimanale"
|
lastPeak: "Record Settimanale"
|
||||||
lastSeen: "Ultima Visita"
|
lastSeen: "Ultima Visita"
|
||||||
latestJoinAddresses: "Latest Join Addresses"
|
latestJoinAddresses: "Latest Join Addresses"
|
||||||
|
@ -686,6 +694,7 @@ html:
|
||||||
page_player_sessions: "See Player Sessions -tab"
|
page_player_sessions: "See Player Sessions -tab"
|
||||||
page_player_versus: "See PvP & PvE -tab"
|
page_player_versus: "See PvP & PvE -tab"
|
||||||
page_server: "See all of server page"
|
page_server: "See all of server page"
|
||||||
|
page_server_allowlist_bounce: "See list of Game allowlist bounces"
|
||||||
page_server_geolocations: "See Geolocations tab"
|
page_server_geolocations: "See Geolocations tab"
|
||||||
page_server_geolocations_map: "See Geolocations Map"
|
page_server_geolocations_map: "See Geolocations Map"
|
||||||
page_server_geolocations_ping_per_country: "See Ping Per Country table"
|
page_server_geolocations_ping_per_country: "See Ping Per Country table"
|
||||||
|
|
|
@ -294,9 +294,13 @@ html:
|
||||||
afkTime: "離席時間"
|
afkTime: "離席時間"
|
||||||
all: "全て"
|
all: "全て"
|
||||||
allTime: "全体"
|
allTime: "全体"
|
||||||
|
allowed: "Allowed"
|
||||||
|
allowlist: "Allowlist"
|
||||||
|
allowlistBounces: "Allowlist Bounces"
|
||||||
alphabetical: "アルファベット順"
|
alphabetical: "アルファベット順"
|
||||||
apply: "適用"
|
apply: "適用"
|
||||||
asNumbers: "の情報"
|
asNumbers: "の情報"
|
||||||
|
attempts: "Attempts"
|
||||||
average: "平均の初回セッション時間"
|
average: "平均の初回セッション時間"
|
||||||
averageActivePlaytime: "平均アクティブプレイ時間"
|
averageActivePlaytime: "平均アクティブプレイ時間"
|
||||||
averageAfkTime: "平均AFK時間"
|
averageAfkTime: "平均AFK時間"
|
||||||
|
@ -317,6 +321,7 @@ html:
|
||||||
banned: "BAN履歴"
|
banned: "BAN履歴"
|
||||||
bestPeak: "全体のピークタイム"
|
bestPeak: "全体のピークタイム"
|
||||||
bestPing: "最高Ping値"
|
bestPing: "最高Ping値"
|
||||||
|
blocked: "Blocked"
|
||||||
calendar: "カレンダー"
|
calendar: "カレンダー"
|
||||||
comparing7days: "直近1週間との比較"
|
comparing7days: "直近1週間との比較"
|
||||||
connectionInfo: "接続情報"
|
connectionInfo: "接続情報"
|
||||||
|
@ -430,7 +435,10 @@ html:
|
||||||
last24hours: "24時間"
|
last24hours: "24時間"
|
||||||
last30days: "1ヶ月"
|
last30days: "1ヶ月"
|
||||||
last7days: "1週間"
|
last7days: "1週間"
|
||||||
|
lastAllowed: "Last Allowed"
|
||||||
|
lastBlocked: "Last Blocked"
|
||||||
lastConnected: "直近の接続"
|
lastConnected: "直近の接続"
|
||||||
|
lastKnownAttempt: "Last Known Attempt"
|
||||||
lastPeak: "直近のピークタイム"
|
lastPeak: "直近のピークタイム"
|
||||||
lastSeen: "直近のオンライン"
|
lastSeen: "直近のオンライン"
|
||||||
latestJoinAddresses: "最後に参加したサーバーのアドレス"
|
latestJoinAddresses: "最後に参加したサーバーのアドレス"
|
||||||
|
@ -686,6 +694,7 @@ html:
|
||||||
page_player_sessions: "プレイヤーセッションタブを表示"
|
page_player_sessions: "プレイヤーセッションタブを表示"
|
||||||
page_player_versus: "PvP & PvEタブを表示"
|
page_player_versus: "PvP & PvEタブを表示"
|
||||||
page_server: "全てのサーバーページを表示"
|
page_server: "全てのサーバーページを表示"
|
||||||
|
page_server_allowlist_bounce: "See list of Game allowlist bounces"
|
||||||
page_server_geolocations: "ジオロケーションタブを表示"
|
page_server_geolocations: "ジオロケーションタブを表示"
|
||||||
page_server_geolocations_map: "ジオロケーションマップを表示"
|
page_server_geolocations_map: "ジオロケーションマップを表示"
|
||||||
page_server_geolocations_ping_per_country: "国ごとのPing表を表示"
|
page_server_geolocations_ping_per_country: "国ごとのPing表を表示"
|
||||||
|
|
|
@ -294,9 +294,13 @@ html:
|
||||||
afkTime: "AFK 시간"
|
afkTime: "AFK 시간"
|
||||||
all: "모두"
|
all: "모두"
|
||||||
allTime: "모든 시간"
|
allTime: "모든 시간"
|
||||||
|
allowed: "Allowed"
|
||||||
|
allowlist: "Allowlist"
|
||||||
|
allowlistBounces: "Allowlist Bounces"
|
||||||
alphabetical: "Alphabetical"
|
alphabetical: "Alphabetical"
|
||||||
apply: "Apply"
|
apply: "Apply"
|
||||||
asNumbers: "숫자로"
|
asNumbers: "숫자로"
|
||||||
|
attempts: "Attempts"
|
||||||
average: "Average first session length"
|
average: "Average first session length"
|
||||||
averageActivePlaytime: "Average Active Playtime"
|
averageActivePlaytime: "Average Active Playtime"
|
||||||
averageAfkTime: "Average AFK Time"
|
averageAfkTime: "Average AFK Time"
|
||||||
|
@ -317,6 +321,7 @@ html:
|
||||||
banned: "Banned"
|
banned: "Banned"
|
||||||
bestPeak: "최고의 피크"
|
bestPeak: "최고의 피크"
|
||||||
bestPing: "최고 Ping"
|
bestPing: "최고 Ping"
|
||||||
|
blocked: "Blocked"
|
||||||
calendar: " 달력"
|
calendar: " 달력"
|
||||||
comparing7days: "지난 7일 비교"
|
comparing7days: "지난 7일 비교"
|
||||||
connectionInfo: "연결 정보"
|
connectionInfo: "연결 정보"
|
||||||
|
@ -430,7 +435,10 @@ html:
|
||||||
last24hours: "지난 24시간"
|
last24hours: "지난 24시간"
|
||||||
last30days: "지난 30일"
|
last30days: "지난 30일"
|
||||||
last7days: "지난 7일"
|
last7days: "지난 7일"
|
||||||
|
lastAllowed: "Last Allowed"
|
||||||
|
lastBlocked: "Last Blocked"
|
||||||
lastConnected: "마지막 연결"
|
lastConnected: "마지막 연결"
|
||||||
|
lastKnownAttempt: "Last Known Attempt"
|
||||||
lastPeak: "마지막 피크"
|
lastPeak: "마지막 피크"
|
||||||
lastSeen: "마지막으로 본"
|
lastSeen: "마지막으로 본"
|
||||||
latestJoinAddresses: "Latest Join Addresses"
|
latestJoinAddresses: "Latest Join Addresses"
|
||||||
|
@ -686,6 +694,7 @@ html:
|
||||||
page_player_sessions: "See Player Sessions -tab"
|
page_player_sessions: "See Player Sessions -tab"
|
||||||
page_player_versus: "See PvP & PvE -tab"
|
page_player_versus: "See PvP & PvE -tab"
|
||||||
page_server: "See all of server page"
|
page_server: "See all of server page"
|
||||||
|
page_server_allowlist_bounce: "See list of Game allowlist bounces"
|
||||||
page_server_geolocations: "See Geolocations tab"
|
page_server_geolocations: "See Geolocations tab"
|
||||||
page_server_geolocations_map: "See Geolocations Map"
|
page_server_geolocations_map: "See Geolocations Map"
|
||||||
page_server_geolocations_ping_per_country: "See Ping Per Country table"
|
page_server_geolocations_ping_per_country: "See Ping Per Country table"
|
||||||
|
|
|
@ -294,9 +294,13 @@ html:
|
||||||
afkTime: "AFK Tijd"
|
afkTime: "AFK Tijd"
|
||||||
all: "Alle"
|
all: "Alle"
|
||||||
allTime: "Alle Tijd"
|
allTime: "Alle Tijd"
|
||||||
|
allowed: "Allowed"
|
||||||
|
allowlist: "Allowlist"
|
||||||
|
allowlistBounces: "Allowlist Bounces"
|
||||||
alphabetical: "Alphabetical"
|
alphabetical: "Alphabetical"
|
||||||
apply: "Apply"
|
apply: "Apply"
|
||||||
asNumbers: "als nummers"
|
asNumbers: "als nummers"
|
||||||
|
attempts: "Attempts"
|
||||||
average: "Average first session length"
|
average: "Average first session length"
|
||||||
averageActivePlaytime: "Gemiddelde Actieve Speeltijd"
|
averageActivePlaytime: "Gemiddelde Actieve Speeltijd"
|
||||||
averageAfkTime: "Gemiddelde AFK Tijd"
|
averageAfkTime: "Gemiddelde AFK Tijd"
|
||||||
|
@ -317,6 +321,7 @@ html:
|
||||||
banned: "Verbannen"
|
banned: "Verbannen"
|
||||||
bestPeak: "Piek aller tijden"
|
bestPeak: "Piek aller tijden"
|
||||||
bestPing: "Beste ping"
|
bestPing: "Beste ping"
|
||||||
|
blocked: "Blocked"
|
||||||
calendar: " Kalender"
|
calendar: " Kalender"
|
||||||
comparing7days: "7 dagen vergelijken"
|
comparing7days: "7 dagen vergelijken"
|
||||||
connectionInfo: "Verbindingsinformatie"
|
connectionInfo: "Verbindingsinformatie"
|
||||||
|
@ -430,7 +435,10 @@ html:
|
||||||
last24hours: "Afgelopen 24 uur"
|
last24hours: "Afgelopen 24 uur"
|
||||||
last30days: "Afgelopen 30 dagen"
|
last30days: "Afgelopen 30 dagen"
|
||||||
last7days: "Afgelopen 7 dagen"
|
last7days: "Afgelopen 7 dagen"
|
||||||
|
lastAllowed: "Last Allowed"
|
||||||
|
lastBlocked: "Last Blocked"
|
||||||
lastConnected: "Laatst verbonden"
|
lastConnected: "Laatst verbonden"
|
||||||
|
lastKnownAttempt: "Last Known Attempt"
|
||||||
lastPeak: "Laatste piek"
|
lastPeak: "Laatste piek"
|
||||||
lastSeen: "Laatste gezien"
|
lastSeen: "Laatste gezien"
|
||||||
latestJoinAddresses: "Latest Join Addresses"
|
latestJoinAddresses: "Latest Join Addresses"
|
||||||
|
@ -686,6 +694,7 @@ html:
|
||||||
page_player_sessions: "See Player Sessions -tab"
|
page_player_sessions: "See Player Sessions -tab"
|
||||||
page_player_versus: "See PvP & PvE -tab"
|
page_player_versus: "See PvP & PvE -tab"
|
||||||
page_server: "See all of server page"
|
page_server: "See all of server page"
|
||||||
|
page_server_allowlist_bounce: "See list of Game allowlist bounces"
|
||||||
page_server_geolocations: "See Geolocations tab"
|
page_server_geolocations: "See Geolocations tab"
|
||||||
page_server_geolocations_map: "See Geolocations Map"
|
page_server_geolocations_map: "See Geolocations Map"
|
||||||
page_server_geolocations_ping_per_country: "See Ping Per Country table"
|
page_server_geolocations_ping_per_country: "See Ping Per Country table"
|
||||||
|
|
|
@ -294,9 +294,13 @@ html:
|
||||||
afkTime: "AFK Time"
|
afkTime: "AFK Time"
|
||||||
all: "Todos"
|
all: "Todos"
|
||||||
allTime: "All Time"
|
allTime: "All Time"
|
||||||
|
allowed: "Allowed"
|
||||||
|
allowlist: "Allowlist"
|
||||||
|
allowlistBounces: "Allowlist Bounces"
|
||||||
alphabetical: "Alphabetical"
|
alphabetical: "Alphabetical"
|
||||||
apply: "Apply"
|
apply: "Apply"
|
||||||
asNumbers: "as Numbers"
|
asNumbers: "as Numbers"
|
||||||
|
attempts: "Attempts"
|
||||||
average: "Average first session length"
|
average: "Average first session length"
|
||||||
averageActivePlaytime: "Average Active Playtime"
|
averageActivePlaytime: "Average Active Playtime"
|
||||||
averageAfkTime: "Average AFK Time"
|
averageAfkTime: "Average AFK Time"
|
||||||
|
@ -317,6 +321,7 @@ html:
|
||||||
banned: "Banido"
|
banned: "Banido"
|
||||||
bestPeak: "Pico Máximo"
|
bestPeak: "Pico Máximo"
|
||||||
bestPing: "Best Ping"
|
bestPing: "Best Ping"
|
||||||
|
blocked: "Blocked"
|
||||||
calendar: " Calendário"
|
calendar: " Calendário"
|
||||||
comparing7days: "Comparing 7 days"
|
comparing7days: "Comparing 7 days"
|
||||||
connectionInfo: "Connection Information"
|
connectionInfo: "Connection Information"
|
||||||
|
@ -430,7 +435,10 @@ html:
|
||||||
last24hours: "Últimas 24 horas"
|
last24hours: "Últimas 24 horas"
|
||||||
last30days: "Últimos 30 dias"
|
last30days: "Últimos 30 dias"
|
||||||
last7days: "Últimos 7 dias"
|
last7days: "Últimos 7 dias"
|
||||||
|
lastAllowed: "Last Allowed"
|
||||||
|
lastBlocked: "Last Blocked"
|
||||||
lastConnected: "Última Conexão"
|
lastConnected: "Última Conexão"
|
||||||
|
lastKnownAttempt: "Last Known Attempt"
|
||||||
lastPeak: "Último Pico"
|
lastPeak: "Último Pico"
|
||||||
lastSeen: "Última Vez Visto"
|
lastSeen: "Última Vez Visto"
|
||||||
latestJoinAddresses: "Latest Join Addresses"
|
latestJoinAddresses: "Latest Join Addresses"
|
||||||
|
@ -686,6 +694,7 @@ html:
|
||||||
page_player_sessions: "See Player Sessions -tab"
|
page_player_sessions: "See Player Sessions -tab"
|
||||||
page_player_versus: "See PvP & PvE -tab"
|
page_player_versus: "See PvP & PvE -tab"
|
||||||
page_server: "See all of server page"
|
page_server: "See all of server page"
|
||||||
|
page_server_allowlist_bounce: "See list of Game allowlist bounces"
|
||||||
page_server_geolocations: "See Geolocations tab"
|
page_server_geolocations: "See Geolocations tab"
|
||||||
page_server_geolocations_map: "See Geolocations Map"
|
page_server_geolocations_map: "See Geolocations Map"
|
||||||
page_server_geolocations_ping_per_country: "See Ping Per Country table"
|
page_server_geolocations_ping_per_country: "See Ping Per Country table"
|
||||||
|
|
|
@ -294,9 +294,13 @@ html:
|
||||||
afkTime: "Время AFK"
|
afkTime: "Время AFK"
|
||||||
all: "Все"
|
all: "Все"
|
||||||
allTime: "Все время"
|
allTime: "Все время"
|
||||||
|
allowed: "Allowed"
|
||||||
|
allowlist: "Allowlist"
|
||||||
|
allowlistBounces: "Allowlist Bounces"
|
||||||
alphabetical: "Alphabetical"
|
alphabetical: "Alphabetical"
|
||||||
apply: "Apply"
|
apply: "Apply"
|
||||||
asNumbers: "В числах"
|
asNumbers: "В числах"
|
||||||
|
attempts: "Attempts"
|
||||||
average: "Средняя продолжительность первого сеанса"
|
average: "Средняя продолжительность первого сеанса"
|
||||||
averageActivePlaytime: "Среднее время активной игры"
|
averageActivePlaytime: "Среднее время активной игры"
|
||||||
averageAfkTime: "Среднее время AFK"
|
averageAfkTime: "Среднее время AFK"
|
||||||
|
@ -317,6 +321,7 @@ html:
|
||||||
banned: "Забанен"
|
banned: "Забанен"
|
||||||
bestPeak: "Максимальный Пик"
|
bestPeak: "Максимальный Пик"
|
||||||
bestPing: "Наилучший пинг"
|
bestPing: "Наилучший пинг"
|
||||||
|
blocked: "Blocked"
|
||||||
calendar: " Календарь"
|
calendar: " Календарь"
|
||||||
comparing7days: "Сравнение 7 дней"
|
comparing7days: "Сравнение 7 дней"
|
||||||
connectionInfo: "Информация о соединении"
|
connectionInfo: "Информация о соединении"
|
||||||
|
@ -430,7 +435,10 @@ html:
|
||||||
last24hours: "Последние 24 часа"
|
last24hours: "Последние 24 часа"
|
||||||
last30days: "Последние 30 дней"
|
last30days: "Последние 30 дней"
|
||||||
last7days: "Последние 7 дней"
|
last7days: "Последние 7 дней"
|
||||||
|
lastAllowed: "Last Allowed"
|
||||||
|
lastBlocked: "Last Blocked"
|
||||||
lastConnected: "Последнее подключение"
|
lastConnected: "Последнее подключение"
|
||||||
|
lastKnownAttempt: "Last Known Attempt"
|
||||||
lastPeak: "Последний Пик"
|
lastPeak: "Последний Пик"
|
||||||
lastSeen: "Последнее посещение"
|
lastSeen: "Последнее посещение"
|
||||||
latestJoinAddresses: "Latest Join Addresses"
|
latestJoinAddresses: "Latest Join Addresses"
|
||||||
|
@ -686,6 +694,7 @@ html:
|
||||||
page_player_sessions: "See Player Sessions -tab"
|
page_player_sessions: "See Player Sessions -tab"
|
||||||
page_player_versus: "See PvP & PvE -tab"
|
page_player_versus: "See PvP & PvE -tab"
|
||||||
page_server: "See all of server page"
|
page_server: "See all of server page"
|
||||||
|
page_server_allowlist_bounce: "See list of Game allowlist bounces"
|
||||||
page_server_geolocations: "See Geolocations tab"
|
page_server_geolocations: "See Geolocations tab"
|
||||||
page_server_geolocations_map: "See Geolocations Map"
|
page_server_geolocations_map: "See Geolocations Map"
|
||||||
page_server_geolocations_ping_per_country: "See Ping Per Country table"
|
page_server_geolocations_ping_per_country: "See Ping Per Country table"
|
||||||
|
|
|
@ -294,9 +294,13 @@ html:
|
||||||
afkTime: "AFK Süresi"
|
afkTime: "AFK Süresi"
|
||||||
all: "Tamamı"
|
all: "Tamamı"
|
||||||
allTime: "Tüm zamanlar"
|
allTime: "Tüm zamanlar"
|
||||||
|
allowed: "Allowed"
|
||||||
|
allowlist: "Allowlist"
|
||||||
|
allowlistBounces: "Allowlist Bounces"
|
||||||
alphabetical: "Alphabetical"
|
alphabetical: "Alphabetical"
|
||||||
apply: "Apply"
|
apply: "Apply"
|
||||||
asNumbers: "Sayılar olarak"
|
asNumbers: "Sayılar olarak"
|
||||||
|
attempts: "Attempts"
|
||||||
average: "Average first session length"
|
average: "Average first session length"
|
||||||
averageActivePlaytime: "Ortalama Aktif Oyun Süresi"
|
averageActivePlaytime: "Ortalama Aktif Oyun Süresi"
|
||||||
averageAfkTime: "Ortalama AFK Süresi"
|
averageAfkTime: "Ortalama AFK Süresi"
|
||||||
|
@ -317,6 +321,7 @@ html:
|
||||||
banned: "Yasaklanmış"
|
banned: "Yasaklanmış"
|
||||||
bestPeak: "Tüm Zamanların Zirvesi"
|
bestPeak: "Tüm Zamanların Zirvesi"
|
||||||
bestPing: "En iyi Ping"
|
bestPing: "En iyi Ping"
|
||||||
|
blocked: "Blocked"
|
||||||
calendar: " Takvim"
|
calendar: " Takvim"
|
||||||
comparing7days: "7 gün karşılaştırılıyor"
|
comparing7days: "7 gün karşılaştırılıyor"
|
||||||
connectionInfo: "Bağlantı Bilgisi"
|
connectionInfo: "Bağlantı Bilgisi"
|
||||||
|
@ -430,7 +435,10 @@ html:
|
||||||
last24hours: "Son 24 saat"
|
last24hours: "Son 24 saat"
|
||||||
last30days: "Son 30 gün"
|
last30days: "Son 30 gün"
|
||||||
last7days: "Son 7 gün"
|
last7days: "Son 7 gün"
|
||||||
|
lastAllowed: "Last Allowed"
|
||||||
|
lastBlocked: "Last Blocked"
|
||||||
lastConnected: "Son bağlantı"
|
lastConnected: "Son bağlantı"
|
||||||
|
lastKnownAttempt: "Last Known Attempt"
|
||||||
lastPeak: "Son Zirve"
|
lastPeak: "Son Zirve"
|
||||||
lastSeen: "Son Görülme"
|
lastSeen: "Son Görülme"
|
||||||
latestJoinAddresses: "Latest Join Addresses"
|
latestJoinAddresses: "Latest Join Addresses"
|
||||||
|
@ -686,6 +694,7 @@ html:
|
||||||
page_player_sessions: "See Player Sessions -tab"
|
page_player_sessions: "See Player Sessions -tab"
|
||||||
page_player_versus: "See PvP & PvE -tab"
|
page_player_versus: "See PvP & PvE -tab"
|
||||||
page_server: "See all of server page"
|
page_server: "See all of server page"
|
||||||
|
page_server_allowlist_bounce: "See list of Game allowlist bounces"
|
||||||
page_server_geolocations: "See Geolocations tab"
|
page_server_geolocations: "See Geolocations tab"
|
||||||
page_server_geolocations_map: "See Geolocations Map"
|
page_server_geolocations_map: "See Geolocations Map"
|
||||||
page_server_geolocations_ping_per_country: "See Ping Per Country table"
|
page_server_geolocations_ping_per_country: "See Ping Per Country table"
|
||||||
|
|
|
@ -294,9 +294,13 @@ html:
|
||||||
afkTime: "Час AFK"
|
afkTime: "Час AFK"
|
||||||
all: "Всі"
|
all: "Всі"
|
||||||
allTime: "Весь час"
|
allTime: "Весь час"
|
||||||
|
allowed: "Allowed"
|
||||||
|
allowlist: "Allowlist"
|
||||||
|
allowlistBounces: "Allowlist Bounces"
|
||||||
alphabetical: "За алфавітом"
|
alphabetical: "За алфавітом"
|
||||||
apply: "Застосувати"
|
apply: "Застосувати"
|
||||||
asNumbers: "В числах"
|
asNumbers: "В числах"
|
||||||
|
attempts: "Attempts"
|
||||||
average: "Середня тривалість першого сеансу"
|
average: "Середня тривалість першого сеансу"
|
||||||
averageActivePlaytime: "Середній час активної гри"
|
averageActivePlaytime: "Середній час активної гри"
|
||||||
averageAfkTime: "Середній час AFK"
|
averageAfkTime: "Середній час AFK"
|
||||||
|
@ -317,6 +321,7 @@ html:
|
||||||
banned: "Заблокований"
|
banned: "Заблокований"
|
||||||
bestPeak: "Максимальний Пік"
|
bestPeak: "Максимальний Пік"
|
||||||
bestPing: "Найкращий пінг"
|
bestPing: "Найкращий пінг"
|
||||||
|
blocked: "Blocked"
|
||||||
calendar: "Календар"
|
calendar: "Календар"
|
||||||
comparing7days: "Порівняння 7 днів"
|
comparing7days: "Порівняння 7 днів"
|
||||||
connectionInfo: "Інформація про з`єднання"
|
connectionInfo: "Інформація про з`єднання"
|
||||||
|
@ -430,7 +435,10 @@ html:
|
||||||
last24hours: "Останні 24 години"
|
last24hours: "Останні 24 години"
|
||||||
last30days: "Останні 30 днів"
|
last30days: "Останні 30 днів"
|
||||||
last7days: "Останні 7 днів"
|
last7days: "Останні 7 днів"
|
||||||
|
lastAllowed: "Last Allowed"
|
||||||
|
lastBlocked: "Last Blocked"
|
||||||
lastConnected: "Останнє підключення"
|
lastConnected: "Останнє підключення"
|
||||||
|
lastKnownAttempt: "Last Known Attempt"
|
||||||
lastPeak: "Останній Пік"
|
lastPeak: "Останній Пік"
|
||||||
lastSeen: "Останнє відвідування"
|
lastSeen: "Останнє відвідування"
|
||||||
latestJoinAddresses: "Останні адреси приєднання"
|
latestJoinAddresses: "Останні адреси приєднання"
|
||||||
|
@ -686,6 +694,7 @@ html:
|
||||||
page_player_sessions: "See Player Sessions -tab"
|
page_player_sessions: "See Player Sessions -tab"
|
||||||
page_player_versus: "See PvP & PvE -tab"
|
page_player_versus: "See PvP & PvE -tab"
|
||||||
page_server: "See all of server page"
|
page_server: "See all of server page"
|
||||||
|
page_server_allowlist_bounce: "See list of Game allowlist bounces"
|
||||||
page_server_geolocations: "See Geolocations tab"
|
page_server_geolocations: "See Geolocations tab"
|
||||||
page_server_geolocations_map: "See Geolocations Map"
|
page_server_geolocations_map: "See Geolocations Map"
|
||||||
page_server_geolocations_ping_per_country: "See Ping Per Country table"
|
page_server_geolocations_ping_per_country: "See Ping Per Country table"
|
||||||
|
|
|
@ -294,9 +294,13 @@ html:
|
||||||
afkTime: "掛機時間"
|
afkTime: "掛機時間"
|
||||||
all: "全部"
|
all: "全部"
|
||||||
allTime: "所有時間"
|
allTime: "所有時間"
|
||||||
|
allowed: "Allowed"
|
||||||
|
allowlist: "Allowlist"
|
||||||
|
allowlistBounces: "Allowlist Bounces"
|
||||||
alphabetical: "按字母順序"
|
alphabetical: "按字母順序"
|
||||||
apply: "確定"
|
apply: "確定"
|
||||||
asNumbers: "統計"
|
asNumbers: "統計"
|
||||||
|
attempts: "Attempts"
|
||||||
average: "Average first session length"
|
average: "Average first session length"
|
||||||
averageActivePlaytime: "平均活躍時間"
|
averageActivePlaytime: "平均活躍時間"
|
||||||
averageAfkTime: "平均掛機時間"
|
averageAfkTime: "平均掛機時間"
|
||||||
|
@ -317,6 +321,7 @@ html:
|
||||||
banned: "已被封鎖"
|
banned: "已被封鎖"
|
||||||
bestPeak: "所有時間峰值"
|
bestPeak: "所有時間峰值"
|
||||||
bestPing: "最低延遲"
|
bestPing: "最低延遲"
|
||||||
|
blocked: "Blocked"
|
||||||
calendar: " 日誌"
|
calendar: " 日誌"
|
||||||
comparing7days: "對比 7 天的情況"
|
comparing7days: "對比 7 天的情況"
|
||||||
connectionInfo: "連接訊息"
|
connectionInfo: "連接訊息"
|
||||||
|
@ -430,7 +435,10 @@ html:
|
||||||
last24hours: "過去 24 小時"
|
last24hours: "過去 24 小時"
|
||||||
last30days: "過去 30 天"
|
last30days: "過去 30 天"
|
||||||
last7days: "過去 7 天"
|
last7days: "過去 7 天"
|
||||||
|
lastAllowed: "Last Allowed"
|
||||||
|
lastBlocked: "Last Blocked"
|
||||||
lastConnected: "最後連接時間"
|
lastConnected: "最後連接時間"
|
||||||
|
lastKnownAttempt: "Last Known Attempt"
|
||||||
lastPeak: "上次線上峰值"
|
lastPeak: "上次線上峰值"
|
||||||
lastSeen: "最後線上時間"
|
lastSeen: "最後線上時間"
|
||||||
latestJoinAddresses: "最後加入位址"
|
latestJoinAddresses: "最後加入位址"
|
||||||
|
@ -686,6 +694,7 @@ html:
|
||||||
page_player_sessions: "See Player Sessions -tab"
|
page_player_sessions: "See Player Sessions -tab"
|
||||||
page_player_versus: "See PvP & PvE -tab"
|
page_player_versus: "See PvP & PvE -tab"
|
||||||
page_server: "See all of server page"
|
page_server: "See all of server page"
|
||||||
|
page_server_allowlist_bounce: "See list of Game allowlist bounces"
|
||||||
page_server_geolocations: "See Geolocations tab"
|
page_server_geolocations: "See Geolocations tab"
|
||||||
page_server_geolocations_map: "See Geolocations Map"
|
page_server_geolocations_map: "See Geolocations Map"
|
||||||
page_server_geolocations_ping_per_country: "See Ping Per Country table"
|
page_server_geolocations_ping_per_country: "See Ping Per Country table"
|
||||||
|
|
|
@ -163,7 +163,8 @@ class AccessControlTest {
|
||||||
Arguments.of("/v1/preferences", WebPermission.ACCESS, 200, 200),
|
Arguments.of("/v1/preferences", WebPermission.ACCESS, 200, 200),
|
||||||
Arguments.of("/v1/storePreferences", WebPermission.ACCESS, 400, 400),
|
Arguments.of("/v1/storePreferences", WebPermission.ACCESS, 400, 400),
|
||||||
Arguments.of("/v1/pluginHistory?server=" + TestConstants.SERVER_UUID_STRING, WebPermission.PAGE_NETWORK_PLUGIN_HISTORY, 200, 403),
|
Arguments.of("/v1/pluginHistory?server=" + TestConstants.SERVER_UUID_STRING, WebPermission.PAGE_NETWORK_PLUGIN_HISTORY, 200, 403),
|
||||||
Arguments.of("/v1/pluginHistory?server=" + TestConstants.SERVER_UUID_STRING, WebPermission.PAGE_SERVER_PLUGIN_HISTORY, 200, 403)
|
Arguments.of("/v1/pluginHistory?server=" + TestConstants.SERVER_UUID_STRING, WebPermission.PAGE_SERVER_PLUGIN_HISTORY, 200, 403),
|
||||||
|
Arguments.of("/v1/gameAllowlistBounces?server=" + TestConstants.SERVER_UUID_STRING, WebPermission.PAGE_SERVER_ALLOWLIST_BOUNCE, 200, 403)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -136,6 +136,7 @@ class AccessControlVisibilityTest {
|
||||||
Arguments.arguments(WebPermission.PAGE_SERVER_PLAYER_VERSUS_OVERVIEW, "pvp-pve-as-numbers", "pvppve"),
|
Arguments.arguments(WebPermission.PAGE_SERVER_PLAYER_VERSUS_OVERVIEW, "pvp-pve-as-numbers", "pvppve"),
|
||||||
Arguments.arguments(WebPermission.PAGE_SERVER_PLAYER_VERSUS_OVERVIEW, "pvp-pve-insights", "pvppve"),
|
Arguments.arguments(WebPermission.PAGE_SERVER_PLAYER_VERSUS_OVERVIEW, "pvp-pve-insights", "pvppve"),
|
||||||
Arguments.arguments(WebPermission.PAGE_SERVER_PLAYER_VERSUS_KILL_LIST, "pvp-kills-table", "pvppve"),
|
Arguments.arguments(WebPermission.PAGE_SERVER_PLAYER_VERSUS_KILL_LIST, "pvp-kills-table", "pvppve"),
|
||||||
|
Arguments.arguments(WebPermission.PAGE_SERVER_ALLOWLIST_BOUNCE, "allowlist-bounce-table", "allowlist"),
|
||||||
Arguments.arguments(WebPermission.PAGE_SERVER_PLAYERBASE_OVERVIEW, "playerbase-trends", "playerbase"),
|
Arguments.arguments(WebPermission.PAGE_SERVER_PLAYERBASE_OVERVIEW, "playerbase-trends", "playerbase"),
|
||||||
Arguments.arguments(WebPermission.PAGE_SERVER_PLAYERBASE_OVERVIEW, "playerbase-insights", "playerbase"),
|
Arguments.arguments(WebPermission.PAGE_SERVER_PLAYERBASE_OVERVIEW, "playerbase-insights", "playerbase"),
|
||||||
Arguments.arguments(WebPermission.PAGE_SERVER_PLAYERBASE_GRAPHS, "playerbase-graph", "playerbase"),
|
Arguments.arguments(WebPermission.PAGE_SERVER_PLAYERBASE_GRAPHS, "playerbase-graph", "playerbase"),
|
||||||
|
|
|
@ -28,6 +28,7 @@ import com.djrapitops.plan.storage.database.transactions.patches.BadJoinAddressD
|
||||||
|
|
||||||
public interface DatabaseTestAggregate extends
|
public interface DatabaseTestAggregate extends
|
||||||
ActivityIndexQueriesTest,
|
ActivityIndexQueriesTest,
|
||||||
|
AllowlistQueriesTest,
|
||||||
DatabaseBackupTest,
|
DatabaseBackupTest,
|
||||||
ExtensionsDatabaseTest,
|
ExtensionsDatabaseTest,
|
||||||
GeolocationQueriesTest,
|
GeolocationQueriesTest,
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* 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.delivery.domain.datatransfer.AllowlistBounce;
|
||||||
|
import com.djrapitops.plan.storage.database.DatabaseTestPreparer;
|
||||||
|
import com.djrapitops.plan.storage.database.queries.objects.AllowlistQueries;
|
||||||
|
import com.djrapitops.plan.storage.database.transactions.commands.RemoveEverythingTransaction;
|
||||||
|
import com.djrapitops.plan.storage.database.transactions.events.StoreAllowlistBounceTransaction;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import utilities.TestConstants;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
public interface AllowlistQueriesTest extends DatabaseTestPreparer {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("plan_allowlist_bounce is empty")
|
||||||
|
default void allowListTableIsEmpty() {
|
||||||
|
List<AllowlistBounce> expected = List.of();
|
||||||
|
List<AllowlistBounce> result = db().query(AllowlistQueries.getBounces(serverUUID()));
|
||||||
|
assertEquals(expected, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("plan_allowlist_bounce is cleared by RemoveEverythingTransaction")
|
||||||
|
default void allowListTableIsEmptyAfterClear() throws ExecutionException, InterruptedException {
|
||||||
|
allowListBounceIsStored();
|
||||||
|
db().executeTransaction(new RemoveEverythingTransaction());
|
||||||
|
allowListTableIsEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Allowlist bounce is stored")
|
||||||
|
default void allowListBounceIsStored() throws ExecutionException, InterruptedException {
|
||||||
|
AllowlistBounce bounce = new AllowlistBounce(TestConstants.PLAYER_ONE_UUID, TestConstants.PLAYER_ONE_NAME, 1, System.currentTimeMillis());
|
||||||
|
db().executeTransaction(new StoreAllowlistBounceTransaction(bounce.getPlayerUUID(), bounce.getPlayerName(), serverUUID(), bounce.getLastTime()))
|
||||||
|
.get();
|
||||||
|
|
||||||
|
List<AllowlistBounce> expected = List.of(bounce);
|
||||||
|
List<AllowlistBounce> result = db().query(AllowlistQueries.getBounces(serverUUID()));
|
||||||
|
assertEquals(expected, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -37,6 +37,7 @@ import com.djrapitops.plan.storage.database.transactions.commands.RemoveEverythi
|
||||||
import com.djrapitops.plan.storage.database.transactions.events.*;
|
import com.djrapitops.plan.storage.database.transactions.events.*;
|
||||||
import com.djrapitops.plan.utilities.java.Maps;
|
import com.djrapitops.plan.utilities.java.Maps;
|
||||||
import net.playeranalytics.plugin.scheduling.TimeAmount;
|
import net.playeranalytics.plugin.scheduling.TimeAmount;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
import org.junit.jupiter.api.RepeatedTest;
|
import org.junit.jupiter.api.RepeatedTest;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import utilities.RandomData;
|
import utilities.RandomData;
|
||||||
|
@ -485,4 +486,21 @@ public interface SessionQueriesTest extends DatabaseTestPreparer {
|
||||||
Map<String, Long> results = db().query(SessionQueries.playtimePerServer(Long.MIN_VALUE, Long.MAX_VALUE));
|
Map<String, Long> results = db().query(SessionQueries.playtimePerServer(Long.MIN_VALUE, Long.MAX_VALUE));
|
||||||
assertEquals(expected, results);
|
assertEquals(expected, results);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Last seen query by server uuid groups last seen by player")
|
||||||
|
default void lastSeenByServerIsGroupedByPlayer() {
|
||||||
|
prepareForSessionSave();
|
||||||
|
List<FinishedSession> player1Sessions = RandomData.randomSessions(serverUUID(), worlds, playerUUID, player2UUID);
|
||||||
|
List<FinishedSession> player2Sessions = RandomData.randomSessions(serverUUID(), worlds, player2UUID, playerUUID);
|
||||||
|
player1Sessions.forEach(session -> db().executeTransaction(new StoreSessionTransaction(session)));
|
||||||
|
player2Sessions.forEach(session -> db().executeTransaction(new StoreSessionTransaction(session)));
|
||||||
|
|
||||||
|
long lastSeenP1 = new SessionsMutator(player1Sessions).toLastSeen();
|
||||||
|
long lastSeenP2 = new SessionsMutator(player2Sessions).toLastSeen();
|
||||||
|
|
||||||
|
Map<UUID, Long> expected = Map.of(playerUUID, lastSeenP1, player2UUID, lastSeenP2);
|
||||||
|
Map<UUID, Long> result = db().query(SessionQueries.lastSeen(serverUUID()));
|
||||||
|
assertEquals(expected, result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ import com.djrapitops.plan.identification.ServerUUID;
|
||||||
import com.djrapitops.plan.storage.database.DBSystem;
|
import com.djrapitops.plan.storage.database.DBSystem;
|
||||||
import com.djrapitops.plan.storage.database.transactions.events.BanStatusTransaction;
|
import com.djrapitops.plan.storage.database.transactions.events.BanStatusTransaction;
|
||||||
import com.djrapitops.plan.storage.database.transactions.events.KickStoreTransaction;
|
import com.djrapitops.plan.storage.database.transactions.events.KickStoreTransaction;
|
||||||
|
import com.djrapitops.plan.storage.database.transactions.events.StoreAllowlistBounceTransaction;
|
||||||
import com.djrapitops.plan.utilities.logging.ErrorContext;
|
import com.djrapitops.plan.utilities.logging.ErrorContext;
|
||||||
import com.djrapitops.plan.utilities.logging.ErrorLogger;
|
import com.djrapitops.plan.utilities.logging.ErrorLogger;
|
||||||
|
|
||||||
|
@ -95,6 +96,13 @@ public class PlayerOnlineListener implements Listener {
|
||||||
@EventHandler(priority = EventPriority.MONITOR)
|
@EventHandler(priority = EventPriority.MONITOR)
|
||||||
public void onPlayerKick(PlayerKickEvent event) {
|
public void onPlayerKick(PlayerKickEvent event) {
|
||||||
try {
|
try {
|
||||||
|
if (event.getReasonEnum() == PlayerKickEvent.Reason.NOT_WHITELISTED) {
|
||||||
|
dbSystem.getDatabase().executeTransaction(new StoreAllowlistBounceTransaction(
|
||||||
|
event.getPlayer().getUniqueId(),
|
||||||
|
event.getPlayer().getName(),
|
||||||
|
serverInfo.getServerUUID(), System.currentTimeMillis())
|
||||||
|
);
|
||||||
|
}
|
||||||
if (status.areKicksNotCounted() || event.isCancelled()) {
|
if (status.areKicksNotCounted() || event.isCancelled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ const ServerOverview = React.lazy(() => import("./views/server/ServerOverview"))
|
||||||
const OnlineActivity = React.lazy(() => import("./views/server/OnlineActivity"));
|
const OnlineActivity = React.lazy(() => import("./views/server/OnlineActivity"));
|
||||||
const ServerSessions = React.lazy(() => import("./views/server/ServerSessions"));
|
const ServerSessions = React.lazy(() => import("./views/server/ServerSessions"));
|
||||||
const ServerPvpPve = React.lazy(() => import("./views/server/ServerPvpPve"));
|
const ServerPvpPve = React.lazy(() => import("./views/server/ServerPvpPve"));
|
||||||
|
const ServerAllowList = React.lazy(() => import("./views/server/ServerAllowList"));
|
||||||
const PlayerbaseOverview = React.lazy(() => import("./views/server/PlayerbaseOverview"));
|
const PlayerbaseOverview = React.lazy(() => import("./views/server/PlayerbaseOverview"));
|
||||||
const ServerPlayers = React.lazy(() => import("./views/server/ServerPlayers"));
|
const ServerPlayers = React.lazy(() => import("./views/server/ServerPlayers"));
|
||||||
const ServerGeolocations = React.lazy(() => import("./views/server/ServerGeolocations"));
|
const ServerGeolocations = React.lazy(() => import("./views/server/ServerGeolocations"));
|
||||||
|
@ -159,6 +160,7 @@ function App() {
|
||||||
<Route path="online-activity" element={<Lazy><OnlineActivity/></Lazy>}/>
|
<Route path="online-activity" element={<Lazy><OnlineActivity/></Lazy>}/>
|
||||||
<Route path="sessions" element={<Lazy><ServerSessions/></Lazy>}/>
|
<Route path="sessions" element={<Lazy><ServerSessions/></Lazy>}/>
|
||||||
<Route path="pvppve" element={<Lazy><ServerPvpPve/></Lazy>}/>
|
<Route path="pvppve" element={<Lazy><ServerPvpPve/></Lazy>}/>
|
||||||
|
<Route path="allowlist" element={<Lazy><ServerAllowList/></Lazy>}/>
|
||||||
<Route path="playerbase" element={<Lazy><PlayerbaseOverview/></Lazy>}/>
|
<Route path="playerbase" element={<Lazy><PlayerbaseOverview/></Lazy>}/>
|
||||||
<Route path="join-addresses" element={<Lazy><ServerJoinAddresses/></Lazy>}/>
|
<Route path="join-addresses" element={<Lazy><ServerJoinAddresses/></Lazy>}/>
|
||||||
<Route path="retention" element={<Lazy><ServerPlayerRetention/></Lazy>}/>
|
<Route path="retention" element={<Lazy><ServerPlayerRetention/></Lazy>}/>
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
import React from "react";
|
||||||
|
import {FontAwesomeIcon as Fa} from "@fortawesome/react-fontawesome";
|
||||||
|
import {faFilterCircleXmark} from "@fortawesome/free-solid-svg-icons";
|
||||||
|
import {Card} from "react-bootstrap";
|
||||||
|
import AllowlistBounceTable from "../../../table/AllowlistBounceTable.jsx";
|
||||||
|
import {useTranslation} from "react-i18next";
|
||||||
|
|
||||||
|
const AllowlistBounceTableCard = ({bounces, lastSeen}) => {
|
||||||
|
const {t} = useTranslation();
|
||||||
|
return (
|
||||||
|
<Card id={'allowlist-table'}>
|
||||||
|
<Card.Header>
|
||||||
|
<h6 className="col-black">
|
||||||
|
<Fa icon={faFilterCircleXmark} className="col-orange"/> {t('html.label.allowlistBounces')}
|
||||||
|
</h6>
|
||||||
|
</Card.Header>
|
||||||
|
<AllowlistBounceTable bounces={bounces} lastSeen={lastSeen}/>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AllowlistBounceTableCard;
|
|
@ -25,10 +25,11 @@ const QueryPlayerListModal = ({open, toggle, queryData, title}) => {
|
||||||
<PlayerTable data={queryData?.data?.players || {players: [], extensionDescriptors: []}}
|
<PlayerTable data={queryData?.data?.players || {players: [], extensionDescriptors: []}}
|
||||||
orderBy={2}/>}
|
orderBy={2}/>}
|
||||||
<Modal.Footer>
|
<Modal.Footer>
|
||||||
{hasPermission('access.query') && Boolean(queryData?.data?.players.players.length) && <Link className="btn bg-theme"
|
{hasPermission('access.query') && Boolean(queryData?.data?.players.players.length) &&
|
||||||
to={"/query/result?timestamp=" + queryData?.timestamp}>
|
<Link className="btn bg-theme"
|
||||||
{t('html.query.label.showFullQuery')} <Fa icon={faArrowRight}/>
|
to={"/query/result?timestamp=" + queryData?.timestamp}>
|
||||||
</Link>}
|
{t('html.query.label.showFullQuery')} <Fa icon={faArrowRight}/>
|
||||||
|
</Link>}
|
||||||
<button className="btn bg-theme" onClick={toggle}>OK</button>
|
<button className="btn bg-theme" onClick={toggle}>OK</button>
|
||||||
</Modal.Footer>
|
</Modal.Footer>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
import React, {useCallback} from "react";
|
||||||
|
import {useTranslation} from "react-i18next";
|
||||||
|
import {FontAwesomeIcon as Fa} from "@fortawesome/react-fontawesome";
|
||||||
|
import {faDoorOpen, faRepeat, faUser} from "@fortawesome/free-solid-svg-icons";
|
||||||
|
import {usePreferences} from "../../hooks/preferencesHook.jsx";
|
||||||
|
import DataTablesTable from "./DataTablesTable.jsx";
|
||||||
|
import {formatDate, useDatePreferences} from "../text/FormattedDate.jsx";
|
||||||
|
import {faCalendarCheck, faCalendarTimes} from "@fortawesome/free-regular-svg-icons";
|
||||||
|
import {Link} from "react-router-dom";
|
||||||
|
|
||||||
|
const AllowlistBounceTable = ({bounces, lastSeen}) => {
|
||||||
|
const {t} = useTranslation();
|
||||||
|
const {preferencesLoaded} = usePreferences();
|
||||||
|
|
||||||
|
const datePreferences = useDatePreferences();
|
||||||
|
const formatDateEasy = date => {
|
||||||
|
return formatDate(date, datePreferences.offset, datePreferences.pattern, false, datePreferences.recentDaysPattern, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
title: <><Fa icon={faUser}/> {t('html.label.player')}</>,
|
||||||
|
data: {_: "player", display: "link"}
|
||||||
|
}, {
|
||||||
|
title: <><Fa icon={faRepeat}/> {t('html.label.attempts')}</>,
|
||||||
|
data: "attempts"
|
||||||
|
}, {
|
||||||
|
title: <><Fa icon={faDoorOpen}/> {t('html.label.lastKnownAttempt')}</>,
|
||||||
|
data: "lastKnownAttempt"
|
||||||
|
}, {
|
||||||
|
title: <><Fa icon={faCalendarTimes}/> {t('html.label.lastBlocked')}</>,
|
||||||
|
data: {_: "date", display: "dateFormatted"}
|
||||||
|
}, {
|
||||||
|
title: <><Fa icon={faCalendarCheck}/> {t('html.label.lastAllowed')}</>,
|
||||||
|
data: {_: "lastSeen", display: "lastSeenFormatted"}
|
||||||
|
}];
|
||||||
|
|
||||||
|
const rows = bounces.map(bounce => {
|
||||||
|
const seenAfterBounce = bounce.lastBounce < lastSeen[bounce.playerUUID];
|
||||||
|
const playerId = bounce.playerName + ' / ' + bounce.playerUUID;
|
||||||
|
return {
|
||||||
|
player: playerId,
|
||||||
|
link: lastSeen[bounce.playerUUID] ? <Link to={"/player/" + bounce.playerUUID}>{playerId}</Link> : playerId,
|
||||||
|
date: bounce.lastTime,
|
||||||
|
dateFormatted: formatDateEasy(bounce.lastTime),
|
||||||
|
attempts: bounce.count,
|
||||||
|
lastKnownAttempt: seenAfterBounce ? t('html.label.allowed') : t('html.label.blocked'),
|
||||||
|
lastSeen: lastSeen[bounce.playerUUID],
|
||||||
|
lastSeenFormatted: formatDateEasy(lastSeen[bounce.playerUUID])
|
||||||
|
};
|
||||||
|
});
|
||||||
|
const options = {
|
||||||
|
responsive: true,
|
||||||
|
deferRender: true,
|
||||||
|
columns: columns,
|
||||||
|
data: rows,
|
||||||
|
paginationCount: 2,
|
||||||
|
order: [[1, "desc"]]
|
||||||
|
}
|
||||||
|
|
||||||
|
const rowKeyFunction = useCallback((row, column) => {
|
||||||
|
return row.player + "-" + (column ? JSON.stringify(column.data) : '');
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (!preferencesLoaded) return <></>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DataTablesTable id={"allowlist-bounce-table"} options={options} colorClass={"bg-orange"}
|
||||||
|
rowKeyFunction={rowKeyFunction}/>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AllowlistBounceTable;
|
|
@ -100,6 +100,7 @@ export const fetchPlayersTable = async (timestamp, identifier) => {
|
||||||
return await fetchPlayersTableNetwork(timestamp);
|
return await fetchPlayersTableNetwork(timestamp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fetchPlayersTableServer = async (timestamp, identifier) => {
|
const fetchPlayersTableServer = async (timestamp, identifier) => {
|
||||||
let url = `/v1/playersTable?server=${identifier}`;
|
let url = `/v1/playersTable?server=${identifier}`;
|
||||||
if (staticSite) url = `/data/playersTable-${identifier}.json`;
|
if (staticSite) url = `/data/playersTable-${identifier}.json`;
|
||||||
|
@ -112,6 +113,12 @@ const fetchPlayersTableNetwork = async (timestamp) => {
|
||||||
return doGetRequest(url, timestamp);
|
return doGetRequest(url, timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const fetchAllowlistBounces = async (timestamp, identifier) => {
|
||||||
|
let url = `/v1/gameAllowlistBounces?server=${identifier}`;
|
||||||
|
if (staticSite) url = `/data/gameAllowlistBounces-${identifier}.json`;
|
||||||
|
return doGetRequest(url, timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
export const fetchPingTable = async (timestamp, identifier) => {
|
export const fetchPingTable = async (timestamp, identifier) => {
|
||||||
let url = `/v1/pingTable?server=${identifier}`;
|
let url = `/v1/pingTable?server=${identifier}`;
|
||||||
if (staticSite) url = `/data/pingTable-${identifier}.json`;
|
if (staticSite) url = `/data/pingTable-${identifier}.json`;
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {
|
||||||
faCodeCompare,
|
faCodeCompare,
|
||||||
faCogs,
|
faCogs,
|
||||||
faCubes,
|
faCubes,
|
||||||
|
faFilterCircleXmark,
|
||||||
faGlobe,
|
faGlobe,
|
||||||
faInfoCircle,
|
faInfoCircle,
|
||||||
faLocationArrow,
|
faLocationArrow,
|
||||||
|
@ -72,6 +73,12 @@ const ServerSidebar = () => {
|
||||||
icon: faCampground,
|
icon: faCampground,
|
||||||
href: "pvppve",
|
href: "pvppve",
|
||||||
permission: 'page.server.player.versus'
|
permission: 'page.server.player.versus'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'html.label.allowlist',
|
||||||
|
icon: faFilterCircleXmark,
|
||||||
|
href: "allowlist",
|
||||||
|
permission: 'page.server.allowlist.bounce'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
import React from 'react';
|
||||||
|
import {useDataRequest} from "../../hooks/dataFetchHook";
|
||||||
|
import {useParams} from "react-router-dom";
|
||||||
|
import {fetchAllowlistBounces} from "../../service/serverService";
|
||||||
|
import ErrorView from "../ErrorView";
|
||||||
|
import {Col} from "react-bootstrap";
|
||||||
|
import LoadIn from "../../components/animation/LoadIn";
|
||||||
|
import ExtendableRow from "../../components/layout/extension/ExtendableRow";
|
||||||
|
import {useAuth} from "../../hooks/authenticationHook";
|
||||||
|
import AllowlistBounceTableCard from "../../components/cards/server/tables/AllowlistBounceTableCard.jsx";
|
||||||
|
|
||||||
|
const ServerAllowList = () => {
|
||||||
|
const {hasPermission} = useAuth();
|
||||||
|
const {identifier} = useParams();
|
||||||
|
|
||||||
|
const seeBounce = hasPermission('page.server.allowlist.bounce');
|
||||||
|
const {data, loadingError} = useDataRequest(fetchAllowlistBounces, [identifier], seeBounce);
|
||||||
|
|
||||||
|
if (loadingError) return <ErrorView error={loadingError}/>
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LoadIn>
|
||||||
|
<section className="server-allowlist">
|
||||||
|
{seeBounce && <ExtendableRow id={'row-server-allowlist-0'}>
|
||||||
|
<Col md={12}>
|
||||||
|
<AllowlistBounceTableCard bounces={data?.allowlist_bounces || []}
|
||||||
|
lastSeen={data?.last_seen_by_uuid || {}}/>
|
||||||
|
</Col>
|
||||||
|
</ExtendableRow>}
|
||||||
|
</section>
|
||||||
|
</LoadIn>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ServerAllowList
|
|
@ -27,8 +27,10 @@ import com.djrapitops.plan.identification.ServerUUID;
|
||||||
import com.djrapitops.plan.storage.database.DBSystem;
|
import com.djrapitops.plan.storage.database.DBSystem;
|
||||||
import com.djrapitops.plan.storage.database.transactions.events.BanStatusTransaction;
|
import com.djrapitops.plan.storage.database.transactions.events.BanStatusTransaction;
|
||||||
import com.djrapitops.plan.storage.database.transactions.events.KickStoreTransaction;
|
import com.djrapitops.plan.storage.database.transactions.events.KickStoreTransaction;
|
||||||
|
import com.djrapitops.plan.storage.database.transactions.events.StoreAllowlistBounceTransaction;
|
||||||
import com.djrapitops.plan.utilities.logging.ErrorContext;
|
import com.djrapitops.plan.utilities.logging.ErrorContext;
|
||||||
import com.djrapitops.plan.utilities.logging.ErrorLogger;
|
import com.djrapitops.plan.utilities.logging.ErrorLogger;
|
||||||
|
import org.spongepowered.api.Game;
|
||||||
import org.spongepowered.api.Sponge;
|
import org.spongepowered.api.Sponge;
|
||||||
import org.spongepowered.api.entity.living.player.Player;
|
import org.spongepowered.api.entity.living.player.Player;
|
||||||
import org.spongepowered.api.entity.living.player.server.ServerPlayer;
|
import org.spongepowered.api.entity.living.player.server.ServerPlayer;
|
||||||
|
@ -54,6 +56,7 @@ public class PlayerOnlineListener {
|
||||||
private final PlayerJoinEventConsumer joinEventConsumer;
|
private final PlayerJoinEventConsumer joinEventConsumer;
|
||||||
private final PlayerLeaveEventConsumer leaveEventConsumer;
|
private final PlayerLeaveEventConsumer leaveEventConsumer;
|
||||||
|
|
||||||
|
private final Game game;
|
||||||
private final ServerInfo serverInfo;
|
private final ServerInfo serverInfo;
|
||||||
private final DBSystem dbSystem;
|
private final DBSystem dbSystem;
|
||||||
private final Status status;
|
private final Status status;
|
||||||
|
@ -63,13 +66,14 @@ public class PlayerOnlineListener {
|
||||||
public PlayerOnlineListener(
|
public PlayerOnlineListener(
|
||||||
PlayerJoinEventConsumer joinEventConsumer,
|
PlayerJoinEventConsumer joinEventConsumer,
|
||||||
PlayerLeaveEventConsumer leaveEventConsumer,
|
PlayerLeaveEventConsumer leaveEventConsumer,
|
||||||
ServerInfo serverInfo,
|
Game game, ServerInfo serverInfo,
|
||||||
DBSystem dbSystem,
|
DBSystem dbSystem,
|
||||||
Status status,
|
Status status,
|
||||||
ErrorLogger errorLogger
|
ErrorLogger errorLogger
|
||||||
) {
|
) {
|
||||||
this.joinEventConsumer = joinEventConsumer;
|
this.joinEventConsumer = joinEventConsumer;
|
||||||
this.leaveEventConsumer = leaveEventConsumer;
|
this.leaveEventConsumer = leaveEventConsumer;
|
||||||
|
this.game = game;
|
||||||
this.serverInfo = serverInfo;
|
this.serverInfo = serverInfo;
|
||||||
this.dbSystem = dbSystem;
|
this.dbSystem = dbSystem;
|
||||||
this.status = status;
|
this.status = status;
|
||||||
|
@ -89,6 +93,18 @@ public class PlayerOnlineListener {
|
||||||
GameProfile profile = event.profile();
|
GameProfile profile = event.profile();
|
||||||
UUID playerUUID = profile.uniqueId();
|
UUID playerUUID = profile.uniqueId();
|
||||||
ServerUUID serverUUID = serverInfo.getServerUUID();
|
ServerUUID serverUUID = serverInfo.getServerUUID();
|
||||||
|
if (game.server().isWhitelistEnabled()) {
|
||||||
|
game.server().serviceProvider().whitelistService().isWhitelisted(profile)
|
||||||
|
.thenAccept(whitelisted -> {
|
||||||
|
if (Boolean.FALSE.equals(whitelisted)) {
|
||||||
|
dbSystem.getDatabase().executeTransaction(new StoreAllowlistBounceTransaction(
|
||||||
|
playerUUID,
|
||||||
|
event.profile().name().orElse(event.user().uniqueId().toString()),
|
||||||
|
serverUUID,
|
||||||
|
System.currentTimeMillis()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
dbSystem.getDatabase().executeTransaction(new BanStatusTransaction(playerUUID, serverUUID, () -> isBanned(profile)));
|
dbSystem.getDatabase().executeTransaction(new BanStatusTransaction(playerUUID, serverUUID, () -> isBanned(profile)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue