From b78f4a3b0aa8e08c848a6c5ece2e15796d237450 Mon Sep 17 00:00:00 2001 From: Rustam Gilyazov <16064414+rusq@users.noreply.github.com> Date: Fri, 15 Nov 2024 19:43:03 +1000 Subject: [PATCH 1/3] workspace->new fixes --- auth/auth_ui/huh.go | 44 ++++++++++++------- auth/auth_ui/validation.go | 8 ++++ auth/rod.go | 8 ++-- .../internal/ui/bubbles/menu/model.go | 12 +++++ .../workspace/workspaceui/ezlogin3000.go | 19 +++++--- .../workspace/workspaceui/filesecrets.go | 2 +- .../workspace/workspaceui/workspaceui.go | 7 ++- 7 files changed, 73 insertions(+), 27 deletions(-) diff --git a/auth/auth_ui/huh.go b/auth/auth_ui/huh.go index 1b9bc4dd..80d48e51 100644 --- a/auth/auth_ui/huh.go +++ b/auth/auth_ui/huh.go @@ -1,12 +1,14 @@ package auth_ui import ( + "context" "errors" "fmt" "io" "regexp" "strconv" + "github.com/charmbracelet/bubbles/key" "github.com/charmbracelet/huh" "github.com/rusq/slackauth" ) @@ -33,7 +35,7 @@ func (h *Huh) RequestWorkspace(w io.Writer) (string, error) { func (*Huh) Stop() {} -func (*Huh) RequestCreds(w io.Writer, workspace string) (email string, passwd string, err error) { +func (*Huh) RequestCreds(ctx context.Context, w io.Writer, workspace string) (email string, passwd string, err error) { f := huh.NewForm( huh.NewGroup( huh.NewInput(). @@ -46,8 +48,8 @@ func (*Huh) RequestCreds(w io.Writer, workspace string) (email string, passwd st Placeholder("your slack password"). Validate(valRequired).EchoMode(huh.EchoModePassword), ), - ).WithTheme(Theme) - err = f.Run() + ).WithTheme(Theme).WithKeyMap(keymap) + err = f.RunWithContext(ctx) return } @@ -85,15 +87,13 @@ type LoginOpts struct { BrowserPath string } -func valWorkspace(s string) error { - if err := valRequired(s); err != nil { - return err - } - _, err := Sanitize(s) - return err +var keymap = huh.NewDefaultKeyMap() + +func init() { + keymap.Quit = key.NewBinding(key.WithKeys("esc", "ctrl+c"), key.WithHelp("esc", "Quit")) } -func (*Huh) RequestLoginType(w io.Writer, workspace string) (LoginOpts, error) { +func (*Huh) RequestLoginType(ctx context.Context, w io.Writer, workspace string) (LoginOpts, error) { var ret = LoginOpts{ Workspace: workspace, Type: LInteractive, @@ -120,7 +120,11 @@ func (*Huh) RequestLoginType(w io.Writer, workspace string) (LoginOpts, error) { fields = append(fields, huh.NewSelect[LoginType](). TitleFunc(func() string { - return fmt.Sprintf("Select login type for [%s]", ret.Workspace) + wsp, err := Sanitize(ret.Workspace) + if err != nil { + return "Select login type" + } + return fmt.Sprintf("Select login type for [%s]", wsp) }, &ret.Workspace). Options(opts...). Value(&ret.Type). @@ -139,21 +143,31 @@ func (*Huh) RequestLoginType(w io.Writer, workspace string) (LoginOpts, error) { return "" } }, &ret.Type)) - if err := huh.NewForm(huh.NewGroup(fields...)).WithTheme(Theme).Run(); err != nil { + + form := huh.NewForm(huh.NewGroup(fields...)).WithTheme(Theme).WithKeyMap(keymap) + + if err := form.RunWithContext(ctx); err != nil { return ret, err } + var err error + ret.Workspace, err = Sanitize(ret.Workspace) + if err != nil { + return ret, err + } + if ret.Type == LUserBrowser { - path, err := chooseBrowser() + path, err := chooseBrowser(ctx) if err != nil { return ret, err } ret.BrowserPath = path return ret, err } + return ret, nil } -func chooseBrowser() (string, error) { +func chooseBrowser(ctx context.Context) (string, error) { browsers, err := slackauth.ListBrowsers() if err != nil { return "", err @@ -172,7 +186,7 @@ func chooseBrowser() (string, error) { DescriptionFunc(func() string { return browsers[selection].Path }, &selection), - )).WithTheme(Theme).Run() + )).WithTheme(Theme).WithKeyMap(keymap).RunWithContext(ctx) if err != nil { return "", err } diff --git a/auth/auth_ui/validation.go b/auth/auth_ui/validation.go index 94e019bc..1b2b9e44 100644 --- a/auth/auth_ui/validation.go +++ b/auth/auth_ui/validation.go @@ -100,3 +100,11 @@ func valSepEaster() func(v LoginType) error { return nil } } + +func valWorkspace(s string) error { + if err := valRequired(s); err != nil { + return err + } + _, err := Sanitize(s) + return err +} diff --git a/auth/rod.go b/auth/rod.go index 41ad8558..f415ab46 100644 --- a/auth/rod.go +++ b/auth/rod.go @@ -64,10 +64,10 @@ type browserAuthUIExt interface { // RequestLoginType should request the login type from the user and return // one of the [auth_ui.LoginType] constants. The implementation should // provide a way to cancel the login flow, returning [auth_ui.LoginCancel]. - RequestLoginType(w io.Writer, workspace string) (auth_ui.LoginOpts, error) + RequestLoginType(ctx context.Context, w io.Writer, workspace string) (auth_ui.LoginOpts, error) // RequestCreds should request the user's email and password and return // them. - RequestCreds(w io.Writer, workspace string) (email string, passwd string, err error) + RequestCreds(ctx context.Context, w io.Writer, workspace string) (email string, passwd string, err error) // ConfirmationCode should request the confirmation code from the user and // return it. ConfirmationCode(email string) (code int, err error) @@ -95,7 +95,7 @@ func NewRODAuth(ctx context.Context, opts ...Option) (RodAuth, error) { r.opts.workspace = wsp } - resp, err := r.opts.ui.RequestLoginType(os.Stdout, r.opts.workspace) + resp, err := r.opts.ui.RequestLoginType(ctx, os.Stdout, r.opts.workspace) if err != nil { return r, err } @@ -142,7 +142,7 @@ func NewRODAuth(ctx context.Context, opts ...Option) (RodAuth, error) { } func headlessFlow(ctx context.Context, cl *slackauth.Client, workspace string, ui browserAuthUIExt) (sp simpleProvider, err error) { - username, password, err := ui.RequestCreds(os.Stdout, workspace) + username, password, err := ui.RequestCreds(ctx, os.Stdout, workspace) if err != nil { return sp, err } diff --git a/cmd/slackdump/internal/ui/bubbles/menu/model.go b/cmd/slackdump/internal/ui/bubbles/menu/model.go index 032d8092..a810b25b 100644 --- a/cmd/slackdump/internal/ui/bubbles/menu/model.go +++ b/cmd/slackdump/internal/ui/bubbles/menu/model.go @@ -160,6 +160,18 @@ func (m *Model) View() string { return m.view() } +func (m *Model) Select(id string) { + if id == m.items[m.cursor].ID { + return + } + for i, item := range m.items { + if item.ID == id && !item.Separator { + m.cursor = i + break + } + } +} + func capfirst(s string) string { if s == "" { return "" diff --git a/cmd/slackdump/internal/workspace/workspaceui/ezlogin3000.go b/cmd/slackdump/internal/workspace/workspaceui/ezlogin3000.go index cee58ba0..e5ec6687 100644 --- a/cmd/slackdump/internal/workspace/workspaceui/ezlogin3000.go +++ b/cmd/slackdump/internal/workspace/workspaceui/ezlogin3000.go @@ -18,8 +18,8 @@ func ezLogin3000(ctx context.Context, mgr manager) error { ) form := huh.NewForm(huh.NewGroup( huh.NewConfirm(). - Title("Use legacy EZ-Login?"). - Description("Do you want to use the legacy login?"). + Title("Do you want to use the legacy login?"). + Description("Choose 'Yes' if you had problems in the past with the current EZ-Login."). Value(&legacy), )).WithTheme(ui.HuhTheme()).WithKeyMap(ui.DefaultHuhKeymap) if err := form.RunWithContext(ctx); err != nil { @@ -28,11 +28,20 @@ func ezLogin3000(ctx context.Context, mgr manager) error { } return err } + + var err error if legacy { - return playwrightLogin(ctx, mgr) + err = playwrightLogin(ctx, mgr) + } else { + err = rodLogin(ctx, mgr) } - return rodLogin(ctx, mgr) - + if err != nil { + if errors.Is(err, auth.ErrCancelled) { + return nil + } + return err + } + return nil } func playwrightLogin(ctx context.Context, mgr manager) error { diff --git a/cmd/slackdump/internal/workspace/workspaceui/filesecrets.go b/cmd/slackdump/internal/workspace/workspaceui/filesecrets.go index 401e97f2..d2b59c30 100644 --- a/cmd/slackdump/internal/workspace/workspaceui/filesecrets.go +++ b/cmd/slackdump/internal/workspace/workspaceui/filesecrets.go @@ -26,7 +26,7 @@ func fileWithSecrets(ctx context.Context, mgr manager) error { ShowPermissions(true). Value(&filename). Validate(validateSecrets), - )).WithTheme(ui.HuhTheme()).WithHeight(10) + )).WithTheme(ui.HuhTheme()).WithHeight(10).WithKeyMap(ui.DefaultHuhKeymap) if err := form.RunWithContext(ctx); err != nil { if errors.Is(err, huh.ErrUserAborted) { return nil diff --git a/cmd/slackdump/internal/workspace/workspaceui/workspaceui.go b/cmd/slackdump/internal/workspace/workspaceui/workspaceui.go index 40fd068f..6c85766f 100644 --- a/cmd/slackdump/internal/workspace/workspaceui/workspaceui.go +++ b/cmd/slackdump/internal/workspace/workspaceui/workspaceui.go @@ -31,12 +31,12 @@ func WorkspaceNew(ctx context.Context, _ *base.Command, _ []string) error { { ID: actLogin, Name: "Login in Browser", - Help: "Login to Slack in your browser", + Help: "Opens the browser and lets you login in a familiar way.", }, { ID: actToken, Name: "Token/Cookie", - Help: "Enter token and cookie that you grabbed from the browser", + Help: "Enter token and cookie that you grabbed from the browser.", }, { ID: actTokenFile, @@ -66,12 +66,15 @@ func WorkspaceNew(ctx context.Context, _ *base.Command, _ []string) error { actSecrets: fileWithSecrets, } + var lastID string = actLogin LOOP: for { m := menu.New("New Workspace", items, true) + m.Select(lastID) if _, err := tea.NewProgram(&wizModel{m: m}, tea.WithContext(ctx)).Run(); err != nil { return err } + lastID = m.Selected.ID if m.Cancelled { break LOOP } From ea9ced7b19acd6785e91828a5a4e4c60b8feb374 Mon Sep 17 00:00:00 2001 From: Rustam Gilyazov <16064414+rusq@users.noreply.github.com> Date: Fri, 15 Nov 2024 20:58:22 +1000 Subject: [PATCH 2/3] tests --- Makefile | 9 ++ auth/auth_ui/auth_ui.go | 16 +- auth/auth_ui/auth_ui_test.go | 1 + auth/browser/playwright_test.go | 17 ++- clienter_mock_test.go | 2 + .../internal/emoji/emojidl/emoji_mock_test.go | 1 + cmd/slackdump/internal/list/mocks_test.go | 2 + .../ui/bubbles/datepicker/focus_string.go | 26 ++++ .../internal/workspace/mocks_test.go | 1 + .../internal/workspace/workspaceui/api.go | 5 + .../workspace/workspaceui/api_test.go | 117 +++++++++++++++ .../workspace/workspaceui/filesecrets.go | 17 ++- .../workspace/workspaceui/filesecrets_test.go | 137 ++++++++++++++++++ .../workspaceui/test_mock_manager.go | 69 +++++++++ export/mock_dumper_test.go | 1 + internal/chunk/dirproc/dirproc_mock_test.go | 4 + internal/mocks/mock_auth/mock_auth.go | 9 +- internal/mocks/mock_dl/mock_exporter.go | 17 ++- internal/mocks/mock_io/mock_io.go | 18 ++- internal/mocks/mock_os/mock_os.go | 1 + mocks/mock_appauth/mock_appauth.go | 2 + mocks/mock_processor/mock_processor.go | 85 ++++++----- 22 files changed, 481 insertions(+), 76 deletions(-) create mode 100644 cmd/slackdump/internal/ui/bubbles/datepicker/focus_string.go create mode 100644 cmd/slackdump/internal/workspace/workspaceui/api_test.go create mode 100644 cmd/slackdump/internal/workspace/workspaceui/filesecrets_test.go create mode 100644 cmd/slackdump/internal/workspace/workspaceui/test_mock_manager.go diff --git a/Makefile b/Makefile index 51a3efbf..388d0ba9 100644 --- a/Makefile +++ b/Makefile @@ -75,3 +75,12 @@ goreleaser: tags: gotags -R *.go > $@ + +generate: | install_tools + go generate ./... +.PHONY:generate + +install_tools: + go install go.uber.org/mock/mockgen@latest + go install golang.org/x/tools/cmd/stringer@latest +.PHONY: install_tools diff --git a/auth/auth_ui/auth_ui.go b/auth/auth_ui/auth_ui.go index 887c88d6..28f377cf 100644 --- a/auth/auth_ui/auth_ui.go +++ b/auth/auth_ui/auth_ui.go @@ -1,6 +1,8 @@ package auth_ui import ( + "errors" + "fmt" "net/url" "strings" ) @@ -20,9 +22,11 @@ const ( LCancel ) +var ErrInvalidDomain = errors.New("invalid domain") + // Sanitize takes a workspace name or URL and returns the workspace name. func Sanitize(workspace string) (string, error) { - if !strings.Contains(workspace, ".slack.com") { + if !strings.Contains(workspace, ".slack.com") && !strings.Contains(workspace, ".") { return workspace, nil } if strings.HasPrefix(workspace, "https://") { @@ -33,6 +37,12 @@ func Sanitize(workspace string) (string, error) { workspace = uri.Host } // parse - parts := strings.Split(workspace, ".") - return parts[0], nil + name, domain, found := strings.Cut(workspace, ".") + if !found { + return "", errors.New("workspace name is empty") + } + if strings.TrimRight(domain, "/") != "slack.com" { + return "", fmt.Errorf("%s: %w", domain, ErrInvalidDomain) + } + return name, nil } diff --git a/auth/auth_ui/auth_ui_test.go b/auth/auth_ui/auth_ui_test.go index a2f23e8f..a1473def 100644 --- a/auth/auth_ui/auth_ui_test.go +++ b/auth/auth_ui/auth_ui_test.go @@ -17,6 +17,7 @@ func TestSanitize(t *testing.T) { {"url no slash", args{"https://blahblah.slack.com"}, "blahblah", false}, {"url no schema slash", args{"blahblah.slack.com/"}, "blahblah", false}, {"url no schema no slash", args{"blahblah.slack.com"}, "blahblah", false}, + {"not a slack domain", args{"blahblah.example.com"}, "", true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/auth/browser/playwright_test.go b/auth/browser/playwright_test.go index 2c854b46..80d1d410 100644 --- a/auth/browser/playwright_test.go +++ b/auth/browser/playwright_test.go @@ -20,6 +20,7 @@ import ( type MockRequest struct { ctrl *gomock.Controller recorder *MockRequestMockRecorder + isgomock struct{} } // MockRequestMockRecorder is the mock recorder for MockRequest. @@ -83,18 +84,18 @@ func (mr *MockRequestMockRecorder) Frame() *gomock.Call { } // HeaderValue mocks base method. -func (m *MockRequest) HeaderValue(arg0 string) (string, error) { +func (m *MockRequest) HeaderValue(name string) (string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HeaderValue", arg0) + ret := m.ctrl.Call(m, "HeaderValue", name) ret0, _ := ret[0].(string) ret1, _ := ret[1].(error) return ret0, ret1 } // HeaderValue indicates an expected call of HeaderValue. -func (mr *MockRequestMockRecorder) HeaderValue(arg0 any) *gomock.Call { +func (mr *MockRequestMockRecorder) HeaderValue(name any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderValue", reflect.TypeOf((*MockRequest)(nil).HeaderValue), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderValue", reflect.TypeOf((*MockRequest)(nil).HeaderValue), name) } // Headers mocks base method. @@ -185,17 +186,17 @@ func (mr *MockRequestMockRecorder) PostDataBuffer() *gomock.Call { } // PostDataJSON mocks base method. -func (m *MockRequest) PostDataJSON(arg0 any) error { +func (m *MockRequest) PostDataJSON(v any) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "PostDataJSON", arg0) + ret := m.ctrl.Call(m, "PostDataJSON", v) ret0, _ := ret[0].(error) return ret0 } // PostDataJSON indicates an expected call of PostDataJSON. -func (mr *MockRequestMockRecorder) PostDataJSON(arg0 any) *gomock.Call { +func (mr *MockRequestMockRecorder) PostDataJSON(v any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostDataJSON", reflect.TypeOf((*MockRequest)(nil).PostDataJSON), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostDataJSON", reflect.TypeOf((*MockRequest)(nil).PostDataJSON), v) } // RedirectedFrom mocks base method. diff --git a/clienter_mock_test.go b/clienter_mock_test.go index 65c87959..fa0a8871 100644 --- a/clienter_mock_test.go +++ b/clienter_mock_test.go @@ -22,6 +22,7 @@ import ( type MockSlacker struct { ctrl *gomock.Controller recorder *MockSlackerMockRecorder + isgomock struct{} } // MockSlackerMockRecorder is the mock recorder for MockSlacker. @@ -218,6 +219,7 @@ func (mr *MockSlackerMockRecorder) SearchMessagesContext(ctx, query, params any) type mockClienter struct { ctrl *gomock.Controller recorder *mockClienterMockRecorder + isgomock struct{} } // mockClienterMockRecorder is the mock recorder for mockClienter. diff --git a/cmd/slackdump/internal/emoji/emojidl/emoji_mock_test.go b/cmd/slackdump/internal/emoji/emojidl/emoji_mock_test.go index 28c83d5f..17f964d9 100644 --- a/cmd/slackdump/internal/emoji/emojidl/emoji_mock_test.go +++ b/cmd/slackdump/internal/emoji/emojidl/emoji_mock_test.go @@ -20,6 +20,7 @@ import ( type Mockemojidumper struct { ctrl *gomock.Controller recorder *MockemojidumperMockRecorder + isgomock struct{} } // MockemojidumperMockRecorder is the mock recorder for Mockemojidumper. diff --git a/cmd/slackdump/internal/list/mocks_test.go b/cmd/slackdump/internal/list/mocks_test.go index a7ca0203..208499ef 100644 --- a/cmd/slackdump/internal/list/mocks_test.go +++ b/cmd/slackdump/internal/list/mocks_test.go @@ -23,6 +23,7 @@ import ( type MockuserGetter struct { ctrl *gomock.Controller recorder *MockuserGetterMockRecorder + isgomock struct{} } // MockuserGetterMockRecorder is the mock recorder for MockuserGetter. @@ -61,6 +62,7 @@ func (mr *MockuserGetterMockRecorder) GetUsers(ctx any) *gomock.Call { type MockuserCacher struct { ctrl *gomock.Controller recorder *MockuserCacherMockRecorder + isgomock struct{} } // MockuserCacherMockRecorder is the mock recorder for MockuserCacher. diff --git a/cmd/slackdump/internal/ui/bubbles/datepicker/focus_string.go b/cmd/slackdump/internal/ui/bubbles/datepicker/focus_string.go new file mode 100644 index 00000000..eac664f4 --- /dev/null +++ b/cmd/slackdump/internal/ui/bubbles/datepicker/focus_string.go @@ -0,0 +1,26 @@ +// Code generated by "stringer -type=Focus"; DO NOT EDIT. + +package datepicker + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[FocusNone-0] + _ = x[FocusHeaderMonth-1] + _ = x[FocusHeaderYear-2] + _ = x[FocusCalendar-3] +} + +const _Focus_name = "FocusNoneFocusHeaderMonthFocusHeaderYearFocusCalendar" + +var _Focus_index = [...]uint8{0, 9, 25, 40, 53} + +func (i Focus) String() string { + if i < 0 || i >= Focus(len(_Focus_index)-1) { + return "Focus(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _Focus_name[_Focus_index[i]:_Focus_index[i+1]] +} diff --git a/cmd/slackdump/internal/workspace/mocks_test.go b/cmd/slackdump/internal/workspace/mocks_test.go index c4fc8589..f14f0380 100644 --- a/cmd/slackdump/internal/workspace/mocks_test.go +++ b/cmd/slackdump/internal/workspace/mocks_test.go @@ -23,6 +23,7 @@ import ( type Mockmanager struct { ctrl *gomock.Controller recorder *MockmanagerMockRecorder + isgomock struct{} } // MockmanagerMockRecorder is the mock recorder for Mockmanager. diff --git a/cmd/slackdump/internal/workspace/workspaceui/api.go b/cmd/slackdump/internal/workspace/workspaceui/api.go index ea5ae0c9..89bcab23 100644 --- a/cmd/slackdump/internal/workspace/workspaceui/api.go +++ b/cmd/slackdump/internal/workspace/workspaceui/api.go @@ -2,11 +2,13 @@ package workspaceui import ( "context" + "errors" "github.com/rusq/slackdump/v3/auth" "github.com/rusq/slackdump/v3/auth/auth_ui" ) +//go:generate mockgen -package workspaceui -destination=test_mock_manager.go -source api.go manager type manager interface { SaveProvider(workspace string, p auth.Provider) error Select(workspace string) error @@ -24,6 +26,9 @@ func createAndSelect(ctx context.Context, m manager, prov auth.Provider) (string if err != nil { return "", err } + if wsp == "" { + return "", errors.New("workspace name is empty") + } if err := m.SaveProvider(wsp, prov); err != nil { return "", err } diff --git a/cmd/slackdump/internal/workspace/workspaceui/api_test.go b/cmd/slackdump/internal/workspace/workspaceui/api_test.go new file mode 100644 index 00000000..7b58a2de --- /dev/null +++ b/cmd/slackdump/internal/workspace/workspaceui/api_test.go @@ -0,0 +1,117 @@ +package workspaceui + +import ( + "context" + "testing" + + "github.com/rusq/slack" + "github.com/rusq/slackdump/v3/internal/fixtures" + "github.com/rusq/slackdump/v3/internal/mocks/mock_auth" + "github.com/stretchr/testify/assert" + gomock "go.uber.org/mock/gomock" +) + +func Test_createAndSelect(t *testing.T) { + type args struct { + ctx context.Context + // m manager + // prov auth.Provider + } + tests := []struct { + name string + args args + expectFn func(mp *mock_auth.MockProvider, mm *Mockmanager) + want string + wantErr bool + }{ + { + name: "provider test fails", + args: args{ + ctx: context.Background(), + }, + expectFn: func(mp *mock_auth.MockProvider, mm *Mockmanager) { + mp.EXPECT().Test(gomock.Any()).Return(nil, assert.AnError) + }, + want: "", + wantErr: true, + }, + { + name: "save provider fails", + args: args{ + ctx: context.Background(), + }, + expectFn: func(mp *mock_auth.MockProvider, mm *Mockmanager) { + mp.EXPECT().Test(gomock.Any()).Return(fixtures.LoadPtr[slack.AuthTestResponse](string(fixtures.TestAuthTestInfo)), nil) + mm.EXPECT().SaveProvider(gomock.Any(), gomock.Any()).Return(assert.AnError) + }, + want: "", + wantErr: true, + }, + { + name: "select fails", + args: args{ + ctx: context.Background(), + }, + expectFn: func(mp *mock_auth.MockProvider, mm *Mockmanager) { + mp.EXPECT().Test(gomock.Any()).Return(fixtures.LoadPtr[slack.AuthTestResponse](string(fixtures.TestAuthTestInfo)), nil) + mm.EXPECT().SaveProvider(gomock.Any(), gomock.Any()).Return(nil) + mm.EXPECT().Select(gomock.Any()).Return(assert.AnError) + }, + want: "", + wantErr: true, + }, + { + name: "success", + args: args{ + ctx: context.Background(), + }, + expectFn: func(mp *mock_auth.MockProvider, mm *Mockmanager) { + mp.EXPECT().Test(gomock.Any()).Return(fixtures.LoadPtr[slack.AuthTestResponse](string(fixtures.TestAuthTestInfo)), nil) + mm.EXPECT().SaveProvider(gomock.Any(), gomock.Any()).Return(nil) + mm.EXPECT().Select(gomock.Any()).Return(nil) + }, + want: "test", + wantErr: false, + }, + { + name: "url empty fails", + args: args{ + ctx: context.Background(), + }, + expectFn: func(mp *mock_auth.MockProvider, mm *Mockmanager) { + mp.EXPECT().Test(gomock.Any()).Return(&slack.AuthTestResponse{URL: ""}, nil) + }, + want: "", + wantErr: true, + }, + { + name: "url sanitize fails", + args: args{ + ctx: context.Background(), + }, + expectFn: func(mp *mock_auth.MockProvider, mm *Mockmanager) { + mp.EXPECT().Test(gomock.Any()).Return(&slack.AuthTestResponse{URL: "ftp://lol.example.com"}, nil) + }, + want: "", + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + mp := mock_auth.NewMockProvider(ctrl) + mm := NewMockmanager(ctrl) + if tt.expectFn != nil { + tt.expectFn(mp, mm) + } + got, err := createAndSelect(tt.args.ctx, mm, mp) + if (err != nil) != tt.wantErr { + t.Errorf("createAndSelect() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("createAndSelect() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/cmd/slackdump/internal/workspace/workspaceui/filesecrets.go b/cmd/slackdump/internal/workspace/workspaceui/filesecrets.go index d2b59c30..57420dc1 100644 --- a/cmd/slackdump/internal/workspace/workspaceui/filesecrets.go +++ b/cmd/slackdump/internal/workspace/workspaceui/filesecrets.go @@ -32,6 +32,7 @@ func fileWithSecrets(ctx context.Context, mgr manager) error { return nil } } + tok, cookie, err := parseSecretsTxt(filename) if err != nil { return err @@ -54,6 +55,12 @@ func validateSecrets(filename string) error { } func parseSecretsTxt(filename string) (string, string, error) { + const ( + tokenKey = "SLACK_TOKEN" + cookieKey = "SLACK_COOKIE" + + clientTokenPrefix = "xoxc-" + ) f, err := os.Open(filename) if err != nil { return "", "", err @@ -63,19 +70,19 @@ func parseSecretsTxt(filename string) (string, string, error) { if err != nil { return "", "", errors.New("not a secrets file") } - token, ok := secrets["SLACK_TOKEN"] + token, ok := secrets[tokenKey] if !ok { - return "", "", errors.New("no SLACK_TOKEN found") + return "", "", errors.New("no SLACK_TOKEN found in the file") } if err := structures.ValidateToken(token); err != nil { return "", "", err } - if !strings.HasPrefix(token, "xoxc-") { + if !strings.HasPrefix(token, clientTokenPrefix) { return token, "", nil } - cook, ok := secrets["SLACK_COOKIE"] + cook, ok := secrets[cookieKey] if !ok { - return "", "", errors.New("no SLACK_COOKIE found") + return "", "", errors.New("no SLACK_COOKIE found in the file") } if !strings.HasPrefix(cook, "xoxd-") { return "", "", errors.New("invalid cookie") diff --git a/cmd/slackdump/internal/workspace/workspaceui/filesecrets_test.go b/cmd/slackdump/internal/workspace/workspaceui/filesecrets_test.go new file mode 100644 index 00000000..46343361 --- /dev/null +++ b/cmd/slackdump/internal/workspace/workspaceui/filesecrets_test.go @@ -0,0 +1,137 @@ +package workspaceui + +import ( + "os" + "path/filepath" + "testing" + + "github.com/rusq/slackdump/v3/internal/fixtures" +) + +func mkEnvFileData(m map[string]string) []byte { + var data []byte + for k, v := range m { + data = append(data, []byte(k+"="+v+"\n")...) + } + return data +} + +func writeEnvFile(t *testing.T, filename string, m map[string]string) string { + t.Helper() + data := mkEnvFileData(m) + err := os.WriteFile(filename, data, 0644) + if err != nil { + t.Fatal(err) + } + return filename +} + +func Test_parseSecretsTxt(t *testing.T) { + dir := t.TempDir() + type args struct { + filename string + } + tests := []struct { + name string + args args + want string + want1 string + wantErr bool + }{ + { + name: "valid client token and cookie", + args: args{filename: writeEnvFile(t, filepath.Join(dir, "secrets.txt"), map[string]string{ + "SLACK_TOKEN": fixtures.TestClientToken, + "SLACK_COOKIE": "xoxd-cookie", + })}, + want: fixtures.TestClientToken, + want1: "xoxd-cookie", + wantErr: false, + }, + { + name: "valid client token but no cookie (cookie is required)", + args: args{filename: writeEnvFile(t, filepath.Join(dir, "secrets2.txt"), map[string]string{ + "SLACK_TOKEN": fixtures.TestClientToken, + })}, + want: "", + want1: "", + wantErr: true, + }, + { + name: "bot token", + args: args{filename: writeEnvFile(t, filepath.Join(dir, "secrets3.txt"), map[string]string{ + "SLACK_TOKEN": fixtures.TestBotToken, + })}, + want: fixtures.TestBotToken, + want1: "", + wantErr: false, + }, + { + name: "app token", + args: args{filename: writeEnvFile(t, filepath.Join(dir, "secrets4.txt"), map[string]string{ + "SLACK_TOKEN": fixtures.TestAppToken, + })}, + want: fixtures.TestAppToken, + want1: "", + wantErr: false, + }, + { + name: "export token", + args: args{filename: writeEnvFile(t, filepath.Join(dir, "secrets5.txt"), map[string]string{ + "SLACK_TOKEN": fixtures.TestExportToken, + })}, + want: fixtures.TestExportToken, + want1: "", + wantErr: false, + }, + { + name: "legacy token", + args: args{filename: writeEnvFile(t, filepath.Join(dir, "secrets6.txt"), map[string]string{ + "SLACK_TOKEN": fixtures.TestPersonalToken, + })}, + want: fixtures.TestPersonalToken, + want1: "", + wantErr: false, + }, + { + name: "invalid token", + args: args{filename: writeEnvFile(t, filepath.Join(dir, "secrets7.txt"), map[string]string{ + "SLACK_TOKEN": "invalid", + })}, + want: "", + want1: "", + wantErr: true, + }, + { + name: "missing token", + args: args{filename: writeEnvFile(t, filepath.Join(dir, "secrets8.txt"), map[string]string{ + "NOT_SLACK_TOKEN": "invalid", + })}, + want: "", + want1: "", + wantErr: true, + }, + { + name: "non-existent file", + args: args{filename: filepath.Join(dir, "secrets9.txt")}, + want: "", + want1: "", + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, got1, err := parseSecretsTxt(tt.args.filename) + if (err != nil) != tt.wantErr { + t.Errorf("parseSecretsTxt() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("parseSecretsTxt() got = %v, want %v", got, tt.want) + } + if got1 != tt.want1 { + t.Errorf("parseSecretsTxt() got1 = %v, want %v", got1, tt.want1) + } + }) + } +} diff --git a/cmd/slackdump/internal/workspace/workspaceui/test_mock_manager.go b/cmd/slackdump/internal/workspace/workspaceui/test_mock_manager.go new file mode 100644 index 00000000..abb8bde2 --- /dev/null +++ b/cmd/slackdump/internal/workspace/workspaceui/test_mock_manager.go @@ -0,0 +1,69 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: api.go +// +// Generated by this command: +// +// mockgen -package workspaceui -destination=test_mock_manager.go -source api.go manager +// + +// Package workspaceui is a generated GoMock package. +package workspaceui + +import ( + reflect "reflect" + + auth "github.com/rusq/slackdump/v3/auth" + gomock "go.uber.org/mock/gomock" +) + +// Mockmanager is a mock of manager interface. +type Mockmanager struct { + ctrl *gomock.Controller + recorder *MockmanagerMockRecorder + isgomock struct{} +} + +// MockmanagerMockRecorder is the mock recorder for Mockmanager. +type MockmanagerMockRecorder struct { + mock *Mockmanager +} + +// NewMockmanager creates a new mock instance. +func NewMockmanager(ctrl *gomock.Controller) *Mockmanager { + mock := &Mockmanager{ctrl: ctrl} + mock.recorder = &MockmanagerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *Mockmanager) EXPECT() *MockmanagerMockRecorder { + return m.recorder +} + +// SaveProvider mocks base method. +func (m *Mockmanager) SaveProvider(workspace string, p auth.Provider) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SaveProvider", workspace, p) + ret0, _ := ret[0].(error) + return ret0 +} + +// SaveProvider indicates an expected call of SaveProvider. +func (mr *MockmanagerMockRecorder) SaveProvider(workspace, p any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveProvider", reflect.TypeOf((*Mockmanager)(nil).SaveProvider), workspace, p) +} + +// Select mocks base method. +func (m *Mockmanager) Select(workspace string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Select", workspace) + ret0, _ := ret[0].(error) + return ret0 +} + +// Select indicates an expected call of Select. +func (mr *MockmanagerMockRecorder) Select(workspace any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Select", reflect.TypeOf((*Mockmanager)(nil).Select), workspace) +} diff --git a/export/mock_dumper_test.go b/export/mock_dumper_test.go index 5180494c..3082dd0e 100644 --- a/export/mock_dumper_test.go +++ b/export/mock_dumper_test.go @@ -24,6 +24,7 @@ import ( type Mockdumper struct { ctrl *gomock.Controller recorder *MockdumperMockRecorder + isgomock struct{} } // MockdumperMockRecorder is the mock recorder for Mockdumper. diff --git a/internal/chunk/dirproc/dirproc_mock_test.go b/internal/chunk/dirproc/dirproc_mock_test.go index bf4dab0a..f76b7706 100644 --- a/internal/chunk/dirproc/dirproc_mock_test.go +++ b/internal/chunk/dirproc/dirproc_mock_test.go @@ -22,6 +22,7 @@ import ( type MockTransformer struct { ctrl *gomock.Controller recorder *MockTransformerMockRecorder + isgomock struct{} } // MockTransformerMockRecorder is the mock recorder for MockTransformer. @@ -59,6 +60,7 @@ func (mr *MockTransformerMockRecorder) Transform(ctx, id any) *gomock.Call { type Mocktracker struct { ctrl *gomock.Controller recorder *MocktrackerMockRecorder + isgomock struct{} } // MocktrackerMockRecorder is the mock recorder for Mocktracker. @@ -139,6 +141,7 @@ func (mr *MocktrackerMockRecorder) Unregister(id any) *gomock.Call { type Mockdatahandler struct { ctrl *gomock.Controller recorder *MockdatahandlerMockRecorder + isgomock struct{} } // MockdatahandlerMockRecorder is the mock recorder for Mockdatahandler. @@ -302,6 +305,7 @@ func (mr *MockdatahandlerMockRecorder) ThreadMessages(ctx, channelID, parent, th type Mockcounter struct { ctrl *gomock.Controller recorder *MockcounterMockRecorder + isgomock struct{} } // MockcounterMockRecorder is the mock recorder for Mockcounter. diff --git a/internal/mocks/mock_auth/mock_auth.go b/internal/mocks/mock_auth/mock_auth.go index a4e83ada..803c9d38 100644 --- a/internal/mocks/mock_auth/mock_auth.go +++ b/internal/mocks/mock_auth/mock_auth.go @@ -22,6 +22,7 @@ import ( type MockProvider struct { ctrl *gomock.Controller recorder *MockProviderMockRecorder + isgomock struct{} } // MockProviderMockRecorder is the mock recorder for MockProvider. @@ -85,18 +86,18 @@ func (mr *MockProviderMockRecorder) SlackToken() *gomock.Call { } // Test mocks base method. -func (m *MockProvider) Test(arg0 context.Context) (*slack.AuthTestResponse, error) { +func (m *MockProvider) Test(ctx context.Context) (*slack.AuthTestResponse, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Test", arg0) + ret := m.ctrl.Call(m, "Test", ctx) ret0, _ := ret[0].(*slack.AuthTestResponse) ret1, _ := ret[1].(error) return ret0, ret1 } // Test indicates an expected call of Test. -func (mr *MockProviderMockRecorder) Test(arg0 any) *gomock.Call { +func (mr *MockProviderMockRecorder) Test(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Test", reflect.TypeOf((*MockProvider)(nil).Test), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Test", reflect.TypeOf((*MockProvider)(nil).Test), ctx) } // Validate mocks base method. diff --git a/internal/mocks/mock_dl/mock_exporter.go b/internal/mocks/mock_dl/mock_exporter.go index 05274509..11dd5071 100644 --- a/internal/mocks/mock_dl/mock_exporter.go +++ b/internal/mocks/mock_dl/mock_exporter.go @@ -21,6 +21,7 @@ import ( type MockExporter struct { ctrl *gomock.Controller recorder *MockExporterMockRecorder + isgomock struct{} } // MockExporterMockRecorder is the mock recorder for MockExporter. @@ -41,29 +42,29 @@ func (m *MockExporter) EXPECT() *MockExporterMockRecorder { } // ProcessFunc mocks base method. -func (m *MockExporter) ProcessFunc(arg0 string) slackdump.ProcessFunc { +func (m *MockExporter) ProcessFunc(channelName string) slackdump.ProcessFunc { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ProcessFunc", arg0) + ret := m.ctrl.Call(m, "ProcessFunc", channelName) ret0, _ := ret[0].(slackdump.ProcessFunc) return ret0 } // ProcessFunc indicates an expected call of ProcessFunc. -func (mr *MockExporterMockRecorder) ProcessFunc(arg0 any) *gomock.Call { +func (mr *MockExporterMockRecorder) ProcessFunc(channelName any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProcessFunc", reflect.TypeOf((*MockExporter)(nil).ProcessFunc), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProcessFunc", reflect.TypeOf((*MockExporter)(nil).ProcessFunc), channelName) } // Start mocks base method. -func (m *MockExporter) Start(arg0 context.Context) { +func (m *MockExporter) Start(ctx context.Context) { m.ctrl.T.Helper() - m.ctrl.Call(m, "Start", arg0) + m.ctrl.Call(m, "Start", ctx) } // Start indicates an expected call of Start. -func (mr *MockExporterMockRecorder) Start(arg0 any) *gomock.Call { +func (mr *MockExporterMockRecorder) Start(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Start", reflect.TypeOf((*MockExporter)(nil).Start), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Start", reflect.TypeOf((*MockExporter)(nil).Start), ctx) } // Stop mocks base method. diff --git a/internal/mocks/mock_io/mock_io.go b/internal/mocks/mock_io/mock_io.go index 2042ae60..53c5da1b 100644 --- a/internal/mocks/mock_io/mock_io.go +++ b/internal/mocks/mock_io/mock_io.go @@ -19,6 +19,7 @@ import ( type MockReadCloser struct { ctrl *gomock.Controller recorder *MockReadCloserMockRecorder + isgomock struct{} } // MockReadCloserMockRecorder is the mock recorder for MockReadCloser. @@ -53,24 +54,25 @@ func (mr *MockReadCloserMockRecorder) Close() *gomock.Call { } // Read mocks base method. -func (m *MockReadCloser) Read(arg0 []byte) (int, error) { +func (m *MockReadCloser) Read(p []byte) (int, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Read", arg0) + ret := m.ctrl.Call(m, "Read", p) ret0, _ := ret[0].(int) ret1, _ := ret[1].(error) return ret0, ret1 } // Read indicates an expected call of Read. -func (mr *MockReadCloserMockRecorder) Read(arg0 any) *gomock.Call { +func (mr *MockReadCloserMockRecorder) Read(p any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Read", reflect.TypeOf((*MockReadCloser)(nil).Read), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Read", reflect.TypeOf((*MockReadCloser)(nil).Read), p) } // MockWriteCloser is a mock of WriteCloser interface. type MockWriteCloser struct { ctrl *gomock.Controller recorder *MockWriteCloserMockRecorder + isgomock struct{} } // MockWriteCloserMockRecorder is the mock recorder for MockWriteCloser. @@ -105,16 +107,16 @@ func (mr *MockWriteCloserMockRecorder) Close() *gomock.Call { } // Write mocks base method. -func (m *MockWriteCloser) Write(arg0 []byte) (int, error) { +func (m *MockWriteCloser) Write(p []byte) (int, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Write", arg0) + ret := m.ctrl.Call(m, "Write", p) ret0, _ := ret[0].(int) ret1, _ := ret[1].(error) return ret0, ret1 } // Write indicates an expected call of Write. -func (mr *MockWriteCloserMockRecorder) Write(arg0 any) *gomock.Call { +func (mr *MockWriteCloserMockRecorder) Write(p any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Write", reflect.TypeOf((*MockWriteCloser)(nil).Write), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Write", reflect.TypeOf((*MockWriteCloser)(nil).Write), p) } diff --git a/internal/mocks/mock_os/mock_os.go b/internal/mocks/mock_os/mock_os.go index dd4a6049..041e4ee3 100644 --- a/internal/mocks/mock_os/mock_os.go +++ b/internal/mocks/mock_os/mock_os.go @@ -21,6 +21,7 @@ import ( type MockFileInfo struct { ctrl *gomock.Controller recorder *MockFileInfoMockRecorder + isgomock struct{} } // MockFileInfoMockRecorder is the mock recorder for MockFileInfo. diff --git a/mocks/mock_appauth/mock_appauth.go b/mocks/mock_appauth/mock_appauth.go index 79b005be..4315f735 100644 --- a/mocks/mock_appauth/mock_appauth.go +++ b/mocks/mock_appauth/mock_appauth.go @@ -22,6 +22,7 @@ import ( type MockCredentials struct { ctrl *gomock.Controller recorder *MockCredentialsMockRecorder + isgomock struct{} } // MockCredentialsMockRecorder is the mock recorder for MockCredentials. @@ -79,6 +80,7 @@ func (mr *MockCredentialsMockRecorder) IsEmpty() *gomock.Call { type Mockcontainer struct { ctrl *gomock.Controller recorder *MockcontainerMockRecorder + isgomock struct{} } // MockcontainerMockRecorder is the mock recorder for Mockcontainer. diff --git a/mocks/mock_processor/mock_processor.go b/mocks/mock_processor/mock_processor.go index 8b35f75d..c92fa9fd 100644 --- a/mocks/mock_processor/mock_processor.go +++ b/mocks/mock_processor/mock_processor.go @@ -21,6 +21,7 @@ import ( type MockConversations struct { ctrl *gomock.Controller recorder *MockConversationsMockRecorder + isgomock struct{} } // MockConversationsMockRecorder is the mock recorder for MockConversations. @@ -41,31 +42,31 @@ func (m *MockConversations) EXPECT() *MockConversationsMockRecorder { } // ChannelInfo mocks base method. -func (m *MockConversations) ChannelInfo(arg0 context.Context, arg1 *slack.Channel, arg2 string) error { +func (m *MockConversations) ChannelInfo(ctx context.Context, ci *slack.Channel, threadID string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ChannelInfo", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "ChannelInfo", ctx, ci, threadID) ret0, _ := ret[0].(error) return ret0 } // ChannelInfo indicates an expected call of ChannelInfo. -func (mr *MockConversationsMockRecorder) ChannelInfo(arg0, arg1, arg2 any) *gomock.Call { +func (mr *MockConversationsMockRecorder) ChannelInfo(ctx, ci, threadID any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChannelInfo", reflect.TypeOf((*MockConversations)(nil).ChannelInfo), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChannelInfo", reflect.TypeOf((*MockConversations)(nil).ChannelInfo), ctx, ci, threadID) } // ChannelUsers mocks base method. -func (m *MockConversations) ChannelUsers(arg0 context.Context, arg1, arg2 string, arg3 []string) error { +func (m *MockConversations) ChannelUsers(ctx context.Context, channelID, threadTS string, users []string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ChannelUsers", arg0, arg1, arg2, arg3) + ret := m.ctrl.Call(m, "ChannelUsers", ctx, channelID, threadTS, users) ret0, _ := ret[0].(error) return ret0 } // ChannelUsers indicates an expected call of ChannelUsers. -func (mr *MockConversationsMockRecorder) ChannelUsers(arg0, arg1, arg2, arg3 any) *gomock.Call { +func (mr *MockConversationsMockRecorder) ChannelUsers(ctx, channelID, threadTS, users any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChannelUsers", reflect.TypeOf((*MockConversations)(nil).ChannelUsers), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChannelUsers", reflect.TypeOf((*MockConversations)(nil).ChannelUsers), ctx, channelID, threadTS, users) } // Close mocks base method. @@ -83,51 +84,52 @@ func (mr *MockConversationsMockRecorder) Close() *gomock.Call { } // Files mocks base method. -func (m *MockConversations) Files(arg0 context.Context, arg1 *slack.Channel, arg2 slack.Message, arg3 []slack.File) error { +func (m *MockConversations) Files(ctx context.Context, channel *slack.Channel, parent slack.Message, ff []slack.File) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Files", arg0, arg1, arg2, arg3) + ret := m.ctrl.Call(m, "Files", ctx, channel, parent, ff) ret0, _ := ret[0].(error) return ret0 } // Files indicates an expected call of Files. -func (mr *MockConversationsMockRecorder) Files(arg0, arg1, arg2, arg3 any) *gomock.Call { +func (mr *MockConversationsMockRecorder) Files(ctx, channel, parent, ff any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Files", reflect.TypeOf((*MockConversations)(nil).Files), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Files", reflect.TypeOf((*MockConversations)(nil).Files), ctx, channel, parent, ff) } // Messages mocks base method. -func (m *MockConversations) Messages(arg0 context.Context, arg1 string, arg2 int, arg3 bool, arg4 []slack.Message) error { +func (m *MockConversations) Messages(ctx context.Context, channelID string, numThreads int, isLast bool, messages []slack.Message) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Messages", arg0, arg1, arg2, arg3, arg4) + ret := m.ctrl.Call(m, "Messages", ctx, channelID, numThreads, isLast, messages) ret0, _ := ret[0].(error) return ret0 } // Messages indicates an expected call of Messages. -func (mr *MockConversationsMockRecorder) Messages(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call { +func (mr *MockConversationsMockRecorder) Messages(ctx, channelID, numThreads, isLast, messages any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Messages", reflect.TypeOf((*MockConversations)(nil).Messages), arg0, arg1, arg2, arg3, arg4) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Messages", reflect.TypeOf((*MockConversations)(nil).Messages), ctx, channelID, numThreads, isLast, messages) } // ThreadMessages mocks base method. -func (m *MockConversations) ThreadMessages(arg0 context.Context, arg1 string, arg2 slack.Message, arg3, arg4 bool, arg5 []slack.Message) error { +func (m *MockConversations) ThreadMessages(ctx context.Context, channelID string, parent slack.Message, threadOnly, isLast bool, replies []slack.Message) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ThreadMessages", arg0, arg1, arg2, arg3, arg4, arg5) + ret := m.ctrl.Call(m, "ThreadMessages", ctx, channelID, parent, threadOnly, isLast, replies) ret0, _ := ret[0].(error) return ret0 } // ThreadMessages indicates an expected call of ThreadMessages. -func (mr *MockConversationsMockRecorder) ThreadMessages(arg0, arg1, arg2, arg3, arg4, arg5 any) *gomock.Call { +func (mr *MockConversationsMockRecorder) ThreadMessages(ctx, channelID, parent, threadOnly, isLast, replies any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ThreadMessages", reflect.TypeOf((*MockConversations)(nil).ThreadMessages), arg0, arg1, arg2, arg3, arg4, arg5) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ThreadMessages", reflect.TypeOf((*MockConversations)(nil).ThreadMessages), ctx, channelID, parent, threadOnly, isLast, replies) } // MockUsers is a mock of Users interface. type MockUsers struct { ctrl *gomock.Controller recorder *MockUsersMockRecorder + isgomock struct{} } // MockUsersMockRecorder is the mock recorder for MockUsers. @@ -148,23 +150,24 @@ func (m *MockUsers) EXPECT() *MockUsersMockRecorder { } // Users mocks base method. -func (m *MockUsers) Users(arg0 context.Context, arg1 []slack.User) error { +func (m *MockUsers) Users(ctx context.Context, users []slack.User) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Users", arg0, arg1) + ret := m.ctrl.Call(m, "Users", ctx, users) ret0, _ := ret[0].(error) return ret0 } // Users indicates an expected call of Users. -func (mr *MockUsersMockRecorder) Users(arg0, arg1 any) *gomock.Call { +func (mr *MockUsersMockRecorder) Users(ctx, users any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Users", reflect.TypeOf((*MockUsers)(nil).Users), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Users", reflect.TypeOf((*MockUsers)(nil).Users), ctx, users) } // MockChannels is a mock of Channels interface. type MockChannels struct { ctrl *gomock.Controller recorder *MockChannelsMockRecorder + isgomock struct{} } // MockChannelsMockRecorder is the mock recorder for MockChannels. @@ -185,23 +188,24 @@ func (m *MockChannels) EXPECT() *MockChannelsMockRecorder { } // Channels mocks base method. -func (m *MockChannels) Channels(arg0 context.Context, arg1 []slack.Channel) error { +func (m *MockChannels) Channels(ctx context.Context, channels []slack.Channel) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Channels", arg0, arg1) + ret := m.ctrl.Call(m, "Channels", ctx, channels) ret0, _ := ret[0].(error) return ret0 } // Channels indicates an expected call of Channels. -func (mr *MockChannelsMockRecorder) Channels(arg0, arg1 any) *gomock.Call { +func (mr *MockChannelsMockRecorder) Channels(ctx, channels any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Channels", reflect.TypeOf((*MockChannels)(nil).Channels), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Channels", reflect.TypeOf((*MockChannels)(nil).Channels), ctx, channels) } // MockChannelInformer is a mock of ChannelInformer interface. type MockChannelInformer struct { ctrl *gomock.Controller recorder *MockChannelInformerMockRecorder + isgomock struct{} } // MockChannelInformerMockRecorder is the mock recorder for MockChannelInformer. @@ -222,37 +226,38 @@ func (m *MockChannelInformer) EXPECT() *MockChannelInformerMockRecorder { } // ChannelInfo mocks base method. -func (m *MockChannelInformer) ChannelInfo(arg0 context.Context, arg1 *slack.Channel, arg2 string) error { +func (m *MockChannelInformer) ChannelInfo(ctx context.Context, ci *slack.Channel, threadID string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ChannelInfo", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "ChannelInfo", ctx, ci, threadID) ret0, _ := ret[0].(error) return ret0 } // ChannelInfo indicates an expected call of ChannelInfo. -func (mr *MockChannelInformerMockRecorder) ChannelInfo(arg0, arg1, arg2 any) *gomock.Call { +func (mr *MockChannelInformerMockRecorder) ChannelInfo(ctx, ci, threadID any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChannelInfo", reflect.TypeOf((*MockChannelInformer)(nil).ChannelInfo), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChannelInfo", reflect.TypeOf((*MockChannelInformer)(nil).ChannelInfo), ctx, ci, threadID) } // ChannelUsers mocks base method. -func (m *MockChannelInformer) ChannelUsers(arg0 context.Context, arg1, arg2 string, arg3 []string) error { +func (m *MockChannelInformer) ChannelUsers(ctx context.Context, channelID, threadTS string, users []string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ChannelUsers", arg0, arg1, arg2, arg3) + ret := m.ctrl.Call(m, "ChannelUsers", ctx, channelID, threadTS, users) ret0, _ := ret[0].(error) return ret0 } // ChannelUsers indicates an expected call of ChannelUsers. -func (mr *MockChannelInformerMockRecorder) ChannelUsers(arg0, arg1, arg2, arg3 any) *gomock.Call { +func (mr *MockChannelInformerMockRecorder) ChannelUsers(ctx, channelID, threadTS, users any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChannelUsers", reflect.TypeOf((*MockChannelInformer)(nil).ChannelUsers), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChannelUsers", reflect.TypeOf((*MockChannelInformer)(nil).ChannelUsers), ctx, channelID, threadTS, users) } // MockFiler is a mock of Filer interface. type MockFiler struct { ctrl *gomock.Controller recorder *MockFilerMockRecorder + isgomock struct{} } // MockFilerMockRecorder is the mock recorder for MockFiler. @@ -273,15 +278,15 @@ func (m *MockFiler) EXPECT() *MockFilerMockRecorder { } // Files mocks base method. -func (m *MockFiler) Files(arg0 context.Context, arg1 *slack.Channel, arg2 slack.Message, arg3 []slack.File) error { +func (m *MockFiler) Files(ctx context.Context, channel *slack.Channel, parent slack.Message, ff []slack.File) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Files", arg0, arg1, arg2, arg3) + ret := m.ctrl.Call(m, "Files", ctx, channel, parent, ff) ret0, _ := ret[0].(error) return ret0 } // Files indicates an expected call of Files. -func (mr *MockFilerMockRecorder) Files(arg0, arg1, arg2, arg3 any) *gomock.Call { +func (mr *MockFilerMockRecorder) Files(ctx, channel, parent, ff any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Files", reflect.TypeOf((*MockFiler)(nil).Files), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Files", reflect.TypeOf((*MockFiler)(nil).Files), ctx, channel, parent, ff) } From f5befe57e7d01c4eb1f7fcdc2deeb1a5011db652 Mon Sep 17 00:00:00 2001 From: Rustam Gilyazov <16064414+rusq@users.noreply.github.com> Date: Fri, 15 Nov 2024 21:24:37 +1000 Subject: [PATCH 3/3] help update --- cmd/slackdump/internal/workspace/del.go | 3 +-- cmd/slackdump/internal/workspace/select.go | 3 ++- cmd/slackdump/internal/workspace/workspace.go | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cmd/slackdump/internal/workspace/del.go b/cmd/slackdump/internal/workspace/del.go index b369f48b..f5205ae9 100644 --- a/cmd/slackdump/internal/workspace/del.go +++ b/cmd/slackdump/internal/workspace/del.go @@ -25,8 +25,7 @@ Use ` + "`del`" + ` to delete the Slack Workspace login information ("forget" the workspace). If the workspace login information is deleted, you will need to login into that -workspace again by running ` + " `slackdump auth new `" + `, in case you -need to use this workspace again. +workspace again by running ` + " `slackdump workspace new `" + `. Slackdump will ask for the confirmation before deleting. To omit the question, use ` + "`-y`" + ` flag. diff --git a/cmd/slackdump/internal/workspace/select.go b/cmd/slackdump/internal/workspace/select.go index 1ecfbc82..8ae34660 100644 --- a/cmd/slackdump/internal/workspace/select.go +++ b/cmd/slackdump/internal/workspace/select.go @@ -19,7 +19,8 @@ var CmdWspSelect = &base.Command{ that you have previously authenticated in. "Current" means that this workspace will be used by default when running -other commands, unless you specify a different workspace explicitly. +other commands, unless you specify a different workspace explicitly with +the ` + "`-w`" + ` flag. To get the full list of authenticated workspaces, run: diff --git a/cmd/slackdump/internal/workspace/workspace.go b/cmd/slackdump/internal/workspace/workspace.go index f2046bf1..a73ed7c8 100644 --- a/cmd/slackdump/internal/workspace/workspace.go +++ b/cmd/slackdump/internal/workspace/workspace.go @@ -54,9 +54,9 @@ automatically detected to be: }, } -//go:generate mockgen -destination=mocks_test.go -package=workspace -source=workspace.go manager - // manager is used for test rigging. +// +//go:generate mockgen -destination=mocks_test.go -package=workspace -source=workspace.go manager type manager interface { Auth(ctx context.Context, name string, c cache.Credentials) (auth.Provider, error) Delete(name string) error