Skip to content

Commit 6b0bdd1

Browse files
committed
Added more filters to Query and fixed bugs
- Added 'Played on date' filter - Added 'Activity group on date' filter - Added 'Last seen between' filter - Added 'After' and 'Before' variants to all between filters where either date can be disabled via checkbox - Fixed 'View full query' button - Fixed Server calendar 'Click to see' showing players who played on other servers that day
1 parent cbf3973 commit 6b0bdd1

30 files changed

Lines changed: 624 additions & 114 deletions

Plan/common/src/main/java/com/djrapitops/plan/modules/FiltersModule.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public interface FiltersModule {
4343

4444
@Binds
4545
@IntoSet
46-
Filter filter5(ActivityIndexFilter filter);
46+
Filter filter5(ActivityIndexNowFilter filter);
4747

4848
@Binds
4949
@IntoSet
@@ -61,4 +61,16 @@ public interface FiltersModule {
6161
@IntoSet
6262
Filter filter9(PlayedOnServerFilter filter);
6363

64+
@Binds
65+
@IntoSet
66+
Filter filter10(PlayedOnDateFilter filter);
67+
68+
@Binds
69+
@IntoSet
70+
Filter filter11(ActivityIndexOnDateFilter filter);
71+
72+
@Binds
73+
@IntoSet
74+
Filter filter12(LastSeenBetweenDateRangeFilter filter);
75+
6476
}

Plan/common/src/main/java/com/djrapitops/plan/settings/locale/lang/HtmlLang.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,13 +536,23 @@ public enum HtmlLang implements Lang {
536536
LABEL_DAY_OF_WEEK("html.label.dayOfweek", "Day of the Week"),
537537
LABEL_WEEK_DAYS("html.label.weekdays", "'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'"),
538538
QUERY_ARE_ACTIVITY_GROUP("html.query.filter.activity.text", "are in Activity Groups"),
539+
QUERY_ON_DATE("html.query.filter.onDate", "on"),
540+
QUERY_ON_SERVER("html.query.filter.onDate", "on server(s)"),
541+
QUERY_ANY_SERVER("html.query.filter.anyServer", "any server"),
539542
QUERY_JOINED_WITH_ADDRESS("html.query.filter.joinAddress.text", "joined with address"),
540543
QUERY_JOINED_FROM_COUNTRY("html.query.filter.country.text", "have joined from country"),
541544
QUERY_ARE_PLUGIN_GROUP("html.query.filter.pluginGroup.text", "are in {{plugin}}'s {{group}} Groups"),
542545
QUERY_OF_PLAYERS("html.query.filter.generic.start", "of Players who "),
543546
QUERY_AND("html.query.filter.generic.and", "and "),
544547
QUERY_PLAYED_BETWEEN("html.query.filter.playedBetween.text", "Played between"),
548+
QUERY_PLAYED_BEFORE("html.query.filter.playedBefore.text", "Played before"),
549+
QUERY_PLAYED_AFTER("html.query.filter.playedAfter.text", "Played after"),
545550
QUERY_REGISTERED_BETWEEN("html.query.filter.registeredBetween.text", "Registered between"),
551+
QUERY_REGISTERED_BEFORE("html.query.filter.registeredBefore.text", "Registered before"),
552+
QUERY_REGISTERED_AFTER("html.query.filter.registeredAfter.text", "Registered after"),
553+
QUERY_LAST_SEEN_BETWEEN("html.query.filter.lastSeenBetween.text", "Last seen between"),
554+
QUERY_LAST_SEEN_BEFORE("html.query.filter.lastSeenBefore.text", "Last seen before"),
555+
QUERY_LAST_SEEN_AFTER("html.query.filter.lastSeenAfter.text", "Last seen after"),
546556
QUERY_ZERO_RESULTS("html.query.results.none", "Query produced 0 results"),
547557
QUERY_RESULTS("html.query.results.title", "Query Results"),
548558
QUERY_RESULTS_MATCH("html.query.results.match", "matched {{resultCount}} players"),
@@ -559,6 +569,8 @@ public enum HtmlLang implements Lang {
559569
FILTER_GROUP("html.query.filter.pluginGroup.name", "Group: "),
560570
FILTER_ALL_PLAYERS("html.query.filter.generic.allPlayers", "All players"),
561571
FILTER_ACTIVITY_INDEX_NOW("html.query.filter.title.activityGroup", "Current activity group"),
572+
FILTER_ACTIVITY_INDEX_ON_DATE("html.query.filter.title.activityGroupOnDate", "Activity group on date"),
573+
FILTER_PLAYED_ON_DATE("html.query.filter.hasPlayedOnDate.name", "Has played on date"),
562574
FILTER_BANNED("html.query.filter.banStatus.name", "Ban status"),
563575
FILTER_OPS("html.query.filter.operatorStatus.name", "Operator status");
564576

Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/Filter.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ public interface Filter {
3030

3131
String getKind();
3232

33+
/**
34+
* List of expected parameters that is given to frontend, but not necessarily enforced on a per-filter basis.
35+
*
36+
* @return Names of the parameters inside options.
37+
*/
3338
String[] getExpectedParameters();
3439

3540
default Map<String, Object> getOptions() {
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* This file is part of Player Analytics (Plan).
3+
*
4+
* Plan is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU Lesser General Public License v3 as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* Plan is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU Lesser General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Lesser General Public License
15+
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
16+
*/
17+
package com.djrapitops.plan.storage.database.queries.filter.filters;
18+
19+
import com.djrapitops.plan.delivery.domain.datatransfer.InputFilterDto;
20+
import com.djrapitops.plan.settings.config.PlanConfig;
21+
import com.djrapitops.plan.storage.database.DBSystem;
22+
23+
import javax.inject.Inject;
24+
import javax.inject.Singleton;
25+
import java.util.Collections;
26+
import java.util.Map;
27+
28+
/**
29+
* Filter for current activity index group.
30+
*/
31+
@Singleton
32+
public class ActivityIndexNowFilter extends ActivityIndexOnDateFilter {
33+
34+
@Inject
35+
public ActivityIndexNowFilter(PlanConfig config, DBSystem dbSystem) {
36+
super(config, dbSystem);
37+
}
38+
39+
@Override
40+
public String getKind() {
41+
return "activityIndexNow";
42+
}
43+
44+
@Override
45+
public Map<String, Object> getOptions() {
46+
return Collections.singletonMap("options", getOptionsArray());
47+
}
48+
49+
@Override
50+
protected long getDate(InputFilterDto query) {
51+
return System.currentTimeMillis();
52+
}
53+
}

Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/ActivityIndexFilter.java renamed to Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/ActivityIndexOnDateFilter.java

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,39 +27,53 @@
2727

2828
import javax.inject.Inject;
2929
import javax.inject.Singleton;
30-
import java.util.Collections;
3130
import java.util.List;
3231
import java.util.Map;
3332
import java.util.Set;
3433
import java.util.stream.Collectors;
3534

35+
/**
36+
* Filter for activity index group at a specific time.
37+
*/
3638
@Singleton
37-
public class ActivityIndexFilter extends MultiOptionFilter {
39+
public class ActivityIndexOnDateFilter implements MultiOptionFilter {
3840

39-
private final PlanConfig config;
40-
private final DBSystem dbSystem;
41+
protected final PlanConfig config;
42+
protected final DBSystem dbSystem;
4143

4244
@Inject
43-
public ActivityIndexFilter(
44-
PlanConfig config,
45-
DBSystem dbSystem
46-
) {
45+
public ActivityIndexOnDateFilter(PlanConfig config, DBSystem dbSystem) {
4746
this.dbSystem = dbSystem;
4847
this.config = config;
4948
}
5049

50+
protected long getDate(@Untrusted InputFilterDto query) {
51+
return DateRangeFilter.getTime(query, "date", "time", getKind());
52+
}
53+
54+
@Override
55+
public String[] getExpectedParameters() {
56+
return new String[]{
57+
SELECTED,
58+
"date",
59+
"time"
60+
};
61+
}
62+
5163
@Override
5264
public String getKind() {
53-
return "activityIndexNow";
65+
return "activityIndexOn";
5466
}
5567

56-
private String[] getOptionsArray() {
68+
protected String[] getOptionsArray() {
5769
return ActivityIndex.getGroupLocaleKeys();
5870
}
5971

6072
@Override
6173
public Map<String, Object> getOptions() {
62-
return Collections.singletonMap("options", getOptionsArray());
74+
Map<String, Object> options = DateRangeFilter.getOptions(dbSystem.getDatabase());
75+
options.put("options", getOptionsArray());
76+
return options;
6377
}
6478

6579
@Override
@@ -76,7 +90,7 @@ public Set<Integer> getMatchingUserIds(@Untrusted InputFilterDto query) {
7690
if (includeVeryActive && includeActive && includeRegular && includeIrregular && includeInactive) {
7791
throw new CompleteSetException(); // Full set, no need for query
7892
}
79-
long date = System.currentTimeMillis();
93+
long date = getDate(query);
8094
long playtimeThreshold = config.get(TimeSettings.ACTIVE_PLAY_THRESHOLD);
8195
Map<Integer, ActivityIndex> indexes = dbSystem.getDatabase().query(NetworkActivityIndexQueries.activityIndexForAllPlayers(date, playtimeThreshold));
8296

Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/BannedFilter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
import java.util.*;
2929

3030
@Singleton
31-
public class BannedFilter extends MultiOptionFilter {
31+
public class BannedFilter implements MultiOptionFilter {
3232

3333
private final DBSystem dbSystem;
3434

Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/DateRangeFilter.java

Lines changed: 44 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.djrapitops.plan.delivery.domain.datatransfer.InputFilterDto;
2020
import com.djrapitops.plan.delivery.web.resolver.exception.BadRequestException;
2121
import com.djrapitops.plan.storage.database.DBSystem;
22+
import com.djrapitops.plan.storage.database.Database;
2223
import com.djrapitops.plan.storage.database.queries.filter.Filter;
2324
import com.djrapitops.plan.storage.database.queries.objects.BaseUserQueries;
2425
import com.djrapitops.plan.utilities.dev.Untrusted;
@@ -32,52 +33,69 @@
3233

3334
public abstract class DateRangeFilter implements Filter {
3435

36+
public static final String AFTER_DATE = "afterDate";
37+
public static final String AFTER_TIME = "afterTime";
38+
public static final String BEFORE_DATE = "beforeDate";
39+
public static final String BEFORE_TIME = "beforeTime";
40+
41+
private static final String DATE_FORMAT = "dd/MM/yyyy kk:mm";
42+
3543
private final DBSystem dbSystem;
36-
private final SimpleDateFormat dateFormat;
3744

3845
protected DateRangeFilter(DBSystem dbSystem) {
3946
this.dbSystem = dbSystem;
40-
this.dateFormat = new SimpleDateFormat("dd/MM/yyyy kk:mm");
4147
}
4248

43-
@Override
44-
public String[] getExpectedParameters() {
45-
return new String[]{
46-
"afterDate",
47-
"afterTime",
48-
"beforeDate",
49-
"beforeTime"
50-
};
49+
public static long getTime(@Untrusted InputFilterDto query, String dateKey, String timeKey, String kind) {
50+
@Untrusted String date = query.get(dateKey).orElseThrow(() -> new BadRequestException("'" + dateKey + "' not specified in parameters for " + kind));
51+
@Untrusted String time = query.get(timeKey).orElseThrow(() -> new BadRequestException("'" + timeKey + "' not specified in parameters for " + kind));
52+
53+
try {
54+
return new SimpleDateFormat(DATE_FORMAT).parse(date + ' ' + time).getTime();
55+
} catch (@Untrusted ParseException e) {
56+
throw new IllegalArgumentException("Could not parse date from given '" + dateKey + "' and '" + timeKey + "' - expected format dd/MM/yyyy and kk:mm");
57+
}
5158
}
5259

53-
@Override
54-
public Map<String, Object> getOptions() {
55-
Optional<Long> earliestData = dbSystem.getDatabase().query(BaseUserQueries.minimumRegisterDate());
60+
public static Map<String, Object> getOptions(Database database) {
61+
Optional<Long> earliestData = database.query(BaseUserQueries.minimumRegisterDate());
5662
long now = System.currentTimeMillis();
57-
String[] afterDate = StringUtils.split(dateFormat.format(earliestData.orElse(now)), ' ');
58-
String[] beforeDate = StringUtils.split(dateFormat.format(now), ' ');
63+
SimpleDateFormat formatter = new SimpleDateFormat(DATE_FORMAT);
64+
String[] afterDate = StringUtils.split(formatter.format(earliestData.orElse(now)), ' ');
65+
String[] beforeDate = StringUtils.split(formatter.format(now), ' ');
5966
return Maps.builder(String.class, Object.class)
6067
.put("after", afterDate)
6168
.put("before", beforeDate)
6269
.build();
6370
}
6471

65-
protected long getAfter(@Untrusted InputFilterDto query) {
66-
return getTime(query, "afterDate", "afterTime");
72+
@Override
73+
public String[] getExpectedParameters() {
74+
return new String[]{
75+
AFTER_DATE,
76+
AFTER_TIME,
77+
BEFORE_DATE,
78+
BEFORE_TIME
79+
};
6780
}
6881

69-
protected long getBefore(@Untrusted InputFilterDto query) {
70-
return getTime(query, "beforeDate", "beforeTime");
82+
@Override
83+
public Map<String, Object> getOptions() {
84+
Database database = dbSystem.getDatabase();
85+
return getOptions(database);
7186
}
7287

73-
private long getTime(@Untrusted InputFilterDto query, String dateKey, String timeKey) {
74-
@Untrusted String date = query.get(dateKey).orElseThrow(() -> new BadRequestException("'" + dateKey + "' not specified in parameters for " + getKind()));
75-
@Untrusted String time = query.get(timeKey).orElseThrow(() -> new BadRequestException("'" + timeKey + "' not specified in parameters for " + getKind()));
88+
protected long getAfter(@Untrusted InputFilterDto query) {
89+
if (query.get(AFTER_DATE).isEmpty() || query.get(AFTER_TIME).isEmpty()) {
90+
return 0L;
91+
}
92+
return getTime(query, AFTER_DATE, AFTER_TIME, getKind());
93+
}
7694

77-
try {
78-
return dateFormat.parse(date + ' ' + time).getTime();
79-
} catch (@Untrusted ParseException e) {
80-
throw new IllegalArgumentException("Could not parse date from given '" + dateKey + "' and '" + timeKey + "' - expected format dd/MM/yyyy and kk:mm");
95+
protected long getBefore(@Untrusted InputFilterDto query) {
96+
if (query.get(BEFORE_DATE).isEmpty() || query.get(BEFORE_TIME).isEmpty()) {
97+
return Long.MAX_VALUE;
8198
}
99+
return getTime(query, BEFORE_DATE, BEFORE_TIME, getKind());
82100
}
83101
}

Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/GeolocationsFilter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
import java.util.stream.Collectors;
3232

3333
@Singleton
34-
public class GeolocationsFilter extends MultiOptionFilter {
34+
public class GeolocationsFilter implements MultiOptionFilter {
3535

3636
private final DBSystem dbSystem;
3737
private final SpecialGraphFactory specialGraphFactory;

Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/JoinAddressFilter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
import java.util.Set;
3030

3131
@Singleton
32-
public class JoinAddressFilter extends MultiOptionFilter {
32+
public class JoinAddressFilter implements MultiOptionFilter {
3333

3434
private final DBSystem dbSystem;
3535

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* This file is part of Player Analytics (Plan).
3+
*
4+
* Plan is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU Lesser General Public License v3 as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* Plan is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU Lesser General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Lesser General Public License
15+
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
16+
*/
17+
package com.djrapitops.plan.storage.database.queries.filter.filters;
18+
19+
import com.djrapitops.plan.delivery.domain.datatransfer.InputFilterDto;
20+
import com.djrapitops.plan.identification.ServerUUID;
21+
import com.djrapitops.plan.storage.database.DBSystem;
22+
import com.djrapitops.plan.storage.database.queries.objects.ServerQueries;
23+
import com.djrapitops.plan.storage.database.queries.objects.SessionQueries;
24+
import com.djrapitops.plan.utilities.dev.Untrusted;
25+
import com.google.gson.Gson;
26+
27+
import javax.inject.Inject;
28+
import javax.inject.Singleton;
29+
import java.util.Arrays;
30+
import java.util.Collections;
31+
import java.util.List;
32+
import java.util.Set;
33+
34+
@Singleton
35+
public class LastSeenBetweenDateRangeFilter extends DateRangeFilter {
36+
37+
private final DBSystem dbSystem;
38+
39+
@Inject
40+
public LastSeenBetweenDateRangeFilter(DBSystem dbSystem) {
41+
super(dbSystem);
42+
this.dbSystem = dbSystem;
43+
}
44+
45+
@Override
46+
public String getKind() {
47+
return "lastSeenBetween";
48+
}
49+
50+
@Override
51+
public Set<Integer> getMatchingUserIds(@Untrusted InputFilterDto query) {
52+
long after = getAfter(query);
53+
long before = getBefore(query);
54+
@Untrusted List<String> serverNames = getServerNames(query);
55+
List<ServerUUID> serverUUIDs = serverNames.isEmpty() ? Collections.emptyList() : dbSystem.getDatabase().query(ServerQueries.fetchServersMatchingIdentifiers(serverNames));
56+
return dbSystem.getDatabase().query(SessionQueries.userIdsOfLastSeenBetween(after, before, serverUUIDs));
57+
}
58+
59+
private List<String> getServerNames(InputFilterDto query) {
60+
return query.get("servers")
61+
.map(serversList -> new Gson().fromJson(serversList, String[].class))
62+
.map(Arrays::asList)
63+
.orElseGet(Collections::emptyList);
64+
}
65+
}

0 commit comments

Comments
 (0)