diff --git a/pom.xml b/pom.xml index debcd73..7e769c0 100644 --- a/pom.xml +++ b/pom.xml @@ -64,15 +64,11 @@ snakeyaml 1.30 + - com.hubspot.slack - slack-base - 1.12 - - - com.hubspot.slack - slack-java-client - 1.12 + com.slack.api + slack-api-client + 1.23.0 org.junit.jupiter diff --git a/src/main/java/com/bbaga/githubscheduledreminderapp/application/config/SchedulerConfig.java b/src/main/java/com/bbaga/githubscheduledreminderapp/application/config/SchedulerConfig.java index eaeda62..117a752 100644 --- a/src/main/java/com/bbaga/githubscheduledreminderapp/application/config/SchedulerConfig.java +++ b/src/main/java/com/bbaga/githubscheduledreminderapp/application/config/SchedulerConfig.java @@ -4,7 +4,7 @@ import com.bbaga.githubscheduledreminderapp.application.jobs.SlackChannelMessageDelete; import com.bbaga.githubscheduledreminderapp.domain.jobs.scheduling.InstallationScanJobScheduler; import com.bbaga.githubscheduledreminderapp.domain.jobs.scheduling.NotificationJobScheduler; -import com.hubspot.slack.client.SlackClient; +import com.slack.api.methods.MethodsClient; import org.quartz.JobBuilder; import org.quartz.JobDetail; import org.quartz.Scheduler; @@ -24,7 +24,7 @@ public class SchedulerConfig { @Qualifier("Scheduler") public Scheduler schedulerBootstrap( Scheduler scheduler, - @Qualifier("slack.user") ObjectProvider slackUserClient + @Qualifier("slack.user") ObjectProvider slackUserClient ) throws Exception { JobDetail job = JobBuilder.newJob(ScheduledStateDump.class) diff --git a/src/main/java/com/bbaga/githubscheduledreminderapp/application/config/SlackClientConfig.java b/src/main/java/com/bbaga/githubscheduledreminderapp/application/config/SlackClientConfig.java index 6c4b984..7b07a7b 100644 --- a/src/main/java/com/bbaga/githubscheduledreminderapp/application/config/SlackClientConfig.java +++ b/src/main/java/com/bbaga/githubscheduledreminderapp/application/config/SlackClientConfig.java @@ -4,9 +4,8 @@ import com.bbaga.githubscheduledreminderapp.domain.notifications.slack.ChannelMessageDeleteQueueItem; import com.bbaga.githubscheduledreminderapp.domain.notifications.slack.SearchAndDeleteEventListener; import com.bbaga.githubscheduledreminderapp.domain.notifications.slack.SearchMessageQueueItem; -import com.hubspot.slack.client.SlackClient; -import com.hubspot.slack.client.SlackClientFactory; -import com.hubspot.slack.client.SlackClientRuntimeConfig; +import com.slack.api.Slack; +import com.slack.api.methods.MethodsClient; import java.io.FileInputStream; import java.nio.charset.StandardCharsets; import org.apache.commons.io.IOUtils; @@ -35,7 +34,7 @@ public class SlackClientConfig { @Bean @Qualifier("slack.app") - public SlackClient slackApp() throws Exception { + public MethodsClient slackApp() throws Exception { if (!slackApiTokenFile.isEmpty() && slackApiToken.isEmpty()) { try(FileInputStream inputStream = new FileInputStream(slackApiTokenFile)) { slackApiToken = IOUtils.toString(inputStream, StandardCharsets.UTF_8); @@ -46,16 +45,12 @@ public SlackClient slackApp() throws Exception { throw new IllegalStateException("Slack API Token must be configured, see the SLACK_API_TOKEN and SLACK_API_TOKEN_FILE environment variables."); } - SlackClientRuntimeConfig runtimeConfig = SlackClientRuntimeConfig.builder() - .setTokenSupplier(() -> slackApiToken) - .build(); - - return SlackClientFactory.defaultFactory().build(runtimeConfig); + return Slack.getInstance().methods(slackApiToken); } @Bean @Qualifier("slack.user") - public SlackClient slackUser() throws Exception { + public MethodsClient slackUser() throws Exception { if (!slackApiUserTokenFile.isEmpty() && slackApiUserToken.isEmpty()) { try(FileInputStream inputStream = new FileInputStream(slackApiUserTokenFile)) { slackApiUserToken = IOUtils.toString(inputStream, StandardCharsets.UTF_8); @@ -67,11 +62,7 @@ public SlackClient slackUser() throws Exception { return null; } - SlackClientRuntimeConfig runtimeConfig = SlackClientRuntimeConfig.builder() - .setTokenSupplier(() -> slackApiUserToken) - .build(); - - return SlackClientFactory.defaultFactory().build(runtimeConfig); + return Slack.getInstance().methods(slackApiUserToken); } @Bean diff --git a/src/main/java/com/bbaga/githubscheduledreminderapp/application/jobs/SlackChannelMessageDelete.java b/src/main/java/com/bbaga/githubscheduledreminderapp/application/jobs/SlackChannelMessageDelete.java index 2df8a19..bff44f3 100644 --- a/src/main/java/com/bbaga/githubscheduledreminderapp/application/jobs/SlackChannelMessageDelete.java +++ b/src/main/java/com/bbaga/githubscheduledreminderapp/application/jobs/SlackChannelMessageDelete.java @@ -3,8 +3,8 @@ import com.bbaga.githubscheduledreminderapp.domain.notifications.slack.BoundedUniqueQueue; import com.bbaga.githubscheduledreminderapp.domain.notifications.slack.ChannelMessageDeleteQueueItem; import com.bbaga.githubscheduledreminderapp.domain.notifications.slack.SearchMessageQueueItem; -import com.hubspot.slack.client.SlackClient; -import com.hubspot.slack.client.methods.params.chat.ChatDeleteParams; +import com.slack.api.methods.MethodsClient; +import com.slack.api.methods.request.chat.ChatDeleteRequest; import org.quartz.DisallowConcurrentExecution; import org.quartz.Job; import org.quartz.JobExecutionContext; @@ -20,14 +20,14 @@ public class SlackChannelMessageDelete implements Job { private final Logger logger = LoggerFactory.getLogger(SlackChannelMessageDelete.class); private final BoundedUniqueQueue searchMessageQueue; private final BoundedUniqueQueue channelMessageDeleteQueue; - private final SlackClient slackAppClient; - private final SlackClient slackUserClient; + private final MethodsClient slackAppClient; + private final MethodsClient slackUserClient; public SlackChannelMessageDelete( BoundedUniqueQueue searchMessageQueue, BoundedUniqueQueue channelMessageDeleteQueue, - @Qualifier("slack.app") SlackClient slackAppClient, - @Qualifier("slack.user") SlackClient slackUserClient + @Qualifier("slack.app") MethodsClient slackAppClient, + @Qualifier("slack.user") MethodsClient slackUserClient ) { this.searchMessageQueue = searchMessageQueue; this.channelMessageDeleteQueue = channelMessageDeleteQueue; @@ -55,17 +55,16 @@ private void processDeleteQueue() { try { var item = channelMessageDeleteQueue.take(); - var params = ChatDeleteParams.builder() - .setChannelId(item.getChannelId()) - .setMessageToDeleteTs(item.getMessageId()) - .setAsUser(true) + var params = ChatDeleteRequest.builder() + .channel(item.getChannelId()) + .ts(item.getMessageId()) .build(); logger.info( "Deleting: [Channel: " + item.getChannelId() + ", Message ID: " + item.getMessageId() + "]" ); - slackAppClient.deleteMessage(params); + slackAppClient.chatDelete(params); } catch (Exception exception) { logger.error(exception.getLocalizedMessage()); } @@ -80,16 +79,13 @@ private void searchAndAddMessagesToDeleteQueue() { try { var item = searchMessageQueue.take(); logger.info("Searching messages with: \"" + item.getParams().getQuery()+ "\""); - var results = slackUserClient.searchMessages(item.getParams()).join(); + var results = slackUserClient.searchMessages(item.getParams()); - results.ifOk(messages -> { - try { - messages.getMessages().getMatches().forEach(item.getAction()); - } catch (Exception exception) { - logger.error(exception.getLocalizedMessage()); - } - }); + if (!results.isOk()) { + logger.error(results.getError()); + } + results.getMessages().getMatches().forEach(item.getAction()); } catch (Exception exception) { logger.error(exception.getLocalizedMessage()); } diff --git a/src/main/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/ChannelMessageBuilder.java b/src/main/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/ChannelMessageBuilder.java index 397209c..064f66e 100644 --- a/src/main/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/ChannelMessageBuilder.java +++ b/src/main/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/ChannelMessageBuilder.java @@ -4,12 +4,14 @@ import com.bbaga.githubscheduledreminderapp.infrastructure.github.GitHubIssue; import com.bbaga.githubscheduledreminderapp.infrastructure.github.GitHubPullRequest; import com.bbaga.githubscheduledreminderapp.infrastructure.github.GitHubUser; -import com.hubspot.slack.client.models.blocks.Block; -import com.hubspot.slack.client.models.blocks.Header; -import com.hubspot.slack.client.models.blocks.Section; -import com.hubspot.slack.client.models.blocks.elements.Button; -import com.hubspot.slack.client.models.blocks.objects.Text; -import com.hubspot.slack.client.models.blocks.objects.TextType; +import static com.slack.api.model.block.Blocks.*; +import static com.slack.api.model.block.composition.BlockCompositions.*; +import static com.slack.api.model.block.element.BlockElements.*; + +import com.slack.api.model.block.HeaderBlock; +import com.slack.api.model.block.LayoutBlock; +import com.slack.api.model.block.SectionBlock; +import com.slack.api.model.block.element.ButtonElement; import java.util.Map; import java.util.stream.Collectors; import org.slf4j.Logger; @@ -31,12 +33,12 @@ public ChannelMessageBuilder(UrlBuilderInterface urlBuilder) { } @Override - public Block createHeader(String text) { - return Header.of(Text.of(TextType.PLAIN_TEXT, text)); + public HeaderBlock createHeader(String text) { + return header(h -> h.text(plainText(text))); } @Override - public Block createHeaderIssues(String text, String overflowFormat, int showing, int from) { + public SectionBlock createHeaderIssues(String text, String overflowFormat, int showing, int from) { String counter; if (showing < from) { @@ -50,7 +52,7 @@ public Block createHeaderIssues(String text, String overflowFormat, int showing, } @Override - public Block createHeaderPRs(String text, String overflowFormat, int showing, int from) { + public SectionBlock createHeaderPRs(String text, String overflowFormat, int showing, int from) { String counter; if (showing < from) { @@ -64,12 +66,12 @@ public Block createHeaderPRs(String text, String overflowFormat, int showing, in } @Override - public Block createNoResultsMessage(String text) { + public SectionBlock createNoResultsMessage(String text) { return markdownSection(text); } @Override - public Block createLine(GitHubPullRequest pullRequest, String text, Map trackingParams) { + public SectionBlock createLine(GitHubPullRequest pullRequest, String text, Map trackingParams) { String login; String mergeableState = ""; String mergeableEmoji; @@ -78,7 +80,8 @@ public Block createLine(GitHubPullRequest pullRequest, String text, Map trackingParams) { + public SectionBlock createLine(GitHubIssue issue, String text, Map trackingParams) { String login; try { @@ -135,7 +141,7 @@ public Block createLine(GitHubIssue issue, String text, Map trac login = "Unknown"; } - text = text.replaceAll("\\$login", login) + var processedText = text.replaceAll("\\$login", login) .replaceAll("\\$title", issue.getTitle()) .replaceAll("\\$repository", issue.getRepository().getFullName()) .replaceAll("\\$age", getIssueAge(issue)) @@ -143,22 +149,25 @@ public Block createLine(GitHubIssue issue, String text, Map trac .replaceAll("\\$assignee-login-links", getAssigneeLoginLinks(issue)) .replaceAll("\\$link", getUrl(issue, trackingParams)); - if (text.contains("$button")) { - text = text.replaceAll("\\$button", ""); - return markdownSection(text).withAccessory(linkButton(issue, trackingParams)); + if (processedText.contains("$button")) { + processedText = processedText.replaceAll("\\$button", ""); + var section = markdownSection(processedText); + section.setAccessory(linkButton(issue, trackingParams)); + + return section; } - return markdownSection(text); + return markdownSection(processedText); } - private Section markdownSection(String markdown) { - return Section.of(Text.of(TextType.MARKDOWN, markdown)); + private SectionBlock markdownSection(String markdown) { + return section(s -> s.text(markdownText(markdown))); } - private Button linkButton(GitHubIssue issue, Map trackingParams) { + private ButtonElement linkButton(GitHubIssue issue, Map trackingParams) { String url = getUrl(issue, trackingParams); - return Button.of(Text.of(TextType.PLAIN_TEXT, "Open"), issue.getNodeId()).withUrl(url); + return button(b -> b.text(plainText(pt -> pt.text("Open"))).value(issue.getNodeId()).url(url)); } private String getUrl(GitHubIssue issue, Map trackingParams) { diff --git a/src/main/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/ChannelMessageBuilderInterface.java b/src/main/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/ChannelMessageBuilderInterface.java index ac70f3f..db4bc81 100644 --- a/src/main/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/ChannelMessageBuilderInterface.java +++ b/src/main/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/ChannelMessageBuilderInterface.java @@ -2,14 +2,15 @@ import com.bbaga.githubscheduledreminderapp.infrastructure.github.GitHubIssue; import com.bbaga.githubscheduledreminderapp.infrastructure.github.GitHubPullRequest; -import com.hubspot.slack.client.models.blocks.Block; +import com.slack.api.model.block.HeaderBlock; +import com.slack.api.model.block.SectionBlock; import java.util.Map; public interface ChannelMessageBuilderInterface { - Block createHeader(String text); - Block createHeaderIssues(String text, String overflowFormat, int showing, int from); - Block createHeaderPRs(String text, String overflowFormat, int showing, int from); - Block createLine(GitHubPullRequest pullRequest, String text, Map trackingParams); - Block createLine(GitHubIssue issue, String text, Map trackingParams); - Block createNoResultsMessage(String text); + HeaderBlock createHeader(String text); + SectionBlock createHeaderIssues(String text, String overflowFormat, int showing, int from); + SectionBlock createHeaderPRs(String text, String overflowFormat, int showing, int from); + SectionBlock createLine(GitHubPullRequest pullRequest, String text, Map trackingParams); + SectionBlock createLine(GitHubIssue issue, String text, Map trackingParams); + SectionBlock createNoResultsMessage(String text); } diff --git a/src/main/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/ChannelNotification.java b/src/main/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/ChannelNotification.java index c8c11c2..ee3fa54 100644 --- a/src/main/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/ChannelNotification.java +++ b/src/main/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/ChannelNotification.java @@ -1,5 +1,9 @@ package com.bbaga.githubscheduledreminderapp.domain.notifications.slack; +import static com.slack.api.model.block.Blocks.divider; +import static com.slack.api.model.block.Blocks.section; +import static com.slack.api.model.block.composition.BlockCompositions.markdownText; + import com.bbaga.githubscheduledreminderapp.domain.configuration.Notification; import com.bbaga.githubscheduledreminderapp.domain.configuration.NotificationConfigurationInterface; import com.bbaga.githubscheduledreminderapp.domain.configuration.SlackNotificationConfiguration; @@ -8,16 +12,20 @@ import com.bbaga.githubscheduledreminderapp.domain.statistics.StatisticsEvent; import com.bbaga.githubscheduledreminderapp.infrastructure.github.GitHubIssue; import com.bbaga.githubscheduledreminderapp.infrastructure.github.GitHubPullRequest; -import com.hubspot.slack.client.SlackClient; -import com.hubspot.slack.client.methods.ResultSort; -import com.hubspot.slack.client.methods.ResultSortOrder; -import com.hubspot.slack.client.methods.params.chat.ChatPostMessageParams; -import com.hubspot.slack.client.methods.params.search.SearchMessagesParams; -import com.hubspot.slack.client.methods.params.users.UsersInfoParams; -import com.hubspot.slack.client.models.blocks.*; -import com.hubspot.slack.client.models.blocks.objects.Text; -import com.hubspot.slack.client.models.blocks.objects.TextType; +import com.slack.api.methods.MethodsClient; +import com.slack.api.methods.SlackApiException; +import com.slack.api.methods.request.chat.ChatPostMessageRequest; +import com.slack.api.methods.request.search.SearchMessagesRequest; +import com.slack.api.methods.response.chat.ChatPostMessageResponse; +import com.slack.api.methods.response.users.UsersInfoResponse; +import com.slack.api.model.block.HeaderBlock; +import com.slack.api.model.block.LayoutBlock; +import com.slack.api.model.block.SectionBlock; +import com.slack.api.model.block.composition.TextObject; +import java.io.IOException; import java.time.Instant; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; @@ -27,12 +35,14 @@ @Service public class ChannelNotification implements NotificationInterface { - private final SlackClient slackClient; + private final MethodsClient slackClient; private final ChannelMessageBuilderInterface messageBuilder; private final ApplicationEventPublisher eventPublisher; + private final Logger logger = LoggerFactory.getLogger(ChannelNotification.class); + public ChannelNotification( - @Qualifier("slack.app")SlackClient slackClient, + @Qualifier("slack.app")MethodsClient slackClient, ChannelMessageBuilderInterface messageBuilder, ApplicationEventPublisher eventPublisher ) { @@ -99,11 +109,11 @@ public void send(ChannelNotificationDataProvider.Data data) { templateConfig.setDeleteOldMessages(false); } - List sections = new ArrayList<>(); - List issueSections = new ArrayList<>(); - List prSections = new ArrayList<>(); + List sections = new ArrayList<>(); + List issueSections = new ArrayList<>(); + List prSections = new ArrayList<>(); - sections.add(Header.of(Text.of(TextType.PLAIN_TEXT, templateConfig.getHeaderMain()))); + sections.add(messageBuilder.createHeader(templateConfig.getHeaderMain())); var slackChannel = slackConfig.getChannel(); @@ -166,7 +176,7 @@ public void send(ChannelNotificationDataProvider.Data data) { issueSectionsSize ) ); - sections.add(Divider.builder().build()); + sections.add(divider()); sections.addAll(issueSections); } @@ -193,39 +203,40 @@ public void send(ChannelNotificationDataProvider.Data data) { prSectionsSize ) ); - sections.add(Divider.builder().build()); + sections.add(divider()); sections.addAll(prSections); } } String configIdLine = String.format("config id: _%s_", notification.getFullName()); - sections.add(Section.of(Text.of(TextType.MARKDOWN, configIdLine))); + sections.add(section(s -> s.text(markdownText(configIdLine)))); - ChatPostMessageParams.Builder paramBuilder = ChatPostMessageParams.builder(); + var requestBuilder = ChatPostMessageRequest.builder() + .channel(slackChannel); - if (templateConfig.getMode().equals(TemplateConfig.MODE_FREE_TEXT)) { - List textPieces = sections.stream().map(block -> { - Text text = null; + List textPieces = sections.stream().map(block -> { + TextObject text = null; - if (block instanceof Header) { - text = ((Header) block).getText(); - } + if (block instanceof HeaderBlock) { + text = ((HeaderBlock) block).getText(); + } - if (block instanceof SectionIF) { - text = ((SectionIF) block).getText(); - } + if (block instanceof SectionBlock) { + text = ((SectionBlock) block).getText(); + } - if (text != null) { - return text.getText(); - } + if (text != null) { + return text.getText(); + } - return null; - }).filter(Objects::nonNull).collect(Collectors.toList()); + return null; + }).filter(Objects::nonNull).collect(Collectors.toList()); - paramBuilder = paramBuilder.setText(String.join("\n", textPieces)); - } else { - paramBuilder = paramBuilder.setBlocks(sections); + requestBuilder.text(String.join("\n", textPieces)); + + if (templateConfig.getMode().equals(TemplateConfig.MODE_BLOCK)) { + requestBuilder.blocks(sections); } eventPublisher.publishEvent( @@ -234,54 +245,75 @@ public void send(ChannelNotificationDataProvider.Data data) { "notification."+notification.getFullName()+".slack.channel.posted" ) ); + ChatPostMessageResponse response; - var result = slackClient.postMessage( - paramBuilder.setChannelId(slackChannel).build() - ).join(); + try { + response = slackClient.chatPostMessage(requestBuilder.build()); + } catch (SlackApiException | IOException apiException) { + logger.error(apiException.getLocalizedMessage()); + return; + } if (!templateConfig.getDeleteOldMessages()) { return; } - result.ifOk(m -> { - String userId = m.getMessage().get("user").toString(); + if (!response.isOk()) { + logger.error(response.getError()); + return; + } - var timestampParts = m.getTs().split("\\."); - long seconds, nanoAdjustment; - Instant deleteMessagesBefore; + var message = response.getMessage(); + var userId = message.getUser(); - if (timestampParts.length > 0) { - seconds = Long.parseLong(timestampParts[0]); - nanoAdjustment = timestampParts.length > 1 ? Long.parseLong(timestampParts[1]) : 0; + var timestampParts = message.getTs().split("\\."); + long seconds, nanoAdjustment; + Instant deleteMessagesBefore; - deleteMessagesBefore = Instant.ofEpochSecond(seconds, nanoAdjustment); - } else { - // how come there is nothing? - deleteMessagesBefore = Instant.now(); - } + if (timestampParts.length > 0) { + seconds = Long.parseLong(timestampParts[0]); + nanoAdjustment = timestampParts.length > 1 ? Long.parseLong(timestampParts[1]) : 0; + + deleteMessagesBefore = Instant.ofEpochSecond(seconds, nanoAdjustment); + } else { + // how come there is nothing? + deleteMessagesBefore = Instant.now(); + } + + // Setting offset to 5 minutes + deleteMessagesBefore = deleteMessagesBefore.minusSeconds(300); + + UsersInfoResponse userInfoResponse; + + try { + userInfoResponse = slackClient.usersInfo(req -> req.user(userId)); + } catch (IOException | SlackApiException e) { + logger.error(e.getLocalizedMessage()); + return; + } + + if (!userInfoResponse.isOk()) { + logger.error(userInfoResponse.getError()); + } + + Instant finalDeleteMessagesBefore = deleteMessagesBefore; + var user = userInfoResponse.getUser(); + + if (user.getName().isEmpty()) { + logger.debug("Bot's username could not be identified. Skipping old message removal."); + } + + var searchRequest = SearchMessagesRequest.builder() + .query("in:" + slackChannel + " from:" + user.getName()) + .count(25) + .sort("timestamp") + .sortDir("desc") + .build(); - // Setting offset to 5 minutes - deleteMessagesBefore = deleteMessagesBefore.minusSeconds(300); - - var userInfoResults = slackClient.findUser(UsersInfoParams.builder().setUserId(userId).build()).join(); - Instant finalDeleteMessagesBefore = deleteMessagesBefore; - userInfoResults.ifOk(user -> { - user.getUser().getUsername().ifPresent(username -> { - - var params = SearchMessagesParams.builder() - .setCount(100) - .setQuery("in:" + slackChannel + " from:"+username) - .setSort(ResultSort.TIMESTAMP) - .setSortOrder(ResultSortOrder.DESC) - .build(); - - eventPublisher.publishEvent(SearchAndDeleteEvent.create(this, params, finalDeleteMessagesBefore)); - }); - }); - }); + eventPublisher.publishEvent(SearchAndDeleteEvent.create(this, searchRequest, finalDeleteMessagesBefore)); } - private List getTruncatedGroup(List sections, int sectionsSize, int maxGroupSize) { + private List getTruncatedGroup(List sections, int sectionsSize, int maxGroupSize) { return sections.subList(sectionsSize - maxGroupSize, sectionsSize); } } diff --git a/src/main/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/SearchAndDeleteEvent.java b/src/main/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/SearchAndDeleteEvent.java index 6257ff9..29c9be5 100644 --- a/src/main/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/SearchAndDeleteEvent.java +++ b/src/main/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/SearchAndDeleteEvent.java @@ -1,16 +1,16 @@ package com.bbaga.githubscheduledreminderapp.domain.notifications.slack; -import com.hubspot.slack.client.methods.params.search.SearchMessagesParams; +import com.slack.api.methods.request.search.SearchMessagesRequest; import java.time.Instant; import org.springframework.context.ApplicationEvent; public class SearchAndDeleteEvent extends ApplicationEvent { - final private SearchMessagesParams searchMessagesParams; + final private SearchMessagesRequest searchMessagesParams; final private Instant deleteMessagesBefore; public SearchAndDeleteEvent( Object source, - SearchMessagesParams searchMessagesParams, + SearchMessagesRequest searchMessagesParams, Instant deleteMessagesBefore ) { super(source); @@ -18,7 +18,7 @@ public SearchAndDeleteEvent( this.deleteMessagesBefore = deleteMessagesBefore; } - public SearchMessagesParams getSearchMessagesParams() { + public SearchMessagesRequest getSearchMessagesParams() { return searchMessagesParams; } @@ -28,7 +28,7 @@ public Instant getDeleteMessagesBefore() { public static SearchAndDeleteEvent create( Object source, - SearchMessagesParams searchMessagesParams, + SearchMessagesRequest searchMessagesParams, Instant deleteMessagesBefore ) { return new SearchAndDeleteEvent(source, searchMessagesParams, deleteMessagesBefore); diff --git a/src/main/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/SearchAndDeleteEventListener.java b/src/main/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/SearchAndDeleteEventListener.java index ee98c0a..67fbd2a 100644 --- a/src/main/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/SearchAndDeleteEventListener.java +++ b/src/main/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/SearchAndDeleteEventListener.java @@ -1,6 +1,6 @@ package com.bbaga.githubscheduledreminderapp.domain.notifications.slack; -import com.hubspot.slack.client.models.Message; +import com.slack.api.model.MatchedItem; import java.time.Instant; import org.springframework.context.ApplicationListener; @@ -19,8 +19,8 @@ public SearchAndDeleteEventListener( } @Override public void onApplicationEvent(SearchAndDeleteEvent event) { - var item = new SearchMessageQueueItem(event.getSearchMessagesParams(), (Message m) -> { - var timestampParts = m.getTimestamp().split("\\."); + var item = new SearchMessageQueueItem(event.getSearchMessagesParams(), (MatchedItem m) -> { + var timestampParts = m.getTs().split("\\."); long seconds, nanoAdjustment; Instant messageTimestamp; @@ -36,7 +36,7 @@ public void onApplicationEvent(SearchAndDeleteEvent event) { if (messageTimestamp.isBefore(event.getDeleteMessagesBefore())) { channelMessageDeleteQueue.put( - new ChannelMessageDeleteQueueItem(m.getTimestamp(), m.getChannel().getId()) + new ChannelMessageDeleteQueueItem(m.getTs(), m.getChannel().getId()) ); } }); diff --git a/src/main/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/SearchMessageQueueItem.java b/src/main/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/SearchMessageQueueItem.java index dcbf6c1..279b24e 100644 --- a/src/main/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/SearchMessageQueueItem.java +++ b/src/main/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/SearchMessageQueueItem.java @@ -1,24 +1,24 @@ package com.bbaga.githubscheduledreminderapp.domain.notifications.slack; -import com.hubspot.slack.client.methods.params.search.SearchMessagesParams; -import com.hubspot.slack.client.models.Message; +import com.slack.api.methods.request.search.SearchMessagesRequest; +import com.slack.api.model.MatchedItem; import java.util.Objects; import java.util.function.Consumer; public class SearchMessageQueueItem { - protected SearchMessagesParams params; - protected Consumer action; + protected SearchMessagesRequest params; + protected Consumer action; - public SearchMessageQueueItem(SearchMessagesParams params, Consumer action) { + public SearchMessageQueueItem(SearchMessagesRequest params, Consumer action) { this.params = params; this.action = action; } - public SearchMessagesParams getParams() { + public SearchMessagesRequest getParams() { return params; } - public Consumer getAction() { + public Consumer getAction() { return action; } diff --git a/src/test/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/ChannelNotificationTest.java b/src/test/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/ChannelNotificationTest.java index 8949f90..b331deb 100644 --- a/src/test/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/ChannelNotificationTest.java +++ b/src/test/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/ChannelNotificationTest.java @@ -6,17 +6,14 @@ import com.bbaga.githubscheduledreminderapp.infrastructure.github.GitHubIssue; import com.bbaga.githubscheduledreminderapp.infrastructure.github.GitHubPullRequest; import com.bbaga.githubscheduledreminderapp.infrastructure.github.GitHubUser; -import com.hubspot.algebra.Result; -import com.hubspot.slack.client.SlackClient; -import com.hubspot.slack.client.methods.params.chat.ChatPostMessageParams; -import com.hubspot.slack.client.models.blocks.Block; -import com.hubspot.slack.client.models.blocks.Divider; -import com.hubspot.slack.client.models.blocks.Header; -import com.hubspot.slack.client.models.blocks.Section; -import com.hubspot.slack.client.models.blocks.objects.Text; -import com.hubspot.slack.client.models.blocks.objects.TextType; -import com.hubspot.slack.client.models.response.SlackError; -import com.hubspot.slack.client.models.response.chat.ChatPostMessageResponse; +import com.slack.api.methods.MethodsClient; +import com.slack.api.methods.SlackApiException; +import com.slack.api.methods.request.chat.ChatPostMessageRequest; +import com.slack.api.methods.response.chat.ChatPostMessageResponse; +import com.slack.api.model.block.DividerBlock; +import com.slack.api.model.block.HeaderBlock; +import com.slack.api.model.block.LayoutBlock; +import com.slack.api.model.block.SectionBlock; import org.junit.jupiter.api.Test; import org.kohsuke.github.GHRepository; import org.mockito.ArgumentCaptor; @@ -26,26 +23,24 @@ import java.net.URL; import java.time.Instant; import java.util.*; -import java.util.concurrent.CompletableFuture; import org.springframework.context.ApplicationEventPublisher; +import static com.slack.api.model.block.Blocks.section; +import static com.slack.api.model.block.composition.BlockCompositions.plainText; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; class ChannelNotificationTest { @Test - void sendCalledWithEmptySets() { - SlackClient client = Mockito.mock(SlackClient.class); + void sendCalledWithEmptySets() throws SlackApiException, IOException { + MethodsClient client = Mockito.mock(MethodsClient.class); ChannelMessageBuilderInterface mockMessageBuilder = Mockito.mock(ChannelMessageBuilderInterface.class); - Mockito.when(mockMessageBuilder.createNoResultsMessage(Mockito.anyString())).thenReturn(Section.of(Text.of(TextType.PLAIN_TEXT, "text"))); + Mockito.when(mockMessageBuilder.createNoResultsMessage(Mockito.anyString())).thenReturn(section(s -> s.text(plainText("text")))); ApplicationEventPublisher mockEventPublisher = Mockito.mock(ApplicationEventPublisher.class); - //noinspection unchecked - Result result = (Result) Mockito.mock(Result.class); - CompletableFuture> future = new CompletableFuture<>(); - future.complete(result); + ChatPostMessageResponse result = Mockito.mock(ChatPostMessageResponse.class); ChannelNotification service = new ChannelNotification(client, mockMessageBuilder, mockEventPublisher); SlackNotificationConfiguration config = new SlackNotificationConfiguration(); @@ -54,16 +49,16 @@ void sendCalledWithEmptySets() { notification.setConfig(config); ArrayList issues = new ArrayList<>(); - Mockito.when(client.postMessage(Mockito.any())).thenReturn(future); + Mockito.when(client.chatPostMessage(Mockito.any(ChatPostMessageRequest.class))).thenReturn(result); service.send(new ChannelNotificationDataProvider.Data(notification, issues)); - Mockito.verify(client, Mockito.times(1)).postMessage(Mockito.any()); + Mockito.verify(client, Mockito.times(1)).chatPostMessage(Mockito.any(ChatPostMessageRequest.class)); } @Test - void sendCalled() throws IOException { + void sendCalled() throws IOException, SlackApiException { ApplicationEventPublisher mockEventPublisher = Mockito.mock(ApplicationEventPublisher.class); - SlackClient client = Mockito.mock(SlackClient.class); + MethodsClient client = Mockito.mock(MethodsClient.class); UrlBuilderInterface urlBuilder = Mockito.mock(UrlBuilderInterface.class); ChannelMessageBuilderInterface messageBuilder = new ChannelMessageBuilder(urlBuilder); @@ -92,10 +87,7 @@ void sendCalled() throws IOException { Mockito.when(pr.getCreatedAt()).thenReturn(Date.from(Instant.now())); Mockito.when(pr.getMergeableState()).thenReturn("clean"); - //noinspection unchecked - Result result = (Result) Mockito.mock(Result.class); - CompletableFuture> future = new CompletableFuture<>(); - future.complete(result); + ChatPostMessageResponse result = Mockito.mock(ChatPostMessageResponse.class); ChannelNotification service = new ChannelNotification(client, messageBuilder, mockEventPublisher); SlackNotificationConfiguration config = new SlackNotificationConfiguration(); @@ -106,27 +98,27 @@ void sendCalled() throws IOException { issues.add(issue); issues.add(pr); - Mockito.when(client.postMessage(Mockito.any())).thenReturn(future); + Mockito.when(client.chatPostMessage(Mockito.any(ChatPostMessageRequest.class))).thenReturn(result); service.send(new ChannelNotificationDataProvider.Data(notification, issues)); - ArgumentCaptor postCaptor = ArgumentCaptor.forClass(ChatPostMessageParams.class); + ArgumentCaptor postCaptor = ArgumentCaptor.forClass(ChatPostMessageRequest.class); // Verify message - Mockito.verify(client, Mockito.times(1)).postMessage(postCaptor.capture()); + Mockito.verify(client, Mockito.times(1)).chatPostMessage(postCaptor.capture()); - ChatPostMessageParams postMessageParams = postCaptor.getValue(); + ChatPostMessageRequest postMessageParams = postCaptor.getValue(); - List blocks = postMessageParams.getBlocks(); + List blocks = postMessageParams.getBlocks(); assertEquals(8, blocks.size()); - assertTrue(blocks.get(0) instanceof Header); - assertTrue(blocks.get(1) instanceof Section); - assertTrue(blocks.get(2) instanceof Divider); - assertTrue(blocks.get(3) instanceof Section); - assertTrue(blocks.get(4) instanceof Section); - assertTrue(blocks.get(5) instanceof Divider); - assertTrue(blocks.get(6) instanceof Section); - assertTrue(blocks.get(7) instanceof Section); + assertTrue(blocks.get(0) instanceof HeaderBlock); + assertTrue(blocks.get(1) instanceof SectionBlock); + assertTrue(blocks.get(2) instanceof DividerBlock); + assertTrue(blocks.get(3) instanceof SectionBlock); + assertTrue(blocks.get(4) instanceof SectionBlock); + assertTrue(blocks.get(5) instanceof DividerBlock); + assertTrue(blocks.get(6) instanceof SectionBlock); + assertTrue(blocks.get(7) instanceof SectionBlock); // Verify PR methods Mockito.verify(pr, Mockito.times(1)).getAdditions(); diff --git a/src/test/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/SearchMessageQueueItemTest.java b/src/test/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/SearchMessageQueueItemTest.java index 40e22bc..18803d4 100644 --- a/src/test/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/SearchMessageQueueItemTest.java +++ b/src/test/java/com/bbaga/githubscheduledreminderapp/domain/notifications/slack/SearchMessageQueueItemTest.java @@ -2,8 +2,8 @@ import static org.junit.jupiter.api.Assertions.*; -import com.hubspot.slack.client.methods.params.search.SearchMessagesParams; -import com.hubspot.slack.client.models.Message; +import com.slack.api.methods.request.search.SearchMessagesRequest; +import com.slack.api.model.MatchedItem; import java.util.function.Consumer; import org.junit.jupiter.api.Test; @@ -11,9 +11,9 @@ class SearchMessageQueueItemTest { @Test void testEquals() { - var paramsA = SearchMessagesParams.builder().setCount(10).setQuery("from:channel").build(); - var paramsB = SearchMessagesParams.builder().setCount(10).setQuery("from:channel").build(); - Consumer consumer = m -> {}; + var paramsA = SearchMessagesRequest.builder().count(10).query("from:channel").build(); + var paramsB = SearchMessagesRequest.builder().count(10).query("from:channel").build(); + Consumer consumer = m -> {}; assertEquals(new SearchMessageQueueItem(paramsA, consumer), new SearchMessageQueueItem(paramsB, consumer)); } diff --git a/src/test/java/com/bbaga/githubscheduledreminderapp/domain/sources/github/SearchIssuesSourceTest.java b/src/test/java/com/bbaga/githubscheduledreminderapp/domain/sources/github/SearchIssuesSourceTest.java index cb89b81..a2421b3 100644 --- a/src/test/java/com/bbaga/githubscheduledreminderapp/domain/sources/github/SearchIssuesSourceTest.java +++ b/src/test/java/com/bbaga/githubscheduledreminderapp/domain/sources/github/SearchIssuesSourceTest.java @@ -1,12 +1,8 @@ package com.bbaga.githubscheduledreminderapp.domain.sources.github; import com.bbaga.githubscheduledreminderapp.domain.configuration.sources.SearchIssuesSourceConfig; -import com.bbaga.githubscheduledreminderapp.domain.notifications.slack.ChannelNotificationDataProvider; import com.bbaga.githubscheduledreminderapp.domain.sources.github.search.SearchIssueBuilder; import com.bbaga.githubscheduledreminderapp.infrastructure.github.GitHubIssue; -import com.hubspot.algebra.Result; -import com.hubspot.slack.client.models.response.SlackError; -import com.hubspot.slack.client.models.response.chat.ChatPostMessageResponse; import org.junit.jupiter.api.Test; import org.kohsuke.github.*; import org.mockito.MockedStatic; @@ -15,7 +11,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.CompletableFuture; import static org.junit.jupiter.api.Assertions.assertSame; @@ -65,4 +60,4 @@ void get() throws IOException { assertSame(issueMock, issues.get(0).unwrap()); } -} \ No newline at end of file +}