Codebase list golang-github-nlopes-slack / 7e3ea4c
Pulling changes from joefitzgerald Norberto Lopes 8 years ago
36 changed file(s) with 1260 addition(s) and 412 deletion(s). Raw diff Collapse all Expand all
2828 return
2929 }
3030 for _, group := range groups {
31 fmt.Printf("Id: %s, Name: %s\n", group.Id, group.Name)
31 fmt.Printf("ID: %s, Name: %s\n", group.ID, group.Name)
3232 }
3333 }
3434
4747 fmt.Printf("%s\n", err)
4848 return
4949 }
50 fmt.Printf("Id: %s, Fullname: %s, Email: %s\n", user.Id, user.Profile.RealName, user.Profile.Email)
50 fmt.Printf("ID: %s, Fullname: %s, Email: %s\n", user.ID, user.Profile.RealName, user.Profile.Email)
5151 }
5252
5353 ## Why?
6060 Anyone is welcome to contribute. Either open a PR or create an issue.
6161
6262 ## License
63 BSD 2 Clause license
63 BSD 2 Clause license
2424 return adminResponse, nil
2525 }
2626
27 // DisableUser disabled a user account
28 func (api *Slack) DisableUser(teamName string, user string) error {
29 values := url.Values{
30 "user": {user},
31 "token": {api.config.token},
32 "set_active": {"true"},
33 "_attempts": {"1"},
34 }
35
36 _, err := adminRequest("setInactive", teamName, values, api.debug)
37 if err != nil {
38 return fmt.Errorf("Failed to disable user (%s): %s", user, err)
39 }
40
41 return nil
42 }
43
44 // InviteGuest invites a user to Slack as a single-channel guest
2745 func (api *Slack) InviteGuest(
2846 teamName string,
29 channelID string,
47 channel string,
3048 firstName string,
3149 lastName string,
3250 emailAddress string,
3351 ) error {
3452 values := url.Values{
3553 "email": {emailAddress},
36 "channels": {channelID},
54 "channels": {channel},
3755 "first_name": {firstName},
3856 "last_name": {lastName},
3957 "ultra_restricted": {"1"},
5068 return nil
5169 }
5270
71 // InviteRestricted invites a user to Slack as a restricted account
5372 func (api *Slack) InviteRestricted(
5473 teamName string,
55 channelID string,
74 channel string,
5675 firstName string,
5776 lastName string,
5877 emailAddress string,
5978 ) error {
6079 values := url.Values{
6180 "email": {emailAddress},
62 "channels": {channelID},
81 "channels": {channel},
6382 "first_name": {firstName},
6483 "last_name": {lastName},
6584 "restricted": {"1"},
7594
7695 return nil
7796 }
97
98 // SetRegular enables the specified user
99 func (api *Slack) SetRegular(teamName string, user string) error {
100 values := url.Values{
101 "user": {user},
102 "token": {api.config.token},
103 "set_active": {"true"},
104 "_attempts": {"1"},
105 }
106
107 _, err := adminRequest("setRegular", teamName, values, api.debug)
108 if err != nil {
109 return fmt.Errorf("Failed to change the user (%s) to a regular user: %s", user, err)
110 }
111
112 return nil
113 }
114
115 // SendSSOBindingEmail sends an SSO binding email to the specified user
116 func (api *Slack) SendSSOBindingEmail(teamName string, user string) error {
117 values := url.Values{
118 "user": {user},
119 "token": {api.config.token},
120 "set_active": {"true"},
121 "_attempts": {"1"},
122 }
123
124 _, err := adminRequest("sendSSOBind", teamName, values, api.debug)
125 if err != nil {
126 return fmt.Errorf("Failed to send SSO binding email for user (%s): %s", user, err)
127 }
128
129 return nil
130 }
0 package slack
1
2 // AttachmentField contains information for an attachment field
3 // An Attachment can contain multiple of these
4 type AttachmentField struct {
5 Title string `json:"title"`
6 Value string `json:"value"`
7 Short bool `json:"short"`
8 }
9
10 // Attachment contains all the information for an attachment
11 type Attachment struct {
12 Color string `json:"color,omitempty"`
13 Fallback string `json:"fallback"`
14
15 AuthorName string `json:"author_name,omitempty"`
16 AuthorSubname string `json:"author_subname,omitempty"`
17 AuthorLink string `json:"author_link,omitempty"`
18 AuthorIcon string `json:"author_icon,omitempty"`
19
20 Title string `json:"title,omitempty"`
21 TitleLink string `json:"title_link,omitempty"`
22 Pretext string `json:"pretext,omitempty"`
23 Text string `json:"text"`
24
25 ImageURL string `json:"image_url,omitempty"`
26 ThumbURL string `json:"thumb_url,omitempty"`
27
28 Fields []AttachmentField `json:"fields,omitempty"`
29 MarkdownIn []string `json:"mrkdwn_in,omitempty"`
30 }
2929 LastSet JSONTime `json:"last_set"`
3030 }
3131
32 type BaseChannel struct {
33 Id string `json:"id"`
34 Created JSONTime `json:"created"`
35 IsOpen bool `json:"is_open"`
36 LastRead string `json:"last_read,omitempty"`
37 Latest Message `json:"latest,omitempty"`
38 UnreadCount int `json:"unread_count,omitempty"`
39 UnreadCountDisplay int `json:"unread_count_display,omitempty"`
32 type baseChannel struct {
33 ID string `json:"id"`
34 Created JSONTime `json:"created"`
35 IsOpen bool `json:"is_open"`
36 LastRead string `json:"last_read,omitempty"`
37 Latest Message `json:"latest,omitempty"`
38 UnreadCount int `json:"unread_count,omitempty"`
39 UnreadCountDisplay int `json:"unread_count_display,omitempty"`
4040 }
4141
4242 // Channel contains information about the channel
4343 type Channel struct {
44 BaseChannel
45 Name string `json:"name"`
46 IsChannel bool `json:"is_channel"`
47 Creator string `json:"creator"`
48 IsArchived bool `json:"is_archived"`
49 IsGeneral bool `json:"is_general"`
50 Members []string `json:"members"`
51 Topic ChannelTopic `json:"topic"`
52 Purpose ChannelPurpose `json:"purpose"`
53 IsMember bool `json:"is_member"`
54 LastRead string `json:"last_read,omitempty"`
55 Latest *Message `json:"latest,omitempty"`
56 UnreadCount int `json:"unread_count,omitempty"`
57 NumMembers int `json:"num_members,omitempty"`
44 baseChannel
45 Name string `json:"name"`
46 IsChannel bool `json:"is_channel"`
47 Creator string `json:"creator"`
48 IsArchived bool `json:"is_archived"`
49 IsGeneral bool `json:"is_general"`
50 Members []string `json:"members"`
51 Topic ChannelTopic `json:"topic"`
52 Purpose ChannelPurpose `json:"purpose"`
53 IsMember bool `json:"is_member"`
54 LastRead string `json:"last_read,omitempty"`
55 Latest *Message `json:"latest,omitempty"`
56 UnreadCount int `json:"unread_count,omitempty"`
57 NumMembers int `json:"num_members,omitempty"`
5858 }
5959
6060 func channelRequest(path string, values url.Values, debug bool) (*channelResponseFull, error) {
7070 }
7171
7272 // ArchiveChannel archives the given channel
73 func (api *Slack) ArchiveChannel(channelId string) error {
74 values := url.Values{
75 "token": {api.config.token},
76 "channel": {channelId},
73 func (api *Slack) ArchiveChannel(channel string) error {
74 values := url.Values{
75 "token": {api.config.token},
76 "channel": {channel},
7777 }
7878 _, err := channelRequest("channels.archive", values, api.debug)
7979 if err != nil {
8383 }
8484
8585 // UnarchiveChannel unarchives the given channel
86 func (api *Slack) UnarchiveChannel(channelId string) error {
87 values := url.Values{
88 "token": {api.config.token},
89 "channel": {channelId},
86 func (api *Slack) UnarchiveChannel(channel string) error {
87 values := url.Values{
88 "token": {api.config.token},
89 "channel": {channel},
9090 }
9191 _, err := channelRequest("channels.unarchive", values, api.debug)
9292 if err != nil {
109109 }
110110
111111 // GetChannelHistory retrieves the channel history
112 func (api *Slack) GetChannelHistory(channelId string, params HistoryParameters) (*History, error) {
113 values := url.Values{
114 "token": {api.config.token},
115 "channel": {channelId},
112 func (api *Slack) GetChannelHistory(channel string, params HistoryParameters) (*History, error) {
113 values := url.Values{
114 "token": {api.config.token},
115 "channel": {channel},
116116 }
117117 if params.Latest != DEFAULT_HISTORY_LATEST {
118118 values.Add("latest", params.Latest)
138138 }
139139
140140 // GetChannelInfo retrieves the given channel
141 func (api *Slack) GetChannelInfo(channelId string) (*Channel, error) {
142 values := url.Values{
143 "token": {api.config.token},
144 "channel": {channelId},
141 func (api *Slack) GetChannelInfo(channel string) (*Channel, error) {
142 values := url.Values{
143 "token": {api.config.token},
144 "channel": {channel},
145145 }
146146 response, err := channelRequest("channels.info", values, api.debug)
147147 if err != nil {
151151 }
152152
153153 // InviteUserToChannel invites a user to a given channel and returns a *Channel
154 func (api *Slack) InviteUserToChannel(channelId, userId string) (*Channel, error) {
155 values := url.Values{
156 "token": {api.config.token},
157 "channel": {channelId},
158 "user": {userId},
154 func (api *Slack) InviteUserToChannel(channel, user string) (*Channel, error) {
155 values := url.Values{
156 "token": {api.config.token},
157 "channel": {channel},
158 "user": {user},
159159 }
160160 response, err := channelRequest("channels.invite", values, api.debug)
161161 if err != nil {
178178 }
179179
180180 // LeaveChannel makes the authenticated user leave the given channel
181 func (api *Slack) LeaveChannel(channelId string) (bool, error) {
182 values := url.Values{
183 "token": {api.config.token},
184 "channel": {channelId},
181 func (api *Slack) LeaveChannel(channel string) (bool, error) {
182 values := url.Values{
183 "token": {api.config.token},
184 "channel": {channel},
185185 }
186186 response, err := channelRequest("channels.leave", values, api.debug)
187187 if err != nil {
194194 }
195195
196196 // KickUserFromChannel kicks a user from a given channel
197 func (api *Slack) KickUserFromChannel(channelId, userId string) error {
198 values := url.Values{
199 "token": {api.config.token},
200 "channel": {channelId},
201 "user": {userId},
197 func (api *Slack) KickUserFromChannel(channel, user string) error {
198 values := url.Values{
199 "token": {api.config.token},
200 "channel": {channel},
201 "user": {user},
202202 }
203203 _, err := channelRequest("channels.kick", values, api.debug)
204204 if err != nil {
227227 // timer before making the call. In this way, any further updates needed during the timeout will not generate extra calls
228228 // (just one per channel). This is useful for when reading scroll-back history, or following a busy live channel. A
229229 // timeout of 5 seconds is a good starting point. Be sure to flush these calls on shutdown/logout.
230 func (api *Slack) SetChannelReadMark(channelId, ts string) error {
231 values := url.Values{
232 "token": {api.config.token},
233 "channel": {channelId},
230 func (api *Slack) SetChannelReadMark(channel, ts string) error {
231 values := url.Values{
232 "token": {api.config.token},
233 "channel": {channel},
234234 "ts": {ts},
235235 }
236236 _, err := channelRequest("channels.mark", values, api.debug)
241241 }
242242
243243 // RenameChannel renames a given channel
244 func (api *Slack) RenameChannel(channelId, name string) (*Channel, error) {
245 values := url.Values{
246 "token": {api.config.token},
247 "channel": {channelId},
244 func (api *Slack) RenameChannel(channel, name string) (*Channel, error) {
245 values := url.Values{
246 "token": {api.config.token},
247 "channel": {channel},
248248 "name": {name},
249249 }
250250 // XXX: the created entry in this call returns a string instead of a number
259259
260260 // SetChannelPurpose sets the channel purpose and returns the purpose that was
261261 // successfully set
262 func (api *Slack) SetChannelPurpose(channelId, purpose string) (string, error) {
263 values := url.Values{
264 "token": {api.config.token},
265 "channel": {channelId},
262 func (api *Slack) SetChannelPurpose(channel, purpose string) (string, error) {
263 values := url.Values{
264 "token": {api.config.token},
265 "channel": {channel},
266266 "purpose": {purpose},
267267 }
268268 response, err := channelRequest("channels.setPurpose", values, api.debug)
273273 }
274274
275275 // SetChannelTopic sets the channel topic and returns the topic that was successfully set
276 func (api *Slack) SetChannelTopic(channelId, topic string) (string, error) {
277 values := url.Values{
278 "token": {api.config.token},
279 "channel": {channelId},
276 func (api *Slack) SetChannelTopic(channel, topic string) (string, error) {
277 values := url.Values{
278 "token": {api.config.token},
279 "channel": {channel},
280280 "topic": {topic},
281281 }
282282 response, err := channelRequest("channels.setTopic", values, api.debug)
2020 )
2121
2222 type chatResponseFull struct {
23 ChannelId string `json:"channel"`
23 Channel string `json:"channel"`
2424 Timestamp string `json:"ts"`
2525 Text string `json:"text"`
2626 SlackResponse
27 }
28
29 // AttachmentField contains information for an attachment field
30 // An Attachment can contain multiple of these
31 type AttachmentField struct {
32 Title string `json:"title"`
33 Value string `json:"value"`
34 Short bool `json:"short"`
35 }
36
37 // Attachment contains all the information for an attachment
38 type Attachment struct {
39 Fallback string `json:"fallback"`
40
41 Color string `json:"color,omitempty"`
42
43 Pretext string `json:"pretext,omitempty"`
44
45 AuthorName string `json:"author_name,omitempty"`
46 AuthorLink string `json:"author_link,omitempty"`
47 AuthorIcon string `json:"author_icon,omitempty"`
48
49 Title string `json:"title,omitempty"`
50 TitleLink string `json:"title_link,omitempty"`
51
52 Text string `json:"text"`
53
54 ImageURL string `json:"image_url,omitempty"`
55 ThumbURL string `json:"thumb_url,omitempty"`
56
57 Fields []AttachmentField `json:"fields,omitempty"`
58
59 MarkdownIn []string `json:"mrkdwn_in,omitempty"`
6027 }
6128
6229 // PostMessageParameters contains all the parameters necessary (including the optional ones) for a PostMessage() request
10572 }
10673
10774 // DeleteMessage deletes a message in a channel
108 func (api *Slack) DeleteMessage(channelId, messageTimestamp string) (string, string, error) {
75 func (api *Slack) DeleteMessage(channel, messageTimestamp string) (string, string, error) {
10976 values := url.Values{
11077 "token": {api.config.token},
111 "channel": {channelId},
78 "channel": {channel},
11279 "ts": {messageTimestamp},
11380 }
11481 response, err := chatRequest("chat.delete", values, api.debug)
11582 if err != nil {
11683 return "", "", err
11784 }
118 return response.ChannelId, response.Timestamp, nil
85 return response.Channel, response.Timestamp, nil
11986 }
12087
12188 func escapeMessage(message string) string {
13097
13198 // PostMessage sends a message to a channel
13299 // Message is escaped by default according to https://api.slack.com/docs/formatting
133 func (api *Slack) PostMessage(channelId string, text string, params PostMessageParameters) (channel string, timestamp string, err error) {
100 func (api *Slack) PostMessage(channel string, text string, params PostMessageParameters) (string, string, error) {
134101 if params.EscapeText {
135102 text = escapeMessage(text)
136103 }
137104 values := url.Values{
138105 "token": {api.config.token},
139 "channel": {channelId},
106 "channel": {channel},
140107 "text": {text},
141108 }
142109 if params.Username != DEFAULT_MESSAGE_USERNAME {
178145 if err != nil {
179146 return "", "", err
180147 }
181 return response.ChannelId, response.Timestamp, nil
148 return response.Channel, response.Timestamp, nil
182149 }
183150
184151 // UpdateMessage updates a message in a channel
185 func (api *Slack) UpdateMessage(channelId, timestamp, text string) (string, string, string, error) {
152 func (api *Slack) UpdateMessage(channel, timestamp, text string) (string, string, string, error) {
186153 values := url.Values{
187154 "token": {api.config.token},
188 "channel": {channelId},
155 "channel": {channel},
189156 "text": {escapeMessage(text)},
190157 "ts": {timestamp},
191158 }
193160 if err != nil {
194161 return "", "", "", err
195162 }
196 return response.ChannelId, response.Timestamp, response.Text, nil
163 return response.Channel, response.Timestamp, response.Text, nil
197164 }
0 package slack
1
2 // Comment contains all the information relative to a comment
3 type Comment struct {
4 ID string `json:"id,omitempty"`
5 Created JSONTime `json:"created,omitempty"`
6 Timestamp JSONTime `json:"timestamp,omitempty"`
7 User string `json:"user,omitempty"`
8 Comment string `json:"comment,omitempty"`
9 }
+15
-15
dm.go less more
66 )
77
88 type imChannel struct {
9 Id string `json:"id"`
9 ID string `json:"id"`
1010 }
1111
1212 type imResponseFull struct {
2121
2222 // IM contains information related to the Direct Message channel
2323 type IM struct {
24 BaseChannel
25 IsIM bool `json:"is_im"`
26 UserId string `json:"user"`
27 IsUserDeleted bool `json:"is_user_deleted"`
24 baseChannel
25 IsIM bool `json:"is_im"`
26 User string `json:"user"`
27 IsUserDeleted bool `json:"is_user_deleted"`
2828 }
2929
3030 func imRequest(path string, values url.Values, debug bool) (*imResponseFull, error) {
4040 }
4141
4242 // CloseIMChannel closes the direct message channel
43 func (api *Slack) CloseIMChannel(channelId string) (bool, bool, error) {
43 func (api *Slack) CloseIMChannel(channel string) (bool, bool, error) {
4444 values := url.Values{
4545 "token": {api.config.token},
46 "channel": {channelId},
46 "channel": {channel},
4747 }
4848 response, err := imRequest("im.close", values, api.debug)
4949 if err != nil {
5353 }
5454
5555 // OpenIMChannel opens a direct message channel to the user provided as argument
56 // Returns some status and the channelId
57 func (api *Slack) OpenIMChannel(userId string) (bool, bool, string, error) {
56 // Returns some status and the channel
57 func (api *Slack) OpenIMChannel(user string) (bool, bool, string, error) {
5858 values := url.Values{
5959 "token": {api.config.token},
60 "user": {userId},
60 "user": {user},
6161 }
6262 response, err := imRequest("im.open", values, api.debug)
6363 if err != nil {
6464 return false, false, "", err
6565 }
66 return response.NoOp, response.AlreadyOpen, response.Channel.Id, nil
66 return response.NoOp, response.AlreadyOpen, response.Channel.ID, nil
6767 }
6868
6969 // MarkIMChannel sets the read mark of a direct message channel to a specific point
70 func (api *Slack) MarkIMChannel(channelId, ts string) (err error) {
70 func (api *Slack) MarkIMChannel(channel, ts string) (err error) {
7171 values := url.Values{
7272 "token": {api.config.token},
73 "channel": {channelId},
73 "channel": {channel},
7474 "ts": {ts},
7575 }
7676 _, err = imRequest("im.mark", values, api.debug)
8181 }
8282
8383 // GetIMHistory retrieves the direct message channel history
84 func (api *Slack) GetIMHistory(channelId string, params HistoryParameters) (*History, error) {
84 func (api *Slack) GetIMHistory(channel string, params HistoryParameters) (*History, error) {
8585 values := url.Values{
8686 "token": {api.config.token},
87 "channel": {channelId},
87 "channel": {channel},
8888 }
8989 if params.Latest != DEFAULT_HISTORY_LATEST {
9090 values.Add("latest", params.Latest)
1818 fmt.Printf("%s\n", err)
1919 return
2020 }
21 fmt.Printf("Name: %s, Url: %s\n", file.Name, file.URL)
21 fmt.Printf("Name: %s, URL: %s\n", file.Name, file.URL)
2222
23 err = api.DeleteFile(file.Id)
23 err = api.DeleteFile(file.ID)
2424 if err != nil {
2525 fmt.Printf("%s\n", err)
2626 return
1616 return
1717 }
1818 for _, group := range groups {
19 fmt.Printf("Id: %s, Name: %s\n", group.Id, group.Name)
19 fmt.Printf("ID: %s, Name: %s\n", group.ID, group.Name)
2020 }
2121 }
2222 */
2323 }
2424 params.Attachments = []slack.Attachment{attachment}
25 channelId, timestamp, err := api.PostMessage("CHANNEL_ID", "Some text", params)
25 channelID, timestamp, err := api.PostMessage("CHANNEL_ID", "Some text", params)
2626 if err != nil {
2727 fmt.Printf("%s\n", err)
2828 return
2929 }
30 fmt.Printf("Message successfully sent to channel %s at %s", channelId, timestamp)
30 fmt.Printf("Message successfully sent to channel %s at %s", channelID, timestamp)
3131 }
3838
3939 // Post as the authenticated user.
4040 postAsUserName = authTest.User
41 postAsUserID = authTest.UserId
41 postAsUserID = authTest.UserID
4242
4343 // Posting to DM with self causes a conversation with slackbot.
4444 postToUserName = authTest.User
45 postToUserID = authTest.UserId
45 postToUserID = authTest.UserID
4646
4747 // Find the channel.
4848 _, _, chanID, err := api.OpenIMChannel(postToUserID)
1212 fmt.Printf("%s\n", err)
1313 return
1414 }
15 fmt.Printf("Id: %s, Fullname: %s, Email: %s\n", user.Id, user.Profile.RealName, user.Profile.Email)
15 fmt.Printf("ID: %s, Fullname: %s, Email: %s\n", user.ID, user.Profile.RealName, user.Profile.Email)
1616 }
1818 }
1919 go wsAPI.HandleIncomingEvents(chReceiver)
2020 go wsAPI.Keepalive(20 * time.Second)
21 go func(wsAPI *slack.SlackWS, chSender chan slack.OutgoingMessage) {
21 go func(wsAPI *slack.WS, chSender chan slack.OutgoingMessage) {
2222 for {
2323 select {
2424 case msg := <-chSender:
4242 case slack.LatencyReport:
4343 a := msg.Data.(slack.LatencyReport)
4444 fmt.Printf("Current latency: %v\n", a.Value)
45 case *slack.SlackWSError:
46 error := msg.Data.(*slack.SlackWSError)
45 case *slack.WSError:
46 error := msg.Data.(*slack.WSError)
4747 fmt.Printf("Error: %d - %s\n", error.Code, error.Msg)
4848 default:
4949 fmt.Printf("Unexpected: %v\n", msg.Data)
88
99 const (
1010 // Add here the defaults in the siten
11 DEFAULT_FILES_USERID = ""
11 DEFAULT_FILES_USER = ""
1212 DEFAULT_FILES_TS_FROM = 0
1313 DEFAULT_FILES_TS_TO = -1
1414 DEFAULT_FILES_TYPES = "all"
1616 DEFAULT_FILES_PAGE = 1
1717 )
1818
19 // Comment contains all the information relative to a comment
20 type Comment struct {
21 Id string `json:"id"`
22 Timestamp JSONTime `json:"timestamp"`
23 UserId string `json:"user"`
24 Comment string `json:"comment"`
25 Created JSONTime `json:"created,omitempty"`
26 }
27
2819 // File contains all the information for a file
2920 type File struct {
30 Id string `json:"id"`
21 ID string `json:"id"`
3122 Created JSONTime `json:"created"`
3223 Timestamp JSONTime `json:"timestamp"`
3324
3627 Mimetype string `json:"mimetype"`
3728 Filetype string `json:"filetype"`
3829 PrettyType string `json:"pretty_type"`
39 UserId string `json:"user"`
30 User string `json:"user"`
4031
4132 Mode string `json:"mode"`
4233 Editable bool `json:"editable"`
8677
8778 // GetFilesParameters contains all the parameters necessary (including the optional ones) for a GetFiles() request
8879 type GetFilesParameters struct {
89 UserId string
80 User string
9081 TimestampFrom JSONTime
9182 TimestampTo JSONTime
9283 Types string
10697 // NewGetFilesParameters provides an instance of GetFilesParameters with all the sane default values set
10798 func NewGetFilesParameters() GetFilesParameters {
10899 return GetFilesParameters{
109 UserId: DEFAULT_FILES_USERID,
100 User: DEFAULT_FILES_USER,
110101 TimestampFrom: DEFAULT_FILES_TS_FROM,
111102 TimestampTo: DEFAULT_FILES_TS_TO,
112103 Types: DEFAULT_FILES_TYPES,
128119 }
129120
130121 // GetFileInfo retrieves a file and related comments
131 func (api *Slack) GetFileInfo(fileId string, count, page int) (*File, []Comment, *Paging, error) {
132 values := url.Values{
133 "token": {api.config.token},
134 "file": {fileId},
122 func (api *Slack) GetFileInfo(fileID string, count, page int) (*File, []Comment, *Paging, error) {
123 values := url.Values{
124 "token": {api.config.token},
125 "file": {fileID},
135126 "count": {strconv.Itoa(count)},
136127 "page": {strconv.Itoa(page)},
137128 }
147138 values := url.Values{
148139 "token": {api.config.token},
149140 }
150 if params.UserId != DEFAULT_FILES_USERID {
151 values.Add("user", params.UserId)
141 if params.User != DEFAULT_FILES_USER {
142 values.Add("user", params.User)
152143 }
153144 // XXX: this is broken. fix it with a proper unix timestamp
154145 if params.TimestampFrom != DEFAULT_FILES_TS_FROM {
216207 }
217208
218209 // DeleteFile deletes a file
219 func (api *Slack) DeleteFile(fileId string) error {
220 values := url.Values{
221 "token": {api.config.token},
222 "file": {fileId},
210 func (api *Slack) DeleteFile(fileID string) error {
211 values := url.Values{
212 "token": {api.config.token},
213 "file": {fileID},
223214 }
224215 _, err := fileRequest("files.delete", values, api.debug)
225216 if err != nil {
77
88 // Group contains all the information for a group
99 type Group struct {
10 BaseChannel
10 baseChannel
1111 Name string `json:"name"`
1212 IsGroup bool `json:"is_group"`
1313 Creator string `json:"creator"`
5151 }
5252
5353 // ArchiveGroup archives a private group
54 func (api *Slack) ArchiveGroup(groupId string) error {
55 values := url.Values{
56 "token": {api.config.token},
57 "channel": {groupId},
54 func (api *Slack) ArchiveGroup(group string) error {
55 values := url.Values{
56 "token": {api.config.token},
57 "channel": {group},
5858 }
5959 _, err := groupRequest("groups.archive", values, api.debug)
6060 if err != nil {
6464 }
6565
6666 // UnarchiveGroup unarchives a private group
67 func (api *Slack) UnarchiveGroup(groupId string) error {
68 values := url.Values{
69 "token": {api.config.token},
70 "channel": {groupId},
67 func (api *Slack) UnarchiveGroup(group string) error {
68 values := url.Values{
69 "token": {api.config.token},
70 "channel": {group},
7171 }
7272 _, err := groupRequest("groups.unarchive", values, api.debug)
7373 if err != nil {
9595 // 2. Archives the existing group.
9696 // 3. Creates a new group with the name of the existing group.
9797 // 4. Adds all members of the existing group to the new group.
98 func (api *Slack) CreateChildGroup(groupId string) (*Group, error) {
99 values := url.Values{
100 "token": {api.config.token},
101 "channel": {groupId},
98 func (api *Slack) CreateChildGroup(group string) (*Group, error) {
99 values := url.Values{
100 "token": {api.config.token},
101 "channel": {group},
102102 }
103103 response, err := groupRequest("groups.createChild", values, api.debug)
104104 if err != nil {
108108 }
109109
110110 // CloseGroup closes a private group
111 func (api *Slack) CloseGroup(groupId string) (bool, bool, error) {
112 values := url.Values{
113 "token": {api.config.token},
114 "channel": {groupId},
111 func (api *Slack) CloseGroup(group string) (bool, bool, error) {
112 values := url.Values{
113 "token": {api.config.token},
114 "channel": {group},
115115 }
116116 response, err := imRequest("groups.close", values, api.debug)
117117 if err != nil {
121121 }
122122
123123 // GetGroupHistory retrieves message history for a give group
124 func (api *Slack) GetGroupHistory(groupId string, params HistoryParameters) (*History, error) {
125 values := url.Values{
126 "token": {api.config.token},
127 "channel": {groupId},
124 func (api *Slack) GetGroupHistory(group string, params HistoryParameters) (*History, error) {
125 values := url.Values{
126 "token": {api.config.token},
127 "channel": {group},
128128 }
129129 if params.Latest != DEFAULT_HISTORY_LATEST {
130130 values.Add("latest", params.Latest)
150150 }
151151
152152 // InviteUserToGroup invites a user to a group
153 func (api *Slack) InviteUserToGroup(groupId, userId string) (*Group, bool, error) {
154 values := url.Values{
155 "token": {api.config.token},
156 "channel": {groupId},
157 "user": {userId},
153 func (api *Slack) InviteUserToGroup(group, user string) (*Group, bool, error) {
154 values := url.Values{
155 "token": {api.config.token},
156 "channel": {group},
157 "user": {user},
158158 }
159159 response, err := groupRequest("groups.invite", values, api.debug)
160160 if err != nil {
164164 }
165165
166166 // LeaveGroup makes authenticated user leave the group
167 func (api *Slack) LeaveGroup(groupId string) error {
168 values := url.Values{
169 "token": {api.config.token},
170 "channel": {groupId},
167 func (api *Slack) LeaveGroup(group string) error {
168 values := url.Values{
169 "token": {api.config.token},
170 "channel": {group},
171171 }
172172 _, err := groupRequest("groups.leave", values, api.debug)
173173 if err != nil {
177177 }
178178
179179 // KickUserFromGroup kicks a user from a group
180 func (api *Slack) KickUserFromGroup(groupId, userId string) error {
181 values := url.Values{
182 "token": {api.config.token},
183 "channel": {groupId},
184 "user": {userId},
180 func (api *Slack) KickUserFromGroup(group, user string) error {
181 values := url.Values{
182 "token": {api.config.token},
183 "channel": {group},
184 "user": {user},
185185 }
186186 _, err := groupRequest("groups.kick", values, api.debug)
187187 if err != nil {
206206 }
207207
208208 // GetGroupInfo retrieves the given group
209 func (api *Slack) GetGroupInfo(groupId string) (*Group, error) {
210 values := url.Values{
211 "token": {api.config.token},
212 "channel": {groupId},
209 func (api *Slack) GetGroupInfo(group string) (*Group, error) {
210 values := url.Values{
211 "token": {api.config.token},
212 "channel": {group},
213213 }
214214 response, err := groupRequest("groups.info", values, api.debug)
215215 if err != nil {
223223 // timer before making the call. In this way, any further updates needed during the timeout will not generate extra
224224 // calls (just one per channel). This is useful for when reading scroll-back history, or following a busy live
225225 // channel. A timeout of 5 seconds is a good starting point. Be sure to flush these calls on shutdown/logout.
226 func (api *Slack) SetGroupReadMark(groupId, ts string) error {
227 values := url.Values{
228 "token": {api.config.token},
229 "channel": {groupId},
226 func (api *Slack) SetGroupReadMark(group, ts string) error {
227 values := url.Values{
228 "token": {api.config.token},
229 "channel": {group},
230230 "ts": {ts},
231231 }
232232 _, err := groupRequest("groups.mark", values, api.debug)
237237 }
238238
239239 // OpenGroup opens a private group
240 func (api *Slack) OpenGroup(groupId string) (bool, bool, error) {
240 func (api *Slack) OpenGroup(group string) (bool, bool, error) {
241241 values := url.Values{
242242 "token": {api.config.token},
243 "user": {groupId},
243 "user": {group},
244244 }
245245 response, err := groupRequest("groups.open", values, api.debug)
246246 if err != nil {
252252 // RenameGroup renames a group
253253 // XXX: They return a channel, not a group. What is this crap? :(
254254 // Inconsistent api it seems.
255 func (api *Slack) RenameGroup(groupId, name string) (*Channel, error) {
256 values := url.Values{
257 "token": {api.config.token},
258 "channel": {groupId},
255 func (api *Slack) RenameGroup(group, name string) (*Channel, error) {
256 values := url.Values{
257 "token": {api.config.token},
258 "channel": {group},
259259 "name": {name},
260260 }
261261 // XXX: the created entry in this call returns a string instead of a number
269269 }
270270
271271 // SetGroupPurpose sets the group purpose
272 func (api *Slack) SetGroupPurpose(groupId, purpose string) (string, error) {
273 values := url.Values{
274 "token": {api.config.token},
275 "channel": {groupId},
272 func (api *Slack) SetGroupPurpose(group, purpose string) (string, error) {
273 values := url.Values{
274 "token": {api.config.token},
275 "channel": {group},
276276 "purpose": {purpose},
277277 }
278278 response, err := groupRequest("groups.setPurpose", values, api.debug)
283283 }
284284
285285 // SetGroupTopic sets the group topic
286 func (api *Slack) SetGroupTopic(groupId, topic string) (string, error) {
287 values := url.Values{
288 "token": {api.config.token},
289 "channel": {groupId},
286 func (api *Slack) SetGroupTopic(group, topic string) (string, error) {
287 values := url.Values{
288 "token": {api.config.token},
289 "channel": {group},
290290 "topic": {topic},
291291 }
292292 response, err := groupRequest("groups.setTopic", values, api.debug)
44 "time"
55 )
66
7 // XXX: Need to implement
7 // UserPrefs needs to be implemented
88 type UserPrefs struct {
99 // "highlight_words":"",
1010 // "user_colors":"",
105105
106106 // UserDetails contains user details coming in the initial response from StartRTM
107107 type UserDetails struct {
108 Id string `json:"id"`
108 ID string `json:"id"`
109109 Name string `json:"name"`
110110 Created JSONTime `json:"created"`
111111 ManualPresence string `json:"manual_presence"`
123123
124124 // Team contains details about a team
125125 type Team struct {
126 Id string `json:"id"`
126 ID string `json:"id"`
127127 Name string `json:"name"`
128128 Domain string `json:"name"`
129129 }
135135
136136 // Bot contains information about a bot
137137 type Bot struct {
138 Id string `json:"id"`
138 ID string `json:"id"`
139139 Name string `json:"name"`
140140 Deleted bool `json:"deleted"`
141141 Icons Icons `json:"icons"`
144144 // Info contains various details about Users, Channels, Bots and the authenticated user
145145 // It is returned by StartRTM
146146 type Info struct {
147 Url string `json:"url,omitempty"`
147 URL string `json:"url,omitempty"`
148148 User *UserDetails `json:"self,omitempty"`
149149 Team *Team `json:"team,omitempty"`
150150 Users []User `json:"users,omitempty"`
156156
157157 type infoResponseFull struct {
158158 Info
159 SlackWSResponse
160 }
161
162 // GetBotById returns a bot given a bot id
163 func (info Info) GetBotById(botId string) *Bot {
159 WSResponse
160 }
161
162 // GetBotByID returns a bot given a bot id
163 func (info Info) GetBotByID(botID string) *Bot {
164164 for _, bot := range info.Bots {
165 if bot.Id == botId {
165 if bot.ID == botID {
166166 return &bot
167167 }
168168 }
169169 return nil
170170 }
171171
172 // GetUserById returns a user given a user id
173 func (info Info) GetUserById(userId string) *User {
172 // GetUserByID returns a user given a user id
173 func (info Info) GetUserByID(userID string) *User {
174174 for _, user := range info.Users {
175 if user.Id == userId {
175 if user.ID == userID {
176176 return &user
177177 }
178178 }
179179 return nil
180180 }
181181
182 // GetChannelById returns a channel given a channel id
183 func (info Info) GetChannelById(channelId string) *Channel {
182 // GetChannelByID returns a channel given a channel id
183 func (info Info) GetChannelByID(channelID string) *Channel {
184184 for _, channel := range info.Channels {
185 if channel.Id == channelId {
185 if channel.ID == channelID {
186186 return &channel
187187 }
188188 }
189189 return nil
190190 }
191191
192 // GetGroupById returns a group given a group id
193 func (info Info) GetGroupById(groupId string) *Group {
192 // GetGroupByID returns a group given a group id
193 func (info Info) GetGroupByID(groupID string) *Group {
194194 for _, group := range info.Groups {
195 if group.Id == groupId {
195 if group.ID == groupID {
196196 return &group
197197 }
198198 }
5252 // CommentId, or the combination of ChannelId and Timestamp must be
5353 // specified.
5454 type ItemRef struct {
55 ChannelId string `json:"channel"`
55 Channel string `json:"channel"`
5656 Timestamp string `json:"timestamp"`
57 FileId string `json:"file"`
58 CommentId string `json:"file_comment"`
57 File string `json:"file"`
58 Comment string `json:"file_comment"`
5959 }
6060
6161 // NewRefToMessage initializes a reference to to a message.
62 func NewRefToMessage(channelID, timestamp string) ItemRef {
63 return ItemRef{ChannelId: channelID, Timestamp: timestamp}
62 func NewRefToMessage(channel, timestamp string) ItemRef {
63 return ItemRef{Channel: channel, Timestamp: timestamp}
6464 }
6565
6666 // NewRefToFile initializes a reference to a file.
67 func NewRefToFile(fileID string) ItemRef {
68 return ItemRef{FileId: fileID}
67 func NewRefToFile(file string) ItemRef {
68 return ItemRef{File: file}
6969 }
7070
7171 // NewRefToComment initializes a reference to a file comment.
72 func NewRefToComment(commentID string) ItemRef {
73 return ItemRef{CommentId: commentID}
72 func NewRefToComment(comment string) ItemRef {
73 return ItemRef{Comment: comment}
7474 }
7777
7878 func TestNewRefToMessage(t *testing.T) {
7979 ref := NewRefToMessage("chan", "ts")
80 if got, want := ref.ChannelId, "chan"; got != want {
81 t.Errorf("ChannelId got %s, want %s", got, want)
80 if got, want := ref.Channel, "chan"; got != want {
81 t.Errorf("Channel got %s, want %s", got, want)
8282 }
8383 if got, want := ref.Timestamp, "ts"; got != want {
8484 t.Errorf("Timestamp got %s, want %s", got, want)
8585 }
86 if got, want := ref.FileId, ""; got != want {
87 t.Errorf("FileId got %s, want %s", got, want)
86 if got, want := ref.File, ""; got != want {
87 t.Errorf("File got %s, want %s", got, want)
8888 }
89 if got, want := ref.CommentId, ""; got != want {
90 t.Errorf("CommentId got %s, want %s", got, want)
89 if got, want := ref.Comment, ""; got != want {
90 t.Errorf("Comment got %s, want %s", got, want)
9191 }
9292 }
9393
9494 func TestNewRefToFile(t *testing.T) {
9595 ref := NewRefToFile("file")
96 if got, want := ref.ChannelId, ""; got != want {
97 t.Errorf("ChannelId got %s, want %s", got, want)
96 if got, want := ref.Channel, ""; got != want {
97 t.Errorf("Channel got %s, want %s", got, want)
9898 }
9999 if got, want := ref.Timestamp, ""; got != want {
100100 t.Errorf("Timestamp got %s, want %s", got, want)
101101 }
102 if got, want := ref.FileId, "file"; got != want {
103 t.Errorf("FileId got %s, want %s", got, want)
102 if got, want := ref.File, "file"; got != want {
103 t.Errorf("File got %s, want %s", got, want)
104104 }
105 if got, want := ref.CommentId, ""; got != want {
106 t.Errorf("CommentId got %s, want %s", got, want)
105 if got, want := ref.Comment, ""; got != want {
106 t.Errorf("Comment got %s, want %s", got, want)
107107 }
108108 }
109109
110110 func TestNewRefToComment(t *testing.T) {
111111 ref := NewRefToComment("file_comment")
112 if got, want := ref.ChannelId, ""; got != want {
113 t.Errorf("ChannelId got %s, want %s", got, want)
112 if got, want := ref.Channel, ""; got != want {
113 t.Errorf("Channel got %s, want %s", got, want)
114114 }
115115 if got, want := ref.Timestamp, ""; got != want {
116116 t.Errorf("Timestamp got %s, want %s", got, want)
117117 }
118 if got, want := ref.FileId, ""; got != want {
119 t.Errorf("FileId got %s, want %s", got, want)
118 if got, want := ref.File, ""; got != want {
119 t.Errorf("File got %s, want %s", got, want)
120120 }
121 if got, want := ref.CommentId, "file_comment"; got != want {
122 t.Errorf("CommentId got %s, want %s", got, want)
121 if got, want := ref.Comment, "file_comment"; got != want {
122 t.Errorf("Comment got %s, want %s", got, want)
123123 }
124124 }
00 package slack
11
2 // OutgoingMessage is used for the realtime API, and seems incomplete.
23 type OutgoingMessage struct {
3 Id int `json:"id"`
4 ChannelId string `json:"channel,omitempty"`
5 Text string `json:"text,omitempty"`
6 Type string `json:"type,omitempty"`
4 ID int `json:"id"`
5 Channel string `json:"channel,omitempty"`
6 Text string `json:"text,omitempty"`
7 Type string `json:"type,omitempty"`
78 }
89
910 // Message is an auxiliary type to allow us to have a message containing sub messages
1415
1516 // Msg contains information about a slack message
1617 type Msg struct {
17 Id string `json:"id"`
18 BotId string `json:"bot_id,omitempty"`
19 UserId string `json:"user,omitempty"`
20 Username string `json:"username,omitempty"`
21 ChannelId string `json:"channel,omitempty"`
22 Timestamp string `json:"ts,omitempty"`
23 Text string `json:"text,omitempty"`
24 Team string `json:"team,omitempty"`
25 File *File `json:"file,omitempty"`
26 // Type may come if it's part of a message list
27 // e.g.: channel.history
28 Type string `json:"type,omitempty"`
29 IsStarred bool `json:"is_starred,omitempty"`
30 // Submessage
31 SubType string `json:"subtype,omitempty"`
32 Hidden bool `json:"bool,omitempty"`
33 DeletedTimestamp string `json:"deleted_ts,omitempty"`
34 Attachments []Attachment `json:"attachments,omitempty"`
35 ReplyTo int `json:"reply_to,omitempty"`
36 Upload bool `json:"upload,omitempty"`
18 // Basic Message
19 Type string `json:"type,omitempty"`
20 Channel string `json:"channel,omitempty"`
21 User string `json:"user,omitempty"`
22 Text string `json:"text,omitempty"`
23 Timestamp string `json:"ts,omitempty"`
24 IsStarred bool `json:"is_starred,omitempty"`
25 Attachments []Attachment `json:"attachments,omitempty"`
26 Edited *Edited `json:"edited,omitempty"`
27
28 // Message Subtypes
29 SubType string `json:"subtype,omitempty"`
30
31 // Hidden Subtypes
32 Hidden bool `json:"hidden,omitempty"` // message_changed, message_deleted, unpinned_item
33 DeletedTimestamp string `json:"deleted_ts,omitempty"` // message_deleted
34 EventTimestamp string `json:"event_ts,omitempty"`
35
36 // bot_message (https://api.slack.com/events/message/bot_message)
37 BotID string `json:"bot_id,omitempty"`
38 Username string `json:"username,omitempty"`
39 Icons *Icon `json:"icons,omitempty"`
40
41 // channel_join, group_join
42 Inviter string `json:"inviter,omitempty"`
43
44 // channel_topic, group_topic
45 Topic string `json:"topic,omitempty"`
46
47 // channel_purpose, group_purpose
48 Purpose string `json:"purpose,omitempty"`
49
50 // channel_name, group_name
51 Name string `json:"name,omitempty"`
52 OldName string `json:"old_name,omitempty"`
53
54 // channel_archive, group_archive
55 Members []string `json:"members,omitempty"`
56
57 // file_share, file_comment, file_mention
58 File *File `json:"file,omitempty"`
59
60 // file_share
61 Upload bool `json:"upload,omitempty"`
62
63 // file_comment
64 Comment *Comment `json:"comment,omitempty"`
65
66 // pinned_item
67 ItemType string `json:"item_type,omitempty"`
68
69 // https://api.slack.com/rtm
70 ReplyTo int `json:"reply_to,omitempty"`
71 Team string `json:"team,omitempty"`
3772 }
3873
39 // Presence XXX: not used yet
40 type Presence struct {
41 Presence string `json:"presence"`
42 UserId string `json:"user"`
74 // Icon is used for bot messages
75 type Icon struct {
76 IconURL string `json:"icon_url,omitempty"`
77 IconEmoji string `json:"icon_emoji,omitempty"`
78 }
79
80 // Edited indicates that a message has been edited.
81 type Edited struct {
82 User string `json:"user,omitempty"`
83 Timestamp string `json:"ts,omitempty"`
4384 }
4485
4586 // Event contains the event type
4990
5091 // Ping contains information about a Ping Event
5192 type Ping struct {
52 Id int `json:"id"`
93 ID int `json:"id"`
5394 Type string `json:"type"`
5495 }
5596
59100 ReplyTo int `json:"reply_to"`
60101 }
61102
62 // NewOutGoingMessage prepares an OutgoingMessage that the user can use to send a message
63 func (api *SlackWS) NewOutgoingMessage(text string, channel string) *OutgoingMessage {
103 // NewOutgoingMessage prepares an OutgoingMessage that the user can use to send a message
104 func (api *WS) NewOutgoingMessage(text string, channel string) *OutgoingMessage {
64105 api.mutex.Lock()
65106 defer api.mutex.Unlock()
66 api.messageId++
107 api.messageID++
67108 return &OutgoingMessage{
68 Id: api.messageId,
69 Type: "message",
70 ChannelId: channel,
71 Text: text,
109 ID: api.messageID,
110 Type: "message",
111 Channel: channel,
112 Text: text,
72113 }
73114 }
0 package slack
1
2 import (
3 "encoding/json"
4 "fmt"
5 "testing"
6
7 "github.com/stretchr/testify/assert"
8 )
9
10 var simpleMessage = `{
11 "type": "message",
12 "channel": "C2147483705",
13 "user": "U2147483697",
14 "text": "Hello world",
15 "ts": "1355517523.000005"
16 }`
17
18 func unmarshalMessage(j string) (*Message, error) {
19 message := &Message{}
20 if err := json.Unmarshal([]byte(j), &message); err != nil {
21 return nil, err
22 }
23 return message, nil
24 }
25
26 func TestSimpleMessage(t *testing.T) {
27 message, err := unmarshalMessage(simpleMessage)
28 assert.Nil(t, err)
29 assert.NotNil(t, message)
30 assert.Equal(t, "message", message.Type)
31 assert.Equal(t, "C2147483705", message.Channel)
32 assert.Equal(t, "U2147483697", message.User)
33 assert.Equal(t, "Hello world", message.Text)
34 assert.Equal(t, "1355517523.000005", message.Timestamp)
35 }
36
37 var starredMessage = `{
38 "text": "is testing",
39 "type": "message",
40 "subtype": "me_message",
41 "user": "U2147483697",
42 "ts": "1433314126.000003",
43 "is_starred": true
44 }`
45
46 func TestStarredMessage(t *testing.T) {
47 message, err := unmarshalMessage(starredMessage)
48 assert.Nil(t, err)
49 assert.NotNil(t, message)
50 assert.Equal(t, "is testing", message.Text)
51 assert.Equal(t, "message", message.Type)
52 assert.Equal(t, "me_message", message.SubType)
53 assert.Equal(t, "U2147483697", message.User)
54 assert.Equal(t, "1433314126.000003", message.Timestamp)
55 assert.Equal(t, true, message.IsStarred)
56 }
57
58 var editedMessage = `{
59 "type": "message",
60 "user": "U2147483697",
61 "text": "hello edited",
62 "edited": {
63 "user": "U2147483697",
64 "ts": "1433314416.000000"
65 },
66 "ts": "1433314408.000004"
67 }`
68
69 func TestEditedMessage(t *testing.T) {
70 message, err := unmarshalMessage(editedMessage)
71 assert.Nil(t, err)
72 assert.NotNil(t, message)
73 assert.Equal(t, "message", message.Type)
74 assert.Equal(t, "U2147483697", message.User)
75 assert.Equal(t, "hello edited", message.Text)
76 assert.NotNil(t, message.Edited)
77 assert.Equal(t, "U2147483697", message.Edited.User)
78 assert.Equal(t, "1433314416.000000", message.Edited.Timestamp)
79 assert.Equal(t, "1433314408.000004", message.Timestamp)
80 }
81
82 var uploadedFile = `{
83 "type": "message",
84 "subtype": "file_share",
85 "text": "<@U2147483697|tester> uploaded a file: <https:\/\/test.slack.com\/files\/tester\/abc\/test.txt|test.txt> and commented: test comment here",
86 "file": {
87 "id": "abc",
88 "created": 1433314757,
89 "timestamp": 1433314757,
90 "name": "test.txt",
91 "title": "test.txt",
92 "mimetype": "text\/plain",
93 "filetype": "text",
94 "pretty_type": "Plain Text",
95 "user": "U2147483697",
96 "editable": true,
97 "size": 5,
98 "mode": "snippet",
99 "is_external": false,
100 "external_type": "",
101 "is_public": true,
102 "public_url_shared": false,
103 "url": "https:\/\/slack-files.com\/files-pub\/abc-def-ghi\/test.txt",
104 "url_download": "https:\/\/slack-files.com\/files-pub\/abc-def-ghi\/download\/test.txt",
105 "url_private": "https:\/\/files.slack.com\/files-pri\/abc-def\/test.txt",
106 "url_private_download": "https:\/\/files.slack.com\/files-pri\/abc-def\/download\/test.txt",
107 "permalink": "https:\/\/test.slack.com\/files\/tester\/abc\/test.txt",
108 "permalink_public": "https:\/\/slack-files.com\/abc-def-ghi",
109 "edit_link": "https:\/\/test.slack.com\/files\/tester\/abc\/test.txt\/edit",
110 "preview": "test\n",
111 "preview_highlight": "<div class=\"sssh-code\"><div class=\"sssh-line\"><pre>test<\/pre><\/div>\n<div class=\"sssh-line\"><pre><\/pre><\/div>\n<\/div>",
112 "lines": 2,
113 "lines_more": 0,
114 "channels": [
115 "C2147483705"
116 ],
117 "groups": [],
118 "ims": [],
119 "comments_count": 1,
120 "initial_comment": {
121 "id": "Fc066YLGKH",
122 "created": 1433314757,
123 "timestamp": 1433314757,
124 "user": "U2147483697",
125 "comment": "test comment here"
126 }
127 },
128 "user": "U2147483697",
129 "upload": true,
130 "ts": "1433314757.000006"
131 }`
132
133 func TestUploadedFile(t *testing.T) {
134 message, err := unmarshalMessage(uploadedFile)
135 assert.Nil(t, err)
136 assert.NotNil(t, message)
137 assert.Equal(t, "message", message.Type)
138 assert.Equal(t, "file_share", message.SubType)
139 assert.Equal(t, "<@U2147483697|tester> uploaded a file: <https://test.slack.com/files/tester/abc/test.txt|test.txt> and commented: test comment here", message.Text)
140 // TODO: Assert File
141 assert.Equal(t, "U2147483697", message.User)
142 assert.True(t, message.Upload)
143 assert.Equal(t, "1433314757.000006", message.Timestamp)
144 }
145
146 var testPost = `{
147 "type": "message",
148 "subtype": "file_share",
149 "text": "<@U2147483697|tester> shared a file: <https:\/\/test.slack.com\/files\/tester\/abc\/test_post|test post>",
150 "file": {
151 "id": "abc",
152 "created": 1433315398,
153 "timestamp": 1433315398,
154 "name": "test_post",
155 "title": "test post",
156 "mimetype": "text\/plain",
157 "filetype": "post",
158 "pretty_type": "Post",
159 "user": "U2147483697",
160 "editable": true,
161 "size": 14,
162 "mode": "post",
163 "is_external": false,
164 "external_type": "",
165 "is_public": true,
166 "public_url_shared": false,
167 "url": "https:\/\/slack-files.com\/files-pub\/abc-def-ghi\/test_post",
168 "url_download": "https:\/\/slack-files.com\/files-pub\/abc-def-ghi\/download\/test_post",
169 "url_private": "https:\/\/files.slack.com\/files-pri\/abc-def\/test_post",
170 "url_private_download": "https:\/\/files.slack.com\/files-pri\/abc-def\/download\/test_post",
171 "permalink": "https:\/\/test.slack.com\/files\/tester\/abc\/test_post",
172 "permalink_public": "https:\/\/slack-files.com\/abc-def-ghi",
173 "edit_link": "https:\/\/test.slack.com\/files\/tester\/abc\/test_post\/edit",
174 "preview": "test post body",
175 "channels": [
176 "C2147483705"
177 ],
178 "groups": [],
179 "ims": [],
180 "comments_count": 1
181 },
182 "user": "U2147483697",
183 "upload": false,
184 "ts": "1433315416.000008"
185 }`
186
187 func TestPost(t *testing.T) {
188 message, err := unmarshalMessage(testPost)
189 assert.Nil(t, err)
190 assert.NotNil(t, message)
191 assert.Equal(t, "message", message.Type)
192 assert.Equal(t, "file_share", message.SubType)
193 assert.Equal(t, "<@U2147483697|tester> shared a file: <https://test.slack.com/files/tester/abc/test_post|test post>", message.Text)
194 // TODO: Assert File
195 assert.Equal(t, "U2147483697", message.User)
196 assert.False(t, message.Upload)
197 assert.Equal(t, "1433315416.000008", message.Timestamp)
198 }
199
200 var testComment = `{
201 "type": "message",
202 "subtype": "file_comment",
203 "text": "<@U2147483697|tester> commented on <@U2147483697|tester>'s file <https:\/\/test.slack.com\/files\/tester\/abc\/test_post|test post>: another comment",
204 "file": {
205 "id": "abc",
206 "created": 1433315398,
207 "timestamp": 1433315398,
208 "name": "test_post",
209 "title": "test post",
210 "mimetype": "text\/plain",
211 "filetype": "post",
212 "pretty_type": "Post",
213 "user": "U2147483697",
214 "editable": true,
215 "size": 14,
216 "mode": "post",
217 "is_external": false,
218 "external_type": "",
219 "is_public": true,
220 "public_url_shared": false,
221 "url": "https:\/\/slack-files.com\/files-pub\/abc-def-ghi\/test_post",
222 "url_download": "https:\/\/slack-files.com\/files-pub\/abc-def-ghi\/download\/test_post",
223 "url_private": "https:\/\/files.slack.com\/files-pri\/abc-def\/test_post",
224 "url_private_download": "https:\/\/files.slack.com\/files-pri\/abc-def\/download\/test_post",
225 "permalink": "https:\/\/test.slack.com\/files\/tester\/abc\/test_post",
226 "permalink_public": "https:\/\/slack-files.com\/abc-def-ghi",
227 "edit_link": "https:\/\/test.slack.com\/files\/tester\/abc\/test_post\/edit",
228 "preview": "test post body",
229 "channels": [
230 "C2147483705"
231 ],
232 "groups": [],
233 "ims": [],
234 "comments_count": 2
235 },
236 "comment": {
237 "id": "xyz",
238 "created": 1433316360,
239 "timestamp": 1433316360,
240 "user": "U2147483697",
241 "comment": "another comment"
242 },
243 "ts": "1433316360.000009"
244 }`
245
246 func TestComment(t *testing.T) {
247 message, err := unmarshalMessage(testComment)
248 fmt.Println(err)
249 assert.Nil(t, err)
250 assert.NotNil(t, message)
251 assert.Equal(t, "message", message.Type)
252 assert.Equal(t, "file_comment", message.SubType)
253 assert.Equal(t, "<@U2147483697|tester> commented on <@U2147483697|tester>'s file <https://test.slack.com/files/tester/abc/test_post|test post>: another comment", message.Text)
254 // TODO: Assert File
255 // TODO: Assert Comment
256 assert.Equal(t, "1433316360.000009", message.Timestamp)
257 }
258
259 var botMessage = `{
260 "type": "message",
261 "subtype": "bot_message",
262 "ts": "1358877455.000010",
263 "text": "Pushing is the answer",
264 "bot_id": "BB12033",
265 "username": "github",
266 "icons": {}
267 }`
268
269 func TestBotMessage(t *testing.T) {
270 message, err := unmarshalMessage(botMessage)
271 assert.Nil(t, err)
272 assert.NotNil(t, message)
273 assert.Equal(t, "message", message.Type)
274 assert.Equal(t, "bot_message", message.SubType)
275 assert.Equal(t, "1358877455.000010", message.Timestamp)
276 assert.Equal(t, "Pushing is the answer", message.Text)
277 assert.Equal(t, "BB12033", message.BotID)
278 assert.Equal(t, "github", message.Username)
279 assert.NotNil(t, message.Icons)
280 assert.Empty(t, message.Icons.IconURL)
281 assert.Empty(t, message.Icons.IconEmoji)
282 }
283
284 var meMessage = `{
285 "type": "message",
286 "subtype": "me_message",
287 "channel": "C2147483705",
288 "user": "U2147483697",
289 "text": "is doing that thing",
290 "ts": "1355517523.000005"
291 }`
292
293 func TestMeMessage(t *testing.T) {
294 message, err := unmarshalMessage(meMessage)
295 assert.Nil(t, err)
296 assert.NotNil(t, message)
297 assert.Equal(t, "message", message.Type)
298 assert.Equal(t, "me_message", message.SubType)
299 assert.Equal(t, "C2147483705", message.Channel)
300 assert.Equal(t, "U2147483697", message.User)
301 assert.Equal(t, "is doing that thing", message.Text)
302 assert.Equal(t, "1355517523.000005", message.Timestamp)
303 }
304
305 var messageChangedMessage = `{
306 "type": "message",
307 "subtype": "message_changed",
308 "hidden": true,
309 "channel": "C2147483705",
310 "ts": "1358878755.000001",
311 "message": {
312 "type": "message",
313 "user": "U2147483697",
314 "text": "Hello, world!",
315 "ts": "1355517523.000005",
316 "edited": {
317 "user": "U2147483697",
318 "ts": "1358878755.000001"
319 }
320 }
321 }`
322
323 func TestMessageChangedMessage(t *testing.T) {
324 message, err := unmarshalMessage(messageChangedMessage)
325 assert.Nil(t, err)
326 assert.NotNil(t, message)
327 assert.Equal(t, "message", message.Type)
328 assert.Equal(t, "message_changed", message.SubType)
329 assert.True(t, message.Hidden)
330 assert.Equal(t, "C2147483705", message.Channel)
331 assert.NotNil(t, message.SubMessage)
332 assert.Equal(t, "message", message.SubMessage.Type)
333 assert.Equal(t, "U2147483697", message.SubMessage.User)
334 assert.Equal(t, "Hello, world!", message.SubMessage.Text)
335 assert.Equal(t, "1355517523.000005", message.SubMessage.Timestamp)
336 assert.NotNil(t, message.SubMessage.Edited)
337 assert.Equal(t, "U2147483697", message.SubMessage.Edited.User)
338 assert.Equal(t, "1358878755.000001", message.SubMessage.Edited.Timestamp)
339 assert.Equal(t, "1358878755.000001", message.Timestamp)
340 }
341
342 var messageDeletedMessage = `{
343 "type": "message",
344 "subtype": "message_deleted",
345 "hidden": true,
346 "channel": "C2147483705",
347 "ts": "1358878755.000001",
348 "deleted_ts": "1358878749.000002"
349 }`
350
351 func TestMessageDeletedMessage(t *testing.T) {
352 message, err := unmarshalMessage(messageDeletedMessage)
353 assert.Nil(t, err)
354 assert.NotNil(t, message)
355 assert.Equal(t, "message", message.Type)
356 assert.Equal(t, "message_deleted", message.SubType)
357 assert.True(t, message.Hidden)
358 assert.Equal(t, "C2147483705", message.Channel)
359 assert.Equal(t, "1358878755.000001", message.Timestamp)
360 assert.Equal(t, "1358878749.000002", message.DeletedTimestamp)
361 }
362
363 var channelJoinMessage = `{
364 "type": "message",
365 "subtype": "channel_join",
366 "ts": "1358877458.000011",
367 "user": "U2147483828",
368 "text": "<@U2147483828|cal> has joined the channel"
369 }`
370
371 func TestChannelJoinMessage(t *testing.T) {
372 message, err := unmarshalMessage(channelJoinMessage)
373 assert.Nil(t, err)
374 assert.NotNil(t, message)
375 assert.Equal(t, "message", message.Type)
376 assert.Equal(t, "channel_join", message.SubType)
377 assert.Equal(t, "1358877458.000011", message.Timestamp)
378 assert.Equal(t, "U2147483828", message.User)
379 assert.Equal(t, "<@U2147483828|cal> has joined the channel", message.Text)
380 }
381
382 var channelJoinInvitedMessage = `{
383 "type": "message",
384 "subtype": "channel_join",
385 "ts": "1358877458.000011",
386 "user": "U2147483828",
387 "text": "<@U2147483828|cal> has joined the channel",
388 "inviter": "U2147483829"
389 }`
390
391 func TestChannelJoinInvitedMessage(t *testing.T) {
392 message, err := unmarshalMessage(channelJoinInvitedMessage)
393 assert.Nil(t, err)
394 assert.NotNil(t, message)
395 assert.Equal(t, "message", message.Type)
396 assert.Equal(t, "channel_join", message.SubType)
397 assert.Equal(t, "1358877458.000011", message.Timestamp)
398 assert.Equal(t, "U2147483828", message.User)
399 assert.Equal(t, "<@U2147483828|cal> has joined the channel", message.Text)
400 assert.Equal(t, "U2147483829", message.Inviter)
401 }
402
403 var channelLeaveMessage = `{
404 "type": "message",
405 "subtype": "channel_leave",
406 "ts": "1358877455.000010",
407 "user": "U2147483828",
408 "text": "<@U2147483828|cal> has left the channel"
409 }`
410
411 func TestChannelLeaveMessage(t *testing.T) {
412 message, err := unmarshalMessage(channelLeaveMessage)
413 assert.Nil(t, err)
414 assert.NotNil(t, message)
415 assert.Equal(t, "message", message.Type)
416 assert.Equal(t, "channel_leave", message.SubType)
417 assert.Equal(t, "1358877455.000010", message.Timestamp)
418 assert.Equal(t, "U2147483828", message.User)
419 assert.Equal(t, "<@U2147483828|cal> has left the channel", message.Text)
420 }
421
422 var channelTopicMessage = `{
423 "type": "message",
424 "subtype": "channel_topic",
425 "ts": "1358877455.000010",
426 "user": "U2147483828",
427 "topic": "hello world",
428 "text": "<@U2147483828|cal> set the channel topic: hello world"
429 }`
430
431 func TestChannelTopicMessage(t *testing.T) {
432 message, err := unmarshalMessage(channelTopicMessage)
433 assert.Nil(t, err)
434 assert.NotNil(t, message)
435 assert.Equal(t, "message", message.Type)
436 assert.Equal(t, "channel_topic", message.SubType)
437 assert.Equal(t, "1358877455.000010", message.Timestamp)
438 assert.Equal(t, "U2147483828", message.User)
439 assert.Equal(t, "hello world", message.Topic)
440 assert.Equal(t, "<@U2147483828|cal> set the channel topic: hello world", message.Text)
441 }
442
443 var channelPurposeMessage = `{
444 "type": "message",
445 "subtype": "channel_purpose",
446 "ts": "1358877455.000010",
447 "user": "U2147483828",
448 "purpose": "whatever",
449 "text": "<@U2147483828|cal> set the channel purpose: whatever"
450 }`
451
452 func TestChannelPurposeMessage(t *testing.T) {
453 message, err := unmarshalMessage(channelPurposeMessage)
454 assert.Nil(t, err)
455 assert.NotNil(t, message)
456 assert.Equal(t, "message", message.Type)
457 assert.Equal(t, "channel_purpose", message.SubType)
458 assert.Equal(t, "1358877455.000010", message.Timestamp)
459 assert.Equal(t, "U2147483828", message.User)
460 assert.Equal(t, "whatever", message.Purpose)
461 assert.Equal(t, "<@U2147483828|cal> set the channel purpose: whatever", message.Text)
462 }
463
464 var channelNameMessage = `{
465 "type": "message",
466 "subtype": "channel_name",
467 "ts": "1358877455.000010",
468 "user": "U2147483828",
469 "old_name": "random",
470 "name": "watercooler",
471 "text": "<@U2147483828|cal> has renamed the channel from \"random\" to \"watercooler\""
472 }`
473
474 func TestChannelNameMessage(t *testing.T) {
475 message, err := unmarshalMessage(channelNameMessage)
476 assert.Nil(t, err)
477 assert.NotNil(t, message)
478 assert.Equal(t, "message", message.Type)
479 assert.Equal(t, "channel_name", message.SubType)
480 assert.Equal(t, "1358877455.000010", message.Timestamp)
481 assert.Equal(t, "U2147483828", message.User)
482 assert.Equal(t, "random", message.OldName)
483 assert.Equal(t, "watercooler", message.Name)
484 assert.Equal(t, "<@U2147483828|cal> has renamed the channel from \"random\" to \"watercooler\"", message.Text)
485 }
486
487 var channelArchiveMessage = `{
488 "type": "message",
489 "subtype": "channel_archive",
490 "ts": "1361482916.000003",
491 "text": "<U1234|@cal> archived the channel",
492 "user": "U1234",
493 "members": ["U1234", "U5678"]
494 }`
495
496 func TestChannelArchiveMessage(t *testing.T) {
497 message, err := unmarshalMessage(channelArchiveMessage)
498 assert.Nil(t, err)
499 assert.NotNil(t, message)
500 assert.Equal(t, "message", message.Type)
501 assert.Equal(t, "channel_archive", message.SubType)
502 assert.Equal(t, "1361482916.000003", message.Timestamp)
503 assert.Equal(t, "<U1234|@cal> archived the channel", message.Text)
504 assert.Equal(t, "U1234", message.User)
505 assert.NotNil(t, message.Members)
506 assert.Equal(t, 2, len(message.Members))
507 }
508
509 var channelUnarchiveMessage = `{
510 "type": "message",
511 "subtype": "channel_unarchive",
512 "ts": "1361482916.000003",
513 "text": "<U1234|@cal> un-archived the channel",
514 "user": "U1234"
515 }`
516
517 func TestChannelUnarchiveMessage(t *testing.T) {
518 message, err := unmarshalMessage(channelUnarchiveMessage)
519 assert.Nil(t, err)
520 assert.NotNil(t, message)
521 assert.Equal(t, "message", message.Type)
522 assert.Equal(t, "channel_unarchive", message.SubType)
523 assert.Equal(t, "1361482916.000003", message.Timestamp)
524 assert.Equal(t, "<U1234|@cal> un-archived the channel", message.Text)
525 assert.Equal(t, "U1234", message.User)
526 }
527
528 var groupJoinMessage = `{
529 "type": "message",
530 "subtype": "group_join",
531 "ts": "1358877458.000011",
532 "user": "U2147483828",
533 "text": "<@U2147483828|cal> has joined the group"
534 }`
535
536 func TestGroupJoinMessage(t *testing.T) {
537 message, err := unmarshalMessage(groupJoinMessage)
538 assert.Nil(t, err)
539 assert.NotNil(t, message)
540 assert.Equal(t, "message", message.Type)
541 assert.Equal(t, "group_join", message.SubType)
542 assert.Equal(t, "1358877458.000011", message.Timestamp)
543 assert.Equal(t, "U2147483828", message.User)
544 assert.Equal(t, "<@U2147483828|cal> has joined the group", message.Text)
545 }
546
547 var groupJoinInvitedMessage = `{
548 "type": "message",
549 "subtype": "group_join",
550 "ts": "1358877458.000011",
551 "user": "U2147483828",
552 "text": "<@U2147483828|cal> has joined the group",
553 "inviter": "U2147483829"
554 }`
555
556 func TestGroupJoinInvitedMessage(t *testing.T) {
557 message, err := unmarshalMessage(groupJoinInvitedMessage)
558 assert.Nil(t, err)
559 assert.NotNil(t, message)
560 assert.Equal(t, "message", message.Type)
561 assert.Equal(t, "group_join", message.SubType)
562 assert.Equal(t, "1358877458.000011", message.Timestamp)
563 assert.Equal(t, "U2147483828", message.User)
564 assert.Equal(t, "<@U2147483828|cal> has joined the group", message.Text)
565 assert.Equal(t, "U2147483829", message.Inviter)
566 }
567
568 var groupLeaveMessage = `{
569 "type": "message",
570 "subtype": "group_leave",
571 "ts": "1358877455.000010",
572 "user": "U2147483828",
573 "text": "<@U2147483828|cal> has left the group"
574 }`
575
576 func TestGroupLeaveMessage(t *testing.T) {
577 message, err := unmarshalMessage(groupLeaveMessage)
578 assert.Nil(t, err)
579 assert.NotNil(t, message)
580 assert.Equal(t, "message", message.Type)
581 assert.Equal(t, "group_leave", message.SubType)
582 assert.Equal(t, "1358877455.000010", message.Timestamp)
583 assert.Equal(t, "U2147483828", message.User)
584 assert.Equal(t, "<@U2147483828|cal> has left the group", message.Text)
585 }
586
587 var groupTopicMessage = `{
588 "type": "message",
589 "subtype": "group_topic",
590 "ts": "1358877455.000010",
591 "user": "U2147483828",
592 "topic": "hello world",
593 "text": "<@U2147483828|cal> set the group topic: hello world"
594 }`
595
596 func TestGroupTopicMessage(t *testing.T) {
597 message, err := unmarshalMessage(groupTopicMessage)
598 assert.Nil(t, err)
599 assert.NotNil(t, message)
600 assert.Equal(t, "message", message.Type)
601 assert.Equal(t, "group_topic", message.SubType)
602 assert.Equal(t, "1358877455.000010", message.Timestamp)
603 assert.Equal(t, "U2147483828", message.User)
604 assert.Equal(t, "hello world", message.Topic)
605 assert.Equal(t, "<@U2147483828|cal> set the group topic: hello world", message.Text)
606 }
607
608 var groupPurposeMessage = `{
609 "type": "message",
610 "subtype": "group_purpose",
611 "ts": "1358877455.000010",
612 "user": "U2147483828",
613 "purpose": "whatever",
614 "text": "<@U2147483828|cal> set the group purpose: whatever"
615 }`
616
617 func TestGroupPurposeMessage(t *testing.T) {
618 message, err := unmarshalMessage(groupPurposeMessage)
619 assert.Nil(t, err)
620 assert.NotNil(t, message)
621 assert.Equal(t, "message", message.Type)
622 assert.Equal(t, "group_purpose", message.SubType)
623 assert.Equal(t, "1358877455.000010", message.Timestamp)
624 assert.Equal(t, "U2147483828", message.User)
625 assert.Equal(t, "whatever", message.Purpose)
626 assert.Equal(t, "<@U2147483828|cal> set the group purpose: whatever", message.Text)
627 }
628
629 var groupNameMessage = `{
630 "type": "message",
631 "subtype": "group_name",
632 "ts": "1358877455.000010",
633 "user": "U2147483828",
634 "old_name": "random",
635 "name": "watercooler",
636 "text": "<@U2147483828|cal> has renamed the group from \"random\" to \"watercooler\""
637 }`
638
639 func TestGroupNameMessage(t *testing.T) {
640 message, err := unmarshalMessage(groupNameMessage)
641 assert.Nil(t, err)
642 assert.NotNil(t, message)
643 assert.Equal(t, "message", message.Type)
644 assert.Equal(t, "group_name", message.SubType)
645 assert.Equal(t, "1358877455.000010", message.Timestamp)
646 assert.Equal(t, "U2147483828", message.User)
647 assert.Equal(t, "random", message.OldName)
648 assert.Equal(t, "watercooler", message.Name)
649 assert.Equal(t, "<@U2147483828|cal> has renamed the group from \"random\" to \"watercooler\"", message.Text)
650 }
651
652 var groupArchiveMessage = `{
653 "type": "message",
654 "subtype": "group_archive",
655 "ts": "1361482916.000003",
656 "text": "<U1234|@cal> archived the group",
657 "user": "U1234",
658 "members": ["U1234", "U5678"]
659 }`
660
661 func TestGroupArchiveMessage(t *testing.T) {
662 message, err := unmarshalMessage(groupArchiveMessage)
663 assert.Nil(t, err)
664 assert.NotNil(t, message)
665 assert.Equal(t, "message", message.Type)
666 assert.Equal(t, "group_archive", message.SubType)
667 assert.Equal(t, "1361482916.000003", message.Timestamp)
668 assert.Equal(t, "<U1234|@cal> archived the group", message.Text)
669 assert.Equal(t, "U1234", message.User)
670 assert.NotNil(t, message.Members)
671 assert.Equal(t, 2, len(message.Members))
672 }
673
674 var groupUnarchiveMessage = `{
675 "type": "message",
676 "subtype": "group_unarchive",
677 "ts": "1361482916.000003",
678 "text": "<U1234|@cal> un-archived the group",
679 "user": "U1234"
680 }`
681
682 func TestGroupUnarchiveMessage(t *testing.T) {
683 message, err := unmarshalMessage(groupUnarchiveMessage)
684 assert.Nil(t, err)
685 assert.NotNil(t, message)
686 assert.Equal(t, "message", message.Type)
687 assert.Equal(t, "group_unarchive", message.SubType)
688 assert.Equal(t, "1361482916.000003", message.Timestamp)
689 assert.Equal(t, "<U1234|@cal> un-archived the group", message.Text)
690 assert.Equal(t, "U1234", message.User)
691 }
692
693 var fileShareMessage = `{
694 "type": "message",
695 "subtype": "file_share",
696 "ts": "1358877455.000010",
697 "text": "<@cal> uploaded a file: <https:...7.png|7.png>",
698 "file": {
699 "id" : "F2147483862",
700 "created" : 1356032811,
701 "timestamp" : 1356032811,
702 "name" : "file.htm",
703 "title" : "My HTML file",
704 "mimetype" : "text\/plain",
705 "filetype" : "text",
706 "pretty_type": "Text",
707 "user" : "U2147483697",
708 "mode" : "hosted",
709 "editable" : true,
710 "is_external": false,
711 "external_type": "",
712 "size" : 12345,
713 "url": "https:\/\/slack-files.com\/files-pub\/T024BE7LD-F024BERPE-09acb6\/1.png",
714 "url_download": "https:\/\/slack-files.com\/files-pub\/T024BE7LD-F024BERPE-09acb6\/download\/1.png",
715 "url_private": "https:\/\/slack.com\/files-pri\/T024BE7LD-F024BERPE\/1.png",
716 "url_private_download": "https:\/\/slack.com\/files-pri\/T024BE7LD-F024BERPE\/download\/1.png",
717 "thumb_64": "https:\/\/slack-files.com\/files-tmb\/T024BE7LD-F024BERPE-c66246\/1_64.png",
718 "thumb_80": "https:\/\/slack-files.com\/files-tmb\/T024BE7LD-F024BERPE-c66246\/1_80.png",
719 "thumb_360": "https:\/\/slack-files.com\/files-tmb\/T024BE7LD-F024BERPE-c66246\/1_360.png",
720 "thumb_360_gif": "https:\/\/slack-files.com\/files-tmb\/T024BE7LD-F024BERPE-c66246\/1_360.gif",
721 "thumb_360_w": 100,
722 "thumb_360_h": 100,
723 "permalink" : "https:\/\/tinyspeck.slack.com\/files\/cal\/F024BERPE\/1.png",
724 "edit_link" : "https:\/\/tinyspeck.slack.com\/files\/cal\/F024BERPE\/1.png/edit",
725 "preview" : "&lt;!DOCTYPE html&gt;\n&lt;html&gt;\n&lt;meta charset='utf-8'&gt;",
726 "preview_highlight" : "&lt;div class=\"sssh-code\"&gt;&lt;div class=\"sssh-line\"&gt;&lt;pre&gt;&lt;!DOCTYPE html...",
727 "lines" : 123,
728 "lines_more": 118,
729 "is_public": true,
730 "public_url_shared": false,
731 "channels": ["C024BE7LT"],
732 "groups": ["G12345"],
733 "ims": ["D12345"],
734 "initial_comment": {},
735 "num_stars": 7,
736 "is_starred": true
737 },
738 "user": "U2147483697",
739 "upload": true
740 }`
741
742 func TestFileShareMessage(t *testing.T) {
743 message, err := unmarshalMessage(fileShareMessage)
744 fmt.Println(err)
745 assert.Nil(t, err)
746 assert.NotNil(t, message)
747 assert.Equal(t, "message", message.Type)
748 assert.Equal(t, "file_share", message.SubType)
749 assert.Equal(t, "1358877455.000010", message.Timestamp)
750 assert.Equal(t, "<@cal> uploaded a file: <https:...7.png|7.png>", message.Text)
751 assert.Equal(t, "U2147483697", message.User)
752 assert.True(t, message.Upload)
753 assert.NotNil(t, message.File)
754 }
1111 }
1212
1313 // GetOAuthToken retrieves an AccessToken
14 func GetOAuthToken(clientId, clientSecret, code, redirectURI string, debug bool) (accessToken string, scope string, err error) {
14 func GetOAuthToken(clientID, clientSecret, code, redirectURI string, debug bool) (accessToken string, scope string, err error) {
1515 values := url.Values{
16 "client_id": {clientId},
16 "client_id": {clientID},
1717 "client_secret": {clientSecret},
1818 "code": {code},
1919 "redirect_uri": {redirectURI},
5858 }
5959
6060 const (
61 DEFAULT_REACTIONS_USERID = ""
62 DEFAULT_REACTIONS_COUNT = 100
63 DEFAULT_REACTIONS_PAGE = 1
64 DEFAULT_REACTIONS_FULL = false
61 DEFAULT_REACTIONS_USER = ""
62 DEFAULT_REACTIONS_COUNT = 100
63 DEFAULT_REACTIONS_PAGE = 1
64 DEFAULT_REACTIONS_FULL = false
6565 )
6666
6767 // ListReactionsParameters is the inputs to find all reactions by a user.
6868 type ListReactionsParameters struct {
69 UserId string
70 Count int
71 Page int
72 Full bool
69 User string
70 Count int
71 Page int
72 Full bool
7373 }
7474
7575 // NewListReactionsParameters initializes the inputs to find all reactions
7676 // performed by a user.
7777 func NewListReactionsParameters() ListReactionsParameters {
7878 return ListReactionsParameters{
79 UserId: DEFAULT_REACTIONS_USERID,
80 Count: DEFAULT_REACTIONS_COUNT,
81 Page: DEFAULT_REACTIONS_PAGE,
82 Full: DEFAULT_REACTIONS_FULL,
79 User: DEFAULT_REACTIONS_USER,
80 Count: DEFAULT_REACTIONS_COUNT,
81 Page: DEFAULT_REACTIONS_PAGE,
82 Full: DEFAULT_REACTIONS_FULL,
8383 }
8484 }
8585
135135 if name != "" {
136136 values.Set("name", name)
137137 }
138 if item.ChannelId != "" {
139 values.Set("channel", string(item.ChannelId))
138 if item.Channel != "" {
139 values.Set("channel", string(item.Channel))
140140 }
141141 if item.Timestamp != "" {
142142 values.Set("timestamp", string(item.Timestamp))
143143 }
144 if item.FileId != "" {
145 values.Set("file", string(item.FileId))
146 }
147 if item.CommentId != "" {
148 values.Set("file_comment", string(item.CommentId))
144 if item.File != "" {
145 values.Set("file", string(item.File))
146 }
147 if item.Comment != "" {
148 values.Set("file_comment", string(item.Comment))
149149 }
150150 response := &SlackResponse{}
151151 if err := parseResponse("reactions.add", values, response, api.debug); err != nil {
165165 if name != "" {
166166 values.Set("name", name)
167167 }
168 if item.ChannelId != "" {
169 values.Set("channel", string(item.ChannelId))
168 if item.Channel != "" {
169 values.Set("channel", string(item.Channel))
170170 }
171171 if item.Timestamp != "" {
172172 values.Set("timestamp", string(item.Timestamp))
173173 }
174 if item.FileId != "" {
175 values.Set("file", string(item.FileId))
176 }
177 if item.CommentId != "" {
178 values.Set("file_comment", string(item.CommentId))
174 if item.File != "" {
175 values.Set("file", string(item.File))
176 }
177 if item.Comment != "" {
178 values.Set("file_comment", string(item.Comment))
179179 }
180180 response := &SlackResponse{}
181181 if err := parseResponse("reactions.remove", values, response, api.debug); err != nil {
192192 values := url.Values{
193193 "token": {api.config.token},
194194 }
195 if item.ChannelId != "" {
196 values.Set("channel", string(item.ChannelId))
195 if item.Channel != "" {
196 values.Set("channel", string(item.Channel))
197197 }
198198 if item.Timestamp != "" {
199199 values.Set("timestamp", string(item.Timestamp))
200200 }
201 if item.FileId != "" {
202 values.Set("file", string(item.FileId))
203 }
204 if item.CommentId != "" {
205 values.Set("file_comment", string(item.CommentId))
201 if item.File != "" {
202 values.Set("file", string(item.File))
203 }
204 if item.Comment != "" {
205 values.Set("file_comment", string(item.Comment))
206206 }
207207 if params.Full != DEFAULT_REACTIONS_FULL {
208208 values.Set("full", strconv.FormatBool(params.Full))
222222 values := url.Values{
223223 "token": {api.config.token},
224224 }
225 if params.UserId != DEFAULT_REACTIONS_USERID {
226 values.Add("user", params.UserId)
225 if params.User != DEFAULT_REACTIONS_USER {
226 values.Add("user", params.User)
227227 }
228228 if params.Count != DEFAULT_REACTIONS_COUNT {
229229 values.Add("count", strconv.Itoa(params.Count))
336336 },
337337 }
338338 wantParams := map[string]string{
339 "user": "UserID",
339 "user": "User",
340340 "count": "200",
341341 "page": "2",
342342 "full": "true",
343343 }
344344 params := NewListReactionsParameters()
345 params.UserId = "UserID"
345 params.User = "User"
346346 params.Count = 200
347347 params.Page = 2
348348 params.Full = true
2222 }
2323
2424 type CtxChannel struct {
25 Id string `json:"id"`
25 ID string `json:"id"`
2626 Name string `json:"name"`
2727 }
2828
2929 type CtxMessage struct {
30 UserId string `json:"user"`
30 User string `json:"user"`
3131 Username string `json:"username"`
3232 Text string `json:"text"`
3333 Timestamp string `json:"ts"`
3737 type SearchMessage struct {
3838 Type string `json:"type"`
3939 Channel CtxChannel `json:"channel"`
40 UserId string `json:"user"`
40 User string `json:"user"`
4141 Username string `json:"username"`
4242 Timestamp string `json:"ts"`
4343 Text string `json:"text"`
1616 }
1717
1818 type AuthTestResponse struct {
19 Url string `json:"url"`
19 URL string `json:"url"`
2020 Team string `json:"team"`
2121 User string `json:"user"`
22 TeamId string `json:"team_id"`
23 UserId string `json:"user_id"`
22 TeamID string `json:"team_id"`
23 UserID string `json:"user_id"`
2424 }
2525
2626 type authTestResponseFull struct {
66 )
77
88 const (
9 DEFAULT_STARS_USERID = ""
10 DEFAULT_STARS_COUNT = 100
11 DEFAULT_STARS_PAGE = 1
9 DEFAULT_STARS_USER = ""
10 DEFAULT_STARS_COUNT = 100
11 DEFAULT_STARS_PAGE = 1
1212 )
1313
1414 type StarsParameters struct {
3030
3131 func NewStarsParameters() StarsParameters {
3232 return StarsParameters{
33 User: DEFAULT_STARS_USERID,
33 User: DEFAULT_STARS_USER,
3434 Count: DEFAULT_STARS_COUNT,
3535 Page: DEFAULT_STARS_PAGE,
3636 }
5050 values := url.Values{
5151 "token": {api.config.token},
5252 }
53 if params.User != DEFAULT_STARS_USERID {
53 if params.User != DEFAULT_STARS_USER {
5454 values.Add("user", params.User)
5555 }
5656 if params.Count != DEFAULT_STARS_COUNT {
117117 for i, test := range tests {
118118 sh = newStarsHandler()
119119 sh.response = test.json
120 response_items, response_paging, err := api.GetStarred(test.params)
120 responseItems, responsePaging, err := api.GetStarred(test.params)
121121 if err != nil {
122122 t.Fatalf("%d Unexpected error: %s", i, err)
123123 }
124124 if !reflect.DeepEqual(sh.gotParams, test.wantParams) {
125125 t.Errorf("%d got %v; want %v", i, sh.gotParams, test.wantParams)
126126 }
127 if !reflect.DeepEqual(response_items, test.starredItems) {
128 t.Errorf("%d got %v; want %v", i, response_items, test.starredItems)
127 if !reflect.DeepEqual(responseItems, test.starredItems) {
128 t.Errorf("%d got %v; want %v", i, responseItems, test.starredItems)
129129 }
130 if !reflect.DeepEqual(response_paging, test.paging) {
131 t.Errorf("%d got %v; want %v", i, response_paging, test.paging)
130 if !reflect.DeepEqual(responsePaging, test.paging) {
131 t.Errorf("%d got %v; want %v", i, responsePaging, test.paging)
132132 }
133133 }
134134 }
2424
2525 // User contains all the information of a user
2626 type User struct {
27 Id string `json:"id"`
27 ID string `json:"id"`
2828 Name string `json:"name"`
2929 Deleted bool `json:"deleted"`
3030 Color string `json:"color"`
7474 }
7575
7676 // GetUserPresence will retrieve the current presence status of given user.
77 func (api *Slack) GetUserPresence(userId string) (*UserPresence, error) {
77 func (api *Slack) GetUserPresence(user string) (*UserPresence, error) {
7878 values := url.Values{
7979 "token": {api.config.token},
80 "user": {userId},
80 "user": {user},
8181 }
8282 response, err := userRequest("users.getPresence", values, api.debug)
8383 if err != nil {
8787 }
8888
8989 // GetUserInfo will retrive the complete user information
90 func (api *Slack) GetUserInfo(userId string) (*User, error) {
90 func (api *Slack) GetUserInfo(user string) (*User, error) {
9191 values := url.Values{
9292 "token": {api.config.token},
93 "user": {userId},
93 "user": {user},
9494 }
9595 response, err := userRequest("users.info", values, api.debug)
9696 if err != nil {
1515
1616 type MessageEvent Message
1717
18 type SlackWS struct {
18 type WS struct {
1919 conn *websocket.Conn
20 messageId int
20 messageID int
2121 mutex sync.Mutex
2222 pings map[int]time.Time
2323 Slack
2828 ReplyTo int `json:"reply_to"`
2929 Timestamp string `json:"ts"`
3030 Text string `json:"text"`
31 SlackWSResponse
32 }
33
34 type SlackWSResponse struct {
35 Ok bool `json:"ok"`
36 Error *SlackWSError `json:"error"`
37 }
38
39 type SlackWSError struct {
31 WSResponse
32 }
33
34 type WSResponse struct {
35 Ok bool `json:"ok"`
36 Error *WSError `json:"error"`
37 }
38
39 type WSError struct {
4040 Code int
4141 Msg string
4242 }
6363 return fmt.Sprintf("\"%s\"", tm.Format("Mon Jan _2"))
6464 }
6565
66 func (s SlackWSError) Error() string {
66 func (s WSError) Error() string {
6767 return s.Msg
6868 }
6969
7070 var portMapping = map[string]string{"ws": "80", "wss": "443"}
7171
72 func fixUrlPort(orig string) (string, error) {
72 func fixURLPort(orig string) (string, error) {
7373 urlObj, err := url.ParseRequestURI(orig)
7474 if err != nil {
7575 return "", err
8181 return orig, nil
8282 }
8383
84 func (api *Slack) StartRTM(protocol, origin string) (*SlackWS, error) {
84 func (api *Slack) StartRTM(protocol, origin string) (*WS, error) {
8585 response := &infoResponseFull{}
8686 err := parseResponse("rtm.start", url.Values{"token": {api.config.token}}, response, api.debug)
8787 if err != nil {
9494 // websocket.Dial does not accept url without the port (yet)
9595 // Fixed by: https://github.com/golang/net/commit/5058c78c3627b31e484a81463acd51c7cecc06f3
9696 // but slack returns the address with no port, so we have to fix it
97 api.info.Url, err = fixUrlPort(api.info.Url)
97 api.info.URL, err = fixURLPort(api.info.URL)
9898 if err != nil {
9999 return nil, err
100100 }
101101 api.config.protocol, api.config.origin = protocol, origin
102 wsApi := &SlackWS{Slack: *api}
103 wsApi.conn, err = websocket.Dial(api.info.Url, api.config.protocol, api.config.origin)
102 wsAPI := &WS{Slack: *api}
103 wsAPI.conn, err = websocket.Dial(api.info.URL, api.config.protocol, api.config.origin)
104104 if err != nil {
105105 return nil, err
106106 }
107 wsApi.pings = make(map[int]time.Time)
108 return wsApi, nil
109 }
110
111 func (api *SlackWS) Ping() error {
107 wsAPI.pings = make(map[int]time.Time)
108 return wsAPI, nil
109 }
110
111 func (api *WS) Ping() error {
112112 api.mutex.Lock()
113113 defer api.mutex.Unlock()
114 api.messageId++
115 msg := &Ping{Id: api.messageId, Type: "ping"}
114 api.messageID++
115 msg := &Ping{ID: api.messageID, Type: "ping"}
116116 if err := websocket.JSON.Send(api.conn, msg); err != nil {
117117 return err
118118 }
119119 // TODO: What happens if we already have this id?
120 api.pings[api.messageId] = time.Now()
120 api.pings[api.messageID] = time.Now()
121121 return nil
122122 }
123123
124 func (api *SlackWS) Keepalive(interval time.Duration) {
124 func (api *WS) Keepalive(interval time.Duration) {
125125 ticker := time.NewTicker(interval)
126126 defer ticker.Stop()
127127
135135 }
136136 }
137137
138 func (api *SlackWS) SendMessage(msg *OutgoingMessage) error {
138 func (api *WS) SendMessage(msg *OutgoingMessage) error {
139139 if msg == nil {
140140 return fmt.Errorf("Can't send a nil message")
141141 }
146146 return nil
147147 }
148148
149 func (api *SlackWS) HandleIncomingEvents(ch chan SlackEvent) {
149 func (api *WS) HandleIncomingEvents(ch chan SlackEvent) {
150150 for {
151151 event := json.RawMessage{}
152152 if err := websocket.JSON.Receive(api.conn, &event); err == io.EOF {
156156 //}
157157 // should we reconnect here?
158158 if !api.conn.IsClientConn() {
159 api.conn, err = websocket.Dial(api.info.Url, api.config.protocol, api.config.origin)
159 api.conn, err = websocket.Dial(api.info.URL, api.config.protocol, api.config.origin)
160160 if err != nil {
161161 log.Panic(err)
162162 }
179179 }
180180 }
181181
182 func (api *SlackWS) handleEvent(ch chan SlackEvent, event json.RawMessage) {
182 func (api *WS) handleEvent(ch chan SlackEvent, event json.RawMessage) {
183183 em := Event{}
184184 err := json.Unmarshal(event, &em)
185185 if err != nil {
2424 // channel_archive
2525 // channel_unarchive
2626 Type string `json:"type"`
27 ChannelId string `json:"channel"`
28 UserId string `json:"user,omitempty"`
27 Channel string `json:"channel"`
28 User string `json:"user,omitempty"`
2929 Timestamp *JSONTimeString `json:"ts,omitempty"`
3030 }
3131
3535 }
3636
3737 type ChannelRenameInfo struct {
38 Id string `json:"id"`
38 ID string `json:"id"`
3939 Name string `json:"name"`
4040 Created JSONTimeString `json:"created"`
4141 }
11
22 type IMCreatedEvent struct {
33 Type string `json:"type"`
4 UserId string `json:"user"`
4 User string `json:"user"`
55 Channel ChannelCreatedInfo `json:"channel"`
66 }
77
33 Type string `json:"type"`
44 EventTimestamp JSONTimeString `json:"event_ts"`
55 File File `json:"file"`
6 // FileId is used for FileDeletedEvent
7 FileId string `json:"file_id,omitempty"`
6 // FileID is used for FileDeletedEvent
7 FileID string `json:"file_id,omitempty"`
88 }
99
1010 type FileCreatedEvent fileActionEvent
2727
2828 type FileCommentDeletedEvent struct {
2929 fileActionEvent
30 CommentId string `json:"comment"`
30 Comment string `json:"comment"`
3131 }
11
22 type GroupCreatedEvent struct {
33 Type string `json:"type"`
4 UserId string `json:"user"`
4 User string `json:"user"`
55 Channel ChannelCreatedInfo `json:"channel"`
66 }
77
1111 type PresenceChangeEvent struct {
1212 Type string `json:"type"`
1313 Presence string `json:"presence"`
14 UserId string `json:"user"`
14 User string `json:"user"`
1515 }
1616
1717 type UserTypingEvent struct {
18 Type string `json:"type"`
19 UserId string `json:"user"`
20 ChannelId string `json:"channel"`
18 Type string `json:"type"`
19 User string `json:"user"`
20 Channel string `json:"channel"`
2121 }
2222
2323 type LatencyReport struct {
11
22 type starEvent struct {
33 Type string `json:"type"`
4 UserId string `json:"user"`
4 User string `json:"user"`
55 Item StarredItem `json:"item"`
66 EventTimestamp JSONTimeString `json:"event_ts"`
77 }
1818
1919 type TeamDomainChangeEvent struct {
2020 Type string `json:"type"`
21 Url string `json:"url"`
21 URL string `json:"url"`
2222 Domain string `json:"domain"`
2323 }
2424