From ff8ce2977d218b3bb1905c0c315e6972b53e6dc9 Mon Sep 17 00:00:00 2001 From: Oleksii Ivanov Date: Mon, 21 Nov 2022 12:17:36 +0200 Subject: [PATCH] feat: allow post message with user email --- .../element-templates/slack-connector.json | 6 +- .../connector/slack/ChatPostMessageData.java | 28 ++++++- .../slack/ChatPostMessageDataTest.java | 80 +++++++++++++++++++ 3 files changed, 110 insertions(+), 4 deletions(-) create mode 100644 connectors/slack/src/test/java/io/camunda/connector/slack/ChatPostMessageDataTest.java diff --git a/connectors/slack/element-templates/slack-connector.json b/connectors/slack/element-templates/slack-connector.json index 3b2d38f11f..d25ac08b81 100644 --- a/connectors/slack/element-templates/slack-connector.json +++ b/connectors/slack/element-templates/slack-connector.json @@ -86,7 +86,7 @@ } }, { - "label": "Channel/User Name", + "label": "Channel/User Name/Email", "group": "channel", "type": "String", "feel": "optional", @@ -97,8 +97,8 @@ "constraints": { "notEmpty": true, "pattern": { - "value": "^(#|@|=).*", - "message": "Must be a #channel, @user or FEEL expression." + "value": "(^(#|@|=).*)|(^.+[@].+[.].{2,4}$)", + "message": "Must be a #channel, @user, email or FEEL expression." } }, "condition": { diff --git a/connectors/slack/src/main/java/io/camunda/connector/slack/ChatPostMessageData.java b/connectors/slack/src/main/java/io/camunda/connector/slack/ChatPostMessageData.java index e87c14acf0..6ada8657a3 100644 --- a/connectors/slack/src/main/java/io/camunda/connector/slack/ChatPostMessageData.java +++ b/connectors/slack/src/main/java/io/camunda/connector/slack/ChatPostMessageData.java @@ -10,17 +10,22 @@ import com.slack.api.methods.SlackApiException; import com.slack.api.methods.request.chat.ChatPostMessageRequest; import com.slack.api.methods.request.users.UsersListRequest; +import com.slack.api.methods.request.users.UsersLookupByEmailRequest; import com.slack.api.methods.response.chat.ChatPostMessageResponse; import com.slack.api.methods.response.users.UsersListResponse; +import com.slack.api.methods.response.users.UsersLookupByEmailResponse; import com.slack.api.model.User; import io.camunda.connector.api.annotation.Secret; import java.io.IOException; import java.util.Objects; +import java.util.Optional; import javax.validation.constraints.NotEmpty; import org.apache.commons.text.StringEscapeUtils; public class ChatPostMessageData implements SlackRequestData { + private static final String EMAIL_REGEX = "^.+[@].+[.].{2,4}$"; + @NotEmpty @Secret private String channel; @NotEmpty @Secret private String text; @@ -28,8 +33,9 @@ public class ChatPostMessageData implements SlackRequestData { public SlackResponse invoke(MethodsClient methodsClient) throws SlackApiException, IOException { if (channel.startsWith("@")) { channel = getUserId(channel.substring(1), methodsClient); + } else if (isEmail(channel)) { + channel = getUserIdByEmail(methodsClient); } - ChatPostMessageRequest request = ChatPostMessageRequest.builder() .channel(channel) @@ -80,6 +86,26 @@ private String getUserId(String userName, MethodsClient methodsClient) { return userId; } + private boolean isEmail(final String str) { + return str.matches(EMAIL_REGEX); + } + + private String getUserIdByEmail(final MethodsClient methodsClient) + throws IOException, SlackApiException { + UsersLookupByEmailRequest lookupByEmailRequest = + UsersLookupByEmailRequest.builder().email(channel).build(); + + return Optional.ofNullable(methodsClient.usersLookupByEmail(lookupByEmailRequest)) + .map(UsersLookupByEmailResponse::getUser) + .map(User::getId) + .orElseThrow( + () -> + new RuntimeException( + "User with email " + + channel + + " not found; or unable 'users:read.email' permission")); + } + public String getChannel() { return channel; } diff --git a/connectors/slack/src/test/java/io/camunda/connector/slack/ChatPostMessageDataTest.java b/connectors/slack/src/test/java/io/camunda/connector/slack/ChatPostMessageDataTest.java new file mode 100644 index 0000000000..89abd185bd --- /dev/null +++ b/connectors/slack/src/test/java/io/camunda/connector/slack/ChatPostMessageDataTest.java @@ -0,0 +1,80 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. Licensed under a proprietary license. + * See the License.txt file for more information. You may not use this file + * except in compliance with the proprietary license. + */ +package io.camunda.connector.slack; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +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.users.UsersLookupByEmailRequest; +import com.slack.api.methods.response.chat.ChatPostMessageResponse; +import com.slack.api.methods.response.users.UsersLookupByEmailResponse; +import com.slack.api.model.Message; +import com.slack.api.model.User; +import java.io.IOException; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class ChatPostMessageDataTest { + + @Mock private MethodsClient methodsClient; + @Mock private UsersLookupByEmailResponse lookupByEmailResponse; + @Mock private User user; + @Mock private ChatPostMessageResponse chatPostMessageResponse; + + @Captor private ArgumentCaptor chatPostMessageRequest; + + private static final String USERID = "testUserId"; + + @Test + void invoke_shouldThrowExceptionWhenUserWithoutEmail() throws SlackApiException, IOException { + // Given + ChatPostMessageData chatPostMessageData = new ChatPostMessageData(); + chatPostMessageData.setChannel("test@test.com"); + when(methodsClient.usersLookupByEmail(any(UsersLookupByEmailRequest.class))).thenReturn(null); + // When and then + RuntimeException thrown = + assertThrows( + RuntimeException.class, + () -> chatPostMessageData.invoke(methodsClient), + "RuntimeException was expected"); + assertThat(thrown.getMessage()) + .contains( + "User with email test@test.com not found; or unable 'users:read.email' permission"); + } + + @Test + void invoke_shouldFindUserIdByEmail() throws SlackApiException, IOException { + // Given + ChatPostMessageData chatPostMessageData = new ChatPostMessageData(); + chatPostMessageData.setChannel("test@test.com"); + chatPostMessageData.setText("test"); + + when(methodsClient.usersLookupByEmail(any(UsersLookupByEmailRequest.class))) + .thenReturn(lookupByEmailResponse); + when(lookupByEmailResponse.getUser()).thenReturn(user); + when(user.getId()).thenReturn(USERID); + when(methodsClient.chatPostMessage(chatPostMessageRequest.capture())) + .thenReturn(chatPostMessageResponse); + when(chatPostMessageResponse.isOk()).thenReturn(true); + when(chatPostMessageResponse.getMessage()).thenReturn(new Message()); + // When + chatPostMessageData.invoke(methodsClient); + // Then + ChatPostMessageRequest value = chatPostMessageRequest.getValue(); + assertThat(value.getChannel()).isEqualTo(USERID); + } +}