Skip to content

Commit

Permalink
use new workspace/new by default
Browse files Browse the repository at this point in the history
  • Loading branch information
rusq committed Nov 16, 2024
1 parent b0bf651 commit c0477f7
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 30 deletions.
8 changes: 5 additions & 3 deletions cmd/slackdump/internal/bootstrap/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,21 @@ import (
"github.com/rusq/slackdump/v3/auth"
"github.com/rusq/slackdump/v3/cmd/slackdump/internal/cfg"
"github.com/rusq/slackdump/v3/cmd/slackdump/internal/workspace"
"github.com/rusq/slackdump/v3/cmd/slackdump/internal/workspace/workspaceui"
"github.com/rusq/slackdump/v3/internal/cache"
)

func CurrentOrNewProviderCtx(ctx context.Context) (context.Context, error) {
prov, err := workspace.AuthCurrent(ctx, cfg.CacheDir(), cfg.Workspace, cfg.LegacyBrowser)
cachedir := cfg.CacheDir()
prov, err := workspace.AuthCurrent(ctx, cachedir, cfg.Workspace, cfg.LegacyBrowser)
if err != nil {
if errors.Is(err, cache.ErrNoWorkspaces) {
// ask to create a new workspace
if err := workspace.CmdWspNew.Run(ctx, workspace.CmdWspNew, []string{}); err != nil {
if err := workspaceui.ShowUI(ctx, true); err != nil {
return ctx, fmt.Errorf("auth error: %w", err)
}
// one more time...
prov, err = workspace.AuthCurrent(ctx, cfg.CacheDir(), cfg.Workspace, cfg.LegacyBrowser)
prov, err = workspace.AuthCurrent(ctx, cachedir, cfg.Workspace, cfg.LegacyBrowser)
if err != nil {
return ctx, err
}
Expand Down
24 changes: 24 additions & 0 deletions cmd/slackdump/internal/workspace/assets/import.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Workspace Import Command

**Import** allows you to import credentials from a .env or secrets.txt file.

It requires the file to have the following format:
```
SLACK_TOKEN=xoxc-...
SLACK_COOKIE=xoxd-...
```

`SLACK_TOKEN` can be one of the following:

- xoxa-...: app token
- xoxb-...: bot token
- xoxc-...: client token
- xoxe-...: export token
- xoxp-...: legacy user token

`SLACK_COOKIE` is only required, if the `SLACK_TOKEN` is a client type token
(starts with `xoxc-`).

It will test the provided credentials, and if successful, encrypt and save
them to the to the slackdump credential storage. It is recommended to delete
the .env file afterwards.
14 changes: 14 additions & 0 deletions cmd/slackdump/internal/workspace/assets/list.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Workspace List Command

**List** allows to list Slack Workspaces, that you have previously
authenticated in. It supports several output formats:
- full (default): outputs workspace names, filenames, and last modification.
- bare: outputs just workspace names, with the current workspace marked with
an asterisk.
- all: outputs all information, including the team name and the user name for
each workspace.

If the "all" listing is requested, Slackdump will interrogate the Slack API to
get the team name and the user name for each workspace. This may take some
time, as it involves multiple network requests, depending on your network
speed and the number of workspaces.
65 changes: 65 additions & 0 deletions cmd/slackdump/internal/workspace/import.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package workspace

import (
"context"
_ "embed"
"errors"

"github.com/rusq/slackdump/v3/auth"
"github.com/rusq/slackdump/v3/cmd/slackdump/internal/cfg"
"github.com/rusq/slackdump/v3/cmd/slackdump/internal/golang/base"
"github.com/rusq/slackdump/v3/internal/cache"
)

//go:embed assets/import.md
var importMd string

var CmdImport = &base.Command{
UsageLine: baseCommand + " import [flags] filename",
Short: "import credentials from .env or secrets.txt file",
Long: importMd,
FlagMask: flagmask,
PrintFlags: true,
Run: cmdRunImport,
RequireAuth: false,
}

func cmdRunImport(ctx context.Context, cmd *base.Command, args []string) error {
if len(args) != 1 {
base.SetExitStatus(base.SInvalidParameters)
return errors.New("missing filename")
}

filename := args[0]

if err := importFile(ctx, filename); err != nil {
return err
}
return nil
}

func importFile(ctx context.Context, filename string) error {
token, cookies, err := auth.ParseDotEnv(filename)
if err != nil {
base.SetExitStatus(base.SUserError)
return err
}
m, err := cache.NewManager(cfg.CacheDir())
if err != nil {
base.SetExitStatus(base.SCacheError)
return err
}
prov, err := auth.NewValueAuth(token, cookies)
if err != nil {
base.SetExitStatus(base.SAuthError)
return err
}
wsp, err := m.CreateAndSelect(ctx, prov)
if err != nil {
base.SetExitStatus(base.SCacheError)
return err
}
cfg.Log.Printf("Workspace %q added and selected. It is advised that you delete the file %q", wsp, filename)

return nil
}
25 changes: 7 additions & 18 deletions cmd/slackdump/internal/workspace/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package workspace

import (
"context"
_ "embed"
"errors"
"fmt"
"io"
Expand All @@ -19,25 +20,13 @@ import (
"github.com/rusq/slackdump/v3/internal/cache"
)

//go:embed assets/list.md
var listMd string

var CmdWspList = &base.Command{
UsageLine: baseCommand + " list [flags]",
Short: "list saved authentication information",
Long: `
# Workspace List Command
**List** allows to list Slack Workspaces, that you have previously authenticated
in. It supports several output formats:
- full (default): outputs workspace names, filenames, and last modification.
- bare: outputs just workspace names, with the current workspace marked with an
asterisk.
- all: outputs all information, including the team name and the user name for
each workspace.
If the "all" listing is requested, Slackdump will interrogate the Slack API to
get the team name and the user name for each workspace. This may take some
time, as it involves multiple network requests, depending on your network
speed and the number of workspaces.
`,
UsageLine: baseCommand + " list [flags]",
Short: "list saved authentication information",
Long: listMd,
FlagMask: flagmask,
PrintFlags: true,
}
Expand Down
1 change: 1 addition & 0 deletions cmd/slackdump/internal/workspace/workspace.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ automatically detected to be:
RequireAuth: false,
Commands: []*base.Command{
CmdWspNew,
CmdImport,
CmdWspList,
CmdWspSelect,
CmdWspDel,
Expand Down
9 changes: 9 additions & 0 deletions cmd/slackdump/internal/workspace/workspaceui/workspaceui.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ type manager interface {
}

func WorkspaceNew(ctx context.Context, _ *base.Command, _ []string) error {
return ShowUI(ctx, false)
}

// ShowUI shows the authentication menu. If quicklogin is set to true,
// it will quit after the user has successfully authenticated.
func ShowUI(ctx context.Context, quicklogin bool) error {
const (
actLogin = "ezlogin"
actToken = "token"
Expand Down Expand Up @@ -97,6 +103,9 @@ LOOP:
}
return err
}
if quicklogin {
return nil
}
}

return nil
Expand Down
32 changes: 23 additions & 9 deletions cmd/slackdump/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"flag"
"fmt"
"log"
"log/slog"
"os"
"os/signal"
"runtime/trace"
Expand Down Expand Up @@ -239,15 +240,16 @@ func initTrace(filename string) error {
return nil
}

// initLog initialises the logging and returns the context with the Logger. If
// the filename is not empty, the file will be opened, and the logger output will
// be switch to that file. Returns the initialised logger, stop function and an
// error, if any. The stop function must be called in the deferred call, it will
// close the log file, if it is open. If the error is returned the stop function
// is nil.
// initLog initialises the logging and returns the context with the Logger. If the
// filename is not empty, the file will be opened, and the logger output will
// be switch to that file. Returns the initialised logger, stop function and
// an error, if any. The stop function must be called in the deferred call, it
// will close the log file, if it is open. If the error is returned the stop
// function is nil.
func initLog(filename string, verbose bool) (*dlog.Logger, error) {
lg := logger.Default
if verbose {
slog.SetLogLoggerLevel(slog.LevelDebug)
lg.SetDebug(verbose)
lg.SetFlags(lg.Flags() | log.Lmicroseconds)
}
Expand All @@ -262,6 +264,10 @@ func initLog(filename string, verbose bool) (*dlog.Logger, error) {
return lg, fmt.Errorf("failed to create the log file: %w", err)
}
lg.SetOutput(lf)
sl := slog.New(slog.NewTextHandler(lf, &slog.HandlerOptions{
Level: iftrue(verbose, slog.LevelDebug, slog.LevelInfo),
}))
slog.SetDefault(sl)

base.AtExit(func() {
if err := lf.Close(); err != nil {
Expand All @@ -272,6 +278,13 @@ func initLog(filename string, verbose bool) (*dlog.Logger, error) {
return lg, nil
}

func iftrue[T any](cond bool, t T, f T) T {
if cond {
return t
}
return f
}

// secrets defines the names of the supported secret files that we load our
// secrets from. Inexperienced Windows users might have bad experience trying
// to create .env file with the notepad as it will battle for having the
Expand All @@ -295,16 +308,17 @@ const (
)

func whatDo() (choice, error) {
fmt.Print("\n" + cfg.Version.String() + "\n")
versionstr := cfg.Version.String()

var ans choice
err := huh.NewForm(huh.NewGroup(huh.NewSelect[choice]().
Title("What do you want to do?").
Title(versionstr).
Description("What do you want to do?").
Options(
huh.NewOption(string(choiceHelp), choiceHelp),
huh.NewOption(string(choiceWizard), choiceWizard),
huh.NewOption(string(choiceExit), choiceExit),
).Value(&ans))).WithTheme(ui.HuhTheme()).Run()
).Value(&ans))).WithTheme(ui.HuhTheme()).WithKeyMap(ui.DefaultHuhKeymap).Run()

return ans, err
}
Expand Down

0 comments on commit c0477f7

Please sign in to comment.