package gov.nysenate.openleg.service.slack;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimaps;
import gov.nysenate.openleg.model.slack.SlackAddress;
import gov.nysenate.openleg.model.slack.SlackMessage;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;
@Service
public class DefaultSlackChatService implements SlackChatService {
private static final Logger logger = LoggerFactory.getLogger(DefaultSlackChatService.class);
@Value("${slack.webhook.url}")
private String webhookUrl;
private SlackApi slackApi;
@PostConstruct
public void init() {
try {
slackApi = new SlackApi(webhookUrl);
} catch (IllegalArgumentException ex) {
slackApi = null;
logger.error("Invalid Slack webhook URL! " +
"Slack messages will NOT be sent:\n" + ex.getMessage());
}
}
/** {@inheritDoc} */
@Override
public void sendMessage(String text) {
sendMessage(new SlackMessage(text));
}
/** {@inheritDoc} */
@Override
public void sendMessage(String text, Collection<String> mentions) {
sendMessage(new SlackMessage(text).setMentions(mentions));
}
/** {@inheritDoc} */
@Override
public void sendMessage(SlackMessage message) {
if (slackApi == null) {
throw new IllegalStateException("slackApi is null!");
}
try {
slackApi.call(message);
} catch (SlackChannelNotFoundException ex) {
logger.warn("Attempt to post slack message to invalid channel: " + ex.getChannelName());
}
}
/** {@inheritDoc} */
@Override
public void sendMessage(SlackMessage messageContent, Collection<SlackAddress> addresses) {
// Clear any existing channel or mentions
messageContent.setChannel(null);
messageContent.setMentions(null);
// If there are no addresses, just send the message to default channel and get out of here
if (addresses.isEmpty()) {
sendMessage(messageContent);
return;
}
// Map addresses to their channel
HashMultimap<String, SlackAddress> channelMap =
HashMultimap.create(Multimaps.index(addresses, SlackAddress::getChannel));
// Send a message for each channel with appropriate mentions
for (String channel : channelMap.keySet()) {
SlackMessage message = new SlackMessage(messageContent);
// Set channel if it is not default
if (!SlackAddress.DEFAULT_CHANNEL_ID.equals(channel)) {
message.setChannel(channel);
}
// Set mentions to usernames mapped to channel
message.setMentions(
channelMap.get(channel).stream()
.map(SlackAddress::getUsername)
.filter(StringUtils::isNotBlank)
.collect(Collectors.toList()));
this.sendMessage(message);
}
}
/* --- Internal Methods --- */
/** Takes a collection of addresses and transforms it into
* a multimap of channels with all usernames attached to that channel */
private ListMultimap<String, String> getChannelMentionsMap(
Collection<SlackAddress> addresses) {
ListMultimap<String, String> channelMentionsMap = ArrayListMultimap.create();
addresses.forEach(address ->
channelMentionsMap.put(address.getChannel(), address.getUsername()));
return channelMentionsMap;
}
}