Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Patch] Mute and unmute requests #818

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
92 changes: 92 additions & 0 deletions conversation.go
Expand Up @@ -2,6 +2,7 @@ package slack

import (
"context"
"fmt"
"net/url"
"strconv"
"strings"
Expand Down Expand Up @@ -191,6 +192,97 @@ func (api *Client) UnArchiveConversationContext(ctx context.Context, channelID s
return response.Err()
}

// MuteConversation updates the user's preference as to adds a channel id to the
// list of muted channel. This method returns the updated list of muted channels.
func (api *Client) MuteConversation(channelID string) ([]string, error) {
return api.MuteConversationContext(context.Background(), channelID)
}

// MuteConversationContext adds a channel id to the list of muted channel with a custom context.
func (api *Client) MuteConversationContext(ctx context.Context, channelID string) ([]string, error) {
prefs, err := api.GetUserPrefsContext(ctx)
if err != nil {
return nil, err
}

mutedChannels := strings.Split(prefs.UserPrefs.MutedChannels, ",")
for _, mc := range mutedChannels {
if mc == channelID {
return mutedChannels, nil // noop
}
}

values := url.Values{
"token": {api.token},
"prefs": {fmt.Sprintf("{\"muted_channels\": \"%s,%s\"}", prefs.UserPrefs.MutedChannels, channelID)},
"reason": {"update-muted-channels"},
}
response := UserPrefsCarrier{}

err = api.postMethod(ctx, "users.prefs.set", values, &response)
if err != nil {
return nil, err
}

if response.Err() != nil {
return nil, response.Err()
}
if response.UserPrefs == nil {
return nil, nil
}
return strings.Split(response.UserPrefs.MutedChannels, ","), nil
}

// UnMuteConversation updates the user's preference as to remove a channel id from
// the list of muted channel. This method returns the updated list of muted channels.
func (api *Client) UnMuteConversation(channelID string) ([]string, error) {
return api.UnMuteConversationContext(context.Background(), channelID)
}

// UnMuteConversationContext removes a channel id from the list of muted channel with a custom context.
func (api *Client) UnMuteConversationContext(ctx context.Context, channelID string) ([]string, error) {
prefs, err := api.GetUserPrefsContext(ctx)
if err != nil {
return nil, err
}

mutedChannels := strings.Split(prefs.UserPrefs.MutedChannels, ",")
update := []string{}
isMuted := false
for _, mc := range mutedChannels {
if mc == channelID {
isMuted = true
continue
}

update = append(update, mc)
}

if !isMuted {
return mutedChannels, nil // noop
}

values := url.Values{
"token": {api.token},
"prefs": {fmt.Sprintf("{\"muted_channels\": \"%s\"}", strings.Join(update, ","))},
"reason": {"update-muted-channels"},
}
response := UserPrefsCarrier{}

err = api.postMethod(ctx, "users.prefs.set", values, &response)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this exist? I could not find Slack's documentation...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

User preferences is part of the "undocumented" Slack API found here.
I've tested this in production and it is working as expected.

Copy link
Member

@kanata2 kanata2 Mar 26, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

undocumented"

Ah, thanks 😢

if err != nil {
return nil, err
}

if response.Err() != nil {
return nil, response.Err()
}
if response.UserPrefs == nil {
return nil, nil
}
return strings.Split(response.UserPrefs.MutedChannels, ","), nil
}

// SetTopicOfConversation sets the topic for a conversation
func (api *Client) SetTopicOfConversation(channelID, topic string) (*Channel, error) {
return api.SetTopicOfConversationContext(context.Background(), channelID, topic)
Expand Down
36 changes: 36 additions & 0 deletions conversation_test.go
Expand Up @@ -263,6 +263,42 @@ func TestUnArchiveConversation(t *testing.T) {
}
}

func getUsersPrefs(rw http.ResponseWriter, r *http.Request) {
rw.Header().Set("Content-Type", "application/json")
response, _ := json.Marshal(UserPrefsCarrier{
SlackResponse: SlackResponse{Ok: true},
UserPrefs: &UserPrefs{
MutedChannels: "CYYYYYYYY",
},
})
rw.Write(response)
}

func TestMuteConversation(t *testing.T) {
http.HandleFunc("/users.prefs.get", getUsersPrefs)
http.HandleFunc("/users.prefs.set", getUsersPrefs)
once.Do(startServer)
api := New("testing-token", OptionAPIURL("http://"+serverAddr+"/"))
_, err := api.MuteConversation("CXXXXXXXX")
if err != nil {
t.Errorf("Unexpected error: %s", err)
return
}
}

func TestUnMuteConversation(t *testing.T) {
// Handlers are commented out to avoid double declaration.
// http.HandleFunc("/users.prefs.get", getUsersPrefs)
// http.HandleFunc("/users.prefs.set", okJSONHandler)
once.Do(startServer)
api := New("testing-token", OptionAPIURL("http://"+serverAddr+"/"))
_, err := api.UnMuteConversation("CYYYYYYYY")
if err != nil {
t.Errorf("Unexpected error: %s", err)
return
}
}

func getTestChannel() *Channel {
return &Channel{
GroupConversation: GroupConversation{
Expand Down
54 changes: 6 additions & 48 deletions info.go
Expand Up @@ -6,7 +6,6 @@ import (
"fmt"
"net/url"
"strconv"
"strings"
"time"
)

Expand Down Expand Up @@ -320,58 +319,17 @@ type UserPrefs struct {
TZ string `json:"tz,omitempty"`
}

// GetUserPrefs gets the user's preferences.
func (api *Client) GetUserPrefs() (*UserPrefsCarrier, error) {
values := url.Values{"token": {api.token}}
response := UserPrefsCarrier{}

err := api.getMethod(context.Background(), "users.prefs.get", values, &response)
if err != nil {
return nil, err
}

return &response, response.Err()
}

func (api *Client) MuteChat(channelID string) (*UserPrefsCarrier, error) {
prefs, err := api.GetUserPrefs()
if err != nil {
return nil, err
}
chnls := strings.Split(prefs.UserPrefs.MutedChannels, ",")
for _, chn := range chnls {
if chn == channelID {
return nil, nil // noop
}
}
newChnls := prefs.UserPrefs.MutedChannels + "," + channelID
values := url.Values{"token": {api.token}, "muted_channels": {newChnls}, "reason": {"update-muted-channels"}}
response := UserPrefsCarrier{}

err = api.postMethod(context.Background(), "users.prefs.set", values, &response)
if err != nil {
return nil, err
}

return &response, response.Err()
return api.GetUserPrefsContext(context.Background())
}

func (api *Client) UnMuteChat(channelID string) (*UserPrefsCarrier, error) {
prefs, err := api.GetUserPrefs()
if err != nil {
return nil, err
}
chnls := strings.Split(prefs.UserPrefs.MutedChannels, ",")
newChnls := make([]string, len(chnls)-1)
for i, chn := range chnls {
if chn == channelID {
return nil, nil // noop
}
newChnls[i] = chn
}
values := url.Values{"token": {api.token}, "muted_channels": {strings.Join(newChnls, ",")}, "reason": {"update-muted-channels"}}
// GetUserPrefsContext gets the user's preferences with a custom context.
func (api *Client) GetUserPrefsContext(ctx context.Context) (*UserPrefsCarrier, error) {
values := url.Values{"token": {api.token}}
response := UserPrefsCarrier{}

err = api.postMethod(context.Background(), "users.prefs.set", values, &response)
err := api.getMethod(ctx, "users.prefs.get", values, &response)
if err != nil {
return nil, err
}
Expand Down