[Merge] Version 4.8.3 (#1040)

This commit is contained in:
Risto Lahtela 2019-05-12 19:46:24 +03:00 committed by GitHub
commit a537be8761
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 460 additions and 91 deletions

View File

@ -2,7 +2,7 @@ plugins {
id "com.jfrog.bintray" version "1.8.4"
}
ext.apiVersion = '0.0.4'
ext.apiVersion = '0.0.5'
bintray {
user = System.getenv('BINTRAY_USER')

View File

@ -40,7 +40,17 @@ enum Capability {
/**
* DataExtension API table package, TableProvider, Table and Table.Factory
*/
DATA_EXTENSION_TABLES;
DATA_EXTENSION_TABLES,
/**
* DataExtension API addition, allows throwing {@link com.djrapitops.plan.extension.NotReadyException} inside a Provider method when your API is not ready for a method call.
*/
DATA_EXTENSION_NOT_READY_EXCEPTION,
/**
* DataExtension API addition, parameter {@code showInPlayerTable} for BooleanProvider, DoubleProvider, PercentageProvider, NumberProvider, StringProvider annotations.
* <p>
* When the parameter is set to {@code true} the value from this Provider is shown on a table alongside players.
*/
DATA_EXTENSION_SHOW_IN_PLAYER_TABLE;
static Optional<Capability> getByName(String name) {
if (name == null) {

View File

@ -0,0 +1,37 @@
/*
* 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.extension;
/**
* Exception to throw inside DataExtension if a method is not ready to be called (Data is not available etc).
* <p>
* This Exception will not cause Plan to "yell" about the exception.
* <p>
* Requires {@link com.djrapitops.plan.capability.Capability#DATA_EXTENSION_NOT_READY_EXCEPTION}.
*
* @author Rsl1122
*/
public class NotReadyException extends IllegalStateException {
/**
* Construct the exception.
* <p>
* The Exception is not logged (Fails silently) so no message is available.
*/
public NotReadyException() {
}
}

View File

@ -112,4 +112,13 @@ public @interface BooleanProvider {
* @return Preferred color. If none are specified defaults are used.
*/
Color iconColor() default Color.NONE;
/**
* When the parameter is set to {@code true} the value from this Provider is shown on a table alongside players.
* <p>
* If {@link BooleanProvider#hidden()} is {@code true} then this value will not be shown in the table regardless of the value of this parameter.
*
* @return false by default.
*/
boolean showInPlayerTable() default false;
}

View File

@ -91,4 +91,10 @@ public @interface DoubleProvider {
*/
Color iconColor() default Color.NONE;
/**
* When the parameter is set to {@code true} the value from this Provider is shown on a table alongside players.
*
* @return false by default.
*/
boolean showInPlayerTable() default false;
}

View File

@ -103,4 +103,10 @@ public @interface NumberProvider {
*/
Color iconColor() default Color.NONE;
/**
* When the parameter is set to {@code true} the value from this Provider is shown on a table alongside players.
*
* @return false by default.
*/
boolean showInPlayerTable() default false;
}

View File

@ -94,4 +94,10 @@ public @interface PercentageProvider {
*/
Color iconColor() default Color.NONE;
/**
* When the parameter is set to {@code true} the value from this Provider is shown on a table alongside players.
*
* @return false by default.
*/
boolean showInPlayerTable() default false;
}

View File

@ -103,4 +103,10 @@ public @interface StringProvider {
*/
Color iconColor() default Color.NONE;
/**
* When the parameter is set to {@code true} the value from this Provider is shown on a table alongside players.
*
* @return false by default.
*/
boolean showInPlayerTable() default false;
}

View File

@ -12,7 +12,7 @@ allprojects {
wrapper.gradleVersion = "5.0"
group "com.djrapitops"
version "4.8.2"
version "4.8.3"
test {
useJUnitPlatform()

View File

@ -15,6 +15,7 @@ dependencies {
compileOnly "com.google.guava:guava:$guavaVersion"
testCompile project(":api")
testCompile "com.google.code.gson:gson:2.8.5"
}
shadowJar {

View File

@ -29,6 +29,7 @@ import com.djrapitops.plan.db.patches.*;
import com.djrapitops.plan.system.DebugChannels;
import com.djrapitops.plan.system.locale.Locale;
import com.djrapitops.plan.system.settings.config.PlanConfig;
import com.djrapitops.plan.system.settings.paths.PluginSettings;
import com.djrapitops.plan.system.settings.paths.TimeSettings;
import com.djrapitops.plan.utilities.java.ThrowableUtils;
import com.djrapitops.plugin.api.TimeAmount;
@ -68,6 +69,8 @@ public abstract class SQLDB extends AbstractDatabase {
private Supplier<ExecutorService> transactionExecutorServiceProvider;
private ExecutorService transactionExecutor;
private final boolean devMode;
public SQLDB(
Supplier<UUID> serverUUIDSupplier,
Locale locale,
@ -84,6 +87,8 @@ public abstract class SQLDB extends AbstractDatabase {
this.logger = logger;
this.errorHandler = errorHandler;
devMode = config.get(PluginSettings.DEV_MODE);
this.transactionExecutorServiceProvider = () -> Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("Plan " + getClass().getSimpleName() + "-transaction-thread-%d").build());
}
@ -155,7 +160,8 @@ public abstract class SQLDB extends AbstractDatabase {
new TransferTableRemovalPatch(),
new IPAnonPatch(),
new BadAFKThresholdValuePatch(),
new DeleteIPHashesPatch()
new DeleteIPHashesPatch(),
new ExtensionShowInPlayersTablePatch()
};
}
@ -224,7 +230,9 @@ public abstract class SQLDB extends AbstractDatabase {
return CompletableFuture.supplyAsync(() -> {
accessLock.checkAccess(transaction);
logger.getDebugLogger().logOn(DebugChannels.SQL, "Executing: " + transaction.getClass().getSimpleName());
if (devMode) {
logger.getDebugLogger().logOn(DebugChannels.SQL, "Executing: " + transaction.getClass().getSimpleName());
}
transaction.executeTransaction(this);
return CompletableFuture.completedFuture(null);
}, getTransactionExecutor()).handle(errorHandler(origin));

View File

@ -0,0 +1,38 @@
/*
* 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.db.patches;
import com.djrapitops.plan.db.sql.parsing.Sql;
import com.djrapitops.plan.db.sql.tables.ExtensionProviderTable;
/**
* Patch to add 'show_in_players_table' to 'plan_extension_providers'
*
* @author Rsl1122
*/
public class ExtensionShowInPlayersTablePatch extends Patch {
@Override
public boolean hasBeenApplied() {
return hasColumn(ExtensionProviderTable.TABLE_NAME, ExtensionProviderTable.SHOW_IN_PLAYERS_TABLE);
}
@Override
protected void applyPatch() {
addColumn(ExtensionProviderTable.TABLE_NAME, ExtensionProviderTable.SHOW_IN_PLAYERS_TABLE + ' ' + Sql.BOOL + " NOT NULL DEFAULT 0");
}
}

View File

@ -45,6 +45,7 @@ public class ExtensionProviderTable {
public static final String PLUGIN_ID = "plugin_id";
public static final String ICON_ID = "icon_id";
public static final String TAB_ID = "tab_id"; // Can be null, related to @Tab
public static final String SHOW_IN_PLAYERS_TABLE = "show_in_players_table"; // default false
public static final String HIDDEN = "hidden"; // default false, related to @BooleanProvider
public static final String PROVIDED_CONDITION = "provided_condition"; // Can be null, related to @BooleanProvider
@ -71,6 +72,7 @@ public class ExtensionProviderTable {
.column(TEXT, Sql.varchar(50)).notNull()
.column(DESCRIPTION, Sql.varchar(150))
.column(PRIORITY, INT).notNull().defaultValue("0")
.column(SHOW_IN_PLAYERS_TABLE, BOOL).notNull().defaultValue(false)
.column(GROUPABLE, BOOL).notNull().defaultValue(false)
.column(CONDITION, Sql.varchar(54)) // 50 + 4 for "not_"
.column(PROVIDED_CONDITION, Sql.varchar(50))

View File

@ -32,14 +32,16 @@ import java.util.Optional;
public class ProviderInformation extends ExtensionDescriptive {
private final String pluginName;
private final boolean showInPlayersTable;
private final String tab; // can be null
private final Conditional condition; // can be null
public ProviderInformation(
String pluginName, String name, String text, String description, Icon icon, int priority, String tab, Conditional condition
String pluginName, String name, String text, String description, Icon icon, int priority, boolean showInPlayersTable, String tab, Conditional condition
) {
super(name, text, description, icon, priority);
this.pluginName = pluginName;
this.showInPlayersTable = showInPlayersTable;
this.tab = tab;
this.condition = condition;
}
@ -48,6 +50,10 @@ public class ProviderInformation extends ExtensionDescriptive {
return StringUtils.truncate(pluginName, 50);
}
public boolean isShownInPlayersTable() {
return showInPlayersTable;
}
public Optional<String> getTab() {
return tab == null || tab.isEmpty()
? Optional.empty()

View File

@ -52,7 +52,7 @@ public class BooleanDataProvider extends DataProvider<Boolean> {
Icon providerIcon = new Icon(annotation.iconFamily(), annotation.iconName(), annotation.iconColor());
ProviderInformation providerInformation = new ProviderInformation(
pluginName, method.getName(), annotation.text(), annotation.description(), providerIcon, annotation.priority(), tab, condition
pluginName, method.getName(), annotation.text(), annotation.description(), providerIcon, annotation.priority(), annotation.showInPlayerTable(), tab, condition
);
dataProviders.put(new BooleanDataProvider(providerInformation, methodWrapper, annotation.conditionName(), annotation.hidden()));

View File

@ -44,7 +44,7 @@ public class DoubleDataProvider extends DataProvider<Double> {
Icon providerIcon = new Icon(annotation.iconFamily(), annotation.iconName(), annotation.iconColor());
ProviderInformation providerInformation = new ProviderInformation(
pluginName, method.getName(), annotation.text(), annotation.description(), providerIcon, annotation.priority(), tab, condition
pluginName, method.getName(), annotation.text(), annotation.description(), providerIcon, annotation.priority(), annotation.showInPlayerTable(), tab, condition
);
dataProviders.put(new DoubleDataProvider(providerInformation, methodWrapper));

View File

@ -18,6 +18,7 @@ package com.djrapitops.plan.extension.implementation.providers;
import com.djrapitops.plan.extension.DataExtension;
import com.djrapitops.plan.extension.Group;
import com.djrapitops.plan.extension.NotReadyException;
import com.djrapitops.plan.extension.implementation.MethodType;
import java.io.Serializable;
@ -78,11 +79,11 @@ public class MethodWrapper<T> implements Serializable {
default:
throw new IllegalArgumentException(method.getDeclaringClass() + " method " + method.getName() + " had invalid parameters.");
}
} catch (NotReadyException notReadyToBeCalled) {
/* Data or API not available to make the call. */
return null;
} catch (InvocationTargetException | IllegalAccessException e) {
Throwable cause = e.getCause();
boolean hasCause = cause != null;
throw new IllegalArgumentException(method.getDeclaringClass() + " method " + method.getName() + " had invalid parameters; caused " +
(hasCause ? cause.toString() : e.toString()));
throw new IllegalArgumentException(method.getDeclaringClass() + " method " + method.getName() + " could not be called: " + e.getMessage(), e);
}
}

View File

@ -48,7 +48,7 @@ public class NumberDataProvider extends DataProvider<Long> {
Icon providerIcon = new Icon(annotation.iconFamily(), annotation.iconName(), annotation.iconColor());
ProviderInformation providerInformation = new ProviderInformation(
pluginName, method.getName(), annotation.text(), annotation.description(), providerIcon, annotation.priority(), tab, condition
pluginName, method.getName(), annotation.text(), annotation.description(), providerIcon, annotation.priority(), annotation.showInPlayerTable(), tab, condition
);
dataProviders.put(new NumberDataProvider(providerInformation, methodWrapper, annotation.format()));

View File

@ -44,7 +44,7 @@ public class PercentageDataProvider extends DataProvider<Double> {
Icon providerIcon = new Icon(annotation.iconFamily(), annotation.iconName(), annotation.iconColor());
ProviderInformation providerInformation = new ProviderInformation(
pluginName, method.getName(), annotation.text(), annotation.description(), providerIcon, annotation.priority(), tab, condition
pluginName, method.getName(), annotation.text(), annotation.description(), providerIcon, annotation.priority(), annotation.showInPlayerTable(), tab, condition
);
dataProviders.put(new PercentageDataProvider(providerInformation, methodWrapper));

View File

@ -47,7 +47,7 @@ public class StringDataProvider extends DataProvider<String> {
Icon providerIcon = new Icon(annotation.iconFamily(), annotation.iconName(), annotation.iconColor());
ProviderInformation providerInformation = new ProviderInformation(
pluginName, method.getName(), annotation.text(), annotation.description(), providerIcon, annotation.priority(), tab, condition
pluginName, method.getName(), annotation.text(), annotation.description(), providerIcon, annotation.priority(), annotation.showInPlayerTable(), tab, condition
);
boolean playerName = annotation.playerName();

View File

@ -50,7 +50,7 @@ public class TableDataProvider extends DataProvider<Table> {
MethodWrapper<Table> methodWrapper = new MethodWrapper<>(method, Table.class);
ProviderInformation providerInformation = new ProviderInformation(
pluginName, method.getName(), null, null, null, 0, tab, condition
pluginName, method.getName(), null, null, null, 0, false, tab, condition
);
dataProviders.put(new TableDataProvider(providerInformation, methodWrapper, annotation.tableColor()));

View File

@ -104,7 +104,7 @@ class DoubleAndPercentageProviderValueGatherer {
MethodWrapper<Double> method = doubleProvider.getMethod();
Double result = getMethodResult(methodCaller.apply(method), method);
if (result == null) {
return;
return; // Error during call
}
database.executeTransaction(new StoreIconTransaction(providerInformation.getIcon()));

View File

@ -99,7 +99,7 @@ class NumberProviderValueGatherer {
MethodWrapper<Long> method = numberProvider.getMethod();
Long result = getMethodResult(methodCaller.apply(method), method);
if (result == null) {
return;
return; // Error during call
}
FormatType formatType = NumberDataProvider.getFormatType(numberProvider);

View File

@ -100,7 +100,7 @@ class StringProviderValueGatherer {
MethodWrapper<String> method = stringProvider.getMethod();
String result = getMethodResult(methodCaller.apply(method), method);
if (result == null) {
return;
return; // Error during call
}
result = StringUtils.truncate(result, 50);

View File

@ -101,7 +101,7 @@ class TableProviderValueGatherer {
MethodWrapper<Table> method = tableProvider.getMethod();
Table result = getMethodResult(methodCaller.apply(method), method);
if (result == null) {
return;
return; // Error during call
}
for (Icon icon : result.getIcons()) {

View File

@ -63,12 +63,14 @@ public class ExtensionServerPlayerDataTableQuery implements Query<Map<UUID, Exte
SessionsTable.TABLE_NAME + '.' + SessionsTable.USER_UUID +
",MAX(" + SessionsTable.SESSION_END + ") as last_seen" +
FROM + SessionsTable.TABLE_NAME +
GROUP_BY + SessionsTable.USER_UUID +
GROUP_BY + SessionsTable.TABLE_NAME + '.' + SessionsTable.USER_UUID + ',' + SessionsTable.SESSION_END +
ORDER_BY + SessionsTable.SESSION_END + " DESC LIMIT ?";
String sql = SELECT +
"v1." + ExtensionPlayerValueTable.USER_UUID + " as uuid," +
"v1." + ExtensionPlayerValueTable.BOOLEAN_VALUE + " as boolean_value," +
"v1." + ExtensionPlayerValueTable.DOUBLE_VALUE + " as double_value," +
"v1." + ExtensionPlayerValueTable.PERCENTAGE_VALUE + " as percentage_value," +
"v1." + ExtensionPlayerValueTable.LONG_VALUE + " as long_value," +
"v1." + ExtensionPlayerValueTable.STRING_VALUE + " as string_value," +
"p1." + ExtensionProviderTable.PROVIDER_NAME + " as provider_name," +
@ -83,16 +85,16 @@ public class ExtensionServerPlayerDataTableQuery implements Query<Map<UUID, Exte
INNER_JOIN + ExtensionPluginTable.TABLE_NAME + " e1 on e1." + ExtensionPluginTable.ID + "=p1." + ExtensionProviderTable.PLUGIN_ID +
LEFT_JOIN + ExtensionIconTable.TABLE_NAME + " i1 on i1." + ExtensionIconTable.ID + "=p1." + ExtensionProviderTable.ICON_ID +
WHERE + "e1." + ExtensionPluginTable.SERVER_UUID + "=?" +
AND + " v1." + ExtensionPlayerValueTable.BOOLEAN_VALUE + IS_NULL + // Don't select Boolean value rows
AND + " v1." + ExtensionPlayerValueTable.PERCENTAGE_VALUE + IS_NULL + // Don't select Percentage value rows
AND + " p1." + ExtensionProviderTable.IS_PLAYER_NAME + "=?";
AND + "p1." + ExtensionProviderTable.SHOW_IN_PLAYERS_TABLE + "=?" +
AND + "p1." + ExtensionProviderTable.IS_PLAYER_NAME + "=?";
return new QueryStatement<Map<UUID, ExtensionTabData>>(sql, 1000) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setInt(1, xMostRecentPlayers); // Limit to x most recently seen players
statement.setString(2, serverUUID.toString());
statement.setBoolean(3, false); // Don't select player_name String values
statement.setBoolean(3, true); // Select only values that should be shown
statement.setBoolean(4, false); // Don't select player_name String values
}
@Override
@ -118,12 +120,24 @@ public class ExtensionServerPlayerDataTableQuery implements Query<Map<UUID, Exte
}
private void extractAndPutDataTo(ExtensionTabData.Factory extensionTab, ExtensionDescriptive descriptive, ResultSet set) throws SQLException {
boolean booleanValue = set.getBoolean(ExtensionServerValueTable.BOOLEAN_VALUE);
if (!set.wasNull()) {
extensionTab.putBooleanData(new ExtensionBooleanData(descriptive, booleanValue));
return;
}
double doubleValue = set.getDouble(ExtensionPlayerValueTable.DOUBLE_VALUE);
if (!set.wasNull()) {
extensionTab.putDoubleData(new ExtensionDoubleData(descriptive, doubleValue));
return;
}
double percentageValue = set.getDouble(ExtensionServerValueTable.PERCENTAGE_VALUE);
if (!set.wasNull()) {
extensionTab.putPercentageData(new ExtensionDoubleData(descriptive, percentageValue));
return;
}
long numberValue = set.getLong(ExtensionPlayerValueTable.LONG_VALUE);
if (!set.wasNull()) {
FormatType formatType = FormatType.getByName(set.getString(ExtensionProviderTable.FORMAT_TYPE)).orElse(FormatType.NONE);

View File

@ -78,7 +78,8 @@ public class StoreBooleanProviderTransaction extends Transaction {
PROVIDED_CONDITION + "=?," +
TAB_ID + '=' + ExtensionTabTable.STATEMENT_SELECT_TAB_ID + ',' +
ICON_ID + '=' + ExtensionIconTable.STATEMENT_SELECT_ICON_ID + ',' +
HIDDEN + "=?" +
HIDDEN + "=?," +
SHOW_IN_PLAYERS_TABLE + "=?" +
WHERE + PLUGIN_ID + '=' + ExtensionPluginTable.STATEMENT_SELECT_PLUGIN_ID +
AND + PROVIDER_NAME + "=?";
@ -107,8 +108,9 @@ public class StoreBooleanProviderTransaction extends Transaction {
ExtensionTabTable.set3TabValuesToStatement(statement, 6, providerInformation.getTab().orElse("No Tab"), providerInformation.getPluginName(), serverUUID);
ExtensionIconTable.set3IconValuesToStatement(statement, 9, providerInformation.getIcon());
statement.setBoolean(12, hidden);
ExtensionPluginTable.set2PluginValuesToStatement(statement, 13, providerInformation.getPluginName(), serverUUID);
statement.setString(15, providerInformation.getName());
statement.setBoolean(13, providerInformation.isShownInPlayersTable());
ExtensionPluginTable.set2PluginValuesToStatement(statement, 14, providerInformation.getPluginName(), serverUUID);
statement.setString(16, providerInformation.getName());
}
};
}
@ -122,10 +124,11 @@ public class StoreBooleanProviderTransaction extends Transaction {
CONDITION + ',' +
PROVIDED_CONDITION + ',' +
HIDDEN + ',' +
SHOW_IN_PLAYERS_TABLE + ',' +
TAB_ID + ',' +
ICON_ID + ',' +
PLUGIN_ID +
") VALUES (?,?,?,?,?,?,?," +
") VALUES (?,?,?,?,?,?,?,?," +
ExtensionTabTable.STATEMENT_SELECT_TAB_ID + ',' +
ExtensionIconTable.STATEMENT_SELECT_ICON_ID + ',' +
ExtensionPluginTable.STATEMENT_SELECT_PLUGIN_ID + ')';
@ -153,9 +156,10 @@ public class StoreBooleanProviderTransaction extends Transaction {
statement.setNull(6, Types.VARCHAR);
}
statement.setBoolean(7, hidden);
ExtensionTabTable.set3TabValuesToStatement(statement, 8, providerInformation.getTab().orElse("No Tab"), providerInformation.getPluginName(), serverUUID);
ExtensionIconTable.set3IconValuesToStatement(statement, 11, providerInformation.getIcon());
ExtensionPluginTable.set2PluginValuesToStatement(statement, 14, providerInformation.getPluginName(), serverUUID);
statement.setBoolean(8, providerInformation.isShownInPlayersTable());
ExtensionTabTable.set3TabValuesToStatement(statement, 9, providerInformation.getTab().orElse("No Tab"), providerInformation.getPluginName(), serverUUID);
ExtensionIconTable.set3IconValuesToStatement(statement, 12, providerInformation.getIcon());
ExtensionPluginTable.set2PluginValuesToStatement(statement, 15, providerInformation.getPluginName(), serverUUID);
}
};
}

View File

@ -76,7 +76,8 @@ public class StoreDoubleProviderTransaction extends Transaction {
PRIORITY + "=?," +
CONDITION + "=?," +
TAB_ID + "=" + ExtensionTabTable.STATEMENT_SELECT_TAB_ID + "," +
ICON_ID + "=" + ExtensionIconTable.STATEMENT_SELECT_ICON_ID +
ICON_ID + "=" + ExtensionIconTable.STATEMENT_SELECT_ICON_ID + ',' +
SHOW_IN_PLAYERS_TABLE + "=?" +
WHERE + PLUGIN_ID + "=" + ExtensionPluginTable.STATEMENT_SELECT_PLUGIN_ID +
AND + PROVIDER_NAME + "=?";
@ -99,8 +100,9 @@ public class StoreDoubleProviderTransaction extends Transaction {
}
ExtensionTabTable.set3TabValuesToStatement(statement, 5, providerInformation.getTab().orElse("No Tab"), providerInformation.getPluginName(), serverUUID);
ExtensionIconTable.set3IconValuesToStatement(statement, 8, providerInformation.getIcon());
ExtensionPluginTable.set2PluginValuesToStatement(statement, 11, providerInformation.getPluginName(), serverUUID);
statement.setString(13, providerInformation.getName());
statement.setBoolean(11, providerInformation.isShownInPlayersTable());
ExtensionPluginTable.set2PluginValuesToStatement(statement, 12, providerInformation.getPluginName(), serverUUID);
statement.setString(14, providerInformation.getName());
}
};
}
@ -112,10 +114,11 @@ public class StoreDoubleProviderTransaction extends Transaction {
DESCRIPTION + "," +
PRIORITY + "," +
CONDITION + "," +
SHOW_IN_PLAYERS_TABLE + ',' +
TAB_ID + "," +
ICON_ID + "," +
PLUGIN_ID +
") VALUES (?,?,?,?,?," +
") VALUES (?,?,?,?,?,?," +
ExtensionTabTable.STATEMENT_SELECT_TAB_ID + "," +
ExtensionIconTable.STATEMENT_SELECT_ICON_ID + "," +
ExtensionPluginTable.STATEMENT_SELECT_PLUGIN_ID + ")";
@ -137,9 +140,10 @@ public class StoreDoubleProviderTransaction extends Transaction {
} else {
statement.setNull(5, Types.VARCHAR);
}
ExtensionTabTable.set3TabValuesToStatement(statement, 6, providerInformation.getTab().orElse("No Tab"), providerInformation.getPluginName(), serverUUID);
ExtensionIconTable.set3IconValuesToStatement(statement, 9, providerInformation.getIcon());
ExtensionPluginTable.set2PluginValuesToStatement(statement, 12, providerInformation.getPluginName(), serverUUID);
statement.setBoolean(6, providerInformation.isShownInPlayersTable());
ExtensionTabTable.set3TabValuesToStatement(statement, 7, providerInformation.getTab().orElse("No Tab"), providerInformation.getPluginName(), serverUUID);
ExtensionIconTable.set3IconValuesToStatement(statement, 10, providerInformation.getIcon());
ExtensionPluginTable.set2PluginValuesToStatement(statement, 13, providerInformation.getPluginName(), serverUUID);
}
};
}

View File

@ -74,6 +74,7 @@ public class StoreNumberProviderTransaction extends Transaction {
DESCRIPTION + "=?," +
PRIORITY + "=?," +
CONDITION + "=?," +
SHOW_IN_PLAYERS_TABLE + "=?," +
FORMAT_TYPE + "=?," +
TAB_ID + "=" + ExtensionTabTable.STATEMENT_SELECT_TAB_ID + "," +
ICON_ID + "=" + ExtensionIconTable.STATEMENT_SELECT_ICON_ID +
@ -97,11 +98,12 @@ public class StoreNumberProviderTransaction extends Transaction {
} else {
statement.setNull(4, Types.VARCHAR);
}
statement.setString(5, formatType.name());
ExtensionTabTable.set3TabValuesToStatement(statement, 6, providerInformation.getTab().orElse("No Tab"), providerInformation.getPluginName(), serverUUID);
ExtensionIconTable.set3IconValuesToStatement(statement, 9, providerInformation.getIcon());
ExtensionPluginTable.set2PluginValuesToStatement(statement, 12, providerInformation.getPluginName(), serverUUID);
statement.setString(14, providerInformation.getName());
statement.setBoolean(5, providerInformation.isShownInPlayersTable());
statement.setString(6, formatType.name());
ExtensionTabTable.set3TabValuesToStatement(statement, 7, providerInformation.getTab().orElse("No Tab"), providerInformation.getPluginName(), serverUUID);
ExtensionIconTable.set3IconValuesToStatement(statement, 10, providerInformation.getIcon());
ExtensionPluginTable.set2PluginValuesToStatement(statement, 13, providerInformation.getPluginName(), serverUUID);
statement.setString(15, providerInformation.getName());
}
};
}
@ -113,11 +115,12 @@ public class StoreNumberProviderTransaction extends Transaction {
DESCRIPTION + "," +
PRIORITY + "," +
CONDITION + "," +
SHOW_IN_PLAYERS_TABLE + ',' +
FORMAT_TYPE + "," +
TAB_ID + "," +
ICON_ID + "," +
PLUGIN_ID +
") VALUES (?,?,?,?,?,?," +
") VALUES (?,?,?,?,?,?,?," +
ExtensionTabTable.STATEMENT_SELECT_TAB_ID + "," +
ExtensionIconTable.STATEMENT_SELECT_ICON_ID + "," +
ExtensionPluginTable.STATEMENT_SELECT_PLUGIN_ID + ")";
@ -139,10 +142,11 @@ public class StoreNumberProviderTransaction extends Transaction {
} else {
statement.setNull(5, Types.VARCHAR);
}
statement.setString(6, formatType.name());
ExtensionTabTable.set3TabValuesToStatement(statement, 7, providerInformation.getTab().orElse("No Tab"), providerInformation.getPluginName(), serverUUID);
ExtensionIconTable.set3IconValuesToStatement(statement, 10, providerInformation.getIcon());
ExtensionPluginTable.set2PluginValuesToStatement(statement, 13, providerInformation.getPluginName(), serverUUID);
statement.setBoolean(6, providerInformation.isShownInPlayersTable());
statement.setString(7, formatType.name());
ExtensionTabTable.set3TabValuesToStatement(statement, 8, providerInformation.getTab().orElse("No Tab"), providerInformation.getPluginName(), serverUUID);
ExtensionIconTable.set3IconValuesToStatement(statement, 11, providerInformation.getIcon());
ExtensionPluginTable.set2PluginValuesToStatement(statement, 14, providerInformation.getPluginName(), serverUUID);
}
};
}

View File

@ -73,6 +73,7 @@ public class StoreStringProviderTransaction extends Transaction {
DESCRIPTION + "=?," +
PRIORITY + "=?," +
CONDITION + "=?," +
SHOW_IN_PLAYERS_TABLE + "=?," +
IS_PLAYER_NAME + "=?," +
TAB_ID + "=" + ExtensionTabTable.STATEMENT_SELECT_TAB_ID + "," +
ICON_ID + "=" + ExtensionIconTable.STATEMENT_SELECT_ICON_ID +
@ -96,11 +97,12 @@ public class StoreStringProviderTransaction extends Transaction {
} else {
statement.setNull(4, Types.VARCHAR);
}
statement.setBoolean(5, playerName);
ExtensionTabTable.set3TabValuesToStatement(statement, 6, providerInformation.getTab().orElse("No Tab"), providerInformation.getPluginName(), serverUUID);
ExtensionIconTable.set3IconValuesToStatement(statement, 9, providerInformation.getIcon());
ExtensionPluginTable.set2PluginValuesToStatement(statement, 12, providerInformation.getPluginName(), serverUUID);
statement.setString(14, providerInformation.getName());
statement.setBoolean(5, providerInformation.isShownInPlayersTable());
statement.setBoolean(6, playerName);
ExtensionTabTable.set3TabValuesToStatement(statement, 7, providerInformation.getTab().orElse("No Tab"), providerInformation.getPluginName(), serverUUID);
ExtensionIconTable.set3IconValuesToStatement(statement, 10, providerInformation.getIcon());
ExtensionPluginTable.set2PluginValuesToStatement(statement, 13, providerInformation.getPluginName(), serverUUID);
statement.setString(15, providerInformation.getName());
}
};
}
@ -112,11 +114,12 @@ public class StoreStringProviderTransaction extends Transaction {
DESCRIPTION + "," +
PRIORITY + "," +
CONDITION + "," +
SHOW_IN_PLAYERS_TABLE + "," +
IS_PLAYER_NAME + "," +
TAB_ID + "," +
ICON_ID + "," +
PLUGIN_ID +
") VALUES (?,?,?,?,?,?," +
") VALUES (?,?,?,?,?,?,?," +
ExtensionTabTable.STATEMENT_SELECT_TAB_ID + "," +
ExtensionIconTable.STATEMENT_SELECT_ICON_ID + "," +
ExtensionPluginTable.STATEMENT_SELECT_PLUGIN_ID + ")";
@ -138,10 +141,11 @@ public class StoreStringProviderTransaction extends Transaction {
} else {
statement.setNull(5, Types.VARCHAR);
}
statement.setBoolean(6, playerName);
ExtensionTabTable.set3TabValuesToStatement(statement, 7, providerInformation.getTab().orElse("No Tab"), providerInformation.getPluginName(), serverUUID);
ExtensionIconTable.set3IconValuesToStatement(statement, 10, providerInformation.getIcon());
ExtensionPluginTable.set2PluginValuesToStatement(statement, 13, providerInformation.getPluginName(), serverUUID);
statement.setBoolean(6, providerInformation.isShownInPlayersTable());
statement.setBoolean(7, playerName);
ExtensionTabTable.set3TabValuesToStatement(statement, 8, providerInformation.getTab().orElse("No Tab"), providerInformation.getPluginName(), serverUUID);
ExtensionIconTable.set3IconValuesToStatement(statement, 11, providerInformation.getIcon());
ExtensionPluginTable.set2PluginValuesToStatement(statement, 14, providerInformation.getPluginName(), serverUUID);
}
};
}

View File

@ -34,7 +34,6 @@ import com.djrapitops.plan.utilities.html.icon.Family;
import com.djrapitops.plan.utilities.html.icon.Icon;
import java.util.*;
import java.util.stream.Collectors;
/**
* Parsing utility for creating jQuery Datatables JSON for a Players Table.
@ -70,11 +69,11 @@ public class PlayersTableJSONParser {
// Data
this.players = players;
this.extensionData = extensionData;
extensionDescriptives = extensionData.values().stream()
.map(ExtensionTabData::getDescriptives)
.flatMap(Collection::stream)
.distinct().sorted((one, two) -> String.CASE_INSENSITIVE_ORDER.compare(one.getName(), two.getName()))
.collect(Collectors.toList());
extensionDescriptives = new ArrayList<>();
addExtensionDescriptives(extensionData);
extensionDescriptives.sort((one, two) -> String.CASE_INSENSITIVE_ORDER.compare(one.getName(), two.getName()));
// Settings
this.maxPlayers = maxPlayers;
this.activeMsThreshold = activeMsThreshold;
@ -90,6 +89,18 @@ public class PlayersTableJSONParser {
this.decimalFormatter = formatters.decimals();
}
private void addExtensionDescriptives(Map<UUID, ExtensionTabData> extensionData) {
Set<String> foundDescriptives = new HashSet<>();
for (ExtensionTabData tabData : extensionData.values()) {
for (ExtensionDescriptive descriptive : tabData.getDescriptives()) {
if (!foundDescriptives.contains(descriptive.getName())) {
extensionDescriptives.add(descriptive);
foundDescriptives.add(descriptive.getName());
}
}
}
}
public String toJSONString() {
String data = parseData();
String columnHeaders = parseColumnHeaders();

View File

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

View File

@ -1,7 +1,7 @@
name: Plan
author: Rsl1122
main: com.djrapitops.plan.Plan
version: 4.8.2
version: 4.8.3
softdepend:
- ASkyBlock
- AdvancedAchievements

View File

@ -1187,15 +1187,23 @@ public abstract class CommonDBTest {
extensionPlayerValuesAreStored();
sessionsAreStoredWithAllData(); // This query requires sessions for a last seen date
// Store a second session to check against issue https://github.com/plan-player-analytics/Plan/issues/1039
Session session = new Session(playerUUID, serverUUID, 32345L, worlds[0], "SURVIVAL");
session.endSession(42345L);
session.setWorldTimes(createWorldTimes());
session.setPlayerKills(createKills());
execute(DataStoreQueries.storeSession(session));
Map<UUID, ExtensionTabData> result = db.query(new ExtensionServerPlayerDataTableQuery(serverUUID, 50));
assertEquals(1, result.size());
ExtensionTabData playerData = result.get(playerUUID);
assertNotNull(playerData);
OptionalAssert.equals("5", playerData.getNumber("value").map(data -> data.getFormattedValue(Object::toString)));
assertFalse(playerData.getBoolean("boolVal").isPresent());
OptionalAssert.equals("No", playerData.getBoolean("boolVal").map(ExtensionBooleanData::getFormattedValue));
OptionalAssert.equals("0.5", playerData.getDouble("doubleVal").map(data -> data.getFormattedValue(Object::toString)));
assertFalse(playerData.getBoolean("percentageVal").isPresent());
OptionalAssert.equals("0.5", playerData.getPercentage("percentageVal").map(data -> data.getFormattedValue(Object::toString)));
OptionalAssert.equals("Something", playerData.getString("stringVal").map(ExtensionStringData::getFormattedValue));
}
@ -1493,27 +1501,27 @@ public abstract class CommonDBTest {
@PluginInfo(name = "PlayerExtension")
public class PlayerExtension implements DataExtension {
@NumberProvider(text = "a number")
@NumberProvider(text = "a number", showInPlayerTable = true)
public long value(UUID playerUUD) {
return 5L;
}
@BooleanProvider(text = "a boolean")
@BooleanProvider(text = "a boolean", showInPlayerTable = true)
public boolean boolVal(UUID playerUUID) {
return false;
}
@DoubleProvider(text = "a double")
@DoubleProvider(text = "a double", showInPlayerTable = true)
public double doubleVal(UUID playerUUID) {
return 0.5;
}
@PercentageProvider(text = "a percentage")
@PercentageProvider(text = "a percentage", showInPlayerTable = true)
public double percentageVal(UUID playerUUID) {
return 0.5;
}
@StringProvider(text = "a string")
@StringProvider(text = "a string", showInPlayerTable = true)
public String stringVal(UUID playerUUID) {
return "Something";
}

View File

@ -0,0 +1,184 @@
/*
* 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.utilities.html.tables;
import com.djrapitops.plan.data.container.Session;
import com.djrapitops.plan.db.Database;
import com.djrapitops.plan.db.access.queries.containers.ServerPlayersTableContainersQuery;
import com.djrapitops.plan.db.access.transactions.Transaction;
import com.djrapitops.plan.db.access.transactions.events.PlayerRegisterTransaction;
import com.djrapitops.plan.db.access.transactions.events.PlayerServerRegisterTransaction;
import com.djrapitops.plan.db.access.transactions.events.SessionEndTransaction;
import com.djrapitops.plan.db.access.transactions.events.WorldNameStoreTransaction;
import com.djrapitops.plan.extension.CallEvents;
import com.djrapitops.plan.extension.DataExtension;
import com.djrapitops.plan.extension.ExtensionService;
import com.djrapitops.plan.extension.ExtensionServiceImplementation;
import com.djrapitops.plan.extension.annotation.*;
import com.djrapitops.plan.extension.implementation.storage.queries.ExtensionServerPlayerDataTableQuery;
import com.djrapitops.plan.system.PlanSystem;
import com.djrapitops.plan.system.locale.Locale;
import com.djrapitops.plan.system.settings.config.PlanConfig;
import com.djrapitops.plan.system.settings.paths.WebserverSettings;
import com.djrapitops.plan.utilities.formatting.Formatters;
import com.google.gson.Gson;
import org.junit.Assume;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.junit.platform.runner.JUnitPlatform;
import org.junit.runner.RunWith;
import utilities.RandomData;
import utilities.TestConstants;
import utilities.mocks.PluginMockComponent;
import java.nio.file.Path;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import static org.junit.jupiter.api.Assertions.assertFalse;
/**
* Test against PlayersTableJSONParser JSON issues as well as other issues.
*
* @author Rsl1122
*/
@RunWith(JUnitPlatform.class)
class PlayersTableJSONParserTest {
private static final int TEST_PORT_NUMBER = RandomData.randomInt(9005, 9500);
private Database db;
private PlanSystem system;
private UUID serverUUID;
private UUID playerUUID = TestConstants.PLAYER_ONE_UUID;
private UUID player2UUID = TestConstants.PLAYER_TWO_UUID;
@BeforeEach
void setUp(@TempDir Path tempDir) throws Exception {
Assume.assumeTrue(false); // TODO Skipped due to problems with Gson, parsed 'columns' is null even though it's not.
PluginMockComponent component = new PluginMockComponent(tempDir);
system = component.getPlanSystem();
PlanConfig config = system.getConfigSystem().getConfig();
config.set(WebserverSettings.PORT, TEST_PORT_NUMBER);
system.enable();
db = system.getDatabaseSystem().getDatabase();
serverUUID = system.getServerInfo().getServerUUID();
storePlayerData();
}
private void storePlayerData() throws Exception {
db.executeTransaction(new WorldNameStoreTransaction(serverUUID, "World"));
db.executeTransaction(new PlayerServerRegisterTransaction(playerUUID, () -> 1000L, TestConstants.PLAYER_ONE_NAME, serverUUID));
db.executeTransaction(new PlayerRegisterTransaction(player2UUID, () -> 123456789L, TestConstants.PLAYER_TWO_NAME));
Session session = new Session(playerUUID, serverUUID, 12345L, "World", "SURVIVAL");
session.endSession(22345L);
db.executeTransaction(new SessionEndTransaction(session));
Session session2 = new Session(player2UUID, serverUUID, 12345L, "World", "SURVIVAL");
session2.endSession(22345L);
db.executeTransaction(new SessionEndTransaction(session2));
ExtensionService extensionService = ExtensionService.getInstance();
extensionService.register(new PlayerExtension());
((ExtensionServiceImplementation) extensionService).updatePlayerValues(playerUUID, TestConstants.PLAYER_ONE_NAME, CallEvents.MANUAL);
((ExtensionServiceImplementation) extensionService).updatePlayerValues(player2UUID, TestConstants.PLAYER_TWO_NAME, CallEvents.MANUAL);
db.executeTransaction(new Transaction() {
@Override
protected void performOperations() {
}
}).get(); // Wait for transactions to finish
}
@Test
void playersTableJSONDoesNotContainDuplicateColumns() {
PlayersTableJSONParser parser = createParser();
class Column {
String title;
}
class Table {
Column[] columns;
}
String json = parser.toJSONString();
System.out.println("Parsed: " + json);
Table table = new Gson().fromJson(json, Table.class);
Set<String> foundColumnNames = new HashSet<>();
for (Column column : table.columns) {
assertFalse(foundColumnNames.contains(column.title), () -> "Duplicate column title: '" + column.title + "'");
foundColumnNames.add(column.title);
}
}
private PlayersTableJSONParser createParser() {
int xMostRecentPlayers = 5;
int loginThreshold = 5;
long playtimeThreshold = TimeUnit.DAYS.toMillis(1L);
boolean openPlayerLinksInNewTab = false;
return new PlayersTableJSONParser(
db.query(new ServerPlayersTableContainersQuery(serverUUID)),
db.query(new ExtensionServerPlayerDataTableQuery(serverUUID, xMostRecentPlayers)),
xMostRecentPlayers, playtimeThreshold, loginThreshold, openPlayerLinksInNewTab,
new Formatters(system.getConfigSystem().getConfig(), new Locale())
);
}
@AfterEach
void tearDown() {
system.disable();
}
@PluginInfo(name = "PlayerExtension")
public class PlayerExtension implements DataExtension {
@NumberProvider(text = "a number", showInPlayerTable = true)
public long value(UUID playerUUD) {
return 5L;
}
@BooleanProvider(text = "a boolean", showInPlayerTable = true)
public boolean boolVal(UUID playerUUID) {
return false;
}
@DoubleProvider(text = "a double", showInPlayerTable = true)
public double doubleVal(UUID playerUUID) {
return 0.5;
}
@PercentageProvider(text = "a percentage", showInPlayerTable = true)
public double percentageVal(UUID playerUUID) {
return 0.5;
}
@StringProvider(text = "a string", showInPlayerTable = true)
public String stringVal(UUID playerUUID) {
return "Something";
}
}
}

View File

@ -1,21 +1,21 @@
dependencies {
compile project(path: ":api")
compile "com.djrapitops:Extension-AdvancedAchievements:1.1-R0.2"
compile "com.djrapitops:Extension-AdvancedBan:2.1.5-R0.5"
compile "com.djrapitops:Extension-ASkyBlock:3.0.9.4-R0.3"
compile "com.djrapitops:Extension-BanManager:5.15.0-R0.4"
compile "com.djrapitops:Extension-CoreProtect:2.16.0-R0.2"
compile "com.djrapitops:Extension-DiscordSRV:1.16.6-R0.2"
compile "com.djrapitops:Extension-AdvancedAchievements:1.1-R0.3"
compile "com.djrapitops:Extension-AdvancedBan:2.1.5-R0.6"
compile "com.djrapitops:Extension-ASkyBlock:3.0.9.4-R0.4"
compile "com.djrapitops:Extension-BanManager:5.15.0-R0.5"
compile "com.djrapitops:Extension-CoreProtect:2.16.0-R0.3"
compile "com.djrapitops:Extension-DiscordSRV:1.16.6-R0.4"
compile "com.djrapitops:Extension-EssentialsX:2.15.0-R0.3"
compile "com.djrapitops:Extension-GriefPrevention:16.11.6-R0.1"
compile "com.djrapitops:Extension-GriefPrevention-Sponge:4.0.1-R0.1"
compile "com.djrapitops:Extension-GriefPreventionPlus:13.3-R0.1"
compile "com.djrapitops:Extension-McMMO:2.1.44-R0.1"
compile 'com.djrapitops:Extension-MinigamesLib:1.14.17-R0.1'
compile 'com.djrapitops:Extension-Nucleus:1.9.2-R0.1'
compile "com.djrapitops:Extension-RedProtect:7.5.6-R0.1"
compile "com.djrapitops:Extension-Sponge-Economy:7.1.0-R0.2"
compile "com.djrapitops:Extension-Vault:1.7-R0.1"
compile "com.djrapitops:Extension-GriefPrevention:16.11.6-R0.2"
compile "com.djrapitops:Extension-GriefPrevention-Sponge:4.0.1-R0.2"
compile "com.djrapitops:Extension-GriefPreventionPlus:13.3-R0.2"
compile "com.djrapitops:Extension-McMMO:2.1.44-R0.2"
compile 'com.djrapitops:Extension-MinigamesLib:1.14.17-R0.2'
compile 'com.djrapitops:Extension-Nucleus:1.9.2-R0.2'
compile "com.djrapitops:Extension-RedProtect:7.5.6-R0.2"
compile "com.djrapitops:Extension-Sponge-Economy:7.1.0-R0.3"
compile "com.djrapitops:Extension-Vault:1.7-R0.2"
}
shadowJar {

View File

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

View File

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