Skip to content
This repository was archived by the owner on Dec 1, 2021. It is now read-only.

Commit 1f62ce2

Browse files
authored
Merge pull request #18 from Java-Discord/andrew/moderation_services
Improved Moderation Service
2 parents c0bae6f + 794e7e8 commit 1f62ce2

26 files changed

+1101
-95
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
.idea/
22
.gradle/
33
build/
4-
/javabot_config/
4+
/javabot_config/
5+
/javabot.mv.db
6+
/javabot.trace.db

build.gradle

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,20 @@ targetCompatibility = 16
1111

1212
repositories {
1313
mavenCentral()
14+
maven {
15+
url "https://oss.sonatype.org/content/repositories/snapshots/"
16+
}
1417
}
1518

1619
dependencies {
17-
implementation 'org.javacord:javacord:3.3.2'
20+
implementation 'org.javacord:javacord:3.4.0-SNAPSHOT'
1821

1922
implementation 'org.yaml:snakeyaml:1.29'
2023
implementation 'com.google.code.gson:gson:2.8.9'
2124

2225
// Persistence Dependencies
2326
implementation 'org.mongodb:mongodb-driver:3.12.10'
24-
implementation 'org.postgresql:postgresql:42.3.0'
27+
implementation 'com.h2database:h2:1.4.200'
2528
implementation 'com.zaxxer:HikariCP:5.0.0'
2629

2730
// Lombok annotations

checkstyle/checkstyle.xml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ See https://checkstyle.org/ for more information.
4949
<module name="IllegalToken"/>
5050
<module name="IllegalType"/>
5151
<module name="InnerAssignment"/>
52-
<module name="MagicNumber"/>
5352
<module name="MultipleStringLiterals">
5453
<property name="allowedDuplicates" value="3"/>
5554
</module>
@@ -58,8 +57,8 @@ See https://checkstyle.org/ for more information.
5857
<module name="OneStatementPerLine"/>
5958
<module name="PackageDeclaration"/>
6059
<module name="ReturnCount">
61-
<property name="max" value="5"/>
62-
<property name="maxForVoid" value="8"/>
60+
<property name="max" value="8"/>
61+
<property name="maxForVoid" value="10"/>
6362
</module>
6463
<module name="SimplifyBooleanExpression"/>
6564
<module name="SimplifyBooleanReturn"/>

docker-compose.yaml

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -22,27 +22,3 @@ services:
2222
ME_CONFIG_MONGODB_ADMINUSERNAME: root
2323
ME_CONFIG_MONGODB_ADMINPASSWORD: example
2424
ME_CONFIG_MONGODB_URL: mongodb://root:example@mongo:27017/
25-
# Postgresql Relational Database
26-
postgres:
27-
image: postgres:latest
28-
container_name: javabot_postgres
29-
restart: unless-stopped
30-
environment:
31-
POSTGRES_USER: javabot_dev
32-
POSTGRES_PASSWORD: javabot_dev_pass
33-
POSTGRES_DB: javabot
34-
ports:
35-
- "27172:5432"
36-
37-
# Admin site for postgres. Connect via http://localhost:5051
38-
pgadmin:
39-
image: dpage/pgadmin4
40-
container_name: javabot_pgadmin
41-
environment:
42-
PGADMIN_DEFAULT_EMAIL: pgadmin4@pgadmin.org
43-
PGADMIN_DEFAULT_PASSWORD: admin
44-
PGADMIN_CONFIG_SERVER_MODE: 'False'
45-
depends_on:
46-
- postgres
47-
ports:
48-
- "5051:80"

src/main/java/net/javadiscord/javabot2/Bot.java

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,27 @@
55
import com.mongodb.client.MongoDatabase;
66
import com.mongodb.client.model.IndexOptions;
77
import com.mongodb.client.model.Indexes;
8-
import com.zaxxer.hikari.HikariConfig;
98
import com.zaxxer.hikari.HikariDataSource;
9+
import lombok.extern.slf4j.Slf4j;
1010
import net.javadiscord.javabot2.command.SlashCommandListener;
1111
import net.javadiscord.javabot2.config.BotConfig;
12+
import net.javadiscord.javabot2.db.DbHelper;
13+
import net.javadiscord.javabot2.systems.moderation.ModerationService;
1214
import org.javacord.api.DiscordApi;
1315
import org.javacord.api.DiscordApiBuilder;
1416
import org.javacord.api.entity.intent.Intent;
1517

1618
import java.nio.file.Path;
19+
import java.time.ZoneOffset;
20+
import java.util.TimeZone;
1721
import java.util.concurrent.Executors;
1822
import java.util.concurrent.ScheduledExecutorService;
23+
import java.util.concurrent.TimeUnit;
1924

2025
/**
2126
* The main program entry point.
2227
*/
28+
@Slf4j
2329
public class Bot {
2430
/**
2531
* A connection pool that can be used to obtain new JDBC connections.
@@ -28,12 +34,18 @@ public class Bot {
2834

2935
/**
3036
* A thread-safe MongoDB client that can be used to interact with MongoDB.
37+
* @deprecated Use the relational data source for all future persistence
38+
* needs; it promotes more organized code that's less prone to failures.
3139
*/
40+
@Deprecated
3241
public static MongoClient mongoClient;
3342

3443
/**
3544
* The single Mongo database where all bot data is stored.
45+
* @deprecated Use the relational data source for all future persistence
46+
* needs; it promotes more organized code that's less prone to failures.
3647
*/
48+
@Deprecated
3749
public static MongoDatabase mongoDb;
3850

3951
/**
@@ -54,6 +66,7 @@ private Bot() {}
5466
* @param args Command-line arguments.
5567
*/
5668
public static void main(String[] args) {
69+
TimeZone.setDefault(TimeZone.getTimeZone(ZoneOffset.UTC));
5770
initDataSources();
5871
asyncPool = Executors.newScheduledThreadPool(config.getSystems().getAsyncPoolSize());
5972
DiscordApi api = new DiscordApiBuilder()
@@ -68,6 +81,7 @@ public static void main(String[] args) {
6881
"commands/moderation.yaml"
6982
);
7083
api.addSlashCommandCreateListener(commandListener);
84+
initScheduledTasks(api);
7185
}
7286

7387
/**
@@ -80,14 +94,7 @@ private static void initDataSources() {
8094
if (config.getSystems().getDiscordBotToken() == null || config.getSystems().getDiscordBotToken().isBlank()) {
8195
throw new IllegalStateException("Missing required Discord bot token! Please edit config/systems.json to add it, then run again.");
8296
}
83-
var hikariConfig = new HikariConfig();
84-
var hikariConfigSource = config.getSystems().getHikariConfig();
85-
hikariConfig.setJdbcUrl(hikariConfigSource.getJdbcUrl());
86-
hikariConfig.setUsername(hikariConfigSource.getUsername());
87-
hikariConfig.setPassword(hikariConfigSource.getPassword());
88-
hikariConfig.setMaximumPoolSize(hikariConfigSource.getMaximumPoolSize());
89-
hikariConfig.setConnectionInitSql(hikariConfigSource.getConnectionInitSql());
90-
hikariDataSource = new HikariDataSource(hikariConfig);
97+
hikariDataSource = DbHelper.initDataSource(config);
9198
mongoDb = initMongoDatabase();
9299
}
93100

@@ -99,4 +106,13 @@ private static MongoDatabase initMongoDatabase() {
99106
warnCollection.createIndex(Indexes.descending("createdAt"), new IndexOptions().unique(false));
100107
return db;
101108
}
109+
110+
private static void initScheduledTasks(DiscordApi api) {
111+
// Regularly check for and unmute users whose mutes have expired.
112+
asyncPool.scheduleAtFixedRate(() -> {
113+
for (var server : api.getServers()) {
114+
new ModerationService(api, config.get(server).getModeration()).unmuteExpired();
115+
}
116+
}, 1L, 1L, TimeUnit.MINUTES);
117+
}
102118
}

src/main/java/net/javadiscord/javabot2/command/ResponseException.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,13 @@ public static Supplier<ResponseException> warning(String message) {
4545
public static Supplier<ResponseException> error(String message) {
4646
return () -> new ResponseException(Responses.deferredErrorBuilder().message(message));
4747
}
48+
49+
/**
50+
* Standard helper method to generate a supplier of a response exception
51+
* with a simple "invalid argument" warning message.
52+
* @return The exception supplier.
53+
*/
54+
public static Supplier<ResponseException> invalidArgument() {
55+
return () -> new ResponseException(Responses.deferredWarningBuilder().message("Invalid argument."));
56+
}
4857
}

src/main/java/net/javadiscord/javabot2/command/Responses.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package net.javadiscord.javabot2.command;
22

3-
import org.javacord.api.entity.message.MessageFlag;
43
import org.javacord.api.entity.message.embed.EmbedBuilder;
54
import org.javacord.api.event.interaction.SlashCommandCreateEvent;
65
import org.javacord.api.interaction.InteractionBase;
6+
import org.javacord.api.interaction.callback.InteractionCallbackDataFlag;
77
import org.javacord.api.interaction.callback.InteractionImmediateResponseBuilder;
88
import org.javacord.api.interaction.callback.InteractionOriginalResponseUpdater;
99

@@ -90,7 +90,7 @@ private static InteractionImmediateResponseBuilder reply(
9090
.setTimestampToNow()
9191
.setDescription(message));
9292
if (ephemeral) {
93-
responder.setFlags(MessageFlag.EPHEMERAL);
93+
responder.setFlags(InteractionCallbackDataFlag.EPHEMERAL);
9494
}
9595
return responder;
9696
}

src/main/java/net/javadiscord/javabot2/config/SystemsConfig.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,7 @@ public class SystemsConfig {
3838
@Data
3939
public static class HikariConfig {
4040
private static final int DEFAULT_POOL_SIZE = 5;
41-
private String jdbcUrl = "jdbc:postgresql://localhost:27172/javabot";
42-
private String username = "javabot_dev";
43-
private String password = "javabot_dev_pass";
41+
private String jdbcUrl = "jdbc:h2:tcp://localhost:9123/./javabot";
4442
private int maximumPoolSize = DEFAULT_POOL_SIZE;
45-
private String connectionInitSql = "SET TIME ZONE 'UTC'";
4643
}
4744
}

src/main/java/net/javadiscord/javabot2/config/guild/ModerationConfig.java

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import lombok.Data;
44
import lombok.EqualsAndHashCode;
55
import net.javadiscord.javabot2.config.GuildConfigItem;
6+
import org.javacord.api.entity.channel.ServerTextChannel;
67
import org.javacord.api.entity.permission.Role;
78

89
/**
@@ -21,15 +22,33 @@ public class ModerationConfig extends GuildConfigItem {
2122
* being removed from the server. Warnings older than this are still kept,
2223
* but ignored.
2324
*/
24-
private int warnTimeoutDays;
25+
private int warnTimeoutDays = 30;
2526

2627
/**
2728
* The maximum total severity that a user can accrue from warnings before
2829
* being removed from the server.
2930
*/
30-
private int maxWarnSeverity;
31+
private int maxWarnSeverity = 100;
32+
33+
/**
34+
* The id of the server's mute role.
35+
*/
36+
private long muteRoleId;
37+
38+
/**
39+
* The id of the channel where log messages are sent.
40+
*/
41+
private long logChannelId;
3142

3243
public Role getStaffRole() {
3344
return this.getGuild().getRoleById(staffRoleId).orElseThrow();
3445
}
46+
47+
public Role getMuteRole() {
48+
return this.getGuild().getRoleById(muteRoleId).orElseThrow();
49+
}
50+
51+
public ServerTextChannel getLogChannel() {
52+
return this.getGuild().getChannelById(logChannelId).orElseThrow().asServerTextChannel().orElseThrow();
53+
}
3554
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package net.javadiscord.javabot2.db;
2+
3+
import java.sql.Connection;
4+
import java.sql.SQLException;
5+
6+
/**
7+
* Functional interface for defining operations that use a Connection.
8+
*/
9+
@FunctionalInterface
10+
public interface ConnectionConsumer {
11+
void consume(Connection con) throws SQLException;
12+
}

0 commit comments

Comments
 (0)