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  }