github.com/shashidharatd/test-infra@v0.0.0-20171006011030-71304e1ca560/prow/slack/client.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package slack 18 19 import ( 20 "encoding/json" 21 "errors" 22 "fmt" 23 "io/ioutil" 24 "net/http" 25 "net/url" 26 "strings" 27 ) 28 29 type Logger interface { 30 Debugf(s string, v ...interface{}) 31 } 32 33 // Client allows you to provide connection to Slack API Server 34 // It contains a token that allows to authenticate connection to post and work with channels in the domain 35 type Client struct { 36 // If Logger is non-nil, log all method calls with it. 37 Logger Logger 38 39 token string 40 fake bool 41 } 42 43 const ( 44 apiURL = "https://slack.com/api/" 45 46 authTest = apiURL + "auth.test" 47 apiTest = apiURL + "api.test" 48 49 channelsList = apiURL + "channels.list" 50 51 chatPostMessage = apiURL + "chat.postMessage" 52 ) 53 54 type APIResponse struct { 55 Ok bool `json:"ok"` 56 } 57 58 type AuthResponse struct { 59 Ok bool `json:"ok"` 60 URL string `json:"url"` 61 Team string `json:"team"` 62 User string `json:"user"` 63 TeamID string `json:"team_id"` 64 UserID string `json:"user_id"` 65 } 66 67 type Channel struct { 68 ID string `json:"id"` 69 Name string `json:"name"` 70 IsChannel bool `json:"is_channel"` 71 Created int `json:"created"` 72 Creator string `json:"creator"` 73 IsArchived bool `json:"is_archived"` 74 IsGeneral bool `json:"is_general"` 75 NameNormalized string `json:"name_normalized"` 76 IsShared bool `json:"is_shared"` 77 IsOrgShared bool `json:"is_org_shared"` 78 IsMember bool `json:"is_member"` 79 Members []string `json:"members"` 80 Topic struct { 81 Value string `json:"value"` 82 Creator string `json:"creator"` 83 LastSet int `json:"last_set"` 84 } `json:"topic"` 85 Purpose struct { 86 Value string `json:"value"` 87 Creator string `json:"creator"` 88 LastSet int `json:"last_set"` 89 } `json:"purpose"` 90 PreviousNames []interface{} `json:"previous_names"` 91 NumMembers int `json:"num_members"` 92 } 93 94 type ChannelList struct { 95 Ok bool `json:"ok"` 96 Channels []Channel `json:"channels"` 97 } 98 99 // NewClient creates a slack client with an API token. 100 func NewClient(token string) *Client { 101 return &Client{ 102 token: token, 103 } 104 } 105 106 // NewFakeClient returns a client that takes no actions. 107 func NewFakeClient() *Client { 108 return &Client{ 109 fake: true, 110 } 111 } 112 113 func (sl *Client) log(methodName string, args ...interface{}) { 114 if sl.Logger == nil { 115 return 116 } 117 var as []string 118 for _, arg := range args { 119 as = append(as, fmt.Sprintf("%v", arg)) 120 } 121 sl.Logger.Debugf("%s(%s)", methodName, strings.Join(as, ", ")) 122 } 123 124 func (sl *Client) VerifyAPI() (bool, error) { 125 sl.log("VerifyAPI") 126 if sl.fake { 127 return true, nil 128 } 129 t, e := sl.postMessage(apiTest, sl.urlValues()) 130 if e != nil { 131 return false, e 132 } 133 134 var apiResponse APIResponse 135 e = json.Unmarshal(t, &apiResponse) 136 if e != nil { 137 return false, e 138 } 139 return apiResponse.Ok, nil 140 } 141 142 func (sl *Client) VerifyAuth() (bool, error) { 143 sl.log("VerifyAuth") 144 if sl.fake { 145 return true, nil 146 } 147 t, e := sl.postMessage(authTest, sl.urlValues()) 148 if e != nil { 149 return false, e 150 } 151 152 var authResponse AuthResponse 153 e = json.Unmarshal(t, &authResponse) 154 if e != nil { 155 return false, e 156 } 157 return authResponse.Ok, nil 158 } 159 160 func (sl *Client) urlValues() *url.Values { 161 uv := url.Values{} 162 uv.Add("token", sl.token) 163 return &uv 164 } 165 166 func (sl *Client) postMessage(url string, uv *url.Values) ([]byte, error) { 167 resp, err := http.PostForm(url, *uv) 168 if err != nil { 169 return nil, err 170 } 171 defer resp.Body.Close() 172 173 if resp.StatusCode != 200 { 174 t, _ := ioutil.ReadAll(resp.Body) 175 return nil, errors.New(string(t)) 176 } 177 t, _ := ioutil.ReadAll(resp.Body) 178 return t, nil 179 } 180 181 func (sl *Client) GetChannels() ([]Channel, error) { 182 sl.log("GetChannels") 183 if sl.fake { 184 return []Channel{}, nil 185 } 186 var uv *url.Values = sl.urlValues() 187 t, _ := sl.postMessage(channelsList, uv) 188 var chanList ChannelList 189 err := json.Unmarshal(t, &chanList) 190 if err != nil { 191 return nil, err 192 } 193 return chanList.Channels, nil 194 } 195 196 func (sl *Client) WriteMessage(text, channel string) error { 197 sl.log("WriteMessage", text, channel) 198 if sl.fake { 199 return nil 200 } 201 var uv *url.Values = sl.urlValues() 202 uv.Add("channel", channel) 203 uv.Add("text", text) 204 205 _, err := sl.postMessage(chatPostMessage, uv) 206 return err 207 }