sxcybot

Discord bot for OSRS based channels
git clone git://git.wimdupont.com/sxcybot.git
Log | Files | Refs | README | LICENSE

commit 94b35942862a04d01c8e7176ccbda017b9f3d5da
parent a56b6f2d64000c6c60c53fa0ff77ebcaf6a1e9ff
Author: Wim Dupont <wim@wimdupont.com>
Date:   Sat,  1 Nov 2025 07:02:48 +0100

pvm autoadd

Diffstat:
Mpom.xml | 4++--
Asrc/main/java/com/wimdupont/sxcybot/client/WiseOldManClient.java | 37+++++++++++++++++++++++++++++++++++++
Msrc/main/java/com/wimdupont/sxcybot/enums/Command.java | 3++-
Msrc/main/java/com/wimdupont/sxcybot/listeners/AdminCommandListener.java | 8++++++++
Asrc/main/java/com/wimdupont/sxcybot/listeners/admin/pvmrole/AutoUpdatePvmListener.java | 30++++++++++++++++++++++++++++++
Asrc/main/java/com/wimdupont/sxcybot/model/wiseoldman/GroupDto.java | 13+++++++++++++
Asrc/main/java/com/wimdupont/sxcybot/model/wiseoldman/MembershipDto.java | 13+++++++++++++
Asrc/main/java/com/wimdupont/sxcybot/model/wiseoldman/PlayerDto.java | 17+++++++++++++++++
Asrc/main/java/com/wimdupont/sxcybot/services/guild/pvmrole/PvmRoleUserAutoAddService.java | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
9 files changed, 239 insertions(+), 3 deletions(-)

diff --git a/pom.xml b/pom.xml @@ -5,7 +5,7 @@ <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> - <version>3.5.0</version> + <version>3.5.6</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.wimdupont</groupId> @@ -16,7 +16,7 @@ <properties> <java.version>21</java.version> - <dv8ation.jda.version>5.5.1</dv8ation.jda.version> + <dv8ation.jda.version>5.6.1</dv8ation.jda.version> </properties> <dependencies> diff --git a/src/main/java/com/wimdupont/sxcybot/client/WiseOldManClient.java b/src/main/java/com/wimdupont/sxcybot/client/WiseOldManClient.java @@ -0,0 +1,37 @@ +package com.wimdupont.sxcybot.client; + +import com.wimdupont.sxcybot.exceptions.EntityNotFoundException; +import com.wimdupont.sxcybot.model.wiseoldman.GroupDto; +import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import java.time.Duration; + +@Component +public class WiseOldManClient { + + private static final String URL = "https://api.wiseoldman.net/v2/groups/%s"; + private static final String GROUP = "6516"; //"Best guild of Gielinor" - Wise Old Man + private final Logger LOGGER = LoggerFactory.getLogger(this.getClass()); + + public GroupDto getGroup(MessageChannel channel) throws EntityNotFoundException { + RestTemplate restTemplate = new RestTemplateBuilder() + .errorHandler(new ClientErrorHandler(channel)) + .readTimeout(Duration.ofSeconds(30)) + .build(); + try { + GroupDto result = restTemplate.getForObject(String.format(URL, GROUP), GroupDto.class); + if (result == null) { + throw new Exception("Wise Old Man Groupo is null"); + } + return result; + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + throw new EntityNotFoundException(String.format("No WoM group available for %s.", GROUP)); + } + } +} diff --git a/src/main/java/com/wimdupont/sxcybot/enums/Command.java b/src/main/java/com/wimdupont/sxcybot/enums/Command.java @@ -31,7 +31,8 @@ public enum Command { ROLE("Add/remove a role to/from a member."), EDITROLE("Add/Delete record of roles."), EDITPVM("Add/Edit/Delete record of the PvM Role competition"), - EDITBOSS("Update multiplier for a OSRS Boss of the PvM Role competition"); + EDITBOSS("Update multiplier for a OSRS Boss of the PvM Role competition"), + UPDATEPVM("Attempts to add Pvm Role Competitors using Wise Old Man data"); public final String description; diff --git a/src/main/java/com/wimdupont/sxcybot/listeners/AdminCommandListener.java b/src/main/java/com/wimdupont/sxcybot/listeners/AdminCommandListener.java @@ -9,6 +9,7 @@ import com.wimdupont.sxcybot.listeners.admin.EditPvmListener; import com.wimdupont.sxcybot.listeners.admin.EditRoleListener; import com.wimdupont.sxcybot.listeners.admin.EditRuleListener; import com.wimdupont.sxcybot.listeners.admin.RoleAssignListener; +import com.wimdupont.sxcybot.listeners.admin.pvmrole.AutoUpdatePvmListener; import com.wimdupont.sxcybot.services.AccessService; import jakarta.annotation.Nonnull; import net.dv8tion.jda.api.entities.Role; @@ -34,6 +35,7 @@ public class AdminCommandListener extends ListenerAdapter { private final BanlistListener banlistListener; private final EditRoleListener editRoleListener; private final EditPvmListener editPvmListener; + private final AutoUpdatePvmListener autoUpdatePvmListener; private final BossUpdateMultiplierListener bossUpdateMultiplierListener; private final AccessService accessService; @@ -43,6 +45,7 @@ public class AdminCommandListener extends ListenerAdapter { BanlistListener banlistListener, EditRoleListener editRoleListener, EditPvmListener editPvmListener, + AutoUpdatePvmListener autoUpdatePvmListener, BossUpdateMultiplierListener bossUpdateMultiplierListener, AccessService accessService) { this.editRuleListener = editRuleListener; @@ -51,6 +54,7 @@ public class AdminCommandListener extends ListenerAdapter { this.banlistListener = banlistListener; this.editRoleListener = editRoleListener; this.editPvmListener = editPvmListener; + this.autoUpdatePvmListener = autoUpdatePvmListener; this.bossUpdateMultiplierListener = bossUpdateMultiplierListener; this.accessService = accessService; } @@ -88,6 +92,10 @@ public class AdminCommandListener extends ListenerAdapter { accessService.isAllowed(roleStream, event, GENERAL); bossUpdateMultiplierListener.process(event); } + case UPDATEPVM -> { + accessService.isAllowed(roleStream, event, ADMIN_ROLE); + autoUpdatePvmListener.process(event); + } } } catch (InsufficientPrivilegesException e) { event.getChannel().sendMessage(e.getMessage()).queue(); diff --git a/src/main/java/com/wimdupont/sxcybot/listeners/admin/pvmrole/AutoUpdatePvmListener.java b/src/main/java/com/wimdupont/sxcybot/listeners/admin/pvmrole/AutoUpdatePvmListener.java @@ -0,0 +1,30 @@ +package com.wimdupont.sxcybot.listeners.admin.pvmrole; + +import com.wimdupont.sxcybot.exceptions.EntityNotFoundException; +import com.wimdupont.sxcybot.listeners.Listener; +import com.wimdupont.sxcybot.services.guild.pvmrole.PvmRoleUserAutoAddService; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Component +public class AutoUpdatePvmListener implements Listener { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final PvmRoleUserAutoAddService pvmRoleUserAutoAddService; + + public AutoUpdatePvmListener(PvmRoleUserAutoAddService pvmRoleUserAutoAddService) { + this.pvmRoleUserAutoAddService = pvmRoleUserAutoAddService; + } + + @Override + public void process(MessageReceivedEvent event) { + try { + pvmRoleUserAutoAddService.autoAdd(event.getChannel().asTextChannel()); + } catch (EntityNotFoundException e) { + logger.error(e.getMessage(), e); + event.getMessage().getChannel().sendMessage(String.format("Error during Auto adding: %s.", e.getMessage())).queue(); + } + } +} diff --git a/src/main/java/com/wimdupont/sxcybot/model/wiseoldman/GroupDto.java b/src/main/java/com/wimdupont/sxcybot/model/wiseoldman/GroupDto.java @@ -0,0 +1,13 @@ +package com.wimdupont.sxcybot.model.wiseoldman; + +import java.util.List; + +public record GroupDto( + int id, + String name, + String description, + int homeworld, + List<MembershipDto> memberships +) { + +} diff --git a/src/main/java/com/wimdupont/sxcybot/model/wiseoldman/MembershipDto.java b/src/main/java/com/wimdupont/sxcybot/model/wiseoldman/MembershipDto.java @@ -0,0 +1,13 @@ +package com.wimdupont.sxcybot.model.wiseoldman; + +import java.time.LocalDateTime; + +public record MembershipDto( + int playerId, + int groupId, + String role, + LocalDateTime createdAt, + LocalDateTime updatedAt, + PlayerDto player +) { +} diff --git a/src/main/java/com/wimdupont/sxcybot/model/wiseoldman/PlayerDto.java b/src/main/java/com/wimdupont/sxcybot/model/wiseoldman/PlayerDto.java @@ -0,0 +1,17 @@ +package com.wimdupont.sxcybot.model.wiseoldman; + +import java.time.LocalDateTime; + +public record PlayerDto( + int id, + String username, + String displayName, + String type, + String build, + String status, + LocalDateTime registeredAt, + LocalDateTime updatedAt, + LocalDateTime lastChangedAt, + LocalDateTime lastImportedAt +) { +} diff --git a/src/main/java/com/wimdupont/sxcybot/services/guild/pvmrole/PvmRoleUserAutoAddService.java b/src/main/java/com/wimdupont/sxcybot/services/guild/pvmrole/PvmRoleUserAutoAddService.java @@ -0,0 +1,117 @@ +package com.wimdupont.sxcybot.services.guild.pvmrole; + +import com.wimdupont.sxcybot.client.WiseOldManClient; +import com.wimdupont.sxcybot.exceptions.EntityNotFoundException; +import com.wimdupont.sxcybot.model.wiseoldman.MembershipDto; +import com.wimdupont.sxcybot.repository.guild.pvmrole.dao.PvmRoleUser; +import com.wimdupont.sxcybot.services.guild.ChannelDetailService; +import com.wimdupont.sxcybot.util.JdaUtil; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.MessageEmbed.Field; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import java.awt.Color; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map.Entry; + +@Service +public class PvmRoleUserAutoAddService { + + private final WiseOldManClient wiseOldManClient; + private final ChannelDetailService channelDetailService; + private final PvmRoleUserService pvmRoleUserService; + private final PvmRoleSnapshotComparatorService pvmRoleSnapshotComparatorService; + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + public PvmRoleUserAutoAddService(WiseOldManClient wiseOldManClient, + ChannelDetailService channelDetailService, + PvmRoleUserService pvmRoleUserService, + PvmRoleSnapshotComparatorService pvmRoleSnapshotComparatorService) { + this.wiseOldManClient = wiseOldManClient; + this.channelDetailService = channelDetailService; + this.pvmRoleUserService = pvmRoleUserService; + this.pvmRoleSnapshotComparatorService = pvmRoleSnapshotComparatorService; + } + + public void autoAdd(TextChannel channel) throws EntityNotFoundException { + var group = wiseOldManClient.getGroup(channel); + var obscureList = new HashMap<String, List<String>>(); + var unknownList = new ArrayList<String>(); + channelDetailService.getJda().getGuilds().forEach(guild -> { + for (MembershipDto membership : group.memberships()) { + try { + pvmRoleUserService.findByRsn(membership.player().username()); + } catch (EntityNotFoundException e) { + var discordUsers = guild.getMembersByNickname(membership.player().username(), true); + if (discordUsers.size() > 1) { + obscureList.put(membership.player().username(), + discordUsers.stream() + .map(f -> f.getUser().getEffectiveName()) + .toList()); + logger.warn("Multiple users found for rsn {}", membership.player().username()); + } + if (!discordUsers.isEmpty()) { + var pvmRoleUser = pvmRoleUserService.save(PvmRoleUser.Builder.newBuilder() + .discordId(discordUsers.getFirst().getId()) + .rsn(membership.player().username()) + .build()); + try { + pvmRoleSnapshotComparatorService.takeSnapshot(channel, pvmRoleUser, true, true); + } catch (EntityNotFoundException ex) { + logger.error("No snapshot taken for {} : {}", pvmRoleUser, ex.getMessage()); + channel.sendMessage(String.format("Error whilst taking snapshot for %s.", pvmRoleUser.getRsn())).queue(); + } + } else { + unknownList.add(membership.player().username()); + logger.warn("No users found for rsn {}", membership.player().username()); + } + } + } + if (!obscureList.isEmpty()) { + postObscures(channel, obscureList); + } + if (!unknownList.isEmpty()) { + postUnknowns(channel, unknownList); + } + }); + } + + private void postObscures(TextChannel channel, HashMap<String, List<String>> obscureList) { + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(Color.red); + embedBuilder.setTitle("Obscure RSN's"); + int i = 1; + for (Entry<String, List<String>> obscureRsn : obscureList.entrySet()) { + embedBuilder.addField(new Field(obscureRsn.getKey(), String.join(", ", obscureRsn.getValue()), true)); + if (JdaUtil.requiresBuild(embedBuilder, obscureList.size(), i)) { + channel.sendMessageEmbeds(embedBuilder.build()).queue(); + embedBuilder.clearFields(); + } + i++; + } + if (!embedBuilder.getFields().isEmpty()) + channel.sendMessageEmbeds(embedBuilder.build()).queue(); + } + + private void postUnknowns(TextChannel channel, List<String> unknownList) { + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(Color.red); + embedBuilder.setTitle("Unknown RSN's"); + int i = 1; + for (String unknownRsn : unknownList) { + embedBuilder.addField(new Field(unknownRsn, "", true)); + if (JdaUtil.requiresBuild(embedBuilder, unknownList.size(), i)) { + channel.sendMessageEmbeds(embedBuilder.build()).queue(); + embedBuilder.clearFields(); + } + i++; + } + if (!embedBuilder.getFields().isEmpty()) + channel.sendMessageEmbeds(embedBuilder.build()).queue(); + } +}