mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2024-12-21 05:50:18 +08:00
Added a Join Address filter to query page
This commit is contained in:
parent
9ee2a15008
commit
8624d86793
@ -45,4 +45,8 @@ public interface FiltersModule {
|
||||
@IntoSet
|
||||
Filter filter5(ActivityIndexFilter filter);
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
Filter filter6(JoinAddressFilter filter);
|
||||
|
||||
}
|
||||
|
@ -190,7 +190,8 @@ public class Locale extends HashMap<Lang, Message> {
|
||||
HtmlLang.LABEL_AVG_AFK_TIME,
|
||||
HtmlLang.LABEL_AVG_PLAYTIME,
|
||||
HtmlLang.SIDE_GEOLOCATIONS,
|
||||
HtmlLang.LABEL_PER_PLAYER
|
||||
HtmlLang.LABEL_PER_PLAYER,
|
||||
HtmlLang.TITLE_JOIN_ADDRESSES
|
||||
|
||||
}) {
|
||||
getNonDefault(extra).ifPresent(replacement ->
|
||||
|
@ -41,6 +41,7 @@ public enum JSLang implements Lang {
|
||||
LABEL_WEEK_DAYS("'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'"),
|
||||
|
||||
QUERY_ARE_ACTIVITY_GROUP("are in Activity Groups"),
|
||||
QUERY_JOINED_WITH_ADDRESS("joined with address"),
|
||||
QUERY_ARE_PLUGIN_GROUP("are in ${plugin}'s ${group} Groups"),
|
||||
QUERY_OF_PLAYERS("of Players who "),
|
||||
QUERY_AND("and "),
|
||||
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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.filter.filters;
|
||||
|
||||
import com.djrapitops.plan.storage.database.DBSystem;
|
||||
import com.djrapitops.plan.storage.database.queries.filter.SpecifiedFilterInformation;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.UserInfoQueries;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.*;
|
||||
|
||||
@Singleton
|
||||
public class JoinAddressFilter extends MultiOptionFilter {
|
||||
|
||||
private final DBSystem dbSystem;
|
||||
|
||||
@Inject
|
||||
public JoinAddressFilter(DBSystem dbSystem) {this.dbSystem = dbSystem;}
|
||||
|
||||
@Override
|
||||
public String getKind() {
|
||||
return "joinAddresses";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getOptions() {
|
||||
return Collections.singletonMap("options", getSelectionOptions());
|
||||
}
|
||||
|
||||
private List<String> getSelectionOptions() {
|
||||
return dbSystem.getDatabase().query(UserInfoQueries.uniqueJoinAddresses());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> getMatchingUUIDs(SpecifiedFilterInformation query) {
|
||||
return dbSystem.getDatabase().query(UserInfoQueries.uuidsOfPlayersWithJoinAddresses(getSelected(query)));
|
||||
}
|
||||
}
|
@ -23,6 +23,7 @@ import com.djrapitops.plan.storage.database.queries.QueryAllStatement;
|
||||
import com.djrapitops.plan.storage.database.queries.QueryStatement;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.UserInfoTable;
|
||||
import com.djrapitops.plan.utilities.java.Lists;
|
||||
import org.apache.commons.text.TextStringBuilder;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
@ -251,6 +252,25 @@ public class UserInfoQueries {
|
||||
};
|
||||
}
|
||||
|
||||
public static Query<List<String>> uniqueJoinAddresses() {
|
||||
String sql = SELECT + DISTINCT + "LOWER(COALESCE(" + UserInfoTable.JOIN_ADDRESS + ", ?)) as address" +
|
||||
FROM + UserInfoTable.TABLE_NAME +
|
||||
ORDER_BY + UserInfoTable.JOIN_ADDRESS + " DESC";
|
||||
return new QueryStatement<List<String>>(sql, 100) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, "unknown");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> processResults(ResultSet set) throws SQLException {
|
||||
List<String> joinAddresses = new ArrayList<>();
|
||||
while (set.next()) joinAddresses.add(set.getString("address"));
|
||||
return joinAddresses;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Query<Set<UUID>> uuidsOfOperators() {
|
||||
return getUUIDsForBooleanGroup(UserInfoTable.OP, true);
|
||||
}
|
||||
@ -266,15 +286,19 @@ public class UserInfoQueries {
|
||||
|
||||
@Override
|
||||
public Set<UUID> processResults(ResultSet set) throws SQLException {
|
||||
Set<UUID> uuids = new HashSet<>();
|
||||
while (set.next()) {
|
||||
uuids.add(UUID.fromString(set.getString(UserInfoTable.USER_UUID)));
|
||||
}
|
||||
return uuids;
|
||||
return extractUUIDs(set);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Set<UUID> extractUUIDs(ResultSet set) throws SQLException {
|
||||
Set<UUID> uuids = new HashSet<>();
|
||||
while (set.next()) {
|
||||
uuids.add(UUID.fromString(set.getString(UserInfoTable.USER_UUID)));
|
||||
}
|
||||
return uuids;
|
||||
}
|
||||
|
||||
public static Query<Set<UUID>> uuidsOfNonOperators() {
|
||||
return getUUIDsForBooleanGroup(UserInfoTable.OP, false);
|
||||
}
|
||||
@ -286,4 +310,32 @@ public class UserInfoQueries {
|
||||
public static Query<Set<UUID>> uuidsOfNotBanned() {
|
||||
return getUUIDsForBooleanGroup(UserInfoTable.BANNED, false);
|
||||
}
|
||||
|
||||
public static Query<Set<UUID>> uuidsOfPlayersWithJoinAddresses(List<String> joinAddresses) {
|
||||
String selectLowercaseJoinAddresses = SELECT +
|
||||
UserInfoTable.USER_UUID + ',' +
|
||||
"LOWER(COALESCE(" + UserInfoTable.JOIN_ADDRESS + ", ?)) as address" +
|
||||
FROM + UserInfoTable.TABLE_NAME;
|
||||
String sql = SELECT + DISTINCT + UserInfoTable.USER_UUID +
|
||||
FROM + '(' + selectLowercaseJoinAddresses + ") q1" +
|
||||
WHERE + "address IN (" +
|
||||
new TextStringBuilder().appendWithSeparators(joinAddresses.stream().map(item -> '?').iterator(), ",") +
|
||||
')'; // Don't append addresses directly, SQL incjection hazard
|
||||
|
||||
return new QueryStatement<Set<UUID>>(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, "unknown");
|
||||
for (int i = 1; i <= joinAddresses.size(); i++) {
|
||||
String address = joinAddresses.get(i - 1);
|
||||
statement.setString(i + 1, address);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> processResults(ResultSet set) throws SQLException {
|
||||
return extractUUIDs(set);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ import com.djrapitops.plan.storage.database.transactions.ExecStatement;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
import static com.djrapitops.plan.storage.database.sql.building.Sql.FROM;
|
||||
|
||||
@ -66,7 +67,7 @@ public class UserInfoHostnameAllowNullPatch extends Patch {
|
||||
) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, null);
|
||||
statement.setNull(1, Types.VARCHAR);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -78,6 +78,14 @@ class OperatorsFilter extends MultipleChoiceFilter {
|
||||
}
|
||||
}
|
||||
|
||||
class JoinAddressFilter extends MultipleChoiceFilter {
|
||||
constructor(
|
||||
id, options
|
||||
) {
|
||||
super(id, "joinAddresses", `joined with address`, options);
|
||||
}
|
||||
}
|
||||
|
||||
class PluginGroupsFilter extends MultipleChoiceFilter {
|
||||
constructor(
|
||||
id, kind, options
|
||||
@ -187,6 +195,8 @@ function createFilter(filter, id) {
|
||||
return new BannedFilter(id, filter.options);
|
||||
case "operators":
|
||||
return new OperatorsFilter(id, filter.options);
|
||||
case "joinAddresses":
|
||||
return new JoinAddressFilter(id, filter.options);
|
||||
case "playedBetween":
|
||||
return new PlayedBetweenFilter(id, filter.options);
|
||||
case "registeredBetween":
|
||||
@ -209,6 +219,8 @@ function getReadableFilterName(filter) {
|
||||
return "Ban status";
|
||||
case "operators":
|
||||
return "Operator status";
|
||||
case "joinAddresses":
|
||||
return "Join Addresses";
|
||||
case "playedBetween":
|
||||
return "Played between";
|
||||
case "registeredBetween":
|
||||
|
@ -309,4 +309,26 @@ public interface UserInfoQueriesTest extends DatabaseTestPreparer {
|
||||
Map<String, Integer> result = db().query(UserInfoQueries.joinAddresses());
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
default void joinAddressFilterUUIDsAreFetched() {
|
||||
joinAddressIsUpdatedUponSecondLogin();
|
||||
|
||||
Set<UUID> expected = Collections.singleton(playerUUID);
|
||||
Set<UUID> result = db().query(UserInfoQueries.uuidsOfPlayersWithJoinAddresses(
|
||||
Collections.singletonList(TestConstants.GET_PLAYER_HOSTNAME.get().toLowerCase()))
|
||||
);
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
default void joinAddressFilterUUIDsAreFetchedWhenUnknown() {
|
||||
joinAddressCanBeNull();
|
||||
|
||||
Set<UUID> expected = Collections.singleton(playerUUID);
|
||||
Set<UUID> result = db().query(UserInfoQueries.uuidsOfPlayersWithJoinAddresses(
|
||||
Collections.singletonList("unknown"))
|
||||
);
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user