diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cd274f9cb..eb84ad5e9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -39,3 +39,15 @@ jobs: -Dsonar.java.binaries=**/target/classes -Dsonar.coverage.jacoco.xmlReportPaths=abstracto-application/coverage/target/site/jacoco-aggregate/jacoco.xml -Dsonar.coverage.exclusions=**/*Test.java + - uses: actions/setup-ruby@v1 + - name: Send Webhook Notification + if: always() + env: + JOB_STATUS: ${{ job.status }} + WEBHOOK_URL: ${{ secrets.WEBHOOK_URL }} + HOOK_OS_NAME: ${{ runner.os }} + WORKFLOW_NAME: ${{ github.workflow }} + run: | + git clone https://github.com/DiscordHooks/github-actions-discord-webhook.git webhook + bash webhook/send.sh $JOB_STATUS $WEBHOOK_URL + shell: bash diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/MemberParameterHandlerImpl.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/MemberParameterHandlerImpl.java index c558d1735..2c533444b 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/MemberParameterHandlerImpl.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/MemberParameterHandlerImpl.java @@ -1,12 +1,15 @@ package dev.sheldan.abstracto.core.command.handler; import dev.sheldan.abstracto.core.command.CommandConstants; +import dev.sheldan.abstracto.core.command.exception.AbstractoTemplatedException; import dev.sheldan.abstracto.core.command.execution.UnparsedCommandParameterPiece; import dev.sheldan.abstracto.core.command.handler.provided.MemberParameterHandler; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; +import org.apache.commons.lang3.math.NumberUtils; import org.springframework.stereotype.Component; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.regex.Matcher; @@ -29,9 +32,20 @@ public class MemberParameterHandlerImpl implements MemberParameterHandler { if(matcher.matches()) { return CompletableFuture.completedFuture(iterators.getMemberIterator().next()); } else { - // TODO add handling for names - long userId = Long.parseLong(inputString); - return context.getGuild().retrieveMemberById(userId).submit().thenApply(member -> member); + if(NumberUtils.isParsable(inputString)) { + long userId = Long.parseLong(inputString); + return context.getGuild().retrieveMemberById(userId).submit().thenApply(member -> member); + } else { + List possibleMembers = context.getGuild().getMembersByName(inputString, true); + if(possibleMembers.isEmpty()) { + throw new AbstractoTemplatedException("No member found with name.", "no_member_found_by_name_exception"); + } + if(possibleMembers.size() > 1) { + throw new AbstractoTemplatedException("Multiple members found with name.", "multiple_members_found_by_name_exception"); + } + return CompletableFuture.completedFuture(possibleMembers.get(0)); + } + } } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/RoleParameterHandlerImpl.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/RoleParameterHandlerImpl.java index cd602736f..78447ae9a 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/RoleParameterHandlerImpl.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/RoleParameterHandlerImpl.java @@ -1,12 +1,15 @@ package dev.sheldan.abstracto.core.command.handler; import dev.sheldan.abstracto.core.command.CommandConstants; +import dev.sheldan.abstracto.core.command.exception.AbstractoTemplatedException; import dev.sheldan.abstracto.core.command.execution.UnparsedCommandParameterPiece; import dev.sheldan.abstracto.core.command.handler.provided.RoleParameterHandler; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.Role; +import org.apache.commons.lang3.math.NumberUtils; import org.springframework.stereotype.Component; +import java.util.List; import java.util.regex.Matcher; @Component @@ -23,8 +26,19 @@ public class RoleParameterHandlerImpl implements RoleParameterHandler { if(matcher.matches()) { return iterators.getRoleIterator().next(); } else { - long roleId = Long.parseLong(inputString); - return context.getGuild().getRoleById(roleId); + if(NumberUtils.isParsable(inputString)) { + long roleId = Long.parseLong(inputString); + return context.getGuild().getRoleById(roleId); + } else { + List roles = context.getGuild().getRolesByName(inputString, true); + if(roles.isEmpty()) { + throw new AbstractoTemplatedException("No role found with name.", "no_role_found_by_name_exception"); + } + if(roles.size() > 1) { + throw new AbstractoTemplatedException("Multiple roles found with name.", "multiple_roles_found_by_name_exception"); + } + return roles.get(0); + } } } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/TextChannelParameterHandlerImpl.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/TextChannelParameterHandlerImpl.java index bc98c88ee..2929c2440 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/TextChannelParameterHandlerImpl.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/TextChannelParameterHandlerImpl.java @@ -1,12 +1,15 @@ package dev.sheldan.abstracto.core.command.handler; import dev.sheldan.abstracto.core.command.CommandConstants; +import dev.sheldan.abstracto.core.command.exception.AbstractoTemplatedException; import dev.sheldan.abstracto.core.command.execution.UnparsedCommandParameterPiece; import dev.sheldan.abstracto.core.command.handler.provided.TextChannelParameterHandler; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.TextChannel; +import org.apache.commons.lang3.math.NumberUtils; import org.springframework.stereotype.Component; +import java.util.List; import java.util.regex.Matcher; @Component @@ -23,8 +26,19 @@ public class TextChannelParameterHandlerImpl implements TextChannelParameterHand if(matcher.matches()) { return iterators.getChannelIterator().next(); } else { - long channelId = Long.parseLong(inputString); - return context.getGuild().getTextChannelById(channelId); + if(NumberUtils.isParsable(inputString)) { + long channelId = Long.parseLong(inputString); + return context.getGuild().getTextChannelById(channelId); + } else { + List possibleTextChannels = context.getGuild().getTextChannelsByName(inputString, true); + if(possibleTextChannels.isEmpty()) { + throw new AbstractoTemplatedException("No channel found with name.", "no_channel_found_by_name_exception"); + } + if(possibleTextChannels.size() > 1) { + throw new AbstractoTemplatedException("Multiple channels found with name.", "multiple_channels_found_by_name_exception"); + } + return possibleTextChannels.get(0); + } } } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/ExceptionServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/ExceptionServiceBean.java index 8798ad7c8..992cd7636 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/ExceptionServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/ExceptionServiceBean.java @@ -41,25 +41,30 @@ public class ExceptionServiceBean implements ExceptionService { @Override public CommandResult reportExceptionToContext(Throwable throwable, CommandContext context, Command command) { - if(command != null && command.getConfiguration().isSupportsEmbedException()) { + if(command != null) { + log.info("Reporting generic exception {} of command {} towards channel {} in server {}.", + throwable.getClass().getSimpleName(), command.getConfiguration().getName(), context.getChannel().getId(), context.getGuild().getId()); + } else { + log.info("Reporting generic exception {} towards channel {} in server {}.", + throwable.getClass().getSimpleName(), context.getChannel().getId(), context.getGuild().getId()); + } + if((command != null && command.getConfiguration().isSupportsEmbedException()) || throwable instanceof Templatable) { try { - GenericExceptionModel exceptionModel = buildCommandModel(throwable, context); - log.info("Reporting generic exception {} of command {} towards channel {} in server {}.", - throwable.getClass().getSimpleName(), command.getConfiguration().getName(), context.getChannel().getId(), context.getGuild().getId()); - channelService.sendEmbedTemplateInTextChannelList("generic_command_exception", exceptionModel, context.getChannel()); + reportGenericException(throwable, context); } catch (Exception e) { log.error("Failed to notify about exception.", e); } - } else if(throwable instanceof Templatable){ - GenericExceptionModel exceptionModel = buildCommandModel(throwable, context); - String text = templateService.renderTemplate(MODEL_WRAPPER_TEMPLATE_KEY, exceptionModel, context.getGuild().getIdLong()); - channelService.sendTextToChannel(text, context.getChannel()); } else { channelService.sendTextToChannel(throwable.getLocalizedMessage(), context.getChannel()); } return CommandResult.fromReportedError(); } + private void reportGenericException(Throwable throwable, CommandContext context) { + GenericExceptionModel exceptionModel = buildCommandModel(throwable, context); + channelService.sendEmbedTemplateInTextChannelList("generic_command_exception", exceptionModel, context.getChannel()); + } + @Override public void reportExceptionToGuildMessageReceivedContext(Throwable exception, GuildMessageReceivedEvent event) { if(exception instanceof Templatable){ diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ReactionServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ReactionServiceBean.java index 3ebff955e..a9620dcf9 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ReactionServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ReactionServiceBean.java @@ -225,9 +225,9 @@ public class ReactionServiceBean implements ReactionService { public CompletableFuture removeReaction(CachedMessage message, CachedEmote cachedEmote, ServerUser user) { CompletableFuture messageFuture = messageService.loadMessageFromCachedMessage(message); CompletableFuture memberFuture = memberService.retrieveMemberInServer(user); - return FutureUtils.toSingleFuture(Arrays.asList(messageFuture, memberFuture)).thenCompose(unused -> { - return removeReaction(messageFuture.join(), cachedEmote, memberFuture.join().getUser()); - }); + return FutureUtils.toSingleFuture(Arrays.asList(messageFuture, memberFuture)).thenCompose(unused -> + removeReaction(messageFuture.join(), cachedEmote, memberFuture.join().getUser()) + ); } @Override diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/StartupServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/StartupServiceBean.java index 440046bc9..f3cfc6374 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/StartupServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/StartupServiceBean.java @@ -88,9 +88,9 @@ public class StartupServiceBean implements Startup { Set knownRolesId = SnowflakeUtils.getOwnItemsIds(knownARoles); Set availableRoles = SnowflakeUtils.getSnowflakeIds(existingRoles); Set newRoles = SetUtils.difference(availableRoles, knownRolesId); - newRoles.forEach(aLong -> { - roleManagementService.createRole(aLong, existingAServer); - }); + newRoles.forEach(aLong -> + roleManagementService.createRole(aLong, existingAServer) + ); } private void synchronizeChannelsOf(Guild guild, AServer existingServer){ diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/templating/service/TemplateServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/templating/service/TemplateServiceBean.java index 9941378e4..a664f1b8a 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/templating/service/TemplateServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/templating/service/TemplateServiceBean.java @@ -286,7 +286,7 @@ public class TemplateServiceBean implements TemplateService { public String renderSimpleTemplate(String key, Long serverId) { try { serverContext.setServerId(serverId); - return renderSimpleTemplate(key, serverId); + return renderSimpleTemplate(key); } finally { serverContext.clear(); } diff --git a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/MemberParameterHandlerImplTest.java b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/MemberParameterHandlerImplTest.java index 19a6ea40f..d7f295072 100644 --- a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/MemberParameterHandlerImplTest.java +++ b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/MemberParameterHandlerImplTest.java @@ -1,5 +1,6 @@ package dev.sheldan.abstracto.core.command.handler; +import dev.sheldan.abstracto.core.command.exception.AbstractoTemplatedException; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; @@ -12,6 +13,7 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -54,7 +56,7 @@ public class MemberParameterHandlerImplTest extends AbstractParameterHandlerTest oneMemberInIterator(); String input = getUserMention(); CompletableFuture parsed = (CompletableFuture) testUnit.handleAsync(getPieceWithValue(input), iterators, Member.class, null); - Assert.assertEquals(parsed.join(), member); + Assert.assertEquals(member, parsed.join()); } @Test @@ -63,13 +65,35 @@ public class MemberParameterHandlerImplTest extends AbstractParameterHandlerTest setupMessage(); String input = USER_ID.toString(); CompletableFuture parsed = (CompletableFuture) testUnit.handleAsync(getPieceWithValue(input), null, Member.class, message); - Assert.assertEquals(parsed.join(), member); + Assert.assertEquals(member, parsed.join()); } - @Test(expected = NumberFormatException.class) - public void testInvalidMemberMention() { + @Test(expected = AbstractoTemplatedException.class) + public void testNotExistingMember() { String input = "test"; - testUnit.handleAsync(getPieceWithValue(input), null, Member.class, null); + when(message.getGuild()).thenReturn(guild); + when(guild.getMembersByName(input, true)).thenReturn(new ArrayList<>()); + testUnit.handleAsync(getPieceWithValue(input), null, Member.class, message); + } + + @Test(expected = AbstractoTemplatedException.class) + public void testMultipleFoundMemberByName() { + String input = "test"; + Member secondMember = Mockito.mock(Member.class); + when(message.getGuild()).thenReturn(guild); + when(guild.getMembersByName(input, true)).thenReturn(Arrays.asList(member, secondMember)); + testUnit.handleAsync(getPieceWithValue(input), null, Member.class, message); + } + + @Test + public void testFindMemberByName() { + String input = "test"; + when(message.getGuild()).thenReturn(guild); + when(guild.getMembersByName(input, true)).thenReturn(Arrays.asList(member)); + CompletableFuture future = testUnit.handleAsync(getPieceWithValue(input), null, Member.class, message); + Member returnedMember = (Member) future.join(); + Assert.assertFalse(future.isCompletedExceptionally()); + Assert.assertEquals(member, returnedMember); } private String getUserMention() { diff --git a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/RoleParameterHandlerImplTest.java b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/RoleParameterHandlerImplTest.java index b9d30c28b..f949efba6 100644 --- a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/RoleParameterHandlerImplTest.java +++ b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/RoleParameterHandlerImplTest.java @@ -1,5 +1,6 @@ package dev.sheldan.abstracto.core.command.handler; +import dev.sheldan.abstracto.core.command.exception.AbstractoTemplatedException; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.Role; @@ -8,8 +9,10 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -50,7 +53,7 @@ public class RoleParameterHandlerImplTest extends AbstractParameterHandlerTest { oneRoleIterator(); String input = getRoleMention(); Role parsed = (Role) testUnit.handle(getPieceWithValue(input), iterators, Role.class, null); - Assert.assertEquals(parsed, role); + Assert.assertEquals(role, parsed); } @Test @@ -58,13 +61,33 @@ public class RoleParameterHandlerImplTest extends AbstractParameterHandlerTest { setupMessage(); String input = ROLE_ID.toString(); Role parsed = (Role) testUnit.handle(getPieceWithValue(input), null, Role.class, message); - Assert.assertEquals(parsed, role); + Assert.assertEquals(role, parsed); } - @Test(expected = NumberFormatException.class) + @Test(expected = AbstractoTemplatedException.class) public void testInvalidRoleMention() { String input = "test"; - testUnit.handle(getPieceWithValue(input), null, Role.class, null); + when(message.getGuild()).thenReturn(guild); + when(guild.getRolesByName(input, true)).thenReturn(new ArrayList<>()); + testUnit.handle(getPieceWithValue(input), null, Role.class, message); + } + + @Test(expected = AbstractoTemplatedException.class) + public void testMultipleRolesFoundByName() { + String input = "test"; + Role secondRole = Mockito.mock(Role.class); + when(message.getGuild()).thenReturn(guild); + when(guild.getRolesByName(input, true)).thenReturn(Arrays.asList(role, secondRole)); + testUnit.handle(getPieceWithValue(input), null, Role.class, message); + } + + @Test + public void testFindRoleByName() { + String input = "test"; + when(message.getGuild()).thenReturn(guild); + when(guild.getRolesByName(input, true)).thenReturn(Arrays.asList(role)); + Role returnedRole = (Role) testUnit.handle(getPieceWithValue(input), null, Role.class, message); + Assert.assertEquals(role, returnedRole); } private String getRoleMention() { diff --git a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/TextChannelParameterHandlerImplTest.java b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/TextChannelParameterHandlerImplTest.java index 13c1b7043..1adbc2e91 100644 --- a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/TextChannelParameterHandlerImplTest.java +++ b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/TextChannelParameterHandlerImplTest.java @@ -1,5 +1,6 @@ package dev.sheldan.abstracto.core.command.handler; +import dev.sheldan.abstracto.core.command.exception.AbstractoTemplatedException; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.TextChannel; @@ -8,8 +9,10 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -50,7 +53,7 @@ public class TextChannelParameterHandlerImplTest extends AbstractParameterHandle oneChannelInIterator(); String input = getChannelMention(); TextChannel parsed = (TextChannel) testUnit.handle(getPieceWithValue(input), iterators, TextChannel.class, null); - Assert.assertEquals(parsed, channel); + Assert.assertEquals(channel, parsed); } @Test @@ -58,15 +61,36 @@ public class TextChannelParameterHandlerImplTest extends AbstractParameterHandle setupMessage(); String input = CHANNEL_ID.toString(); TextChannel parsed = (TextChannel) testUnit.handle(getPieceWithValue(input), null, TextChannel.class, message); - Assert.assertEquals(parsed, channel); + Assert.assertEquals(channel, parsed); } - @Test(expected = NumberFormatException.class) - public void testInvalidChannelMention() { + @Test(expected = AbstractoTemplatedException.class) + public void testInvalidChannelName() { String input = "test"; - testUnit.handle(getPieceWithValue(input), null, TextChannel.class, null); + when(message.getGuild()).thenReturn(guild); + when(guild.getTextChannelsByName(input, true)).thenReturn(new ArrayList<>()); + testUnit.handle(getPieceWithValue(input), null, TextChannel.class, message); } + @Test(expected = AbstractoTemplatedException.class) + public void testFoundMultipleChannelsByName() { + String input = "test"; + TextChannel secondChannel = Mockito.mock(TextChannel.class); + when(message.getGuild()).thenReturn(guild); + when(guild.getTextChannelsByName(input, true)).thenReturn(Arrays.asList(channel, secondChannel)); + testUnit.handle(getPieceWithValue(input), null, TextChannel.class, message); + } + + @Test + public void testFindChannelByName() { + String input = "test"; + when(message.getGuild()).thenReturn(guild); + when(guild.getTextChannelsByName(input, true)).thenReturn(Arrays.asList(channel)); + TextChannel returnedChannel = (TextChannel) testUnit.handle(getPieceWithValue(input), null, TextChannel.class, message); + Assert.assertEquals(channel, returnedChannel); + } + + private String getChannelMention() { return String.format("<#%d>", CHANNEL_ID); } diff --git a/abstracto-application/scheduling/scheduling-impl/src/main/java/dev/sheldan/abstracto/scheduling/service/SchedulerStartupService.java b/abstracto-application/scheduling/scheduling-impl/src/main/java/dev/sheldan/abstracto/scheduling/service/SchedulerStartupService.java index 422896092..97dda795f 100644 --- a/abstracto-application/scheduling/scheduling-impl/src/main/java/dev/sheldan/abstracto/scheduling/service/SchedulerStartupService.java +++ b/abstracto-application/scheduling/scheduling-impl/src/main/java/dev/sheldan/abstracto/scheduling/service/SchedulerStartupService.java @@ -26,7 +26,7 @@ public class SchedulerStartupService { @EventListener @Transactional(isolation = Isolation.SERIALIZABLE) public void handleContextRefreshEvent(ContextRefreshedEvent ctxStartEvt) { - schedulerJobManagementServiceBean.findAll().forEach((schedulerJob) -> { + schedulerJobManagementServiceBean.findAll().forEach(schedulerJob -> { if(!schedulerJobManagementServiceBean.doesJobExist(schedulerJob) || !schedulerJobManagementServiceBean.isJobDefinitionTheSame(schedulerJob)) { schedulerJobManagementServiceBean.createOrUpdate(schedulerJob); }