Skip to content

Commit db33cb2

Browse files
committed
Merge branch 'main' into help-history-chart
2 parents 1ff40f6 + b81420e commit db33cb2

File tree

14 files changed

+183
-70
lines changed

14 files changed

+183
-70
lines changed

src/main/java/net/javadiscord/javabot/data/config/guild/HelpConfig.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,18 @@ public class HelpConfig extends GuildConfigItem {
3838
*/
3939
private String dormantChannelMessageTemplate = "`\uD83D\uDCA4` **Post marked as dormant**\n> This post has been inactive for over %s minutes, thus, it has been **archived**.\n> If your question was not answered yet, feel free to re-open this post or create a new one.";
4040

41+
/**
42+
* The message that's sent in a post to tell users that it
43+
* is now marked as dormant and no more messages can be sent.
44+
*/
45+
private String dormantChannelPrivateMessageTemplate = """
46+
Your post %s in %s has been inactive for over %s minutes, thus, it has been **archived**.
47+
If your question was not answered yet, feel free to re-open this post by sending another message in that channel.
48+
You can disable notifications like this using the `/preferences` command.
49+
[Post link](%s)
50+
""";
51+
52+
4153
/**
4254
* The message that's sent when a user unreserved a channel where other users
4355
* participated in.

src/main/java/net/javadiscord/javabot/listener/SuggestionListener.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ private MessageEmbed buildSuggestionEmbed(Message message) {
8787
.setColor(Responses.Type.DEFAULT.getColor())
8888
.setTimestamp(Instant.now())
8989
.setDescription(message.getContentRaw())
90+
.setFooter(message.getAuthor().getId())
9091
.build();
9192
}
9293
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package net.javadiscord.javabot.listener;
2+
3+
import lombok.RequiredArgsConstructor;
4+
import net.dv8tion.jda.api.entities.Message;
5+
import net.dv8tion.jda.api.entities.emoji.Emoji;
6+
import net.dv8tion.jda.api.events.message.react.MessageReactionAddEvent;
7+
import net.dv8tion.jda.api.hooks.ListenerAdapter;
8+
import net.javadiscord.javabot.data.config.BotConfig;
9+
10+
/**
11+
* Makes sure users don't vote on/star their own messages.
12+
*/
13+
@RequiredArgsConstructor
14+
public class VotingRegulationListener extends ListenerAdapter{
15+
16+
private final BotConfig botConfig;
17+
18+
@Override
19+
public void onMessageReactionAdd(MessageReactionAddEvent event) {
20+
if(isCriticalEmoji(event)) {
21+
event.retrieveMessage().queue(msg->{
22+
if(doesAuthorMatch(event.getUserIdLong(), msg)) {
23+
msg.removeReaction(event.getEmoji(), event.getUser()).queue();
24+
}
25+
});
26+
}
27+
}
28+
29+
private boolean doesAuthorMatch(long userId, Message msg) {
30+
long suggestionChannelId = botConfig.get(msg.getGuild()).getModerationConfig().getSuggestionChannelId();
31+
return msg.getAuthor().getIdLong() == userId||
32+
msg.getChannel().getIdLong() == suggestionChannelId &&
33+
!msg.getEmbeds().isEmpty() &&
34+
msg.getEmbeds().get(0).getFooter() != null &&
35+
String.valueOf(userId).equals(msg.getEmbeds().get(0).getFooter().getText());
36+
}
37+
38+
private boolean isCriticalEmoji(MessageReactionAddEvent event) {
39+
return getUpvoteEmoji(event).equals(event.getEmoji()) ||
40+
event.getEmoji().getType() == Emoji.Type.UNICODE &&
41+
botConfig.get(event.getGuild()).getStarboardConfig().getEmojis().contains(event.getEmoji().asUnicode());
42+
}
43+
44+
private Emoji getUpvoteEmoji(MessageReactionAddEvent event) {
45+
return botConfig.getSystems().getEmojiConfig().getUpvoteEmote(event.getJDA());
46+
}
47+
}

src/main/java/net/javadiscord/javabot/systems/help/HelpExperienceService.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
import lombok.extern.slf4j.Slf4j;
55
import net.dv8tion.jda.api.entities.Guild;
66
import net.dv8tion.jda.api.entities.Role;
7+
import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel;
78
import net.javadiscord.javabot.data.config.BotConfig;
9+
import net.javadiscord.javabot.data.config.guild.HelpConfig;
810
import net.javadiscord.javabot.systems.help.dao.HelpAccountRepository;
911
import net.javadiscord.javabot.systems.help.dao.HelpTransactionRepository;
1012
import net.javadiscord.javabot.systems.help.model.HelpAccount;
@@ -18,6 +20,7 @@
1820

1921
import java.util.Collections;
2022
import java.util.List;
23+
import java.util.Map;
2124
import java.util.Optional;
2225

2326
/**
@@ -75,17 +78,19 @@ public List<HelpAccount> getTopAccounts(int amount, int page) {
7578
* @param recipient The recipient's user id.
7679
* @param value The transaction's value.
7780
* @param guild The current guild.
81+
* @param channelId The ID of the channel the transaction should be performed in
7882
* @throws DataAccessException If an error occurs.
7983
*/
8084
@Transactional
81-
public void performTransaction(long recipient, double value, Guild guild) throws DataAccessException {
85+
public void performTransaction(long recipient, double value, Guild guild, long channelId) throws DataAccessException {
8286
if (value == 0) {
8387
log.error("Cannot make zero-value transactions");
8488
return;
8589
}
8690
HelpTransaction transaction = new HelpTransaction();
8791
transaction.setRecipient(recipient);
8892
transaction.setWeight(value);
93+
transaction.setChannelId(channelId);
8994
HelpAccount account = getOrCreateAccount(recipient);
9095
account.updateExperience(value);
9196
helpAccountRepository.update(account);
@@ -109,4 +114,24 @@ private void checkExperienceRoles(@NotNull Guild guild, @NotNull HelpAccount acc
109114
}
110115
}), e -> {});
111116
}
117+
118+
/**
119+
* add XP to all helpers depending on the messages they sent.
120+
*
121+
* @param post The {@link ThreadChannel} post
122+
* @param allowIfXPAlreadyGiven {@code true} if XP should be awarded if XP have already been awarded
123+
*/
124+
public void addMessageBasedHelpXP(ThreadChannel post, boolean allowIfXPAlreadyGiven) {
125+
HelpConfig config = botConfig.get(post.getGuild()).getHelpConfig();
126+
try {
127+
Map<Long, Double> experience = HelpManager.calculateExperience(HelpListener.HELP_POST_MESSAGES.get(post.getIdLong()), post.getOwnerIdLong(), config);
128+
for (Map.Entry<Long, Double> entry : experience.entrySet()) {
129+
if(entry.getValue()>0 && (allowIfXPAlreadyGiven||!helpTransactionRepository.existsTransactionWithRecipientInChannel(entry.getKey(), post.getIdLong()))) {
130+
performTransaction(entry.getKey(), entry.getValue(), config.getGuild(), post.getIdLong());
131+
}
132+
}
133+
} catch (DataAccessException e) {
134+
ExceptionLogger.capture(e, getClass().getName());
135+
}
136+
}
112137
}

src/main/java/net/javadiscord/javabot/systems/help/HelpForumUpdater.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,18 @@
22

33
import lombok.RequiredArgsConstructor;
44
import lombok.extern.slf4j.Slf4j;
5+
import net.dv8tion.jda.api.EmbedBuilder;
56
import net.dv8tion.jda.api.JDA;
67
import net.dv8tion.jda.api.entities.Guild;
78
import net.dv8tion.jda.api.entities.Message;
9+
import net.dv8tion.jda.api.entities.MessageEmbed;
810
import net.dv8tion.jda.api.entities.channel.concrete.ForumChannel;
911
import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel;
1012
import net.javadiscord.javabot.data.config.BotConfig;
1113
import net.javadiscord.javabot.data.config.guild.HelpConfig;
14+
import net.javadiscord.javabot.systems.user_preferences.UserPreferenceService;
15+
import net.javadiscord.javabot.systems.user_preferences.model.Preference;
16+
1217
import org.jetbrains.annotations.NotNull;
1318
import org.springframework.scheduling.annotation.Scheduled;
1419
import org.springframework.stereotype.Service;
@@ -24,6 +29,8 @@
2429
public class HelpForumUpdater {
2530
private final JDA jda;
2631
private final BotConfig botConfig;
32+
private final UserPreferenceService preferenceService;
33+
private final HelpExperienceService experienceService;
2734

2835
/**
2936
* Updates all help channels.
@@ -61,13 +68,42 @@ private void checkForumPost(@NotNull ThreadChannel post, HelpConfig config) {
6168
}
6269
post.sendMessage(config.getDormantChannelMessageTemplate().formatted(config.getInactivityTimeoutMinutes())).queue(s -> {
6370
post.getManager().setArchived(true).queue();
71+
sendDMDormantInfoIfEnabled(post, config);
72+
experienceService.addMessageBasedHelpXP(post, false);
6473
log.info("Archived forum thread '{}' (by {}) for inactivity (last message sent {} minutes ago)",
6574
post.getName(), post.getOwnerId(), minutesAgo);
75+
6676
});
6777
}
6878
}, e -> log.error("Could not find latest message in forum thread {}:", post.getId(), e));
6979
}
7080

81+
private void sendDMDormantInfoIfEnabled(ThreadChannel post, HelpConfig config) {
82+
if(Boolean.parseBoolean(preferenceService.getOrCreate(post.getOwnerIdLong(), Preference.PRIVATE_DORMANT_NOTIFICATIONS).getState())) {
83+
post
84+
.getOwner()
85+
.getUser()
86+
.openPrivateChannel()
87+
.flatMap(c -> c.sendMessageEmbeds(createDMDormantInfo(post, config)))
88+
.queue();
89+
}
90+
}
91+
92+
private MessageEmbed createDMDormantInfo(ThreadChannel post, HelpConfig config) {
93+
return new EmbedBuilder()
94+
.setTitle("Post marked as dormant")
95+
.setDescription(
96+
config
97+
.getDormantChannelPrivateMessageTemplate()
98+
.formatted(
99+
post.getAsMention(),
100+
post.getParentChannel().getAsMention(),
101+
config.getInactivityTimeoutMinutes(),
102+
post.getJumpUrl()))
103+
.build()
104+
;
105+
}
106+
71107
private boolean isThanksMessage(@NotNull Message m) {
72108
return m.getAuthor().isBot() && !m.getButtons().isEmpty() &&
73109
m.getButtons().stream().allMatch(b -> b.getId() != null && b.getId().contains(HelpManager.HELP_THANKS_IDENTIFIER));

src/main/java/net/javadiscord/javabot/systems/help/HelpListener.java

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,9 @@
2222
import net.javadiscord.javabot.data.h2db.DbActions;
2323
import net.javadiscord.javabot.systems.help.dao.HelpAccountRepository;
2424
import net.javadiscord.javabot.systems.help.dao.HelpTransactionRepository;
25-
import net.javadiscord.javabot.util.ExceptionLogger;
2625
import net.javadiscord.javabot.util.InteractionUtils;
2726
import net.javadiscord.javabot.util.Responses;
2827
import org.jetbrains.annotations.NotNull;
29-
import org.springframework.dao.DataAccessException;
3028
import xyz.dynxsty.dih4jda.interactions.components.ButtonHandler;
3129
import xyz.dynxsty.dih4jda.util.ComponentIdBuilder;
3230

@@ -48,7 +46,7 @@ public class HelpListener extends ListenerAdapter implements ButtonHandler {
4846
/**
4947
* A static Map that holds all messages that was sent in a specific reserved forum channel.
5048
*/
51-
protected static final Map<Long, List<Message>> HELP_POST_MESSAGES = new HashMap<>();
49+
static final Map<Long, List<Message>> HELP_POST_MESSAGES = new HashMap<>();
5250
private static final Set<Long> newThreadChannels;
5351

5452
static {
@@ -58,6 +56,7 @@ public class HelpListener extends ListenerAdapter implements ButtonHandler {
5856
private final BotConfig botConfig;
5957
private final HelpAccountRepository helpAccountRepository;
6058
private final HelpTransactionRepository helpTransactionRepository;
59+
private final HelpExperienceService experienceService;
6160
private final DbActions dbActions;
6261
private final String[][] closeSuggestionDetectors = {
6362
{"close", "post"},
@@ -158,7 +157,6 @@ public void onChannelCreate(@NotNull ChannelCreateEvent event) {
158157
if (isInvalidForumPost(event.getChannel())) {
159158
return;
160159
}
161-
HelpConfig config = botConfig.get(event.getGuild()).getHelpConfig();
162160
ThreadChannel post = event.getChannel().asThreadChannel();
163161
if (isInvalidHelpForumChannel(post.getParentChannel().asForumChannel())) {
164162
return;
@@ -229,20 +227,11 @@ private void handleThanksCloseButton(@NotNull ButtonInteractionEvent event, Help
229227
event.getMessage().delete().queue(s -> {
230228
// close post
231229
manager.close(event, false, null);
232-
// add experience
233-
try {
234-
HelpExperienceService service = new HelpExperienceService(botConfig, helpAccountRepository, helpTransactionRepository);
235-
Map<Long, Double> experience = HelpManager.calculateExperience(HELP_POST_MESSAGES.get(post.getIdLong()), post.getOwnerIdLong(), config);
236-
for (Map.Entry<Long, Double> entry : experience.entrySet()) {
237-
service.performTransaction(entry.getKey(), entry.getValue(), config.getGuild());
238-
}
239-
} catch (DataAccessException e) {
240-
ExceptionLogger.capture(e, getClass().getName());
241-
}
230+
experienceService.addMessageBasedHelpXP(post, true);
242231
// thank all helpers
243232
buttons.stream().filter(ActionComponent::isDisabled)
244233
.filter(b -> b.getId() != null)
245-
.forEach(b -> manager.thankHelper(event, post, Long.parseLong(ComponentIdBuilder.split(b.getId())[2])));
234+
.forEach(b -> manager.thankHelper(event.getGuild(), post, Long.parseLong(ComponentIdBuilder.split(b.getId())[2])));
246235
});
247236
}
248237

src/main/java/net/javadiscord/javabot/systems/help/HelpManager.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import net.dv8tion.jda.api.entities.UserSnowflake;
1212
import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel;
1313
import net.dv8tion.jda.api.entities.emoji.Emoji;
14-
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
1514
import net.dv8tion.jda.api.interactions.Interaction;
1615
import net.dv8tion.jda.api.interactions.callbacks.IReplyCallback;
1716
import net.dv8tion.jda.api.interactions.components.ActionRow;
@@ -28,6 +27,7 @@
2827
import net.javadiscord.javabot.util.Responses;
2928
import org.jetbrains.annotations.NotNull;
3029
import org.jetbrains.annotations.Nullable;
30+
3131
import xyz.dynxsty.dih4jda.util.ComponentIdBuilder;
3232

3333
import java.sql.SQLException;
@@ -120,16 +120,16 @@ public void close(UserSnowflake closedBy, @Nullable String reason) {
120120
postThread.sendMessageEmbeds(buildPostClosedEmbed(closedBy, reason))
121121
.queue(s -> postThread.getManager().setArchived(true).queue());
122122
}
123-
123+
124124
/**
125125
* Thanks a single user.
126126
*
127-
* @param event The {@link ButtonInteractionEvent} that was fired.
127+
* @param guild The {@link Guild} the helper is thanked in
128128
* @param postThread The {@link ThreadChannel} post.
129129
* @param helperId The helpers' discord id.
130130
*/
131-
public void thankHelper(@NotNull ButtonInteractionEvent event, ThreadChannel postThread, long helperId) {
132-
event.getJDA().retrieveUserById(helperId).queue(helper -> {
131+
public void thankHelper(@NotNull Guild guild, ThreadChannel postThread, long helperId) {
132+
guild.getJDA().retrieveUserById(helperId).queue(helper -> {
133133
// First insert the new thanks data.
134134
try {
135135
dbActions.update(
@@ -139,13 +139,13 @@ public void thankHelper(@NotNull ButtonInteractionEvent event, ThreadChannel pos
139139
postThread.getIdLong(),
140140
helper.getIdLong()
141141
);
142-
HelpConfig config = botConfig.get(event.getGuild()).getHelpConfig();
142+
HelpConfig config = botConfig.get(guild).getHelpConfig();
143143
HelpExperienceService service = new HelpExperienceService(botConfig, helpAccountRepository, helpTransactionRepository);
144144
// Perform experience transactions
145-
service.performTransaction(helper.getIdLong(), config.getThankedExperience(), event.getGuild());
145+
service.performTransaction(helper.getIdLong(), config.getThankedExperience(), guild, postThread.getIdLong());
146146
} catch (SQLException e) {
147147
ExceptionLogger.capture(e, getClass().getSimpleName());
148-
botConfig.get(event.getGuild()).getModerationConfig().getLogChannel().sendMessageFormat(
148+
botConfig.get(guild).getModerationConfig().getLogChannel().sendMessageFormat(
149149
"Could not record user %s thanking %s for help in post %s: %s",
150150
postThread.getOwner().getUser().getAsTag(),
151151
helper.getAsTag(),

src/main/java/net/javadiscord/javabot/systems/help/dao/HelpTransactionRepository.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,13 @@ public class HelpTransactionRepository {
3737
public HelpTransaction save(HelpTransaction transaction) throws DataAccessException {
3838
SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate)
3939
.withTableName("help_transaction")
40-
.usingColumns("recipient","weight","messageType")
40+
.usingColumns("recipient","weight","messageType", "channel")
4141
.usingGeneratedKeyColumns("id");
4242
Number key = simpleJdbcInsert.executeAndReturnKey(Map.of(
4343
"recipient",transaction.getRecipient(),
4444
"weight",transaction.getWeight(),
45-
"messageType",transaction.getMessageType())
45+
"messageType",transaction.getMessageType(),
46+
"channel",transaction.getChannelId())
4647
);
4748
transaction.setId(key.longValue());
4849
log.info("Inserted new Help Transaction: {}", transaction);
@@ -83,9 +84,10 @@ private HelpTransaction read(ResultSet rs) throws SQLException {
8384
transaction.setCreatedAt(rs.getTimestamp("created_at").toLocalDateTime());
8485
transaction.setWeight(rs.getDouble("weight"));
8586
transaction.setMessageType(rs.getInt("messageType"));
87+
transaction.setChannelId(rs.getLong("channel"));
8688
return transaction;
8789
}
88-
90+
8991
/**
9092
* Gets the total earned XP of a user since a specific timestamp grouped by months.
9193
* @param userId the user to get XP from
@@ -97,4 +99,17 @@ public List<Pair<Pair<Integer, Integer>, Double>> getTotalTransactionWeightByMon
9799
(rs, row)-> new Pair<>(new Pair<>(rs.getInt("m"), rs.getInt("y")), rs.getDouble("total")),
98100
userId, start);
99101
}
102+
103+
/**
104+
* Checks whether a transaction with a specific recipient exists in a specific channel.
105+
* @param recipient The ID of the recipient
106+
* @param channelId The ID of the channel
107+
* @return {@code true} if it exists, else {@code false}
108+
*/
109+
public boolean existsTransactionWithRecipientInChannel(long recipient, long channelId) {
110+
return jdbcTemplate.queryForObject(
111+
"SELECT count(*) FROM help_transaction WHERE recipient=? AND channel = ?",
112+
Integer.class,
113+
recipient, channelId) > 0;
114+
}
100115
}

src/main/java/net/javadiscord/javabot/systems/help/model/HelpTransaction.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@ public class HelpTransaction {
1414
private LocalDateTime createdAt;
1515
private double weight;
1616
private int messageType;
17+
private long channelId = -1;
1718
}

0 commit comments

Comments
 (0)