~poptart/smack

e14eb5163b3c1015561296b4e4742f7078d44b63 — cblack 2 years ago 4bf194d
Added emoji command

This can be used to list information about slack emoji and has a flag
for outputing a count per user. Need to revist output and file output as
I think it might be broken
3 files changed, 147 insertions(+), 1 deletions(-)

M api.go
M cmd/smack/smack.go
A emoji.go
M api.go => api.go +1 -0
@@ 4,6 4,7 @@ package smack
var (
	APIBoot                 = "/api/client.boot"
	APIEmojiAdd             = "/api/emoji.add"
	APIEmojiList            = "/api/emoji.adminList"
	APISearch               = "/api/search.modules"
	APIConversationsView    = "/api/conversations.view"
	APIConversationsHistory = "/api/conversations.history"

M cmd/smack/smack.go => cmd/smack/smack.go +43 -1
@@ 26,11 26,13 @@ var (
	flagVerbose         bool
	flagDisableDownload bool
	flagPrivateOnly     bool
	flagStats           bool
	flagQuiet           bool
	flagPrivateMessages bool
)

var FileFlags flag.FlagSet
var EmojiFlags flag.FlagSet
var MessageFlags flag.FlagSet
var ChannelFlags flag.FlagSet
var ClientFlags flag.FlagSet


@@ 57,6 59,16 @@ func initFileFlags() {
	FileFlags.BoolVar(&flagDisableDownload, "n", false, "Don't download the files, just list them")
}

func initEmojiFlags() {
	EmojiFlags.StringVar(&flagUserAgent, "a", UA, "User-Agent string")
	EmojiFlags.BoolVar(&flagQuiet, "q", false, "Do not output information, just ensure that everything is in order")
	EmojiFlags.BoolVar(&flagStats, "s", false, "Generate per-user statistics on emojis")
	EmojiFlags.StringVar(&flagToken, "t", "", "Set the authorization token for API and undocumented API calls")
	EmojiFlags.StringVar(&flagSlackURL, "u", "", "Slack subdomain e.g. 'fakename' will call 'fakename.slack.com'")
	EmojiFlags.StringVar(&flagConfigFile, "c", "", "JSON configuration file. Flags override config variables.")
	EmojiFlags.StringVar(&flagOutput, "o", "", "Output file for channels")
}

func initMessageFlags() {
	MessageFlags.StringVar(&flagUserAgent, "a", UA, "User-Agent string")
	MessageFlags.StringVar(&flagXCookie, "x", "", "Set the slack 'x' cookie for 'Visitor session cookie'")


@@ 111,6 123,9 @@ Globally used flags:
                   in the source "examples/config.json". Flags should 
		   override settings in configuation.
Command specific flags:
   emoji: Retrieves information about emojis
      -o: output file
      -s: per user stats
   files: Retrieves all files on a Slack server
      -n: Do not download the documents only retrieve their information
      -q query: query is used for Slack search. Currently all built in 


@@ 194,6 209,12 @@ func main() {
		return
	}
	switch os.Args[1] {
	case "emoji":
		initEmojiFlags()
		err := EmojiFlags.Parse(os.Args[2:])
		if err == flag.ErrHelp {
			return
		}
	case "files":
		initFileFlags()
		err := FileFlags.Parse(os.Args[2:])


@@ 246,6 267,27 @@ func main() {
		return
	}
	switch os.Args[1] {
	case "emoji":
		items, err := sm.GetEmojiInfo(flagToken)
		if err != nil {
			sm.Log.Printf("Error: %s\n", err.Error())
			return
		}
		sm.Log.Printf("Count: %d\n", items.Count)
		if flagStats {
			var count = make(map[string]int)
			for _, emoji := range items.EmojiList {
				count[emoji.AddedBy]++
			}
			for n, c := range count {
				sm.Log.Printf("%s | %d", n, c)
			}

		} else {
			for _, emoji := range items.EmojiList {
				sm.Log.Printf("%s | %s | %d", emoji.Name, emoji.AddedBy, emoji.Created)
			}
		}
	case "files":
		items, err := sm.GetFileList(flagToken, flagQuery)
		if err != nil {


@@ 419,7 461,7 @@ func main() {
			}
		}
	default:
		sm.Log.Printf("Valid commands are: check channels messages files help")
		sm.Log.Printf("Valid commands are: check channels emoji messages files help")
		return
	}
}

A emoji.go => emoji.go +103 -0
@@ 0,0 1,103 @@
package smack

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
	"strconv"
	"time"
)

type EmojiList struct {
	Ok         bool
	Count      int        `json:"custom_emoji_total_count"`
	Pagination EmojiPages `json:"paging"`
	EmojiList  []Emoji    `json:"emoji"`
}

type EmojiPages struct {
	Count int
	Pages int
	Page  int
}

type Emoji struct {
	Name    string
	Alias   string `json:"alias_for"`
	IsAlias int    `json:"is_alias"`
	AddedBy string `json:"user_display_name"`
	URL     string `json:"url"`
	Created int
}

func (s *Smack) GetEmojiInfo(token string) (EmojiList, error) {
	var forms = map[string]string{
		"token":     token,
		"page":      "1",
		"count":     "100",
		"_x_reason": "customize-emoji-new-query",
		"_x_mode":   "online",
	}
	b, mw, err := addMultipart(forms)
	if err != nil {
		return EmojiList{}, err
	}
	s.Request, err = http.NewRequest("POST", "https://"+s.URL+APIEmojiList, b)
	if err != nil {
		return EmojiList{}, err
	}
	s.Headers["Content-Type"] = mw
	s.applyHeaders()
	var client http.Client
	res, err := client.Do(s.Request)
	if err != nil {
		return EmojiList{}, err
	}
	if res.StatusCode != http.StatusOK {
		return EmojiList{}, errors.New("Bad HTTP status " + res.Status)
	}
	body, err := ioutil.ReadAll(res.Body)
	var f EmojiList
	err = json.Unmarshal(body, &f)
	if f.Pagination.Pages > 1 {
		for p := 2; p < f.Pagination.Pages; p++ {
			var forms = map[string]string{
				"token":     token,
				"page":      strconv.Itoa(p),
				"count":     "100",
				"_x_reason": "customize-emoji-new-query",
				"_x_mode":   "online",
			}
			b, mw, err := addMultipart(forms)
			if err != nil {
				return EmojiList{}, err
			}
			s.Request, err = http.NewRequest("POST", "https://"+s.URL+APIEmojiList, b)
			if err != nil {
				return EmojiList{}, err
			}
			s.Headers["Content-Type"] = mw
			s.applyHeaders()
			var client http.Client
			time.Sleep(1000 * time.Millisecond)
			res, err := client.Do(s.Request)
			if err != nil {
				return EmojiList{}, err
			}
			if res.StatusCode != http.StatusOK {
				if res.Status == "429" {
					time.Sleep(5000 * time.Millisecond)
					p = p - 1
					continue
				}
				return EmojiList{}, errors.New("Bad HTTP status " + res.Status)
			}
			body, err := ioutil.ReadAll(res.Body)
			var e EmojiList
			err = json.Unmarshal(body, &e)
			f.EmojiList = append(f.EmojiList, e.EmojiList...)
		}
	}
	return f, nil
}