Skip to content

Commit

Permalink
take on dump
Browse files Browse the repository at this point in the history
  • Loading branch information
rusq committed Nov 9, 2022
1 parent c1cb7cf commit fa5c14c
Show file tree
Hide file tree
Showing 15 changed files with 188 additions and 137 deletions.
12 changes: 8 additions & 4 deletions cmd/slackdump/internal/cfg/cfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ var (
SlackToken string
SlackCookie string
SlackOptions = slackdump.DefOptions

DownloadFiles bool
)

type FlagMask int
Expand All @@ -48,6 +46,7 @@ const (
)

// SetBaseFlags sets base flags
// TODO: tests.
func SetBaseFlags(fs *flag.FlagSet, mask FlagMask) {
fs.StringVar(&TraceFile, "trace", os.Getenv("TRACE_FILE"), "trace `filename`")
fs.StringVar(&LogFile, "log", os.Getenv("LOG_FILE"), "log `file`, if not specified, messages are printed to STDERR")
Expand All @@ -59,17 +58,22 @@ func SetBaseFlags(fs *flag.FlagSet, mask FlagMask) {
fs.StringVar(&SlackCookie, "cookie", osenv.Secret("SLACK_COOKIE", osenv.Secret("COOKIE", "")), "d= cookie `value` or a path to a cookie.txt file (environment: SLACK_COOKIE)")
}
if mask&OmitDownloadFlag == 0 {
fs.BoolVar(&DownloadFiles, "download", true, "enables file attachments download")
fs.BoolVar(&SlackOptions.DumpFiles, "files", true, "enables file attachments download (to disable, specify: -files=false)")
}
if mask&OmitConfigFlag == 0 {
fs.StringVar(&ConfigFile, "api-config", "", "configuration `file` with Slack API limits overrides.\nYou can generate one with default values with 'slackdump config new`")
}
if mask&OmitBaseLoc == 0 {
base := fmt.Sprintf("slackdump_%s.zip", time.Now().Format("20060102_150304"))
base := fmt.Sprintf("slackdump_%s.zip", time.Now().Format("20060102_150405"))
fs.StringVar(&BaseLoc, "base", osenv.Value("BASE_LOC", base), "a `location` (directory or a ZIP file) on a local disk where the files will be saved.")
}
if mask&OmitCacheDir == 0 {
fs.StringVar(&SlackOptions.CacheDir, "cache-dir", osenv.Value("CACHE_DIR", CacheDir()), "cache `directory` location")
} else {
// If the OmitCacheDir is specified, then the CacheDir will end up being
// the default value, which is "". Therefore, we need to init the
// cache directory.
SlackOptions.CacheDir = CacheDir()
}
if mask&OmitWorkspaceFlag == 0 {
fs.StringVar(&Workspace, "workspace", osenv.Value("SLACK_WORKSPACE", ""), "Slack workspace to use") // TODO: load from configuration.
Expand Down
19 changes: 13 additions & 6 deletions cmd/slackdump/internal/dump/assets/dump.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,27 @@ Dump is the mode that allows to dump the following type of conversations:
- private messages (DMs)
- individual threads

It downloads file attachments as well, if the `-download` flag is set.
It downloads file attachments as well, if the `-files` flag is set.

This is the original low-level mode that applies almost no transformations to
the API output mode of the Slackdump, and its behaviour would be familiar
to those who used it since the very first release.
the API output mode of the Slackdump, and its behaviour would be familiar to
those who used it since the very first release.

### IDs or URLs Parameter

The `<IDs or URLs>` parameter should list the IDs of conversations or URLs of
the channel or thread that you'd like to download, for example `C051D4052` is
a channel ID, and `https://ora600.slack.com/archives/DHYNUJ00Y` is a URL of a
private conversation (DM). You can also use an input file with the list of
IDs or URLs or combine file with conversations and individual conversation
links.
private conversation (DM). You can also use an input file with the list of IDs
or URLs or combine file with conversations and individual conversation links.

## Converting JSON Dumps to Other Formats

To convert the JSON file generated by `slackdump dump` to other formats (for
example, text), use `slackdump convert`. Run `slackdump help convert` to
learn mode.

For reference, in the old version this function was controlled by `-r` flag.

## Examples

Expand Down
106 changes: 102 additions & 4 deletions cmd/slackdump/internal/dump/dump.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,114 @@
package dump

import (
"context"
_ "embed"
"encoding/json"
"errors"
"time"

"github.com/rusq/slackdump/v2"
"github.com/rusq/slackdump/v2/auth"
"github.com/rusq/slackdump/v2/cmd/slackdump/internal/cfg"
"github.com/rusq/slackdump/v2/cmd/slackdump/internal/golang/base"
"github.com/rusq/slackdump/v2/fsadapter"
"github.com/rusq/slackdump/v2/internal/app/config"
"github.com/rusq/slackdump/v2/internal/structures"
"github.com/rusq/slackdump/v2/types"
)

//go:embed assets/dump.md
var dumpLong string
var mdDump string

var CmdDump = &base.Command{
UsageLine: "slackdump dump [flags] <IDs or URLs>",
Short: "dump individual conversations or threads",
Long: base.Render(dumpLong),
UsageLine: "slackdump dump [flags] <IDs or URLs>",
Short: "dump individual conversations or threads",
Long: base.Render(mdDump),
RequireAuth: true,
PrintFlags: true,
}

var ErrNothingToDo = errors.New("no conversations to dump, seek help")

type options struct {
Oldest time.Time
Latest time.Time
NameTemplate string
}

var opts options

func ptr[T any](a T) *T {
return &a
}

func init() {
CmdDump.Run = runDump
CmdDump.Flag.Var(ptr(config.TimeValue(opts.Oldest)), "from", "timestamp of the oldest message to fetch")
CmdDump.Flag.Var(ptr(config.TimeValue(opts.Latest)), "to", "timestamp of the newest message to fetch")
CmdDump.Flag.StringVar(&opts.NameTemplate, "ft", "{{.ID}}{{ if .ThreadTS}}-{{.ThreadTS}}{{end}}", "output file naming template.")
}

func runDump(ctx context.Context, cmd *base.Command, args []string) error {
if len(args) == 0 {
base.SetExitStatus(base.SInvalidParameters)
return ErrNothingToDo
}

list, err := structures.NewEntityList(args)
if err != nil {
base.SetExitStatus(base.SInvalidParameters)
return err
}
if list.IsEmpty() {
base.SetExitStatus(base.SInvalidParameters)
return ErrNothingToDo
}

prov, err := auth.FromContext(ctx)
if err != nil {
base.SetExitStatus(base.SApplicationError)
return err
}

if fs, err := fsadapter.New(cfg.BaseLoc); err != nil {
base.SetExitStatus(base.SApplicationError)
return err
} else {
cfg.SlackOptions.Filesystem = fs
defer fsadapter.Close(fs)
}

sess, err := slackdump.NewWithOptions(ctx, prov, cfg.SlackOptions)
if err != nil {
base.SetExitStatus(base.SApplicationError)
return err
}

for _, link := range list.Include {
conv, err := sess.Dump(ctx, link, opts.Oldest, opts.Latest)
if err != nil {
base.SetExitStatus(base.SApplicationError)
return err
}
if err := saveConversation(cfg.SlackOptions.Filesystem, "test.json", conv); err != nil {
return err
}

}
return nil
}

func saveConversation(fs fsadapter.FS, filename string, conv *types.Conversation) error {
f, err := fs.Create(filename)
if err != nil {
return err
}
defer f.Close()
enc := json.NewEncoder(f)
enc.SetIndent("", " ")
if err := enc.Encode(conv); err != nil {
return err
}
return nil
}
2 changes: 1 addition & 1 deletion cmd/slackdump/internal/export/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func runExport(ctx context.Context, cmd *base.Command, args []string) error {
return err
}

fs, err := fsadapter.ForFilename(cfg.BaseLoc)
fs, err := fsadapter.New(cfg.BaseLoc)
if err != nil {
return err
}
Expand Down
39 changes: 28 additions & 11 deletions cmd/slackdump/internal/man/assets/changelog.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,46 @@
# v2.3.0

## Breaking changes

- legacy command line interface moved under "v1" command, so if you need to
use the old CLI, instead of `./slackdump`, run `./slackdump v1`. The
legacy CLI will be phased out: deprecated in v2.4.0, and removed in v2.5.0.
- download flag is set to "true" by default.
use the old CLI, instead of `./slackdump`, run `./slackdump v1`. The legacy
CLI will be phased out: deprecated in v2.4.0, and removed in v2.5.0;
- `-download` flag renamed to `-files` and is set to "true" by default;
- `-r` flag that allowed to generate text files was moved to
`slackdump convert` command.

## New features

- Completely rewritten CLI, based on `go` command source code (see
[Licenses][1]).
- Default API limits can be overridden with configuration file (use
`-config <file>`).
- Slack Workspaces:
- Slackdump remembers credentials for multiple Slack Workspaces;
- It is possible to select the "_Current_" Workspace using the
`workspace select` command;
- The "_Current_" workspace can be overridden by providing the `-w <name>` flag.
- Slackdump remembers credentials for multiple Slack Workspaces;
- It is possible to select the "_Current_" Workspace using the
`workspace select` command;
- The "_Current_" workspace can be overridden by providing the `-w <name>`
flag.

## Changes

- Default output location (**BASE_LOC** environment variable), if not set by the
user, defaults to the ZIP file "slackdump_YYYYMMDD_HHmmSS.zip", where
`YYYYMMDD` is the current date (for example `20221103`) and `HHmmSS` is the
current time with seconds (for example `185803`).
`YYYYMMDD` is the current date (for example `20221103`) and `HHmmSS` is the
current time with seconds (for example `185803`).

## Licenses
# Library changes

## Deprecation of Dump* functions

## Slackdump Core

- `Options` reorganised, API limits are extracted into a Limits variable. Tier
limits are extracted to TierLimits, and are accessible via `Limits.Tier2` and
`Limits.Tier3` variables. Requests limits are accessible via
`Limits.Request`.
- `Session.SetFS` method is removed, set the filesystem in `Options.Filesystem`.

## Licenses

[1]: #licenses
[1]: #licenses
68 changes: 0 additions & 68 deletions deprecated.go

This file was deleted.

15 changes: 8 additions & 7 deletions fsadapter/fsadapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,18 @@ type FS interface {
WriteFile(name string, data []byte, perm os.FileMode) error
}

// ForFilename returns appropriate filesystem based on the name of the file or
// directory given.
// New returns appropriate filesystem based on the name of the location.
// Logic is simple:
// - if file has a known extension, the appropriate adapter will be returned.
// - if location has a known extension, the appropriate adapter is returned.
// - else: it's a directory.
func ForFilename(name string) (FS, error) {
switch strings.ToUpper(filepath.Ext(name)) {
//
// Currently supported extensions: ".zip" (case insensitive)
func New(location string) (FS, error) {
switch strings.ToUpper(filepath.Ext(location)) {
case ".ZIP":
return NewZipFile(name)
return NewZipFile(location)
default:
return NewDirectory(name), nil
return NewDirectory(location), nil
}
}

Expand Down
2 changes: 1 addition & 1 deletion fsadapter/fsadapter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func TestForFilename(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ForFilename(tt.args.name)
got, err := New(tt.args.name)
if (err != nil) != tt.wantErr {
t.Errorf("ForFilename() error = %v, wantErr %v", err, tt.wantErr)
return
Expand Down
Loading

0 comments on commit fa5c14c

Please sign in to comment.