Skip to content

Commit

Permalink
Merge pull request #4 from rusq/arg-parsing
Browse files Browse the repository at this point in the history
Arg parsing is off, fix it. Immediately.
  • Loading branch information
rusq authored Dec 10, 2021
2 parents 8056945 + f34aea1 commit c06dbf2
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 142 deletions.
6 changes: 6 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/sh
OSES="windows linux darwin"

for os in $OSES; do
make slackdump-${os}.zip
done
102 changes: 0 additions & 102 deletions cmd/sdconv/sdconv.go

This file was deleted.

75 changes: 40 additions & 35 deletions cmd/slackdump/slackdump.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"log"
"os"
"os/signal"
"path/filepath"
"strings"

"github.com/joho/godotenv"
"github.com/rusq/slackdump"
Expand All @@ -18,6 +20,9 @@ import (
const (
outputTypeJSON = "json"
outputTypeText = "text"

slackTokenEnv = "SLACK_TOKEN"
slackCookieEnv = "COOKIE"
)

var _ = godotenv.Load()
Expand Down Expand Up @@ -60,21 +65,8 @@ func (lf listFlags) present() bool {
return lf.users || lf.channels
}

func init() {
flag.Usage = func() {
fmt.Fprintf(
flag.CommandLine.Output(),
"Slackdump dumps messages and files from slack using the provided api token.\n"+
"Will create a number of files having the channel_id as a name.\n"+
"Files are downloaded into a respective folder with channel_id\n\n"+
"Usage: %s [flags] [channel_id1 ... channel_idN]\n",
os.Args[0])
flag.PrintDefaults()
}
}

func main() {
params, err := checkParameters()
params, err := checkParameters(os.Args[1:])
if err != nil {
flag.Usage()
log.Fatal(err)
Expand Down Expand Up @@ -113,36 +105,48 @@ func createFile(filename string) (f io.WriteCloser, err error) {
return os.Create(filename)
}

func checkParameters() (params, error) {
func checkParameters(args []string) (params, error) {
fs := flag.NewFlagSet("", flag.ExitOnError)
fs.Usage = func() {
fmt.Fprintf(
flag.CommandLine.Output(),
"Slackdump dumps messages and files from slack using the provided api token.\n"+
"Will create a number of files having the channel_id as a name.\n"+
"Files are downloaded into a respective folder with channel_id name\n\n"+
"Usage: %s [flags] [channel_id1 ... channel_idN]\n\n",
filepath.Base(os.Args[0]))
fs.PrintDefaults()
}

var p params
// flags
{
flag.BoolVar(&p.list.channels, "c", false, "list channels (aka conversations) and their IDs for export.")
flag.BoolVar(&p.list.users, "u", false, "list users and their IDs. ")
flag.BoolVar(&p.dumpFiles, "f", false, "enable files download")
flag.StringVar(&p.output.filename, "o", "-", "output `filename` for users and channels. Use '-' for standard\noutput.")
flag.StringVar(&p.output.format, "r", "", "report `format`. One of 'json' or 'text'")
flag.StringVar(&p.creds.token, "t", os.Getenv("SLACK_TOKEN"), "Specify slack `API_token`, get it here:\nhttps://api.slack.com/custom-integrations/legacy-tokens\n"+
"It is also possible to define SLACK_TOKEN environment variable.")
flag.StringVar(&p.creds.cookie, "cookie", os.Getenv("COOKIE"), "d= cookie value")
flag.Parse()
fs.BoolVar(&p.list.channels, "c", false, "list channels (aka conversations) and their IDs for export.")
fs.BoolVar(&p.list.users, "u", false, "list users and their IDs. ")
fs.BoolVar(&p.dumpFiles, "f", false, "enable files download")
fs.StringVar(&p.output.filename, "o", "-", "output `filename` for users and channels. Use '-' for standard\noutput.")
fs.StringVar(&p.output.format, "r", "", "report `format`. One of 'json' or 'text'")
fs.StringVar(&p.creds.token, "t", os.Getenv(slackTokenEnv), "Specify slack `API_token`, (environment: "+slackTokenEnv+")")
fs.StringVar(&p.creds.cookie, "cookie", os.Getenv(slackCookieEnv), "d= cookie `value` (environment: "+slackCookieEnv+")")
fs.Parse(args)

os.Unsetenv("SLACK_TOKEN")
os.Unsetenv("COOKIE")
os.Unsetenv(slackTokenEnv)
os.Unsetenv(slackCookieEnv)

p.channelsToExport = flag.Args()
}
p.channelsToExport = fs.Args()

return p, p.validate()
}

func (p *params) validate() error {
if !p.creds.valid() {
return p, fmt.Errorf("slack token or cookie not specified")
return fmt.Errorf("slack token or cookie not specified")
}

if len(p.channelsToExport) == 0 && !p.list.present() {
return p, fmt.Errorf("no list flags specified and no channels to export")
return fmt.Errorf("no list flags specified and no channels to export")
}

if !p.output.validFormat() {
return p, fmt.Errorf("invalid output type: %q, must use one of %v", p.output.format, []string{outputTypeJSON, outputTypeText})
if !p.list.present() && !p.output.validFormat() {
return fmt.Errorf("invalid output type: %q, must use one of %v", p.output.format, []string{outputTypeJSON, outputTypeText})
}

// channels and users listings will be in the text format (if not specified otherwise)
Expand All @@ -153,8 +157,9 @@ func checkParameters() (params, error) {
p.output.format = outputTypeJSON
}
}
p.creds.cookie = strings.TrimPrefix(p.creds.cookie, "d=")

return p, nil
return nil
}

func listEntities(ctx context.Context, output output, creds slackCreds, list listFlags) error {
Expand Down
63 changes: 62 additions & 1 deletion cmd/slackdump/slackdump_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package main

import "testing"
import (
"testing"

"github.com/stretchr/testify/assert"
)

func Test_output_validFormat(t *testing.T) {
type fields struct {
Expand Down Expand Up @@ -29,3 +33,60 @@ func Test_output_validFormat(t *testing.T) {
})
}
}

func Test_checkParameters(t *testing.T) {
type args struct {
args []string
}
tests := []struct {
name string
args args
want params
wantErr bool
}{
{
"channels",
args{[]string{"-c", "-t", "x", "-cookie", "d"}},
params{
list: listFlags{
users: false,
channels: true,
},
creds: slackCreds{
token: "x",
cookie: "d",
},
output: output{filename: "-"},
channelsToExport: []string{},
},
false,
},
{
"users",
args{[]string{"-u", "-t", "x", "-cookie", "d"}},
params{
list: listFlags{
channels: false,
users: true,
},
creds: slackCreds{
token: "x",
cookie: "d",
},
output: output{filename: "-"},
channelsToExport: []string{},
},
false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := checkParameters(tt.args.args)
if (err != nil) != tt.wantErr {
t.Errorf("checkParameters() error = %v, wantErr %v", err, tt.wantErr)
return
}
assert.Equal(t, tt.want, got)
})
}
}
12 changes: 8 additions & 4 deletions messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,20 @@ import (
"github.com/slack-go/slack"
)

// Messages keeps slice of messages
// minMsgTimeApart defines the time interval in minutes to separate group
// of messages from a single user in the conversation. This increases the
// readability of the text output.
const minMsgTimeApart = 2

// Messages keeps the slice of messages.
type Messages struct {
Messages []slack.Message
ChannelID string
SD *SlackDumper
}

// ToText outputs Messages m to io.Writer w in Text format
func (m Messages) ToText(w io.Writer) (err error) {
const minMsgTimeApart = 2 //minutes
// ToText outputs Messages m to io.Writer w in text format.
func (m *Messages) ToText(w io.Writer) (err error) {
writer := bufio.NewWriter(w)
defer writer.Flush()

Expand Down
12 changes: 12 additions & 0 deletions slackdump.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package slackdump

import (
"context"
"errors"
"fmt"
"io"
"log"
Expand Down Expand Up @@ -139,6 +140,17 @@ func (sd *SlackDumper) DumpMessages(ctx context.Context, channelID string, dumpF
return &Messages{Messages: allMessages, ChannelID: channelID, SD: sd}, nil
}

// ErrNoThread is the error indicating that error is not a threaded message.
var ErrNoThread = errors.New("message has no thread")

// DumpThread retrieves all messages in the thread and returns them as a slice of messages.
func (sd *SlackDumper) DumpThread(m *slack.Message) ([]slack.Message, error) {
if m.ThreadTimestamp == "" {
return nil, ErrNoThread
}
panic("implement me")
}

// UpdateUserMap updates user[id]->*User mapping from the current Users slice.
func (sd *SlackDumper) UpdateUserMap() error {
if sd.Users.Len() == 0 {
Expand Down

0 comments on commit c06dbf2

Please sign in to comment.