initial commit
This commit is contained in:
commit
88e73ca726
|
@ -0,0 +1,14 @@
|
||||||
|
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||||
|
Version 2, December 2004
|
||||||
|
|
||||||
|
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||||
|
|
||||||
|
Everyone is permitted to copy and distribute verbatim or modified
|
||||||
|
copies of this license document, and changing it is allowed as long
|
||||||
|
as the name is changed.
|
||||||
|
|
||||||
|
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
// © 2018 the slacktricks Authors under the WTFPL license. See AUTHORS for the list of authors.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/json"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var dataDir = flag.String("data", "data", "Where to save emoji")
|
||||||
|
|
||||||
|
type emojyResp struct {
|
||||||
|
Emoji map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
f, err := ioutil.ReadAll(bufio.NewReader(os.Stdin))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var resp emojyResp
|
||||||
|
if err := json.Unmarshal(f, &resp); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
for k, v := range resp.Emoji {
|
||||||
|
if !strings.HasPrefix(v, "alias") {
|
||||||
|
ext := filepath.Ext(v)
|
||||||
|
resp, err := http.Get(v)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fname := fmt.Sprintf("%s%s", k, ext)
|
||||||
|
f, err := os.Create(filepath.Join(*dataDir, fname))
|
||||||
|
defer f.Close()
|
||||||
|
b, err := io.Copy(f, resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
log.Printf("Saved %d bytes to %s", b, fname)
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Printf("Saved %d emojys", count)
|
||||||
|
}
|
|
@ -0,0 +1,220 @@
|
||||||
|
// © 2018 the slacktricks Authors under the WTFPL license. See AUTHORS for the list of authors.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
token = flag.String("token", "", "Slack API token")
|
||||||
|
channel = flag.String("channel", "", "Slack channel ID")
|
||||||
|
limit = flag.Int("limit", 100, "Number of items to return")
|
||||||
|
byChannel = flag.Bool("byChannel", false, "Arrange data by channel (default by user)")
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
users := getUsers()
|
||||||
|
history := getHistory(*channel)
|
||||||
|
|
||||||
|
if !*byChannel {
|
||||||
|
for _, u := range users.Members {
|
||||||
|
writeUser(history, u)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
writeChannel(history)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUsers() userResp {
|
||||||
|
users := userResp{}
|
||||||
|
|
||||||
|
log.Printf("Getting users")
|
||||||
|
body := mkReq("https://slack.com/api/users.list",
|
||||||
|
"token", *token,
|
||||||
|
)
|
||||||
|
|
||||||
|
err := json.Unmarshal(body, &users)
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
return users
|
||||||
|
}
|
||||||
|
|
||||||
|
func getHistory(ch string) []histResp {
|
||||||
|
history := []histResp{}
|
||||||
|
cursor := ""
|
||||||
|
for {
|
||||||
|
log.Printf("Getting history cursor: '%s'", cursor)
|
||||||
|
body := mkReq("https://slack.com/api/conversations.history",
|
||||||
|
"token", *token,
|
||||||
|
"channel", ch,
|
||||||
|
"limit", strconv.Itoa(*limit),
|
||||||
|
"cursor", cursor,
|
||||||
|
)
|
||||||
|
resp := histResp{}
|
||||||
|
err := json.Unmarshal(body, &resp)
|
||||||
|
checkErr(err)
|
||||||
|
history = append(history, resp)
|
||||||
|
if resp.ResponseMetadata.NextCursor == "" {
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
cursor = resp.ResponseMetadata.NextCursor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return history
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkErr(err error) {
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mkReq(path string, arg ...string) []byte {
|
||||||
|
if len(arg)%2 != 0 {
|
||||||
|
log.Fatal("Bad request arg number.")
|
||||||
|
}
|
||||||
|
|
||||||
|
u, err := url.Parse(path)
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
q := u.Query()
|
||||||
|
for i := 0; i < len(arg); i += 2 {
|
||||||
|
key := arg[i]
|
||||||
|
val := arg[i+1]
|
||||||
|
if val != "" {
|
||||||
|
q.Set(key, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
u.RawQuery = q.Encode()
|
||||||
|
|
||||||
|
resp, err := http.Get(u.String())
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
return body
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeChannel(history []histResp) {
|
||||||
|
fname := *channel + ".json"
|
||||||
|
f, err := os.Create(fname)
|
||||||
|
checkErr(err)
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
j, err := json.Marshal(history)
|
||||||
|
checkErr(err)
|
||||||
|
f.Write(j)
|
||||||
|
|
||||||
|
reactionCount := map[string]int{}
|
||||||
|
for _, h := range history {
|
||||||
|
for _, m := range h.Messages {
|
||||||
|
if len(m.Reactions) > 0 {
|
||||||
|
for _, r := range m.Reactions {
|
||||||
|
reactionCount[r.Name] += r.Count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%+v", reactionCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeUser(history []histResp, u user) {
|
||||||
|
// open file and write shit out
|
||||||
|
fname := u.Name + ".txt"
|
||||||
|
id := u.ID
|
||||||
|
|
||||||
|
f, err := os.OpenFile(fname, os.O_RDWR|os.O_CREATE, 0755)
|
||||||
|
checkErr(err)
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
for _, h := range history {
|
||||||
|
for _, m := range h.Messages {
|
||||||
|
if m.User == id {
|
||||||
|
fmt.Fprintf(f, "%s\n", m.Text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type histResp struct {
|
||||||
|
Ok bool `json:"ok"`
|
||||||
|
Messages []struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
User string `json:"user"`
|
||||||
|
Text string `json:"text"`
|
||||||
|
Ts string `json:"ts"`
|
||||||
|
Reactions []reaction `json:"reactions"`
|
||||||
|
} `json:"messages"`
|
||||||
|
HasMore bool `json:"has_more"`
|
||||||
|
PinCount int `json:"pin_count"`
|
||||||
|
ResponseMetadata struct {
|
||||||
|
NextCursor string `json:"next_cursor"`
|
||||||
|
} `json:"response_metadata"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type reaction struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Users []string `json:"users"`
|
||||||
|
Count int `json:"count"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type user struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
TeamID string `json:"team_id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Deleted bool `json:"deleted"`
|
||||||
|
Color string `json:"color"`
|
||||||
|
RealName string `json:"real_name"`
|
||||||
|
Tz string `json:"tz"`
|
||||||
|
TzLabel string `json:"tz_label"`
|
||||||
|
TzOffset int `json:"tz_offset"`
|
||||||
|
Profile struct {
|
||||||
|
AvatarHash string `json:"avatar_hash"`
|
||||||
|
StatusText string `json:"status_text"`
|
||||||
|
StatusEmoji string `json:"status_emoji"`
|
||||||
|
RealName string `json:"real_name"`
|
||||||
|
DisplayName string `json:"display_name"`
|
||||||
|
RealNameNormalized string `json:"real_name_normalized"`
|
||||||
|
DisplayNameNormalized string `json:"display_name_normalized"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
Image24 string `json:"image_24"`
|
||||||
|
Image32 string `json:"image_32"`
|
||||||
|
Image48 string `json:"image_48"`
|
||||||
|
Image72 string `json:"image_72"`
|
||||||
|
Image192 string `json:"image_192"`
|
||||||
|
Image512 string `json:"image_512"`
|
||||||
|
Team string `json:"team"`
|
||||||
|
} `json:"profile"`
|
||||||
|
IsAdmin bool `json:"is_admin"`
|
||||||
|
IsOwner bool `json:"is_owner"`
|
||||||
|
IsPrimaryOwner bool `json:"is_primary_owner"`
|
||||||
|
IsRestricted bool `json:"is_restricted"`
|
||||||
|
IsUltraRestricted bool `json:"is_ultra_restricted"`
|
||||||
|
IsBot bool `json:"is_bot"`
|
||||||
|
Updated int `json:"updated"`
|
||||||
|
IsAppUser bool `json:"is_app_user,omitempty"`
|
||||||
|
Has2Fa bool `json:"has_2fa"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type userResp struct {
|
||||||
|
Ok bool `json:"ok"`
|
||||||
|
Members []user `json:"members"`
|
||||||
|
CacheTs int `json:"cache_ts"`
|
||||||
|
ResponseMetadata struct {
|
||||||
|
NextCursor string `json:"next_cursor"`
|
||||||
|
} `json:"response_metadata"`
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
= Slack Tricks
|
||||||
|
|
||||||
|
Just a collection of silly slack utils that have come in handy.
|
||||||
|
|
||||||
|
== emojytool
|
||||||
|
|
||||||
|
Back up your slack "emojy" as local image files. Suitable for mass exodus from
|
||||||
|
Slack.
|
||||||
|
|
||||||
|
== gethistory
|
||||||
|
|
||||||
|
Grab the available history from slack. This works by user for text hisory,
|
||||||
|
suitable for babbler purposes or by channel if more detailed information is
|
||||||
|
desired.
|
Loading…
Reference in New Issue