factory) {
diff --git a/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/providers/GroupDataProvider.java b/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/providers/GroupDataProvider.java
new file mode 100644
index 000000000..eee44da69
--- /dev/null
+++ b/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/providers/GroupDataProvider.java
@@ -0,0 +1,54 @@
+/*
+ * 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 .
+ */
+package com.djrapitops.plan.extension.implementation.providers;
+
+import com.djrapitops.plan.extension.Group;
+import com.djrapitops.plan.extension.annotation.Conditional;
+import com.djrapitops.plan.extension.annotation.GroupProvider;
+import com.djrapitops.plan.extension.annotation.StringProvider;
+import com.djrapitops.plan.extension.icon.Icon;
+import com.djrapitops.plan.extension.implementation.ProviderInformation;
+
+import java.lang.reflect.Method;
+
+/**
+ * Represents a DataExtension API method annotated with {@link StringProvider} annotation.
+ *
+ * Used to obtain data to place in the database.
+ *
+ * @author Rsl1122
+ */
+public class GroupDataProvider extends DataProvider {
+
+ private GroupDataProvider(ProviderInformation providerInformation, MethodWrapper methodWrapper) {
+ super(providerInformation, methodWrapper);
+ }
+
+ public static void placeToDataProviders(
+ DataProviders dataProviders, Method method, GroupProvider annotation,
+ Conditional condition, String tab, String pluginName
+ ) {
+ MethodWrapper methodWrapper = new MethodWrapper<>(method, Group[].class);
+ Icon providerIcon = new Icon(annotation.iconFamily(), annotation.iconName(), annotation.groupColor());
+
+ ProviderInformation providerInformation = new ProviderInformation(
+ pluginName, method.getName(), annotation.text(), null, providerIcon, 0, true, tab, condition
+ );
+
+ dataProviders.put(new GroupDataProvider(providerInformation, methodWrapper));
+ }
+}
\ No newline at end of file
diff --git a/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/providers/gathering/GroupProviderValueGatherer.java b/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/providers/gathering/GroupProviderValueGatherer.java
new file mode 100644
index 000000000..b2ab4bc2d
--- /dev/null
+++ b/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/providers/gathering/GroupProviderValueGatherer.java
@@ -0,0 +1,91 @@
+/*
+ * 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 .
+ */
+package com.djrapitops.plan.extension.implementation.providers.gathering;
+
+import com.djrapitops.plan.api.exceptions.DataExtensionMethodCallException;
+import com.djrapitops.plan.db.Database;
+import com.djrapitops.plan.extension.DataExtension;
+import com.djrapitops.plan.extension.Group;
+import com.djrapitops.plan.extension.implementation.ProviderInformation;
+import com.djrapitops.plan.extension.implementation.providers.DataProvider;
+import com.djrapitops.plan.extension.implementation.providers.DataProviders;
+import com.djrapitops.plan.extension.implementation.providers.MethodWrapper;
+import com.djrapitops.plan.extension.implementation.storage.transactions.StoreIconTransaction;
+import com.djrapitops.plan.extension.implementation.storage.transactions.providers.StoreGroupProviderTransaction;
+import com.djrapitops.plan.extension.implementation.storage.transactions.results.StorePlayerGroupsResultTransaction;
+
+import java.util.Optional;
+import java.util.UUID;
+
+/**
+ * Gathers GroupProvider method data.
+ *
+ * @author Rsl1122
+ */
+class GroupProviderValueGatherer {
+
+ private final String pluginName;
+ private final DataExtension extension;
+ private final UUID serverUUID;
+
+ private final Database database;
+ private final DataProviders dataProviders;
+
+ GroupProviderValueGatherer(
+ String pluginName, DataExtension extension,
+ UUID serverUUID, Database database,
+ DataProviders dataProviders
+ ) {
+ this.pluginName = pluginName;
+ this.extension = extension;
+ this.serverUUID = serverUUID;
+ this.database = database;
+ this.dataProviders = dataProviders;
+ }
+
+ void gatherGroupDataOfPlayer(UUID playerUUID, String playerName, Conditions conditions) {
+ for (DataProvider groupProvider : dataProviders.getPlayerMethodsByType(Group[].class)) {
+ gatherGroupDataOfProvider(playerUUID, playerName, conditions, groupProvider);
+ }
+ }
+
+ private void gatherGroupDataOfProvider(
+ UUID playerUUID, String playerName,
+ Conditions conditions,
+ DataProvider groupProvider
+ ) {
+ ProviderInformation providerInformation = groupProvider.getProviderInformation();
+ Optional condition = providerInformation.getCondition();
+ if (condition.isPresent() && conditions.isNotFulfilled(condition.get())) {
+ return;
+ }
+
+ MethodWrapper method = groupProvider.getMethod();
+ try {
+ Group[] result = method.callMethod(extension, playerUUID, playerName);
+ if (result == null) {
+ return; // Error during call
+ }
+
+ database.executeTransaction(new StoreIconTransaction(providerInformation.getIcon()));
+ database.executeTransaction(new StoreGroupProviderTransaction(groupProvider, serverUUID));
+ database.executeTransaction(new StorePlayerGroupsResultTransaction(pluginName, serverUUID, method.getMethodName(), playerUUID, result));
+ } catch (Exception | NoClassDefFoundError | NoSuchFieldError | NoSuchMethodError e) {
+ throw new DataExtensionMethodCallException(e, pluginName, method);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/providers/gathering/ProviderValueGatherer.java b/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/providers/gathering/ProviderValueGatherer.java
index 45ecfc273..972848ce2 100644
--- a/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/providers/gathering/ProviderValueGatherer.java
+++ b/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/providers/gathering/ProviderValueGatherer.java
@@ -51,6 +51,7 @@ public class ProviderValueGatherer {
private DoubleAndPercentageProviderValueGatherer doubleAndPercentageGatherer;
private StringProviderValueGatherer stringGatherer;
private TableProviderValueGatherer tableGatherer;
+ private GroupProviderValueGatherer groupGatherer;
public ProviderValueGatherer(
@@ -83,6 +84,9 @@ public class ProviderValueGatherer {
tableGatherer = new TableProviderValueGatherer(
pluginName, extension, serverUUID, database, dataProviders
);
+ groupGatherer = new GroupProviderValueGatherer(
+ pluginName, extension, serverUUID, database, dataProviders
+ );
}
public void disableMethodFromUse(MethodWrapper method) {
@@ -129,6 +133,7 @@ public class ProviderValueGatherer {
doubleAndPercentageGatherer.gatherDoubleDataOfPlayer(playerUUID, playerName, conditions);
stringGatherer.gatherStringDataOfPlayer(playerUUID, playerName, conditions);
tableGatherer.gatherTableDataOfPlayer(playerUUID, playerName, conditions);
+ groupGatherer.gatherGroupDataOfPlayer(playerUUID, playerName, conditions);
}
public void updateValues() {
diff --git a/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/storage/transactions/providers/StoreGroupProviderTransaction.java b/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/storage/transactions/providers/StoreGroupProviderTransaction.java
new file mode 100644
index 000000000..9def72001
--- /dev/null
+++ b/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/storage/transactions/providers/StoreGroupProviderTransaction.java
@@ -0,0 +1,127 @@
+/*
+ * 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 .
+ */
+package com.djrapitops.plan.extension.implementation.storage.transactions.providers;
+
+import com.djrapitops.plan.db.access.ExecStatement;
+import com.djrapitops.plan.db.access.Executable;
+import com.djrapitops.plan.db.access.transactions.Transaction;
+import com.djrapitops.plan.db.sql.tables.ExtensionIconTable;
+import com.djrapitops.plan.db.sql.tables.ExtensionPluginTable;
+import com.djrapitops.plan.db.sql.tables.ExtensionTabTable;
+import com.djrapitops.plan.extension.Group;
+import com.djrapitops.plan.extension.implementation.ProviderInformation;
+import com.djrapitops.plan.extension.implementation.providers.DataProvider;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Optional;
+import java.util.UUID;
+
+import static com.djrapitops.plan.db.sql.parsing.Sql.AND;
+import static com.djrapitops.plan.db.sql.parsing.Sql.WHERE;
+import static com.djrapitops.plan.db.sql.tables.ExtensionProviderTable.*;
+
+/**
+ * Transaction to store information about a {@link com.djrapitops.plan.extension.implementation.providers.GroupDataProvider}.
+ *
+ * @author Rsl1122
+ */
+public class StoreGroupProviderTransaction extends Transaction {
+
+ private final UUID serverUUID;
+ private ProviderInformation providerInformation;
+
+ public StoreGroupProviderTransaction(DataProvider provider, UUID serverUUID) {
+ this.serverUUID = serverUUID;
+ providerInformation = provider.getProviderInformation();
+ }
+
+ @Override
+ protected void performOperations() {
+ execute(storeProvider());
+ }
+
+ private Executable storeProvider() {
+ return connection -> {
+ if (!updateProvider().execute(connection)) {
+ return insertProvider().execute(connection);
+ }
+ return false;
+ };
+ }
+
+ private Executable updateProvider() {
+ String sql = "UPDATE " + TABLE_NAME +
+ " SET " +
+ TEXT + "=?," +
+ CONDITION + "=?," +
+ TAB_ID + "=" + ExtensionTabTable.STATEMENT_SELECT_TAB_ID + "," +
+ ICON_ID + "=" + ExtensionIconTable.STATEMENT_SELECT_ICON_ID +
+ WHERE + PLUGIN_ID + "=" + ExtensionPluginTable.STATEMENT_SELECT_PLUGIN_ID +
+ AND + PROVIDER_NAME + "=?";
+
+ return new ExecStatement(sql) {
+ @Override
+ public void prepare(PreparedStatement statement) throws SQLException {
+ statement.setString(1, providerInformation.getText());
+ Optional condition = providerInformation.getCondition();
+ if (condition.isPresent()) {
+ statement.setString(2, condition.get());
+ } else {
+ statement.setNull(2, Types.VARCHAR);
+ }
+ ExtensionTabTable.set3TabValuesToStatement(statement, 3, providerInformation.getTab().orElse("No Tab"), providerInformation.getPluginName(), serverUUID);
+ ExtensionIconTable.set3IconValuesToStatement(statement, 6, providerInformation.getIcon());
+ ExtensionPluginTable.set2PluginValuesToStatement(statement, 9, providerInformation.getPluginName(), serverUUID);
+ statement.setString(11, providerInformation.getName());
+ }
+ };
+ }
+
+ private Executable insertProvider() {
+ String sql = "INSERT INTO " + TABLE_NAME + "(" +
+ PROVIDER_NAME + "," +
+ TEXT + "," +
+ CONDITION + "," +
+ SHOW_IN_PLAYERS_TABLE + "," +
+ TAB_ID + "," +
+ ICON_ID + "," +
+ PLUGIN_ID +
+ ") VALUES (?,?,?,?," +
+ ExtensionTabTable.STATEMENT_SELECT_TAB_ID + "," +
+ ExtensionIconTable.STATEMENT_SELECT_ICON_ID + "," +
+ ExtensionPluginTable.STATEMENT_SELECT_PLUGIN_ID + ")";
+ return new ExecStatement(sql) {
+ @Override
+ public void prepare(PreparedStatement statement) throws SQLException {
+ statement.setString(1, providerInformation.getName());
+ statement.setString(2, providerInformation.getText());
+ Optional condition = providerInformation.getCondition();
+ if (condition.isPresent()) {
+ statement.setString(3, condition.get());
+ } else {
+ statement.setNull(3, Types.VARCHAR);
+ }
+ statement.setBoolean(4, providerInformation.isShownInPlayersTable());
+ 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);
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/storage/transactions/results/RemoveUnsatisfiedConditionalPlayerResultsTransaction.java b/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/storage/transactions/results/RemoveUnsatisfiedConditionalPlayerResultsTransaction.java
index d223917db..141f1dafe 100644
--- a/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/storage/transactions/results/RemoveUnsatisfiedConditionalPlayerResultsTransaction.java
+++ b/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/storage/transactions/results/RemoveUnsatisfiedConditionalPlayerResultsTransaction.java
@@ -45,14 +45,12 @@ public class RemoveUnsatisfiedConditionalPlayerResultsTransaction extends Transa
private final String playerTableValueTable;
private final String tableTable;
private final String groupTable;
- private final String playerGroupTable;
public RemoveUnsatisfiedConditionalPlayerResultsTransaction() {
providerTable = ExtensionProviderTable.TABLE_NAME;
playerValueTable = ExtensionPlayerValueTable.TABLE_NAME;
tableTable = ExtensionTableProviderTable.TABLE_NAME;
groupTable = ExtensionGroupsTable.TABLE_NAME;
- playerGroupTable = ExtensionPlayerGroupsTable.TABLE_NAME;
playerTableValueTable = ExtensionPlayerTableValueTable.TABLE_NAME;
}
@@ -162,13 +160,12 @@ public class RemoveUnsatisfiedConditionalPlayerResultsTransaction extends Transa
// -
// Conditions are in plan_extensions_providers
// selectSatisfiedConditions lists 'provided_condition' Strings
- String selectUnsatisfiedIDs = SELECT + playerGroupTable + '.' + ID +
- FROM + playerGroupTable +
- INNER_JOIN + groupTable + " on " + groupTable + '.' + ID + '=' + playerGroupTable + '.' + ExtensionPlayerGroupsTable.GROUP_ID +
+ String selectUnsatisfiedIDs = SELECT + groupTable + '.' + ID +
+ FROM + groupTable +
INNER_JOIN + providerTable + " on " + providerTable + '.' + ID + '=' + groupTable + '.' + ExtensionGroupsTable.PROVIDER_ID +
LEFT_JOIN + selectSatisfiedConditions + // Left join to preserve values that don't have their condition fulfilled
" on (" + // Join when uuid and plugin_id match and condition for the group provider is satisfied
- playerGroupTable + '.' + P_UUID +
+ groupTable + '.' + P_UUID +
"=q1." + P_UUID +
AND + ExtensionProviderTable.CONDITION +
"=q1." + ExtensionProviderTable.PROVIDED_CONDITION +
@@ -181,7 +178,7 @@ public class RemoveUnsatisfiedConditionalPlayerResultsTransaction extends Transa
// Nested query here is required because MySQL limits update statements with nested queries:
// The nested query creates a temporary table that bypasses the same table query-update limit.
// Note: MySQL versions 5.6.7+ might optimize this nested query away leading to an exception.
- String deleteValuesSQL = "DELETE FROM " + playerGroupTable +
+ String deleteValuesSQL = "DELETE FROM " + groupTable +
WHERE + ID + " IN (" + SELECT + ID + FROM + '(' + selectUnsatisfiedIDs + ") as ids)";
return new ExecStatement(deleteValuesSQL) {
diff --git a/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/storage/transactions/results/StorePlayerGroupsResultTransaction.java b/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/storage/transactions/results/StorePlayerGroupsResultTransaction.java
new file mode 100644
index 000000000..9f47b4d8b
--- /dev/null
+++ b/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/storage/transactions/results/StorePlayerGroupsResultTransaction.java
@@ -0,0 +1,94 @@
+/*
+ * 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 .
+ */
+package com.djrapitops.plan.extension.implementation.storage.transactions.results;
+
+import com.djrapitops.plan.db.access.ExecStatement;
+import com.djrapitops.plan.db.access.Executable;
+import com.djrapitops.plan.db.access.transactions.Transaction;
+import com.djrapitops.plan.db.sql.tables.ExtensionGroupsTable;
+import com.djrapitops.plan.db.sql.tables.ExtensionProviderTable;
+import com.djrapitops.plan.extension.Group;
+import org.apache.commons.lang3.StringUtils;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.UUID;
+
+import static com.djrapitops.plan.db.sql.parsing.Sql.AND;
+import static com.djrapitops.plan.db.sql.parsing.Sql.WHERE;
+
+/**
+ * Transaction to store method result of a {@link com.djrapitops.plan.extension.implementation.providers.GroupDataProvider}.
+ *
+ * @author Rsl1122
+ */
+public class StorePlayerGroupsResultTransaction extends Transaction {
+
+ private final String pluginName;
+ private final UUID serverUUID;
+ private final String providerName;
+ private final UUID playerUUID;
+
+ private final Group[] value;
+
+ public StorePlayerGroupsResultTransaction(String pluginName, UUID serverUUID, String providerName, UUID playerUUID, Group[] value) {
+ this.pluginName = pluginName;
+ this.serverUUID = serverUUID;
+ this.providerName = providerName;
+ this.playerUUID = playerUUID;
+ this.value = value;
+ }
+
+ @Override
+ protected void performOperations() {
+ execute(deleteOldValues());
+ for (Group group : value) {
+ String groupName = StringUtils.truncate(group.getGroupName(), 50);
+ execute(insertGroup(groupName));
+ }
+ }
+
+ private Executable deleteOldValues() {
+ String sql = "DELETE FROM " + ExtensionGroupsTable.TABLE_NAME +
+ WHERE + ExtensionGroupsTable.USER_UUID + "=?" +
+ AND + ExtensionGroupsTable.PROVIDER_ID + "=" + ExtensionProviderTable.STATEMENT_SELECT_PROVIDER_ID;
+
+ return new ExecStatement(sql) {
+ @Override
+ public void prepare(PreparedStatement statement) throws SQLException {
+ statement.setString(1, playerUUID.toString());
+ ExtensionProviderTable.set3PluginValuesToStatement(statement, 2, providerName, pluginName, serverUUID);
+ }
+ };
+ }
+
+ private Executable insertGroup(String group) {
+ String sql = "INSERT INTO " + ExtensionGroupsTable.TABLE_NAME + "(" +
+ ExtensionGroupsTable.GROUP_NAME + "," +
+ ExtensionGroupsTable.USER_UUID + "," +
+ ExtensionGroupsTable.PROVIDER_ID +
+ ") VALUES (?,?," + ExtensionProviderTable.STATEMENT_SELECT_PROVIDER_ID + ")";
+ return new ExecStatement(sql) {
+ @Override
+ public void prepare(PreparedStatement statement) throws SQLException {
+ statement.setString(1, group);
+ statement.setString(2, playerUUID.toString());
+ ExtensionProviderTable.set3PluginValuesToStatement(statement, 3, providerName, pluginName, serverUUID);
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/Plan/common/src/test/java/com/djrapitops/plan/db/DatabaseTest.java b/Plan/common/src/test/java/com/djrapitops/plan/db/DatabaseTest.java
index 428b28942..b99815cae 100644
--- a/Plan/common/src/test/java/com/djrapitops/plan/db/DatabaseTest.java
+++ b/Plan/common/src/test/java/com/djrapitops/plan/db/DatabaseTest.java
@@ -1238,6 +1238,7 @@ public interface DatabaseTest {
OptionalAssert.equals("0.5", tabData.getDouble("doubleVal_total").map(data -> data.getFormattedValue(Objects::toString)));
OptionalAssert.equals("5", tabData.getNumber("value_avg").map(data -> data.getFormattedValue(Objects::toString)));
OptionalAssert.equals("5", tabData.getNumber("value_total").map(data -> data.getFormattedValue(Objects::toString)));
+ // TODO Add test that group exists
}
@Test
@@ -1527,6 +1528,11 @@ public interface DatabaseTest {
public String stringVal(UUID playerUUID) {
return "Something";
}
+
+ @GroupProvider(text = "a group")
+ public Group[] group(UUID playerUUID) {
+ return new Group[]{() -> "group"};
+ }
}
@PluginInfo(name = "TableExtension")