From 20d5f37b51297678390e9afad867391bc1936e32 Mon Sep 17 00:00:00 2001 From: Ian Gulliver Date: Thu, 27 Oct 2022 23:38:49 +0000 Subject: [PATCH] Split out slack-specific code --- slack.go | 232 +++++++++++++++++++++++++++++++++++++++++++++++++ slack2asana.go | 227 ++--------------------------------------------- 2 files changed, 238 insertions(+), 221 deletions(-) create mode 100644 slack.go diff --git a/slack.go b/slack.go new file mode 100644 index 0000000..4cf7d04 --- /dev/null +++ b/slack.go @@ -0,0 +1,232 @@ +package main + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "net/http" + "net/url" + "os" +) + +type SlackClient struct { + cli *http.Client + token string +} + +type removeStarRequest struct { + Channel string `json:"channel"` + Timestamp string `json:"timestamp"` +} + +type channelResponse struct { + Ok bool `json:"ok"` + Error string `json:"error"` + Channel *Channel `json:"channel"` +} + +type starsResponse struct { + Ok bool `json:"ok"` + Error string `json:"error"` + Items []*Item `json:"items"` +} + +type userResponse struct { + Ok bool `json:"ok"` + Error string `json:"error"` + User *User `json:"user"` +} + +type simpleResponse struct { + Ok bool `json:"ok"` + Error string `json:"error"` +} + +type Channel struct { + Id string `json:"id"` + Name string `json:"name"` + IsChannel bool `json:"is_channel"` + IsGroup bool `json:"is_group"` + IsIm bool `json:"is_im"` +} + +type Item struct { + Type string `json:"type"` + Channel string `json:"channel"` + Message *Message `json:"message"` +} + +type Message struct { + ClientMessageId string `json:"client_msg_id"` + Text string `json:"text"` + User string `json:"user"` + Ts string `json:"ts"` + Permalink string `json:"permalink"` +} + +type User struct { + Id string `json:"id"` + Name string `json:"name"` +} + +func NewSlackClient() *SlackClient { + return &SlackClient{ + cli: &http.Client{}, + token: os.Getenv("SLACK_TOKEN"), + } +} + +func (sc *SlackClient) GetStars() ([]*Item, error) { + req, err := http.NewRequest("GET", "https://slack.com/api/stars.list", nil) + if err != nil { + return nil, err + } + + sc.addAuth(req) + + resp, err := sc.cli.Do(req) + if err != nil { + return nil, err + } + + dec := json.NewDecoder(resp.Body) + stars := &starsResponse{} + + err = dec.Decode(stars) + if err != nil { + return nil, err + } + + if !stars.Ok { + return nil, errors.New(stars.Error) + } + + return stars.Items, nil +} + +func (sc *SlackClient) GetUser(id string) (*User, error) { + u, err := url.Parse("https://slack.com/api/users.info") + if err != nil { + return nil, err + } + + v := &url.Values{} + v.Add("user", id) + u.RawQuery = v.Encode() + + req, err := http.NewRequest("GET", u.String(), nil) + if err != nil { + return nil, err + } + + sc.addAuth(req) + + resp, err := sc.cli.Do(req) + if err != nil { + return nil, err + } + + dec := json.NewDecoder(resp.Body) + user := &userResponse{} + + err = dec.Decode(user) + if err != nil { + return nil, err + } + + if !user.Ok { + return nil, errors.New(user.Error) + } + + return user.User, nil +} + +func (sc *SlackClient) GetChannel(id string) (*Channel, error) { + u, err := url.Parse("https://slack.com/api/conversations.info") + if err != nil { + return nil, err + } + + v := &url.Values{} + v.Add("channel", id) + u.RawQuery = v.Encode() + + req, err := http.NewRequest("GET", u.String(), nil) + if err != nil { + return nil, err + } + + sc.addAuth(req) + + resp, err := sc.cli.Do(req) + if err != nil { + return nil, err + } + + dec := json.NewDecoder(resp.Body) + channel := &channelResponse{} + + err = dec.Decode(channel) + if err != nil { + return nil, err + } + + if !channel.Ok { + return nil, errors.New(channel.Error) + } + + return channel.Channel, nil +} + +func (sc *SlackClient) RemoveStar(item *Item) error { + body := &removeStarRequest{ + Channel: item.Channel, + Timestamp: item.Message.Ts, + } + + js, err := json.Marshal(body) + if err != nil { + return err + } + + req, err := http.NewRequest("POST", "https://slack.com/api/stars.remove", bytes.NewReader(js)) + if err != nil { + return err + } + + sc.addAuth(req) + req.Header.Add("Content-Type", "application/json") + + resp, err := sc.cli.Do(req) + if err != nil { + return err + } + + dec := json.NewDecoder(resp.Body) + sr := &simpleResponse{} + + err = dec.Decode(sr) + if err != nil { + return err + } + + if !sr.Ok { + return errors.New(sr.Error) + } + + return nil +} + +func (sc *SlackClient) GetTitle(item *Item, user *User, channel *Channel) (string, error) { + switch { + case channel.IsIm: + return fmt.Sprintf("[%s] %s", user.Name, item.Message.Text), nil + default: + return "", fmt.Errorf("unknown channel type: %#v", channel) + } +} + +func (sc *SlackClient) addAuth(req *http.Request) { + req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", sc.token)) +} diff --git a/slack2asana.go b/slack2asana.go index 237b54d..da7d5a3 100644 --- a/slack2asana.go +++ b/slack2asana.go @@ -1,74 +1,13 @@ package main import ( - "bytes" - "encoding/json" - "errors" "fmt" - "net/http" - "net/url" - "os" ) -type RemoveStarRequest struct { - Channel string `json:"channel"` - Timestamp string `json:"timestamp"` -} - -type ChannelResponse struct { - Ok bool `json:"ok"` - Error string `json:"error"` - Channel *Channel `json:"channel"` -} - -type StarsResponse struct { - Ok bool `json:"ok"` - Error string `json:"error"` - Items []*Item `json:"items"` -} - -type UserResponse struct { - Ok bool `json:"ok"` - Error string `json:"error"` - User *User `json:"user"` -} - -type Channel struct { - Id string `json:"id"` - Name string `json:"name"` - IsChannel bool `json:"is_channel"` - IsGroup bool `json:"is_group"` - IsIm bool `json:"is_im"` -} - -type Item struct { - Type string `json:"type"` - Channel string `json:"channel"` - Message *Message `json:"message"` -} - -type Message struct { - ClientMessageId string `json:"client_msg_id"` - Text string `json:"text"` - User string `json:"user"` - Ts string `json:"ts"` - Permalink string `json:"permalink"` -} - -type User struct { - Id string `json:"id"` - Name string `json:"name"` -} - -type SimpleResponse struct { - Ok bool `json:"ok"` - Error string `json:"error"` -} - func main() { - c := &http.Client{} + sc := NewSlackClient() - stars, err := getStars(c) + stars, err := sc.GetStars() if err != nil { panic(err) } @@ -78,180 +17,26 @@ func main() { continue } - user, err := getUser(c, item.Message.User) + user, err := sc.GetUser(item.Message.User) if err != nil { panic(err) } - channel, err := getChannel(c, item.Channel) + channel, err := sc.GetChannel(item.Channel) if err != nil { panic(err) } - title, err := getTitle(item, user, channel) + title, err := sc.GetTitle(item, user, channel) if err != nil { panic(err) } fmt.Printf("%s\n", title) - err = removeStar(c, item) + err = sc.RemoveStar(item) if err != nil { panic(err) } } } - -func getTitle(item *Item, user *User, channel *Channel) (string, error) { - switch { - case channel.IsIm: - return fmt.Sprintf("[%s] %s", user.Name, item.Message.Text), nil - default: - return "", fmt.Errorf("unknown channel type: %#v", channel) - } -} - -func getStars(c *http.Client) ([]*Item, error) { - req, err := http.NewRequest("GET", "https://slack.com/api/stars.list", nil) - if err != nil { - return nil, err - } - - addAuth(req) - - resp, err := c.Do(req) - if err != nil { - return nil, err - } - - dec := json.NewDecoder(resp.Body) - stars := &StarsResponse{} - - err = dec.Decode(stars) - if err != nil { - return nil, err - } - - if !stars.Ok { - return nil, errors.New(stars.Error) - } - - return stars.Items, nil -} - -func getUser(c *http.Client, id string) (*User, error) { - u, err := url.Parse("https://slack.com/api/users.info") - if err != nil { - return nil, err - } - - v := &url.Values{} - v.Add("user", id) - u.RawQuery = v.Encode() - - req, err := http.NewRequest("GET", u.String(), nil) - if err != nil { - return nil, err - } - - addAuth(req) - - resp, err := c.Do(req) - if err != nil { - return nil, err - } - - dec := json.NewDecoder(resp.Body) - user := &UserResponse{} - - err = dec.Decode(user) - if err != nil { - return nil, err - } - - if !user.Ok { - return nil, errors.New(user.Error) - } - - return user.User, nil -} - -func getChannel(c *http.Client, id string) (*Channel, error) { - u, err := url.Parse("https://slack.com/api/conversations.info") - if err != nil { - return nil, err - } - - v := &url.Values{} - v.Add("channel", id) - u.RawQuery = v.Encode() - - req, err := http.NewRequest("GET", u.String(), nil) - if err != nil { - return nil, err - } - - addAuth(req) - - resp, err := c.Do(req) - if err != nil { - return nil, err - } - - dec := json.NewDecoder(resp.Body) - channel := &ChannelResponse{} - - err = dec.Decode(channel) - if err != nil { - return nil, err - } - - if !channel.Ok { - return nil, errors.New(channel.Error) - } - - return channel.Channel, nil -} - -func removeStar(c *http.Client, item *Item) error { - body := &RemoveStarRequest{ - Channel: item.Channel, - Timestamp: item.Message.Ts, - } - - js, err := json.Marshal(body) - if err != nil { - return err - } - - req, err := http.NewRequest("POST", "https://slack.com/api/stars.remove", bytes.NewReader(js)) - if err != nil { - return err - } - - addAuth(req) - req.Header.Add("Content-Type", "application/json") - - resp, err := c.Do(req) - if err != nil { - return err - } - - dec := json.NewDecoder(resp.Body) - sr := &SimpleResponse{} - - err = dec.Decode(sr) - if err != nil { - return err - } - - if !sr.Ok { - return errors.New(sr.Error) - } - - return nil -} - -func addAuth(req *http.Request) { - req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", os.Getenv("SLACK_TOKEN"))) -}