Codebase list golang-github-nlopes-slack / e297819
Add pinning support Norberto Lopes 8 years ago
5 changed file(s) with 478 addition(s) and 0 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 /*
10 WARNING: This example is destructive in the sense that it create a channel called testpinning
11 */
12 func main() {
13 var (
14 apiToken string
15 debug bool
16 )
17
18 flag.StringVar(&apiToken, "token", "YOUR_TOKEN_HERE", "Your Slack API Token")
19 flag.BoolVar(&debug, "debug", false, "Show JSON output")
20 flag.Parse()
21
22 api := slack.New(apiToken)
23 if debug {
24 api.SetDebug(true)
25 }
26
27 var (
28 postAsUserName string
29 postAsUserID string
30 postToChannelID string
31 )
32
33 // Find the user to post as.
34 authTest, err := api.AuthTest()
35 if err != nil {
36 fmt.Printf("Error getting channels: %s\n", err)
37 return
38 }
39
40 channelName := "testpinning"
41
42 // Post as the authenticated user.
43 postAsUserName = authTest.User
44 postAsUserID = authTest.UserID
45
46 // Create a temporary channel
47 channel, err := api.CreateChannel(channelName)
48
49 if err != nil {
50 // If the channel exists, that means we just need to unarchive it
51 if err.Error() == "name_taken" {
52 err = nil
53 channels, err := api.GetChannels(false)
54 if err != nil {
55 fmt.Println("Could not retrieve channels")
56 return
57 }
58 for _, archivedChannel := range channels {
59 if archivedChannel.Name == channelName {
60 if archivedChannel.IsArchived {
61 err = api.UnarchiveChannel(archivedChannel.ID)
62 if err != nil {
63 fmt.Printf("Could not unarchive %s: %s\n", archivedChannel.ID, err)
64 return
65 }
66 }
67 channel = &archivedChannel
68 break
69 }
70 }
71 }
72 if err != nil {
73 fmt.Printf("Error setting test channel for pinning: %s\n", err)
74 return
75 }
76 }
77 postToChannelID = channel.ID
78
79 fmt.Printf("Posting as %s (%s) in channel %s\n", postAsUserName, postAsUserID, postToChannelID)
80
81 // Post a message.
82 postParams := slack.PostMessageParameters{}
83 channelID, timestamp, err := api.PostMessage(postToChannelID, "Is this any good?", postParams)
84 if err != nil {
85 fmt.Printf("Error posting message: %s\n", err)
86 return
87 }
88
89 // Grab a reference to the message.
90 msgRef := slack.NewRefToMessage(channelID, timestamp)
91
92 // Add message pin to channel
93 if err := api.AddPin(channelID, msgRef); err != nil {
94 fmt.Printf("Error adding pin: %s\n", err)
95 return
96 }
97
98 // List all of the users pins.
99 listPins, _, err := api.ListPins(channelID, slack.NewListPinsParameters())
100 if err != nil {
101 fmt.Printf("Error listing pins: %s\n", err)
102 return
103 }
104 fmt.Printf("\n")
105 fmt.Printf("All pins by %s...\n", authTest.User)
106 for _, item := range listPins {
107 fmt.Printf(" > Item type: %s\n", item.Type)
108 }
109
110 // Remove the pin.
111 err = api.RemovePin(channelID, msgRef)
112 if err != nil {
113 fmt.Printf("Error remove pin: %s\n", err)
114 return
115 }
116
117 if err = api.ArchiveChannel(channelID); err != nil {
118 fmt.Printf("Error archiving channel: %s\n", err)
119 return
120 }
121
122 }
0 package slack
1
2 import (
3 "errors"
4 "net/url"
5 "strconv"
6 )
7
8 const (
9 DEFAULT_PINS_COUNT = 100
10 DEFAULT_PINS_PAGE = 1
11 )
12
13 // ListPinsParameters contains all the optional parameters for the pins.list call
14 type ListPinsParameters struct {
15 Count int
16 Page int
17 }
18
19 // NewListPinsParameters initializes the inputs to find all pins
20 // performed by a user.
21 func NewListPinsParameters() ListPinsParameters {
22 return ListPinsParameters{
23 Count: DEFAULT_PINS_COUNT,
24 Page: DEFAULT_PINS_PAGE,
25 }
26 }
27
28 type listPinsResponseFull struct {
29 Items []Item
30 Paging `json:"paging"`
31 SlackResponse
32 }
33
34 // AddPin pins an item in a channel
35 func (api *Client) AddPin(channel string, item ItemRef) error {
36 values := url.Values{
37 "channel": {channel},
38 "token": {api.config.token},
39 }
40 if item.Timestamp != "" {
41 values.Set("timestamp", string(item.Timestamp))
42 }
43 if item.File != "" {
44 values.Set("file", string(item.File))
45 }
46 if item.Comment != "" {
47 values.Set("file_comment", string(item.Comment))
48 }
49 response := &SlackResponse{}
50 if err := post("pins.add", values, response, api.debug); err != nil {
51 return err
52 }
53 if !response.Ok {
54 return errors.New(response.Error)
55 }
56 return nil
57 }
58
59 // RemovePin un-pins an item from a channel
60 func (api *Client) RemovePin(channel string, item ItemRef) error {
61 values := url.Values{
62 "channel": {channel},
63 "token": {api.config.token},
64 }
65 if item.Timestamp != "" {
66 values.Set("timestamp", string(item.Timestamp))
67 }
68 if item.File != "" {
69 values.Set("file", string(item.File))
70 }
71 if item.Comment != "" {
72 values.Set("file_comment", string(item.Comment))
73 }
74 response := &SlackResponse{}
75 if err := post("pins.remove", values, response, api.debug); err != nil {
76 return err
77 }
78 if !response.Ok {
79 return errors.New(response.Error)
80 }
81 return nil
82 }
83
84 // ListPins returns information about the items a user reacted to.
85 func (api *Client) ListPins(channel string, params ListPinsParameters) ([]Item, *Paging, error) {
86 values := url.Values{
87 "channel": {channel},
88 "token": {api.config.token},
89 }
90 if params.Count != DEFAULT_PINS_COUNT {
91 values.Add("count", strconv.Itoa(params.Count))
92 }
93 if params.Page != DEFAULT_PINS_PAGE {
94 values.Add("page", strconv.Itoa(params.Page))
95 }
96 response := &listPinsResponseFull{}
97 err := post("pins.list", values, response, api.debug)
98 if err != nil {
99 return nil, nil, err
100 }
101 if !response.Ok {
102 return nil, nil, errors.New(response.Error)
103 }
104 return response.Items, &response.Paging, nil
105 }
0 package slack
1
2 import (
3 "fmt"
4 "net/http"
5 "reflect"
6 "testing"
7 )
8
9 type pinsHandler struct {
10 gotParams map[string]string
11 response string
12 }
13
14 func newPinsHandler() *pinsHandler {
15 return &pinsHandler{
16 gotParams: make(map[string]string),
17 response: `{ "ok": true }`,
18 }
19 }
20
21 func (rh *pinsHandler) accumulateFormValue(k string, r *http.Request) {
22 if v := r.FormValue(k); v != "" {
23 rh.gotParams[k] = v
24 }
25 }
26
27 func (rh *pinsHandler) 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("page", r)
33 rh.accumulateFormValue("timestamp", r)
34 w.Header().Set("Content-Type", "application/json")
35 w.Write([]byte(rh.response))
36 }
37
38 func TestSlack_AddPin(t *testing.T) {
39 once.Do(startServer)
40 SLACK_API = "http://" + serverAddr + "/"
41 api := New("testing-token")
42 tests := []struct {
43 channel string
44 ref ItemRef
45 wantParams map[string]string
46 }{
47 {
48 "ChannelID",
49 NewRefToMessage("ChannelID", "123"),
50 map[string]string{
51 "channel": "ChannelID",
52 "timestamp": "123",
53 },
54 },
55 {
56 "ChannelID",
57 NewRefToFile("FileID"),
58 map[string]string{
59 "channel": "ChannelID",
60 "file": "FileID",
61 },
62 },
63 {
64 "ChannelID",
65 NewRefToComment("FileCommentID"),
66 map[string]string{
67 "channel": "ChannelID",
68 "file_comment": "FileCommentID",
69 },
70 },
71 }
72 var rh *pinsHandler
73 http.HandleFunc("/pins.add", func(w http.ResponseWriter, r *http.Request) { rh.handler(w, r) })
74 for i, test := range tests {
75 rh = newPinsHandler()
76 err := api.AddPin(test.channel, test.ref)
77 if err != nil {
78 t.Fatalf("%d: Unexpected error: %s", i, err)
79 }
80 if !reflect.DeepEqual(rh.gotParams, test.wantParams) {
81 t.Errorf("%d: Got params %#v, want %#v", i, rh.gotParams, test.wantParams)
82 }
83 }
84 }
85
86 func TestSlack_RemovePin(t *testing.T) {
87 once.Do(startServer)
88 SLACK_API = "http://" + serverAddr + "/"
89 api := New("testing-token")
90 tests := []struct {
91 channel string
92 ref ItemRef
93 wantParams map[string]string
94 }{
95 {
96 "ChannelID",
97 NewRefToMessage("ChannelID", "123"),
98 map[string]string{
99 "channel": "ChannelID",
100 "timestamp": "123",
101 },
102 },
103 {
104 "ChannelID",
105 NewRefToFile("FileID"),
106 map[string]string{
107 "channel": "ChannelID",
108 "file": "FileID",
109 },
110 },
111 {
112 "ChannelID",
113 NewRefToComment("FileCommentID"),
114 map[string]string{
115 "channel": "ChannelID",
116 "file_comment": "FileCommentID",
117 },
118 },
119 }
120 var rh *pinsHandler
121 http.HandleFunc("/pins.remove", func(w http.ResponseWriter, r *http.Request) { rh.handler(w, r) })
122 for i, test := range tests {
123 rh = newPinsHandler()
124 err := api.RemovePin(test.channel, test.ref)
125 if err != nil {
126 t.Fatalf("%d: Unexpected error: %s", i, err)
127 }
128 if !reflect.DeepEqual(rh.gotParams, test.wantParams) {
129 t.Errorf("%d: Got params %#v, want %#v", i, rh.gotParams, test.wantParams)
130 }
131 }
132 }
133
134 func TestSlack_ListPins(t *testing.T) {
135 once.Do(startServer)
136 SLACK_API = "http://" + serverAddr + "/"
137 api := New("testing-token")
138 rh := newPinsHandler()
139 http.HandleFunc("/pins.list", func(w http.ResponseWriter, r *http.Request) { rh.handler(w, r) })
140 rh.response = `{"ok": true,
141 "items": [
142 {
143 "type": "message",
144 "channel": "C1",
145 "message": {
146 "text": "hello",
147 "reactions": [
148 {
149 "name": "astonished",
150 "count": 3,
151 "users": [ "U1", "U2", "U3" ]
152 },
153 {
154 "name": "clock1",
155 "count": 3,
156 "users": [ "U1", "U2" ]
157 }
158 ]
159 }
160 },
161 {
162 "type": "file",
163 "file": {
164 "name": "toy",
165 "reactions": [
166 {
167 "name": "clock1",
168 "count": 3,
169 "users": [ "U1", "U2" ]
170 }
171 ]
172 }
173 },
174 {
175 "type": "file_comment",
176 "file": {
177 "name": "toy"
178 },
179 "comment": {
180 "comment": "cool toy",
181 "reactions": [
182 {
183 "name": "astonished",
184 "count": 3,
185 "users": [ "U1", "U2", "U3" ]
186 }
187 ]
188 }
189 }
190 ],
191 "paging": {
192 "count": 100,
193 "total": 4,
194 "page": 1,
195 "pages": 1
196 }}`
197 want := []Item{
198 NewMessageItem("C1", &Message{Msg: Msg{Text: "hello"}}),
199 NewFileItem(&File{Name: "toy"}),
200 NewFileCommentItem(&File{Name: "toy"}, &Comment{Comment: "cool toy"}),
201 }
202 wantParams := map[string]string{
203 "channel": "ChannelID",
204 "count": "200",
205 "page": "2",
206 }
207 params := NewListPinsParameters()
208 params.Count = 200
209 params.Page = 2
210 got, paging, err := api.ListPins("ChannelID", params)
211 if err != nil {
212 t.Fatalf("Unexpected error: %s", err)
213 }
214 if !reflect.DeepEqual(got, want) {
215 t.Errorf("Got Pins %#v, want %#v", got, want)
216 for i, item := range got {
217 fmt.Printf("Item %d, Type: %s\n", i, item.Type)
218 fmt.Printf("Message %#v\n", item.Message)
219 fmt.Printf("File %#v\n", item.File)
220 fmt.Printf("Comment %#v\n", item.Comment)
221 }
222 }
223 if !reflect.DeepEqual(rh.gotParams, wantParams) {
224 t.Errorf("Got params %#v, want %#v", rh.gotParams, wantParams)
225 }
226 if reflect.DeepEqual(paging, Paging{}) {
227 t.Errorf("Want paging data, got empty struct")
228 }
229 }
387387 "file_comment_edited": FileCommentEditedEvent{},
388388 "file_comment_deleted": FileCommentDeletedEvent{},
389389
390 "pin_added": PinAddedEvent{},
391 "pin_removed": PinRemovedEvent{},
392
390393 "star_added": StarAddedEvent{},
391394 "star_removed": StarRemovedEvent{},
392395
0 package slack
1
2 type pinEvent struct {
3 Type string `json:"type"`
4 User string `json:"user"`
5 Item Item `json:"item"`
6 Channel string `json:"channel_id"`
7 EventTimestamp JSONTimeString `json:"event_ts"`
8 HasPins bool `json:"has_pins,omitempty"`
9 }
10
11 // PinAddedEvent represents the Pin added event
12 type PinAddedEvent pinEvent
13
14 // PinRemovedEvent represents the Pin removed event
15 type PinRemovedEvent pinEvent