Skip to content

Commit cc10a18

Browse files
Merge remote-tracking branch 'origin/main' into dynxsty/fix-message-cache
2 parents d2cdf78 + b681116 commit cc10a18

File tree

92 files changed

+2106
-424
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+2106
-424
lines changed

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,22 @@ public class PingCommand extends SlashCommand {
5656

5757
For more information on how this works, visit the [DIH4JDA Wiki!](https://github.com/DynxstyGIT/DIH4JDA/wiki)
5858

59+
# API Documentation
60+
61+
#### `GET` `guilds/{guild_id}/metrics`
62+
- Responds with guild-specific metrics, such as the member- and (approximate) online count.
63+
64+
#### `GET` `guilds/{guild_id}/users/{user_id}`
65+
- Responds with the specified users' profile which includes some basic info, such as the users' name and avatar url, but also their recent warns, their current help experience and more!
66+
67+
#### `GET` `guilds/{guild_id}/leaderboard/qotw?page=1`
68+
- A paginated endpoint which responds with an ordered list of users, based on their QOTW points.
69+
70+
#### `GET` `guilds/{guild_id}/leaderboard/experience?page=1`
71+
- A paginated endpoint which responds with an ordered list of users, based on their help channel experience.
72+
73+
You can try out the API yourself on `api.javadiscord.net`!
74+
5975
# Credits
6076

6177
Inspiration we took from other communities:

build.gradle.kts

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1+
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
2+
import com.github.jengelman.gradle.plugins.shadow.transformers.*
3+
14
plugins {
25
java
36
id("com.github.johnrengelman.shadow") version "7.1.2"
7+
id("io.spring.dependency-management") version "1.0.11.RELEASE"
48
checkstyle
59
}
610

@@ -19,12 +23,17 @@ repositories {
1923
}
2024

2125
dependencies {
22-
testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2")
23-
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.2")
26+
testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.0")
27+
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.0")
28+
29+
// DIH4JDA (Interaction Framework) & JDA
30+
implementation("com.github.DynxstyGIT:DIH4JDA:f564af77e9")
31+
implementation("net.dv8tion:JDA:5.0.0-alpha.17") {
32+
exclude(module = "opus-java")
33+
}
2434

25-
// DIH4JDA (Interaction Framework) (includes JDA (jda5.0.0-alpha.17))
26-
implementation("com.github.DenuxPlays:DIH4JDA:7ac2c9c77c")
27-
implementation("org.reflections:reflections:0.10.2")
35+
// Caffeine (Caching Library)
36+
implementation("com.github.ben-manes.caffeine:caffeine:3.1.1")
2837

2938
implementation("com.google.code.gson:gson:2.9.0")
3039
implementation("org.yaml:snakeyaml:1.30")
@@ -52,6 +61,9 @@ dependencies {
5261

5362
// Sentry
5463
implementation("io.sentry:sentry:6.3.0")
64+
65+
// Spring Boot
66+
implementation("org.springframework.boot:spring-boot-starter-web:2.7.0")
5567
}
5668

5769
tasks.withType<Jar> {
@@ -67,6 +79,19 @@ tasks.withType<JavaCompile>().configureEach {
6779
}
6880
tasks.withType<Test>{ useJUnitPlatform() }
6981

82+
tasks.withType<ShadowJar> {
83+
isZip64 = true
84+
// Required for Spring
85+
mergeServiceFiles()
86+
append("META-INF/spring.handlers")
87+
append("META-INF/spring.schemas")
88+
append("META-INF/spring.tooling")
89+
transform(PropertiesFileTransformer().apply {
90+
paths = listOf("META-INF/spring.factories")
91+
mergeStrategy = "append"
92+
})
93+
}
94+
7095
checkstyle {
7196
toolVersion = "9.1"
7297
configDirectory.set(File("checkstyle"))

checkstyle/checkstyle.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ See https://checkstyle.org/ for more information.
6969
<module name="UnnecessarySemicolonInEnumeration"/>
7070
<module name="UnnecessarySemicolonInTryWithResources"/>
7171
<module name="InnerTypeLast"/>
72-
<module name="HideUtilityClassConstructor"/>
7372
<module name="InterfaceIsType"/>
7473
<module name="MutableException"/>
7574
<module name="OneTopLevelClass"/>

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

Lines changed: 51 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@
22

33
import com.dynxsty.dih4jda.DIH4JDA;
44
import com.dynxsty.dih4jda.DIH4JDABuilder;
5+
import com.dynxsty.dih4jda.DIH4JDALogger;
6+
import com.dynxsty.dih4jda.interactions.commands.ContextCommand;
57
import com.dynxsty.dih4jda.interactions.commands.RegistrationType;
8+
import com.dynxsty.dih4jda.interactions.commands.SlashCommand;
69
import com.zaxxer.hikari.HikariDataSource;
710
import io.sentry.Sentry;
11+
import lombok.Getter;
812
import lombok.extern.slf4j.Slf4j;
913
import net.dv8tion.jda.api.JDA;
1014
import net.dv8tion.jda.api.JDABuilder;
@@ -27,15 +31,16 @@
2731
import net.javadiscord.javabot.systems.moderation.report.ReportManager;
2832
import net.javadiscord.javabot.systems.moderation.server_lock.ServerLockManager;
2933
import net.javadiscord.javabot.systems.qotw.commands.questions_queue.AddQuestionSubcommand;
34+
import net.javadiscord.javabot.systems.qotw.commands.view.QOTWQuerySubcommand;
3035
import net.javadiscord.javabot.systems.qotw.submissions.SubmissionInteractionManager;
31-
import net.javadiscord.javabot.systems.staff_commands.self_roles.SelfRoleInteractionManager;
3236
import net.javadiscord.javabot.systems.staff_commands.embeds.AddEmbedFieldSubcommand;
3337
import net.javadiscord.javabot.systems.staff_commands.embeds.CreateEmbedSubcommand;
3438
import net.javadiscord.javabot.systems.staff_commands.embeds.EditEmbedSubcommand;
35-
import net.javadiscord.javabot.systems.starboard.StarboardManager;
39+
import net.javadiscord.javabot.systems.staff_commands.self_roles.SelfRoleInteractionManager;
3640
import net.javadiscord.javabot.systems.staff_commands.tags.CustomTagManager;
3741
import net.javadiscord.javabot.systems.staff_commands.tags.commands.CreateCustomTagSubcommand;
3842
import net.javadiscord.javabot.systems.staff_commands.tags.commands.EditCustomTagSubcommand;
43+
import net.javadiscord.javabot.systems.starboard.StarboardManager;
3944
import net.javadiscord.javabot.systems.user_commands.leaderboard.ExperienceLeaderboardSubcommand;
4045
import net.javadiscord.javabot.tasks.MetricsUpdater;
4146
import net.javadiscord.javabot.tasks.PresenceUpdater;
@@ -44,6 +49,11 @@
4449
import net.javadiscord.javabot.util.InteractionUtils;
4550
import org.jetbrains.annotations.NotNull;
4651
import org.quartz.SchedulerException;
52+
import org.springframework.beans.factory.annotation.Autowired;
53+
import org.springframework.boot.SpringApplication;
54+
import org.springframework.boot.autoconfigure.SpringBootApplication;
55+
import org.springframework.context.annotation.ComponentScan;
56+
import org.springframework.context.annotation.FilterType;
4757

4858
import java.nio.file.Path;
4959
import java.time.ZoneOffset;
@@ -58,33 +68,62 @@
5868
* The main class where the bot is initialized.
5969
*/
6070
@Slf4j
71+
@SpringBootApplication
72+
@ComponentScan(includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {SlashCommand.class, ContextCommand.class}))
6173
public class Bot {
6274

75+
@Getter
6376
private static BotConfig config;
6477

78+
@Getter
6579
private static AutoMod autoMod;
6680

81+
@Getter
6782
private static DIH4JDA dih4jda;
6883

84+
@Getter
6985
private static MessageCache messageCache;
7086

87+
@Getter
7188
private static ServerLockManager serverLockManager;
7289

90+
@Getter
7391
private static CustomTagManager customTagManager;
7492

93+
@Getter
7594
private static HikariDataSource dataSource;
7695

96+
@Getter
7797
private static ScheduledExecutorService asyncPool;
7898

79-
private Bot() {
99+
/**
100+
* The constructor of this class, which also adds all {@link SlashCommand} and
101+
* {@link ContextCommand} to the {@link DIH4JDA} instance.
102+
*
103+
* @param commands The {@link Autowired} list of {@link SlashCommand}s.
104+
* @param contexts The {@link Autowired} list of {@link ContextCommand}s.
105+
*/
106+
@Autowired
107+
public Bot(final List<SlashCommand> commands, final List<ContextCommand> contexts) {
108+
if (!commands.isEmpty()) {
109+
getDih4jda().addSlashCommands(commands.toArray(SlashCommand[]::new));
110+
}
111+
if (!contexts.isEmpty()) {
112+
getDih4jda().addContextCommands(contexts.toArray(ContextCommand[]::new));
113+
}
114+
try {
115+
getDih4jda().registerInteractions();
116+
} catch (ReflectiveOperationException e) {
117+
ExceptionLogger.capture(e, getClass().getSimpleName());
118+
}
80119
}
81120

82121
/**
83122
* The main method that starts the bot. This involves a few steps:
84123
* <ol>
85124
* <li>Setting the time zone to UTC, to keep our sanity when working with times.</li>
86125
* <li>Loading the configuration JSON file.</li>
87-
* <li>Creating and configuring the {@link JDA} instance that enables the bot's Discord connectivity.</li>
126+
* <li>Creating and configuring the {@link JDA} instance that enables the bots' Discord connectivity.</li>
88127
* <li>Initializing the {@link DIH4JDA} instance.</li>
89128
* <li>Adding event listeners to the bot.</li>
90129
* </ol>
@@ -108,8 +147,9 @@ public static void main(String[] args) throws Exception {
108147
.build();
109148
AllowedMentions.setDefaultMentions(EnumSet.of(Message.MentionType.ROLE, Message.MentionType.CHANNEL, Message.MentionType.USER, Message.MentionType.EMOJI));
110149
dih4jda = DIH4JDABuilder.setJDA(jda)
111-
.setCommandsPackage("net.javadiscord.javabot")
112-
.setDefaultCommandType(RegistrationType.GUILD)
150+
.setDefaultCommandType(RegistrationType.GLOBAL)
151+
.disableLogging(DIH4JDALogger.Type.SMART_QUEUE_IGNORED)
152+
.disableAutomaticCommandRegistration()
113153
.build();
114154
customTagManager = new CustomTagManager(jda, dataSource);
115155
messageCache = new MessageCache();
@@ -130,10 +170,11 @@ public static void main(String[] args) throws Exception {
130170
log.error("Could not initialize all scheduled tasks.", e);
131171
jda.shutdown();
132172
}
173+
SpringApplication.run(Bot.class, args);
133174
}
134175

135176
/**
136-
* Adds all the bot's event listeners to the JDA instance, except for
177+
* Adds all the bots' event listeners to the JDA instance, except for
137178
* the {@link AutoMod} instance.
138179
*
139180
* @param jda The JDA bot instance to add listeners to.
@@ -157,7 +198,7 @@ private static void addEventListeners(@NotNull JDA jda, @NotNull DIH4JDA dih4jda
157198
new PingableNameListener(),
158199
new HugListener()
159200
);
160-
dih4jda.addListener(new DIH4JDAListener());
201+
dih4jda.addEventListener(new DIH4JDAListener());
161202
}
162203

163204
private static void addComponentHandler(@NotNull DIH4JDA dih4jda) {
@@ -167,7 +208,8 @@ private static void addComponentHandler(@NotNull DIH4JDA dih4jda) {
167208
List.of("resolve-report"), new ReportManager(),
168209
List.of("self-role"), new SelfRoleInteractionManager(),
169210
List.of("qotw-submission"), new SubmissionInteractionManager(),
170-
List.of("help-channel", "help-thank"), new HelpChannelInteractionManager()
211+
List.of("help-channel", "help-thank"), new HelpChannelInteractionManager(),
212+
List.of("qotw-list-questions"), new QOTWQuerySubcommand()
171213
));
172214
dih4jda.addModalHandlers(Map.of(
173215
List.of("qotw-add-question"), new AddQuestionSubcommand(),
@@ -184,80 +226,5 @@ private static void addComponentHandler(@NotNull DIH4JDA dih4jda) {
184226
List.of("qotw-submission-select"), new SubmissionInteractionManager()
185227
));
186228
}
187-
188-
/**
189-
* The set of configuration properties that this bot uses.
190-
*
191-
* @return The {@link BotConfig} which was set in {@link Bot#main(String[])}.
192-
*/
193-
public static BotConfig getConfig() {
194-
return config;
195-
}
196-
197-
/**
198-
* A static reference to the bots' {@link AutoMod} instance.
199-
*
200-
* @return The {@link AutoMod} instance which was created in {@link Bot#main(String[])}.
201-
*/
202-
public static AutoMod getAutoMod() {
203-
return autoMod;
204-
}
205-
206-
/**
207-
* A static reference to the bots' {@link DIH4JDA} instance.
208-
*
209-
* @return The {@link DIH4JDA} instance which was set in {@link Bot#main(String[])}.
210-
*/
211-
public static DIH4JDA getDIH4JDA() {
212-
return dih4jda;
213-
}
214-
215-
/**
216-
* The bots' {@link MessageCache}, which handles logging of deleted and edited messages.
217-
*
218-
* @return The {@link MessageCache} which was initialized in {@link Bot#main(String[])}.
219-
*/
220-
public static MessageCache getMessageCache() {
221-
return messageCache;
222-
}
223-
224-
/**
225-
* A reference to the bots' {@link ServerLockManager}.
226-
*
227-
* @return The {@link ServerLockManager} which was created in {@link Bot#main(String[])}.
228-
*/
229-
public static ServerLockManager getServerLockManager() {
230-
return serverLockManager;
231-
}
232-
233-
/**
234-
* A static reference to the {@link CustomTagManager} which handles and loads all registered Custom Commands.
235-
*
236-
* @return The {@link CustomTagManager} which was created in {@link Bot#main(String[])}.
237-
*/
238-
public static CustomTagManager getCustomTagManager() {
239-
return customTagManager;
240-
}
241-
242-
/**
243-
* A reference to the data source that provides access to the relational
244-
* database that this bot users for certain parts of the application. Use
245-
* this to obtain a connection and perform transactions.
246-
*
247-
* @return The {@link HikariDataSource} which was initialized in {@link Bot#main(String[])}.
248-
*/
249-
public static HikariDataSource getDataSource() {
250-
return dataSource;
251-
}
252-
253-
/**
254-
* A general-purpose thread pool that can be used by the bot to execute
255-
* tasks outside the main event processing thread.
256-
*
257-
* @return The {@link ScheduledExecutorService} which was set in {@link Bot#main(String[])}.
258-
*/
259-
public static ScheduledExecutorService getAsyncPool() {
260-
return asyncPool;
261-
}
262229
}
263230

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package net.javadiscord.javabot.api;
2+
3+
import net.dv8tion.jda.api.JDA;
4+
import net.javadiscord.javabot.Bot;
5+
import org.springframework.context.annotation.Bean;
6+
import org.springframework.context.annotation.Configuration;
7+
8+
/**
9+
* This class holds all configuration settings and {@link Bean}s.
10+
*/
11+
@Configuration
12+
public class SpringConfig {
13+
@Bean
14+
public JDA getJDA() {
15+
return Bot.getDih4jda().getJDA();
16+
}
17+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package net.javadiscord.javabot.api;
2+
3+
import net.javadiscord.javabot.Bot;
4+
import org.apache.catalina.connector.Connector;
5+
import org.apache.coyote.ajp.AjpNioProtocol;
6+
import org.springframework.beans.factory.annotation.Value;
7+
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
8+
import org.springframework.context.annotation.Bean;
9+
import org.springframework.context.annotation.Configuration;
10+
11+
/**
12+
* Holds all configuration for the {@link org.springframework.boot.autoconfigure.web.ServerProperties.Tomcat}
13+
* web service.
14+
*/
15+
@Configuration
16+
public class TomcatConfig {
17+
18+
private final int ajpPort;
19+
20+
private final boolean tomcatAjpEnabled;
21+
22+
public TomcatConfig(@Value("${tomcat.ajp.port}") int ajpPort, @Value("${tomcat.ajp.enabled}") boolean tomcatAjpEnabled) {
23+
this.ajpPort = ajpPort;
24+
this.tomcatAjpEnabled = tomcatAjpEnabled;
25+
}
26+
27+
/**
28+
* Sets up the {@link TomcatServletWebServerFactory} using the {@link Value}s defined in the
29+
* application.properties file.
30+
*
31+
* @return The {@link TomcatServletWebServerFactory}.
32+
*/
33+
@Bean
34+
public TomcatServletWebServerFactory servletContainer() {
35+
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
36+
if (tomcatAjpEnabled) {
37+
Connector ajpConnector = new Connector("org.apache.coyote.ajp.AjpNioProtocol");
38+
AjpNioProtocol protocol= (AjpNioProtocol) ajpConnector.getProtocolHandler();
39+
protocol.setSecret(Bot.getConfig().getSystems().getApiConfig().getAjpSecret());
40+
ajpConnector.setPort(ajpPort);
41+
ajpConnector.setSecure(true);
42+
tomcat.addAdditionalTomcatConnectors(ajpConnector);
43+
}
44+
return tomcat;
45+
}
46+
}

0 commit comments

Comments
 (0)