Codebase list golang-github-nlopes-slack / 98192ca
Merge remote-tracking branch 'upstream/master' Pavel Kiselev 8 years ago
8 changed file(s) with 1096 addition(s) and 65 deletion(s). Raw diff Collapse all Expand all
0 package main
1
2 import (
3 "flag"
4 "fmt"
5
6 "github.com/nlopes/slack"
7 )
8
9 func main() {
10 var (
11 apiToken string
12 debug bool
13 )
14
15 flag.StringVar(&apiToken, "token", "YOUR_TOKEN_HERE", "Your Slack API Token")
16 flag.BoolVar(&debug, "debug", false, "Show JSON output")
17 flag.Parse()
18
19 api := slack.New(apiToken)
20 if debug {
21 api.SetDebug(true)
22 }
23
24 var (
25 postAsUserName string
26 postAsUserID string
27 postToUserName string
28 postToUserID string
29 postToChannelID string
30 )
31
32 // Find the user to post as.
33 authTest, err := api.AuthTest()
34 if err != nil {
35 fmt.Printf("Error getting channels: %s\n", err)
36 return
37 }
38
39 // Post as the authenticated user.
40 postAsUserName = authTest.User
41 postAsUserID = authTest.UserId
42
43 // Posting to DM with self causes a conversation with slackbot.
44 postToUserName = authTest.User
45 postToUserID = authTest.UserId
46
47 // Find the channel.
48 _, _, chanID, err := api.OpenIMChannel(postToUserID)
49 if err != nil {
50 fmt.Printf("Error opening IM: %s\n", err)
51 return
52 }
53 postToChannelID = chanID
54
55 fmt.Printf("Posting as %s (%s) in DM with %s (%s), channel %s\n", postAsUserName, postAsUserID, postToUserName, postToUserID, postToChannelID)
56
57 // Post a message.
58 postParams := slack.PostMessageParameters{}
59 channelID, timestamp, err := api.PostMessage(postToChannelID, "Is this any good?", postParams)
60 if err != nil {
61 fmt.Printf("Error posting message: %s\n", err)
62 return
63 }
64
65 // Grab a reference to the message.
66 msgRef := slack.NewRefToMessage(channelID, timestamp)
67
68 // React with :+1:
69 if err := api.AddReaction("+1", msgRef); err != nil {
70 fmt.Printf("Error adding reaction: %s\n", err)
71 return
72 }
73
74 // React with :-1:
75 if err := api.AddReaction("cry", msgRef); err != nil {
76 fmt.Printf("Error adding reaction: %s\n", err)
77 return
78 }
79
80 // Get all reactions on the message.
81 msgReactions, err := api.GetReactions(msgRef, slack.NewGetReactionsParameters())
82 if err != nil {
83 fmt.Printf("Error getting reactions: %s\n", err)
84 return
85 }
86 fmt.Printf("\n")
87 fmt.Printf("%d reactions to message...\n", len(msgReactions))
88 for _, r := range msgReactions {
89 fmt.Printf(" %d users say %s\n", r.Count, r.Name)
90 }
91
92 // List all of the users reactions.
93 listReactions, _, err := api.ListReactions(slack.NewListReactionsParameters())
94 if err != nil {
95 fmt.Printf("Error listing reactions: %s\n", err)
96 return
97 }
98 fmt.Printf("\n")
99 fmt.Printf("All reactions by %s...\n", authTest.User)
100 for _, item := range listReactions {
101 fmt.Printf("%d on a %s...\n", len(item.Reactions), item.Type)
102 for _, r := range item.Reactions {
103 fmt.Printf(" %s (along with %d others)\n", r.Name, r.Count-1)
104 }
105 }
106
107 // Remove the :cry: reaction.
108 err = api.RemoveReaction("cry", msgRef)
109 if err != nil {
110 fmt.Printf("Error remove reaction: %s\n", err)
111 return
112 }
113
114 // Get all reactions on the message.
115 msgReactions, err = api.GetReactions(msgRef, slack.NewGetReactionsParameters())
116 if err != nil {
117 fmt.Printf("Error getting reactions: %s\n", err)
118 return
119 }
120 fmt.Printf("\n")
121 fmt.Printf("%d reactions to message after removing cry...\n", len(msgReactions))
122 for _, r := range msgReactions {
123 fmt.Printf(" %d users say %s\n", r.Count, r.Name)
124 }
125 }
0 package main
1
2 import (
3 "flag"
4 "fmt"
5
6 "github.com/nlopes/slack"
7 )
8
9 func main() {
10 var (
11 apiToken string
12 debug bool
13 )
14
15 flag.StringVar(&apiToken, "token", "YOUR_TOKEN_HERE", "Your Slack API Token")
16 flag.BoolVar(&debug, "debug", false, "Show JSON output")
17 flag.Parse()
18
19 api := slack.New(apiToken)
20 if debug {
21 api.SetDebug(true)
22 }
23
24 // Get all stars for the usr.
25 params := slack.NewStarsParameters()
26 starredItems, _, err := api.GetStarred(params)
27 if err != nil {
28 fmt.Printf("Error getting stars: %s\n", err)
29 return
30 }
31 for _, s := range starredItems {
32 var desc string
33 switch s.Type {
34 case slack.TYPE_MESSAGE:
35 desc = s.Message.Text
36 case slack.TYPE_FILE:
37 desc = s.File.Name
38 case slack.TYPE_FILE_COMMENT:
39 desc = s.File.Name + " - " + s.Comment.Comment
40 case slack.TYPE_CHANNEL, slack.TYPE_IM, slack.TYPE_GROUP:
41 desc = s.Channel
42 }
43 fmt.Printf("Starred %s: %s\n", s.Type, desc)
44 }
45 }
0 package slack
1
2 const (
3 TYPE_MESSAGE = "message"
4 TYPE_FILE = "file"
5 TYPE_FILE_COMMENT = "file_comment"
6 TYPE_CHANNEL = "channel"
7 TYPE_IM = "im"
8 TYPE_GROUP = "group"
9 )
10
11 // Item is any type of slack message - message, file, or file comment.
12 type Item struct {
13 Type string `json:"type"`
14 Channel string `json:"channel,omitempty"`
15 Message *Message `json:"message,omitempty"`
16 File *File `json:"file,omitempty"`
17 Comment *Comment `json:"comment,omitempty"`
18 }
19
20 // NewMessageItem turns a message on a channel into a typed message struct.
21 func NewMessageItem(ch string, m *Message) Item {
22 return Item{Type: TYPE_MESSAGE, Channel: ch, Message: m}
23 }
24
25 // NewFileItem turns a file into a typed file struct.
26 func NewFileItem(f *File) Item {
27 return Item{Type: TYPE_FILE, File: f}
28 }
29
30 // NewFileCommentItem turns a file and comment into a typed file_comment struct.
31 func NewFileCommentItem(f *File, c *Comment) Item {
32 return Item{Type: TYPE_FILE_COMMENT, File: f, Comment: c}
33 }
34
35 // NewChannelItem turns a channel id into a typed channel struct.
36 func NewChannelItem(ch string) Item {
37 return Item{Type: TYPE_CHANNEL, Channel: ch}
38 }
39
40 // NewIMItem turns a channel id into a typed im struct.
41 func NewIMItem(ch string) Item {
42 return Item{Type: TYPE_IM, Channel: ch}
43 }
44
45 // NewGroupItem turns a channel id into a typed group struct.
46 func NewGroupItem(ch string) Item {
47 return Item{Type: TYPE_GROUP, Channel: ch}
48 }
49
50 // ItemRef is a reference to a message of any type. One of FileID,
51 // CommentId, or the combination of ChannelId and Timestamp must be
52 // specified.
53 type ItemRef struct {
54 ChannelId string `json:"channel"`
55 Timestamp string `json:"timestamp"`
56 FileId string `json:"file"`
57 CommentId string `json:"file_comment"`
58 }
59
60 // NewRefToMessage initializes a reference to to a message.
61 func NewRefToMessage(channelID, timestamp string) ItemRef {
62 return ItemRef{ChannelId: channelID, Timestamp: timestamp}
63 }
64
65 // NewRefToFile initializes a reference to a file.
66 func NewRefToFile(fileID string) ItemRef {
67 return ItemRef{FileId: fileID}
68 }
69
70 // NewRefToComment initializes a reference to a file comment.
71 func NewRefToComment(commentID string) ItemRef {
72 return ItemRef{CommentId: commentID}
73 }
0 package slack
1
2 import "testing"
3
4 func TestNewMessageItem(t *testing.T) {
5 c := "C1"
6 m := &Message{}
7 mi := NewMessageItem(c, m)
8 if mi.Type != TYPE_MESSAGE {
9 t.Errorf("want Type %s, got %s", mi.Type, TYPE_MESSAGE)
10 }
11 if mi.Channel != c {
12 t.Errorf("got Channel %s, want %s", mi.Channel, c)
13 }
14 if mi.Message != m {
15 t.Errorf("got Message %v, want %v", mi.Message, m)
16 }
17 }
18
19 func TestNewFileItem(t *testing.T) {
20 f := &File{}
21 fi := NewFileItem(f)
22 if fi.Type != TYPE_FILE {
23 t.Errorf("got Type %s, want %s", fi.Type, TYPE_FILE)
24 }
25 if fi.File != f {
26 t.Errorf("got File %v, want %v", fi.File, f)
27 }
28 }
29
30 func TestNewFileCommentItem(t *testing.T) {
31 f := &File{}
32 c := &Comment{}
33 fci := NewFileCommentItem(f, c)
34 if fci.Type != TYPE_FILE_COMMENT {
35 t.Errorf("got Type %s, want %s", fci.Type, TYPE_FILE_COMMENT)
36 }
37 if fci.File != f {
38 t.Errorf("got File %v, want %v", fci.File, f)
39 }
40 if fci.Comment != c {
41 t.Errorf("got Comment %v, want %v", fci.Comment, c)
42 }
43 }
44
45 func TestNewChannelItem(t *testing.T) {
46 c := "C1"
47 ci := NewChannelItem(c)
48 if ci.Type != TYPE_CHANNEL {
49 t.Errorf("got Type %s, want %s", ci.Type, TYPE_CHANNEL)
50 }
51 if ci.Channel != "C1" {
52 t.Errorf("got Channel %v, want %v", ci.Channel, "C1")
53 }
54 }
55
56 func TestNewIMItem(t *testing.T) {
57 c := "D1"
58 ci := NewIMItem(c)
59 if ci.Type != TYPE_IM {
60 t.Errorf("got Type %s, want %s", ci.Type, TYPE_IM)
61 }
62 if ci.Channel != "D1" {
63 t.Errorf("got Channel %v, want %v", ci.Channel, "D1")
64 }
65 }
66
67 func TestNewGroupItem(t *testing.T) {
68 c := "G1"
69 ci := NewGroupItem(c)
70 if ci.Type != TYPE_GROUP {
71 t.Errorf("got Type %s, want %s", ci.Type, TYPE_GROUP)
72 }
73 if ci.Channel != "G1" {
74 t.Errorf("got Channel %v, want %v", ci.Channel, "G1")
75 }
76 }
77
78 func TestNewRefToMessage(t *testing.T) {
79 ref := NewRefToMessage("chan", "ts")
80 if got, want := ref.ChannelId, "chan"; got != want {
81 t.Errorf("ChannelId got %s, want %s", got, want)
82 }
83 if got, want := ref.Timestamp, "ts"; got != want {
84 t.Errorf("Timestamp got %s, want %s", got, want)
85 }
86 if got, want := ref.FileId, ""; got != want {
87 t.Errorf("FileId got %s, want %s", got, want)
88 }
89 if got, want := ref.CommentId, ""; got != want {
90 t.Errorf("CommentId got %s, want %s", got, want)
91 }
92 }
93
94 func TestNewRefToFile(t *testing.T) {
95 ref := NewRefToFile("file")
96 if got, want := ref.ChannelId, ""; got != want {
97 t.Errorf("ChannelId got %s, want %s", got, want)
98 }
99 if got, want := ref.Timestamp, ""; got != want {
100 t.Errorf("Timestamp got %s, want %s", got, want)
101 }
102 if got, want := ref.FileId, "file"; got != want {
103 t.Errorf("FileId got %s, want %s", got, want)
104 }
105 if got, want := ref.CommentId, ""; got != want {
106 t.Errorf("CommentId got %s, want %s", got, want)
107 }
108 }
109
110 func TestNewRefToComment(t *testing.T) {
111 ref := NewRefToComment("file_comment")
112 if got, want := ref.ChannelId, ""; got != want {
113 t.Errorf("ChannelId got %s, want %s", got, want)
114 }
115 if got, want := ref.Timestamp, ""; got != want {
116 t.Errorf("Timestamp got %s, want %s", got, want)
117 }
118 if got, want := ref.FileId, ""; got != want {
119 t.Errorf("FileId got %s, want %s", got, want)
120 }
121 if got, want := ref.CommentId, "file_comment"; got != want {
122 t.Errorf("CommentId got %s, want %s", got, want)
123 }
124 }
0 package slack
1
2 import (
3 "errors"
4 "net/url"
5 "strconv"
6 )
7
8 // ItemReaction is the reactions that have happened on an item.
9 type ItemReaction struct {
10 Name string `json:"name"`
11 Count int `json:"count"`
12 Users []string `json:"users"`
13 }
14
15 // ReactedItem is an item that was reacted to, and the details of the
16 // reactions.
17 type ReactedItem struct {
18 Item
19 Reactions []ItemReaction
20 }
21
22 // GetReactionsParameters is the inputs to get reactions to an item.
23 type GetReactionsParameters struct {
24 Full bool
25 }
26
27 // NewGetReactionsParameters initializes the inputs to get reactions to an item.
28 func NewGetReactionsParameters() GetReactionsParameters {
29 return GetReactionsParameters{
30 Full: false,
31 }
32 }
33
34 type getReactionsResponseFull struct {
35 Type string
36 M struct {
37 Reactions []ItemReaction
38 } `json:"message"`
39 F struct {
40 Reactions []ItemReaction
41 } `json:"file"`
42 FC struct {
43 Reactions []ItemReaction
44 } `json:"comment"`
45 SlackResponse
46 }
47
48 func (res getReactionsResponseFull) extractReactions() []ItemReaction {
49 switch res.Type {
50 case "message":
51 return res.M.Reactions
52 case "file":
53 return res.F.Reactions
54 case "file_comment":
55 return res.FC.Reactions
56 }
57 return []ItemReaction{}
58 }
59
60 const (
61 DEFAULT_REACTIONS_USERID = ""
62 DEFAULT_REACTIONS_COUNT = 100
63 DEFAULT_REACTIONS_PAGE = 1
64 DEFAULT_REACTIONS_FULL = false
65 )
66
67 // ListReactionsParameters is the inputs to find all reactions by a user.
68 type ListReactionsParameters struct {
69 UserId string
70 Count int
71 Page int
72 Full bool
73 }
74
75 // NewListReactionsParameters initializes the inputs to find all reactions
76 // performed by a user.
77 func NewListReactionsParameters() ListReactionsParameters {
78 return ListReactionsParameters{
79 UserId: DEFAULT_REACTIONS_USERID,
80 Count: DEFAULT_REACTIONS_COUNT,
81 Page: DEFAULT_REACTIONS_PAGE,
82 Full: DEFAULT_REACTIONS_FULL,
83 }
84 }
85
86 type listReactionsResponseFull struct {
87 Items []struct {
88 Type string
89 Channel string
90 M struct {
91 *Message
92 Reactions []ItemReaction
93 } `json:"message"`
94 F struct {
95 *File
96 Reactions []ItemReaction
97 } `json:"file"`
98 FC struct {
99 *Comment
100 Reactions []ItemReaction
101 } `json:"comment"`
102 }
103 Paging `json:"paging"`
104 SlackResponse
105 }
106
107 func (res listReactionsResponseFull) extractReactedItems() []ReactedItem {
108 items := make([]ReactedItem, len(res.Items))
109 for i, input := range res.Items {
110 item := ReactedItem{}
111 item.Type = input.Type
112 switch input.Type {
113 case "message":
114 item.Channel = input.Channel
115 item.Message = input.M.Message
116 item.Reactions = input.M.Reactions
117 case "file":
118 item.File = input.F.File
119 item.Reactions = input.F.Reactions
120 case "file_comment":
121 item.File = input.F.File
122 item.Comment = input.FC.Comment
123 item.Reactions = input.FC.Reactions
124 }
125 items[i] = item
126 }
127 return items
128 }
129
130 // AddReaction adds a reaction emoji to a message, file or file comment.
131 func (api *Slack) AddReaction(name string, item ItemRef) error {
132 values := url.Values{
133 "token": {api.config.token},
134 }
135 if name != "" {
136 values.Set("name", name)
137 }
138 if item.ChannelId != "" {
139 values.Set("channel", string(item.ChannelId))
140 }
141 if item.Timestamp != "" {
142 values.Set("timestamp", string(item.Timestamp))
143 }
144 if item.FileId != "" {
145 values.Set("file", string(item.FileId))
146 }
147 if item.CommentId != "" {
148 values.Set("file_comment", string(item.CommentId))
149 }
150 response := &SlackResponse{}
151 if err := parseResponse("reactions.add", values, response, api.debug); err != nil {
152 return err
153 }
154 if !response.Ok {
155 return errors.New(response.Error)
156 }
157 return nil
158 }
159
160 // RemoveReaction removes a reaction emoji from a message, file or file comment.
161 func (api *Slack) RemoveReaction(name string, item ItemRef) error {
162 values := url.Values{
163 "token": {api.config.token},
164 }
165 if name != "" {
166 values.Set("name", name)
167 }
168 if item.ChannelId != "" {
169 values.Set("channel", string(item.ChannelId))
170 }
171 if item.Timestamp != "" {
172 values.Set("timestamp", string(item.Timestamp))
173 }
174 if item.FileId != "" {
175 values.Set("file", string(item.FileId))
176 }
177 if item.CommentId != "" {
178 values.Set("file_comment", string(item.CommentId))
179 }
180 response := &SlackResponse{}
181 if err := parseResponse("reactions.remove", values, response, api.debug); err != nil {
182 return err
183 }
184 if !response.Ok {
185 return errors.New(response.Error)
186 }
187 return nil
188 }
189
190 // GetReactions returns details about the reactions on an item.
191 func (api *Slack) GetReactions(item ItemRef, params GetReactionsParameters) ([]ItemReaction, error) {
192 values := url.Values{
193 "token": {api.config.token},
194 }
195 if item.ChannelId != "" {
196 values.Set("channel", string(item.ChannelId))
197 }
198 if item.Timestamp != "" {
199 values.Set("timestamp", string(item.Timestamp))
200 }
201 if item.FileId != "" {
202 values.Set("file", string(item.FileId))
203 }
204 if item.CommentId != "" {
205 values.Set("file_comment", string(item.CommentId))
206 }
207 if params.Full != DEFAULT_REACTIONS_FULL {
208 values.Set("full", strconv.FormatBool(params.Full))
209 }
210 response := &getReactionsResponseFull{}
211 if err := parseResponse("reactions.get", values, response, api.debug); err != nil {
212 return nil, err
213 }
214 if !response.Ok {
215 return nil, errors.New(response.Error)
216 }
217 return response.extractReactions(), nil
218 }
219
220 // ListReactions returns information about the items a user reacted to.
221 func (api *Slack) ListReactions(params ListReactionsParameters) ([]ReactedItem, *Paging, error) {
222 values := url.Values{
223 "token": {api.config.token},
224 }
225 if params.UserId != DEFAULT_REACTIONS_USERID {
226 values.Add("user", params.UserId)
227 }
228 if params.Count != DEFAULT_REACTIONS_COUNT {
229 values.Add("count", strconv.Itoa(params.Count))
230 }
231 if params.Page != DEFAULT_REACTIONS_PAGE {
232 values.Add("page", strconv.Itoa(params.Page))
233 }
234 if params.Full != DEFAULT_REACTIONS_FULL {
235 values.Add("full", strconv.FormatBool(params.Full))
236 }
237 response := &listReactionsResponseFull{}
238 err := parseResponse("reactions.list", values, response, api.debug)
239 if err != nil {
240 return nil, nil, err
241 }
242 if !response.Ok {
243 return nil, nil, errors.New(response.Error)
244 }
245 return response.extractReactedItems(), &response.Paging, nil
246 }
0 package slack
1
2 import (
3 "fmt"
4 "net/http"
5 "reflect"
6 "testing"
7 )
8
9 type reactionsHandler struct {
10 gotParams map[string]string
11 response string
12 }
13
14 func newReactionsHandler() *reactionsHandler {
15 return &reactionsHandler{
16 gotParams: make(map[string]string),
17 response: `{ "ok": true }`,
18 }
19 }
20
21 func (rh *reactionsHandler) accumulateFormValue(k string, r *http.Request) {
22 if v := r.FormValue(k); v != "" {
23 rh.gotParams[k] = v
24 }
25 }
26
27 func (rh *reactionsHandler) handler(w http.ResponseWriter, r *http.Request) {
28 rh.accumulateFormValue("channel", r)
29 rh.accumulateFormValue("count", r)
30 rh.accumulateFormValue("file", r)
31 rh.accumulateFormValue("file_comment", r)
32 rh.accumulateFormValue("full", r)
33 rh.accumulateFormValue("name", r)
34 rh.accumulateFormValue("page", r)
35 rh.accumulateFormValue("timestamp", r)
36 rh.accumulateFormValue("user", r)
37 w.Header().Set("Content-Type", "application/json")
38 w.Write([]byte(rh.response))
39 }
40
41 func TestSlack_AddReaction(t *testing.T) {
42 once.Do(startServer)
43 SLACK_API = "http://" + serverAddr + "/"
44 api := New("testing-token")
45 tests := []struct {
46 name string
47 ref ItemRef
48 wantParams map[string]string
49 }{
50 {
51 "thumbsup",
52 NewRefToMessage("ChannelID", "123"),
53 map[string]string{
54 "name": "thumbsup",
55 "channel": "ChannelID",
56 "timestamp": "123",
57 },
58 },
59 {
60 "thumbsup",
61 NewRefToFile("FileID"),
62 map[string]string{
63 "name": "thumbsup",
64 "file": "FileID",
65 },
66 },
67 {
68 "thumbsup",
69 NewRefToComment("FileCommentID"),
70 map[string]string{
71 "name": "thumbsup",
72 "file_comment": "FileCommentID",
73 },
74 },
75 }
76 var rh *reactionsHandler
77 http.HandleFunc("/reactions.add", func(w http.ResponseWriter, r *http.Request) { rh.handler(w, r) })
78 for i, test := range tests {
79 rh = newReactionsHandler()
80 err := api.AddReaction(test.name, test.ref)
81 if err != nil {
82 t.Fatalf("%d: Unexpected error: %s", i, err)
83 }
84 if !reflect.DeepEqual(rh.gotParams, test.wantParams) {
85 t.Errorf("%d: Got params %#v, want %#v", i, rh.gotParams, test.wantParams)
86 }
87 }
88 }
89
90 func TestSlack_RemoveReaction(t *testing.T) {
91 once.Do(startServer)
92 SLACK_API = "http://" + serverAddr + "/"
93 api := New("testing-token")
94 tests := []struct {
95 name string
96 ref ItemRef
97 wantParams map[string]string
98 }{
99 {
100 "thumbsup",
101 NewRefToMessage("ChannelID", "123"),
102 map[string]string{
103 "name": "thumbsup",
104 "channel": "ChannelID",
105 "timestamp": "123",
106 },
107 },
108 {
109 "thumbsup",
110 NewRefToFile("FileID"),
111 map[string]string{
112 "name": "thumbsup",
113 "file": "FileID",
114 },
115 },
116 {
117 "thumbsup",
118 NewRefToComment("FileCommentID"),
119 map[string]string{
120 "name": "thumbsup",
121 "file_comment": "FileCommentID",
122 },
123 },
124 }
125 var rh *reactionsHandler
126 http.HandleFunc("/reactions.remove", func(w http.ResponseWriter, r *http.Request) { rh.handler(w, r) })
127 for i, test := range tests {
128 rh = newReactionsHandler()
129 err := api.RemoveReaction(test.name, test.ref)
130 if err != nil {
131 t.Fatalf("%d: Unexpected error: %s", i, err)
132 }
133 if !reflect.DeepEqual(rh.gotParams, test.wantParams) {
134 t.Errorf("%d: Got params %#v, want %#v", i, rh.gotParams, test.wantParams)
135 }
136 }
137 }
138
139 func TestSlack_GetReactions(t *testing.T) {
140 once.Do(startServer)
141 SLACK_API = "http://" + serverAddr + "/"
142 api := New("testing-token")
143 tests := []struct {
144 ref ItemRef
145 params GetReactionsParameters
146 wantParams map[string]string
147 json string
148 wantReactions []ItemReaction
149 }{
150 {
151 NewRefToMessage("ChannelID", "123"),
152 GetReactionsParameters{},
153 map[string]string{
154 "channel": "ChannelID",
155 "timestamp": "123",
156 },
157 `{"ok": true,
158 "type": "message",
159 "message": {
160 "reactions": [
161 {
162 "name": "astonished",
163 "count": 3,
164 "users": [ "U1", "U2", "U3" ]
165 },
166 {
167 "name": "clock1",
168 "count": 3,
169 "users": [ "U1", "U2" ]
170 }
171 ]
172 }}`,
173 []ItemReaction{
174 ItemReaction{Name: "astonished", Count: 3, Users: []string{"U1", "U2", "U3"}},
175 ItemReaction{Name: "clock1", Count: 3, Users: []string{"U1", "U2"}},
176 },
177 },
178 {
179 NewRefToFile("FileID"),
180 GetReactionsParameters{Full: true},
181 map[string]string{
182 "file": "FileID",
183 "full": "true",
184 },
185 `{"ok": true,
186 "type": "file",
187 "file": {
188 "reactions": [
189 {
190 "name": "astonished",
191 "count": 3,
192 "users": [ "U1", "U2", "U3" ]
193 },
194 {
195 "name": "clock1",
196 "count": 3,
197 "users": [ "U1", "U2" ]
198 }
199 ]
200 }}`,
201 []ItemReaction{
202 ItemReaction{Name: "astonished", Count: 3, Users: []string{"U1", "U2", "U3"}},
203 ItemReaction{Name: "clock1", Count: 3, Users: []string{"U1", "U2"}},
204 },
205 },
206 {
207
208 NewRefToComment("FileCommentID"),
209 GetReactionsParameters{},
210 map[string]string{
211 "file_comment": "FileCommentID",
212 },
213 `{"ok": true,
214 "type": "file_comment",
215 "file": {},
216 "comment": {
217 "reactions": [
218 {
219 "name": "astonished",
220 "count": 3,
221 "users": [ "U1", "U2", "U3" ]
222 },
223 {
224 "name": "clock1",
225 "count": 3,
226 "users": [ "U1", "U2" ]
227 }
228 ]
229 }}`,
230 []ItemReaction{
231 ItemReaction{Name: "astonished", Count: 3, Users: []string{"U1", "U2", "U3"}},
232 ItemReaction{Name: "clock1", Count: 3, Users: []string{"U1", "U2"}},
233 },
234 },
235 }
236 var rh *reactionsHandler
237 http.HandleFunc("/reactions.get", func(w http.ResponseWriter, r *http.Request) { rh.handler(w, r) })
238 for i, test := range tests {
239 rh = newReactionsHandler()
240 rh.response = test.json
241 got, err := api.GetReactions(test.ref, test.params)
242 if err != nil {
243 t.Fatalf("%d: Unexpected error: %s", i, err)
244 }
245 if !reflect.DeepEqual(got, test.wantReactions) {
246 t.Errorf("%d: Got reaction %#v, want %#v", i, got, test.wantReactions)
247 }
248 if !reflect.DeepEqual(rh.gotParams, test.wantParams) {
249 t.Errorf("%d: Got params %#v, want %#v", i, rh.gotParams, test.wantParams)
250 }
251 }
252 }
253
254 func TestSlack_ListReactions(t *testing.T) {
255 once.Do(startServer)
256 SLACK_API = "http://" + serverAddr + "/"
257 api := New("testing-token")
258 rh := newReactionsHandler()
259 http.HandleFunc("/reactions.list", func(w http.ResponseWriter, r *http.Request) { rh.handler(w, r) })
260 rh.response = `{"ok": true,
261 "items": [
262 {
263 "type": "message",
264 "channel": "C1",
265 "message": {
266 "text": "hello",
267 "reactions": [
268 {
269 "name": "astonished",
270 "count": 3,
271 "users": [ "U1", "U2", "U3" ]
272 },
273 {
274 "name": "clock1",
275 "count": 3,
276 "users": [ "U1", "U2" ]
277 }
278 ]
279 }
280 },
281 {
282 "type": "file",
283 "file": {
284 "name": "toy",
285 "reactions": [
286 {
287 "name": "clock1",
288 "count": 3,
289 "users": [ "U1", "U2" ]
290 }
291 ]
292 }
293 },
294 {
295 "type": "file_comment",
296 "file": {
297 "name": "toy"
298 },
299 "comment": {
300 "comment": "cool toy",
301 "reactions": [
302 {
303 "name": "astonished",
304 "count": 3,
305 "users": [ "U1", "U2", "U3" ]
306 }
307 ]
308 }
309 }
310 ],
311 "paging": {
312 "count": 100,
313 "total": 4,
314 "page": 1,
315 "pages": 1
316 }}`
317 want := []ReactedItem{
318 ReactedItem{
319 Item: NewMessageItem("C1", &Message{Msg: Msg{Text: "hello"}}),
320 Reactions: []ItemReaction{
321 ItemReaction{Name: "astonished", Count: 3, Users: []string{"U1", "U2", "U3"}},
322 ItemReaction{Name: "clock1", Count: 3, Users: []string{"U1", "U2"}},
323 },
324 },
325 ReactedItem{
326 Item: NewFileItem(&File{Name: "toy"}),
327 Reactions: []ItemReaction{
328 ItemReaction{Name: "clock1", Count: 3, Users: []string{"U1", "U2"}},
329 },
330 },
331 ReactedItem{
332 Item: NewFileCommentItem(&File{Name: "toy"}, &Comment{Comment: "cool toy"}),
333 Reactions: []ItemReaction{
334 ItemReaction{Name: "astonished", Count: 3, Users: []string{"U1", "U2", "U3"}},
335 },
336 },
337 }
338 wantParams := map[string]string{
339 "user": "UserID",
340 "count": "200",
341 "page": "2",
342 "full": "true",
343 }
344 params := NewListReactionsParameters()
345 params.UserId = "UserID"
346 params.Count = 200
347 params.Page = 2
348 params.Full = true
349 got, paging, err := api.ListReactions(params)
350 if err != nil {
351 t.Fatalf("Unexpected error: %s", err)
352 }
353 if !reflect.DeepEqual(got, want) {
354 t.Errorf("Got reaction %#v, want %#v", got, want)
355 for i, item := range got {
356 fmt.Printf("Item %d, Type: %s\n", i, item.Type)
357 fmt.Printf("Message %#v\n", item.Message)
358 fmt.Printf("File %#v\n", item.File)
359 fmt.Printf("Comment %#v\n", item.Comment)
360 fmt.Printf("Reactions %#v\n", item.Reactions)
361 }
362 }
363 if !reflect.DeepEqual(rh.gotParams, wantParams) {
364 t.Errorf("Got params %#v, want %#v", rh.gotParams, wantParams)
365 }
366 if reflect.DeepEqual(paging, Paging{}) {
367 t.Errorf("Want paging data, got empty struct")
368 }
369 }
1717 Page int
1818 }
1919
20 // TODO: Verify this. The whole thing is complicated. I don't like the way they mixed things
21 // It also appears to be a bug in parsing the message
20 // StarredItem is an item that has been starred.
2221 type StarredItem struct {
23 Type string `json:"type"`
24 ChannelId string `json:"channel"`
25 Message `json:"message,omitempty"`
26 File `json:"file,omitempty"`
27 Comment `json:"comment,omitempty"`
22 Item
2823 }
2924
3025 type starsResponseFull struct {
5247 // }
5348 // }
5449 func (api *Slack) GetStarred(params StarsParameters) ([]StarredItem, *Paging, error) {
55 response := &starsResponseFull{}
5650 values := url.Values{
5751 "token": {api.config.token},
5852 }
6559 if params.Page != DEFAULT_STARS_PAGE {
6660 values.Add("page", strconv.Itoa(params.Page))
6761 }
62 response := &starsResponseFull{}
6863 err := parseResponse("stars.list", values, response, api.debug)
6964 if err != nil {
7065 return nil, nil, err
55 "testing"
66 )
77
8 var starsTests = struct {
9 in []byte
10 outItems []StarredItem
11 outPaging *Paging
12 }{
13 []byte(`{"ok": true,
8 type starsHandler struct {
9 gotParams map[string]string
10 response string
11 }
12
13 func newStarsHandler() *starsHandler {
14 return &starsHandler{
15 gotParams: make(map[string]string),
16 response: `{ "ok": true }`,
17 }
18 }
19
20 func (sh *starsHandler) accumulateFormValue(k string, r *http.Request) {
21 if v := r.FormValue(k); v != "" {
22 sh.gotParams[k] = v
23 }
24 }
25
26 func (sh *starsHandler) handler(w http.ResponseWriter, r *http.Request) {
27 sh.accumulateFormValue("user", r)
28 sh.accumulateFormValue("count", r)
29 sh.accumulateFormValue("page", r)
30 w.Header().Set("Content-Type", "application/json")
31 w.Write([]byte(sh.response))
32 }
33
34 func TestSlack_GetStarred(t *testing.T) {
35 once.Do(startServer)
36 SLACK_API = "http://" + serverAddr + "/"
37 api := New("testing-token")
38 tests := []struct {
39 params StarsParameters
40 wantParams map[string]string
41 json string
42 starredItems []StarredItem
43 paging *Paging
44 }{
45 {
46 StarsParameters{
47 User: "U1",
48 Count: 10,
49 Page: 100,
50 },
51 map[string]string{
52 "user": "U1",
53 "count": "10",
54 "page": "100",
55 },
56 `{"ok": true,
1457 "items": [
1558 {
1659 "type": "message",
17 "channel": "C2147483705"
60 "channel": "C2147483705",
61 "message": {
62 "text": "hello"
63 }
1864 },
1965 {
20 "type": "file"
66 "type": "file",
67 "file": {
68 "name": "toy"
69 }
2170 },
2271 {
23 "type": "file_comment"
72 "type": "file_comment",
73 "file": {
74 "name": "toy"
75 },
76 "comment": {
77 "comment": "nice"
78 }
2479 },
2580 {
2681 "type": "channel",
2782 "channel": "C2147483705"
83 },
84 {
85 "type": "im",
86 "channel": "D1"
87 },
88 {
89 "type": "group",
90 "channel": "G1"
2891 }
29
3092 ],
3193 "paging": {
3294 "count": 100,
3395 "total": 4,
3496 "page": 1,
3597 "pages": 1
36 }}`),
37 []StarredItem{
38 {
39 Type: "message",
40 ChannelId: "C2147483705",
98 }}`,
99 []StarredItem{
100 {Item: NewMessageItem("C2147483705", &Message{Msg: Msg{Text: "hello"}})},
101 {Item: NewFileItem(&File{Name: "toy"})},
102 {Item: NewFileCommentItem(&File{Name: "toy"}, &Comment{Comment: "nice"})},
103 {Item: NewChannelItem("C2147483705")},
104 {Item: NewIMItem("D1")},
105 {Item: NewGroupItem("G1")},
106 },
107 &Paging{
108 Count: 100,
109 Total: 4,
110 Page: 1,
111 Pages: 1,
112 },
41113 },
42 {
43 Type: "file",
44 },
45 {
46 Type: "file_comment",
47 },
48 {
49 Type: "channel",
50 ChannelId: "C2147483705",
51 },
52 },
53 &Paging{
54 Count: 100,
55 Total: 4,
56 Page: 1,
57 Pages: 1,
58 },
59 }
60
61 func getStarredHandler(rw http.ResponseWriter, r *http.Request) {
62 rw.Header().Set("Content-Type", "application/json")
63 // XXX: I stripped the actual content just to test this test Oo
64 // At some point I should add valid content here
65 rw.Write(starsTests.in)
66 }
67
68 func TestGetStarred(t *testing.T) {
69 http.HandleFunc("/stars.list", getStarredHandler)
70 once.Do(startServer)
71 SLACK_API = "http://" + serverAddr + "/"
72 api := New("testing-token")
73 response_items, response_paging, err := api.GetStarred(NewStarsParameters())
74 if err != nil {
75 t.Errorf("Unexpected error: %s", err)
76 return
77114 }
78 eq := reflect.DeepEqual(response_items, starsTests.outItems)
79 if !eq {
80 t.Errorf("got %v; want %v", response_items, starsTests.outItems)
81 }
82 eq = reflect.DeepEqual(response_paging, starsTests.outPaging)
83 if !eq {
84 t.Errorf("got %v; want %v", response_paging, starsTests.outPaging)
115 var sh *starsHandler
116 http.HandleFunc("/stars.list", func(w http.ResponseWriter, r *http.Request) { sh.handler(w, r) })
117 for i, test := range tests {
118 sh = newStarsHandler()
119 sh.response = test.json
120 response_items, response_paging, err := api.GetStarred(test.params)
121 if err != nil {
122 t.Fatalf("%d Unexpected error: %s", i, err)
123 }
124 if !reflect.DeepEqual(sh.gotParams, test.wantParams) {
125 t.Errorf("%d got %v; want %v", i, sh.gotParams, test.wantParams)
126 }
127 if !reflect.DeepEqual(response_items, test.starredItems) {
128 t.Errorf("%d got %v; want %v", i, response_items, test.starredItems)
129 }
130 if !reflect.DeepEqual(response_paging, test.paging) {
131 t.Errorf("%d got %v; want %v", i, response_paging, test.paging)
132 }
85133 }
86134 }