Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement Slack component #120

Merged
merged 12 commits into from
May 14, 2024
10 changes: 6 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ require (
github.com/stretchr/testify v1.8.4
go.uber.org/zap v1.24.0
golang.org/x/image v0.15.0
golang.org/x/text v0.14.0
golang.org/x/text v0.15.0
google.golang.org/api v0.149.0
google.golang.org/grpc v1.61.1
google.golang.org/protobuf v1.33.0
Expand Down Expand Up @@ -73,6 +73,7 @@ require (
github.com/google/uuid v1.4.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
github.com/gorilla/websocket v1.5.1 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect
github.com/itchyny/timefmt-go v0.1.5 // indirect
github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7 // indirect
Expand All @@ -95,6 +96,7 @@ require (
github.com/rivo/uniseg v0.4.4 // indirect
github.com/rogpeppe/go-internal v1.9.0 // indirect
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca // indirect
github.com/slack-go/slack v0.12.5 // indirect
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
github.com/temoto/robotstxt v1.1.1 // indirect
github.com/zeebo/xxh3 v1.0.2 // indirect
Expand All @@ -105,12 +107,12 @@ require (
go.opentelemetry.io/otel/trace v1.24.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/mod v0.10.0 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/oauth2 v0.15.0 // indirect
golang.org/x/sync v0.5.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/tools v0.9.1 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/appengine v1.6.8 // indirect
Expand Down
16 changes: 16 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre
github.com/go-resty/resty/v2 v2.0.0/go.mod h1:dZGr0i9PLlaaTD4H/hoZIDjQ+r6xq8mgbRzHZf7f2J8=
github.com/go-resty/resty/v2 v2.12.0 h1:rsVL8P90LFvkUYq/V5BTVe203WfRIU4gvcf+yfzJzGA=
github.com/go-resty/resty/v2 v2.12.0/go.mod h1:o0yGPrkS3lOe1+eFajk6kBW8ScXzwU3hD69/gt2yB/0=
github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
Expand Down Expand Up @@ -141,6 +142,7 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
Expand All @@ -155,6 +157,9 @@ github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfF
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas=
github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU=
github.com/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg=
Expand Down Expand Up @@ -247,12 +252,15 @@ github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAm
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/simplereach/timeutils v1.2.0/go.mod h1:VVbQDfN/FHRZa1LSqcwo4kNZ62OOyqLLGQKYB3pB0Q8=
github.com/slack-go/slack v0.12.5 h1:ddZ6uz6XVaB+3MTDhoW04gG+Vc/M/X1ctC+wssy2cqs=
github.com/slack-go/slack v0.12.5/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw=
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo=
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
Expand Down Expand Up @@ -299,6 +307,8 @@ golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 h1:tnebWN09GYg9OLPss1KXj8txwZc6X6uMr6VFdcGNbHw=
golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
Expand Down Expand Up @@ -338,6 +348,8 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ=
golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM=
Expand Down Expand Up @@ -365,6 +377,8 @@ golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
Expand All @@ -383,6 +397,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
Expand Down
2 changes: 2 additions & 0 deletions pkg/connector/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/instill-ai/component/pkg/connector/pinecone/v0"
"github.com/instill-ai/component/pkg/connector/redis/v0"
"github.com/instill-ai/component/pkg/connector/restapi/v0"
"github.com/instill-ai/component/pkg/connector/slack/v0"
"github.com/instill-ai/component/pkg/connector/stabilityai/v0"
"github.com/instill-ai/component/pkg/connector/website/v0"

Expand Down Expand Up @@ -87,6 +88,7 @@ func Init(
conStore.Import(redis.Init(baseConn))
conStore.Import(restapi.Init(baseConn))
conStore.Import(website.Init(baseConn))
conStore.Import(slack.Init(baseConn))

})

Expand Down
58 changes: 58 additions & 0 deletions pkg/connector/slack/v0/README.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
title: "Slack"
lang: "en-US"
draft: false
description: "Learn about how to set up a VDP Slack connector https://github.com/instill-ai/instill-core"
---

The Slack component is a application connector that allows users to get and send message on Slack.
It can carry out the following tasks:

- [Read Message](#read-message)
- [Send Message](#send-message)

## Release Stage

`Alpha`

## Configuration

The component configuration is defined and maintained [here](https://github.com/instill-ai/component/blob/main/pkg/connector/slack/v0/config/definition.json).

## Connection

| Field | Field ID | Type | Note |
| :--- | :--- | :--- | :--- |
| token | `token` | string | Fill your token |

## Supported Tasks

### Read Message

Get the latest message since specific date

| Input | ID | Type | Description |
| :--- | :--- | :--- | :--- |
| Task ID (required) | `task` | string | `TASK_READ_MESSAGE` |
| Channel Name (required) | `channel_name` | string | A channel name display in Slack |
| Start to read date | `start_to_read_date` | string | earliest date in all read messages |
| Public channel | `is_public_channel` | boolean | Whether all members can read the channel |

| Output | ID | Type | Description |
| :--- | :--- | :--- | :--- |
| Conversations | `conversations` | array[object] | An array of conversations with thread messages |

### Send Message

send message to a specific channel

| Input | ID | Type | Description |
| :--- | :--- | :--- | :--- |
| Task ID (required) | `task` | string | `TASK_WRITE_MESSAGE` |
| Channel Name (required) | `channel_name` | string | A channel name display in Slack |
| Message (required) | `message` | string | message to be sent to the target channel |
| Public channel | `is_public_channel` | boolean | Whether all members can read the channel |

| Output | ID | Type | Description |
| :--- | :--- | :--- | :--- |
| Result | `result` | string | result for sending message |
194 changes: 194 additions & 0 deletions pkg/connector/slack/v0/apiFunctions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
package slack

import (
"fmt"
"strconv"
"time"

"github.com/slack-go/slack"
)

func loopChannelListAPI(e *execution, isPublic bool, channelName string) (string, error) {
var apiParams slack.GetConversationsParameters
setChannelType(&apiParams, isPublic)

var targetChannelID string
for {

slackChannels, nextCur, err := e.client.GetConversations(&apiParams)
if err != nil {
return "", err
}

targetChannelID := getChannelID(channelName, slackChannels)

if targetChannelID != "" {
break
}

if targetChannelID == "" && nextCur == "" {
err := fmt.Errorf("there is no match name in slack channel [%v]", channelName)
return "", err
}

apiParams.Cursor = nextCur

}

return targetChannelID, nil
}

// Todo: make it multiple options
func setChannelType(params *slack.GetConversationsParameters, isPublicChannel bool) {
if !isPublicChannel {
params.Types = append(params.Types, "private_channel")
} else {
params.Types = append(params.Types, "public_channel")
}
}

func getChannelID(channelName string, channels []slack.Channel) (channelID string) {
for _, slackChannel := range channels {
if channelName == slackChannel.Name {
return slackChannel.ID
}
}
return ""
}

func getConversationHistory(e *execution, channelID string, nextCur string) (*slack.GetConversationHistoryResponse, error) {
apiHistoryParams := slack.GetConversationHistoryParameters{
ChannelID: channelID,
Cursor: nextCur,
}

historiesResp, err := e.client.GetConversationHistory(&apiHistoryParams)
if err != nil {
return nil, err
}
if !historiesResp.Ok {
err := fmt.Errorf("slack api error: %v", historiesResp.Error)
return nil, err
}

return historiesResp, nil
}

func getConversationReply(e *execution, channelID string, ts string) ([]slack.Message, error) {
apiParams := slack.GetConversationRepliesParameters{
ChannelID: channelID,
Timestamp: ts,
}
msgs, _, nextCur, err := e.client.GetConversationReplies(&apiParams)

if err != nil {
return nil, err
}

if nextCur == "" {
return msgs, nil
}

allMsgs := msgs

for nextCur != "" {
apiParams.Cursor = nextCur
msgs, _, nextCur, err = e.client.GetConversationReplies(&apiParams)
if err != nil {
return nil, err
}
allMsgs = append(allMsgs, msgs...)
}

return allMsgs, nil
}

func setAPIRespToReadTaskResp(apiResp []slack.Message, readTaskResp *ReadTaskResp, startReadDateString string) error {

for _, msg := range apiResp {
formatedDateString, err := transformTSToDate(msg.Timestamp, time.DateOnly)
if err != nil {
return err
}

startReadDate, err := time.Parse("2006-01-02", startReadDateString)
if err != nil {
return err
}

formatedDate, err := time.Parse("2006-01-02", formatedDateString)
if err != nil {
return err
}

if startReadDate.After(formatedDate) {
continue
}

conversation := Conversation{
UserID: msg.User,
Message: msg.Text,
StartDate: formatedDateString,
LastDate: formatedDateString,
ReplyCount: msg.ReplyCount,
TS: msg.Timestamp,
}
conversation.ThreadReplyMessage = []ThreadReplyMessage{}
readTaskResp.Conversations = append(readTaskResp.Conversations, conversation)
}
return nil
}

func setRepliedToConversation(resp *ReadTaskResp, replies []slack.Message, idx int) error {
c := resp.Conversations[idx]
lastDay, err := time.Parse("2006-01-02", c.LastDate)
if err != nil {
return err
}
for _, msg := range replies {

if c.TS == msg.Timestamp {
continue
}

formatedDateTime, err := transformTSToDate(msg.Timestamp, time.RFC3339)
if err != nil {
return err
}
reply := ThreadReplyMessage{
UserID: msg.User,
DateTime: formatedDateTime,
Message: msg.Text,
}

foramtedDate, err := transformTSToDate(msg.Timestamp, time.DateOnly)
if err != nil {
return err
}

replyDate, err := time.Parse("2006-01-02", foramtedDate)
if err != nil {
return err
}

if replyDate.After(lastDay) {
replyDateString := replyDate.Format("2006-01-02")
resp.Conversations[idx].LastDate = replyDateString
}
resp.Conversations[idx].ThreadReplyMessage = append(resp.Conversations[idx].ThreadReplyMessage, reply)
}
return nil
}

func transformTSToDate(ts string, format string) (string, error) {

tsFloat, err := strconv.ParseFloat(ts, 64)
if err != nil {
return "", err
}

timestamp := time.Unix(int64(tsFloat), int64((tsFloat-float64(int64(tsFloat)))*1e9))

formatedTS := timestamp.Format(format)
return formatedTS, nil
}
Loading
Loading