Gh 19916 mmctl list deactivated users only (#26646)

Этот коммит содержится в:
Ezekiel
2024-04-30 20:49:50 +08:00
коммит произвёл GitHub
родитель 10a59619c7
Коммит b6a8965969
6 изменённых файлов: 352 добавлений и 88 удалений

Просмотреть файл

@@ -97,6 +97,7 @@ type Client interface {
SyncLdap(ctx context.Context, includeRemovedMembers bool) (*model.Response, error)
MigrateIdLdap(ctx context.Context, toAttribute string) (*model.Response, error)
GetUsers(ctx context.Context, page, perPage int, etag string) ([]*model.User, *model.Response, error)
GetUsersWithCustomQueryParameters(ctx context.Context, page, perPage int, queryParameters string, etag string) ([]*model.User, *model.Response, error)
GetUsersByIds(ctx context.Context, userIDs []string) ([]*model.User, *model.Response, error)
GetUsersInTeam(ctx context.Context, teamID string, page, perPage int, etag string) ([]*model.User, *model.Response, error)
UpdateUserActive(ctx context.Context, userID string, activate bool) (*model.Response, error)

Просмотреть файл

@@ -8,6 +8,7 @@ import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"os"
"sort"
@@ -320,6 +321,7 @@ func init() {
ListUsersCmd.Flags().Int("per-page", DefaultPageSize, "Number of users to be fetched")
ListUsersCmd.Flags().Bool("all", false, "Fetch all users. --page flag will be ignore if provided")
ListUsersCmd.Flags().String("team", "", "If supplied, only users belonging to this team will be listed")
ListUsersCmd.Flags().Bool("inactive", false, "If supplied, only users which are inactive will be fetch")
UserConvertCmd.Flags().Bool("bot", false, "If supplied, convert users to bots")
UserConvertCmd.Flags().Bool("user", false, "If supplied, convert a bot to a user")
@@ -798,6 +800,16 @@ auth_service: {{.AuthService}}`
return nil
}
func ResetListUsersCmd() *cobra.Command {
ListUsersCmd.Flags().Set("page", "0")
ListUsersCmd.Flags().Set("per-page", "200")
ListUsersCmd.Flags().Set("all", "false")
ListUsersCmd.Flags().Set("team", "")
ListUsersCmd.Flags().Set("inactive", "false")
return ListUsersCmd
}
func listUsersCmdF(c client.Client, command *cobra.Command, args []string) error {
page, err := command.Flags().GetInt("page")
if err != nil {
@@ -815,6 +827,11 @@ func listUsersCmdF(c client.Client, command *cobra.Command, args []string) error
if err != nil {
return err
}
// if inactive, DeletedAt != 0
inactive, err := command.Flags().GetBool("inactive")
if err != nil {
return err
}
if showAll {
page = 0
@@ -829,21 +846,21 @@ func listUsersCmdF(c client.Client, command *cobra.Command, args []string) error
}
}
params := url.Values{}
if inactive {
params.Add("inactive", "true")
}
if team != nil {
params.Add("in_team", team.Id)
}
tpl := `{{.Id}}: {{.Username}} ({{.Email}})`
for {
var users []*model.User
var err error
if team != nil {
users, _, err = c.GetUsersInTeam(context.TODO(), team.Id, page, perPage, "")
if err != nil {
return errors.Wrap(err, fmt.Sprintf("Failed to fetch users for team %s", teamName))
}
} else {
users, _, err = c.GetUsers(context.TODO(), page, perPage, "")
if err != nil {
return errors.Wrap(err, "Failed to fetch users")
}
users, _, err := c.GetUsersWithCustomQueryParameters(context.TODO(), page, perPage, params.Encode(), "")
if err != nil {
return errors.Wrap(err, "Failed to fetch users")
}
if len(users) == 0 {
break
}

Просмотреть файл

@@ -164,18 +164,26 @@ func (s *MmctlE2ETestSuite) TestListUserCmd() {
userPool = append(userPool, usr.Username)
}
inactivePool := []string{}
// create inactive users
for i := 0; i < 2; i++ {
userData := model.User{
Username: "fakeuser" + model.NewRandomString(10),
Password: "Pa$$word11",
Email: s.th.GenerateTestEmail(),
DeleteAt: model.GetMillis(),
}
usr, err := s.th.App.CreateUser(s.th.Context, &userData)
s.Require().Nil(err)
userPool = append(userPool, usr.Username)
inactivePool = append(inactivePool, usr.Username)
}
s.RunForAllClients("Get some random user", func(c client.Client) {
printer.Clean()
var page int
var all bool
perpage := 5
team := ""
cmd := &cobra.Command{}
cmd.Flags().IntVar(&page, "page", page, "page")
cmd.Flags().IntVar(&perpage, "per-page", perpage, "perpage")
cmd.Flags().BoolVar(&all, "all", all, "all")
cmd.Flags().StringVar(&team, "team", team, "team")
cmd := ResetListUsersCmd()
cmd.Flags().Set("per-page", "5")
err := listUsersCmdF(c, cmd, []string{})
s.Require().Nil(err)
@@ -191,25 +199,103 @@ func (s *MmctlE2ETestSuite) TestListUserCmd() {
s.RunForAllClients("Get list of all user", func(c client.Client) {
printer.Clean()
var page int
perpage := 10
all := true
team := ""
cmd := &cobra.Command{}
cmd.Flags().IntVar(&page, "page", page, "page")
cmd.Flags().IntVar(&perpage, "per-page", perpage, "perpage")
cmd.Flags().BoolVar(&all, "all", all, "all")
cmd.Flags().StringVar(&team, "team", team, "team")
cmd := ResetListUsersCmd()
cmd.Flags().Set("per-page", "12")
cmd.Flags().Set("all", "true")
err := listUsersCmdF(c, cmd, []string{})
s.Require().Nil(err)
s.Require().GreaterOrEqual(len(printer.GetLines()), 14)
s.Require().GreaterOrEqual(len(printer.GetLines()), 16)
s.Len(printer.GetErrorLines(), 0)
for _, each := range printer.GetLines() {
user := each.(*model.User)
s.Require().Contains(userPool, user.Username)
}
})
s.RunForAllClients("Get list of inactive users", func(c client.Client) {
printer.Clean()
cmd := ResetListUsersCmd()
cmd.Flags().Set("per-page", "12")
cmd.Flags().Set("all", "true")
cmd.Flags().Set("inactive", "true")
err := listUsersCmdF(c, cmd, []string{})
s.Require().Nil(err)
s.Require().GreaterOrEqual(len(printer.GetLines()), 2)
s.Len(printer.GetErrorLines(), 0)
for _, each := range printer.GetLines() {
user := each.(*model.User)
s.Require().Contains(inactivePool, user.Username)
}
})
// create users with team
for i := 0; i < 10; i++ {
userData := model.User{
Username: "teamuser" + model.NewRandomString(10),
Password: "Pa$$word11",
Email: s.th.GenerateTestEmail(),
}
usr, err := s.th.App.CreateUser(s.th.Context, &userData)
s.Require().Nil(err)
userPool = append(userPool, usr.Username)
s.th.LinkUserToTeam(usr, s.th.BasicTeam)
}
s.RunForAllClients("Get list users given team", func(c client.Client) {
printer.Clean()
cmd := ResetListUsersCmd()
cmd.Flags().Set("per-page", "40")
cmd.Flags().Set("all", "true")
cmd.Flags().Set("team", s.th.BasicTeam.Name)
err := listUsersCmdF(c, cmd, []string{})
s.Require().Nil(err)
s.Require().GreaterOrEqual(len(printer.GetLines()), 10)
s.Len(printer.GetErrorLines(), 0)
for _, each := range printer.GetLines() {
user := each.(*model.User)
s.Require().Contains(userPool, user.Username)
}
})
// create inactive users with team
inactiveUserPool := []string{}
for i := 0; i < 10; i++ {
userData := model.User{
Username: "inactiveteamuser" + model.NewRandomString(10),
Password: "Pa$$word11",
Email: s.th.GenerateTestEmail(),
DeleteAt: model.GetMillis(),
}
usr, err := s.th.App.CreateUser(s.th.Context, &userData)
s.Require().Nil(err)
inactiveUserPool = append(inactiveUserPool, usr.Username)
s.th.LinkUserToTeam(usr, s.th.BasicTeam)
}
s.RunForAllClients("Get list of inactive users given team", func(c client.Client) {
printer.Clean()
cmd := ResetListUsersCmd()
cmd.Flags().Set("per-page", "40")
cmd.Flags().Set("all", "true")
cmd.Flags().Set("team", s.th.BasicTeam.Name)
cmd.Flags().Set("inactive", "true")
err := listUsersCmdF(c, cmd, []string{})
s.Require().Nil(err)
s.Require().GreaterOrEqual(len(printer.GetLines()), 10)
s.Len(printer.GetErrorLines(), 0)
for _, each := range printer.GetLines() {
user := each.(*model.User)
s.Require().Contains(inactiveUserPool, user.Username)
}
})
}
func (s *MmctlE2ETestSuite) TestUserInviteCmdf() {

Просмотреть файл

@@ -9,7 +9,6 @@ import (
"fmt"
"net/http"
"os"
"strconv"
"strings"
"github.com/mattermost/mattermost/server/public/model"
@@ -1866,28 +1865,18 @@ func (s *MmctlUnitTestSuite) TestResetUserMfaCmd() {
}
func (s *MmctlUnitTestSuite) TestListUserCmdF() {
cmd := &cobra.Command{}
cmd.Flags().Int("page", 0, "")
cmd.Flags().Int("per-page", 200, "")
cmd.Flags().Bool("all", false, "")
cmd.Flags().String("team", "", "")
s.Run("Listing users with paging", func() {
printer.Clean()
email := "example@example.com"
mockUser := model.User{Username: "ExampleUser", Email: email}
page := 0
perPage := 1
showAll := false
_ = cmd.Flags().Set("page", strconv.Itoa(page))
_ = cmd.Flags().Set("per-page", strconv.Itoa(perPage))
_ = cmd.Flags().Set("all", strconv.FormatBool(showAll))
cmd := ResetListUsersCmd()
cmd.Flags().Set("per-page", "1")
s.client.
EXPECT().
GetUsers(context.TODO(), page, perPage, "").
GetUsersWithCustomQueryParameters(context.TODO(), 0, 1, "", "").
Return([]*model.User{&mockUser}, &model.Response{}, nil).
Times(1)
@@ -1905,28 +1894,25 @@ func (s *MmctlUnitTestSuite) TestListUserCmdF() {
email2 := "example2@example.com"
mockUser2 := model.User{Username: "ExampleUser2", Email: email2}
page := 0
perPage := 1
showAll := true
_ = cmd.Flags().Set("page", strconv.Itoa(page))
_ = cmd.Flags().Set("per-page", strconv.Itoa(perPage))
_ = cmd.Flags().Set("all", strconv.FormatBool(showAll))
cmd := ResetListUsersCmd()
cmd.Flags().Set("per-page", "1")
cmd.Flags().Set("all", "true")
s.client.
EXPECT().
GetUsers(context.TODO(), 0, perPage, "").
GetUsersWithCustomQueryParameters(context.TODO(), 0, 1, "", "").
Return([]*model.User{&mockUser1}, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
GetUsers(context.TODO(), 1, perPage, "").
GetUsersWithCustomQueryParameters(context.TODO(), 1, 1, "", "").
Return([]*model.User{&mockUser2}, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
GetUsers(context.TODO(), 2, perPage, "").
GetUsersWithCustomQueryParameters(context.TODO(), 2, 1, "", "").
Return([]*model.User{}, &model.Response{}, nil).
Times(1)
@@ -1937,19 +1923,116 @@ func (s *MmctlUnitTestSuite) TestListUserCmdF() {
s.Require().Equal(&mockUser2, printer.GetLines()[1])
})
s.Run("Try to list all the users when there are no uses in store", func() {
s.Run("Listing all users including inactive", func() {
printer.Clean()
page := 0
perPage := 1
showAll := false
_ = cmd.Flags().Set("page", strconv.Itoa(page))
_ = cmd.Flags().Set("per-page", strconv.Itoa(perPage))
_ = cmd.Flags().Set("all", strconv.FormatBool(showAll))
email1 := "example1@example.com"
mockUser1 := model.User{Username: "ExampleUser1", Email: email1}
email2 := "example2@example.com"
mockUser2 := model.User{Username: "ExampleUser2", Email: email2, DeleteAt: model.GetMillis()}
cmd := ResetListUsersCmd()
cmd.Flags().Set("per-page", "1")
cmd.Flags().Set("all", "true")
s.client.
EXPECT().
GetUsers(context.TODO(), page, perPage, "").
GetUsersWithCustomQueryParameters(context.TODO(), 0, 1, "", "").
Return([]*model.User{&mockUser1}, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
GetUsersWithCustomQueryParameters(context.TODO(), 1, 1, "", "").
Return([]*model.User{&mockUser2}, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
GetUsersWithCustomQueryParameters(context.TODO(), 2, 1, "", "").
Return([]*model.User{}, &model.Response{}, nil).
Times(1)
err := listUsersCmdF(s.client, cmd, []string{})
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 2)
s.Require().Equal(&mockUser1, printer.GetLines()[0])
s.Require().Equal(&mockUser2, printer.GetLines()[1])
})
s.Run("Listing all inactive users", func() {
printer.Clean()
email2 := "example2@example.com"
mockUser2 := model.User{Username: "ExampleUser2", Email: email2, DeleteAt: model.GetMillis()}
email3 := "example3@example.com"
mockUser3 := model.User{Username: "ExampleUser3", Email: email3, DeleteAt: model.GetMillis()}
cmd := ResetListUsersCmd()
cmd.Flags().Set("per-page", "1")
cmd.Flags().Set("all", "true")
cmd.Flags().Set("inactive", "true")
s.client.
EXPECT().
GetUsersWithCustomQueryParameters(context.TODO(), 0, 1, "inactive=true", "").
Return([]*model.User{&mockUser2}, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
GetUsersWithCustomQueryParameters(context.TODO(), 1, 1, "inactive=true", "").
Return([]*model.User{&mockUser3}, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
GetUsersWithCustomQueryParameters(context.TODO(), 2, 1, "inactive=true", "").
Return([]*model.User{}, &model.Response{}, nil).
Times(1)
err := listUsersCmdF(s.client, cmd, []string{})
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 2)
s.Require().Equal(&mockUser2, printer.GetLines()[0])
s.Require().Equal(&mockUser3, printer.GetLines()[1])
})
s.Run("Listing inactive users with paging skipping 1 page", func() {
printer.Clean()
email := "del@example.com"
_ = model.User{Username: "ExampleUser", Email: email, DeleteAt: model.GetMillis()}
email1 := "del1@example.com"
mockUser1 := model.User{Username: "ExampleUser1", Email: email1, DeleteAt: model.GetMillis()}
cmd := ResetListUsersCmd()
cmd.Flags().Set("page", "1")
cmd.Flags().Set("per-page", "1")
cmd.Flags().Set("inactive", "true")
s.client.
EXPECT().
GetUsersWithCustomQueryParameters(context.TODO(), 1, 1, "inactive=true", "").
Return([]*model.User{&mockUser1}, &model.Response{}, nil).
Times(1)
err := listUsersCmdF(s.client, cmd, []string{})
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Equal(&mockUser1, printer.GetLines()[0])
})
s.Run("Try to list all the users when there are no uses in store", func() {
printer.Clean()
cmd := ResetListUsersCmd()
cmd.Flags().Set("page", "0")
cmd.Flags().Set("per-page", "1")
s.client.
EXPECT().
GetUsersWithCustomQueryParameters(context.TODO(), 0, 1, "", "").
Return([]*model.User{}, &model.Response{}, nil).
Times(1)
@@ -1958,22 +2041,19 @@ func (s *MmctlUnitTestSuite) TestListUserCmdF() {
s.Require().Len(printer.GetLines(), 0)
})
s.Run("Return an error from GetUsers call and verify that error is properly returned", func() {
s.Run("Return an error from GetUsersWithCustomQueryParameters call and verify that error is properly returned", func() {
printer.Clean()
page := 0
perPage := 1
showAll := false
_ = cmd.Flags().Set("page", strconv.Itoa(page))
_ = cmd.Flags().Set("per-page", strconv.Itoa(perPage))
_ = cmd.Flags().Set("all", strconv.FormatBool(showAll))
cmd := ResetListUsersCmd()
cmd.Flags().Set("page", "0")
cmd.Flags().Set("per-page", "1")
mockError := errors.New("mock error")
mockErrorW := errors.Wrap(mockError, "Failed to fetch users")
s.client.
EXPECT().
GetUsers(context.TODO(), page, perPage, "").
GetUsersWithCustomQueryParameters(context.TODO(), 0, 1, "", "").
Return(nil, &model.Response{}, mockError).
Times(1)
@@ -1988,16 +2068,13 @@ func (s *MmctlUnitTestSuite) TestListUserCmdF() {
email := "example@example.com"
mockUser := model.User{Username: "ExampleUser", Email: email}
page := 2
perPage := 1
showAll := false
_ = cmd.Flags().Set("page", strconv.Itoa(page))
_ = cmd.Flags().Set("per-page", strconv.Itoa(perPage))
_ = cmd.Flags().Set("all", strconv.FormatBool(showAll))
cmd := ResetListUsersCmd()
cmd.Flags().Set("page", "2")
cmd.Flags().Set("per-page", "1")
s.client.
EXPECT().
GetUsers(context.TODO(), page, perPage, "").
GetUsersWithCustomQueryParameters(context.TODO(), 2, 1, "", "").
Return([]*model.User{&mockUser}, &model.Response{}, nil).
Times(1)
@@ -2012,16 +2089,14 @@ func (s *MmctlUnitTestSuite) TestListUserCmdF() {
email := "example@example.com"
mockUser := model.User{Username: "ExampleUser", Email: email}
resultID := "teamId"
page := 0
perPage := 1
showAll := false
resultID := "teamId"
team := "teamName"
_ = cmd.Flags().Set("page", strconv.Itoa(page))
_ = cmd.Flags().Set("per-page", strconv.Itoa(perPage))
_ = cmd.Flags().Set("all", strconv.FormatBool(showAll))
_ = cmd.Flags().Set("team", team)
cmd := ResetListUsersCmd()
cmd.Flags().Set("page", "0")
cmd.Flags().Set("per-page", "1")
cmd.Flags().Set("team", team)
s.client.
EXPECT().
@@ -2031,7 +2106,7 @@ func (s *MmctlUnitTestSuite) TestListUserCmdF() {
s.client.
EXPECT().
GetUsersInTeam(context.TODO(), resultID, page, perPage, "").
GetUsersWithCustomQueryParameters(context.TODO(), 0, 1, "in_team="+resultID, "").
Return([]*model.User{&mockUser}, &model.Response{}, nil).
Times(1)
@@ -2040,6 +2115,90 @@ func (s *MmctlUnitTestSuite) TestListUserCmdF() {
s.Require().Len(printer.GetLines(), 1)
s.Require().Equal(&mockUser, printer.GetLines()[0])
})
s.Run("Listing inactive users for given team", func() {
printer.Clean()
email := "example@example.com"
_ = model.User{Username: "ExampleUser", Email: email}
email1 := "example1@example.com"
mockUser1 := model.User{Username: "ExampleUser1", Email: email1, DeleteAt: model.GetMillis()}
resultID := "teamId"
team := "teamName"
cmd := ResetListUsersCmd()
cmd.Flags().Set("page", "0")
cmd.Flags().Set("per-page", "1")
cmd.Flags().Set("team", team)
s.client.
EXPECT().
GetTeamByName(context.TODO(), team, "").
Return(&model.Team{Id: resultID}, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
GetUsersWithCustomQueryParameters(context.TODO(), 0, 1, "in_team="+resultID, "").
Return([]*model.User{&mockUser1}, &model.Response{}, nil).
Times(1)
err := listUsersCmdF(s.client, cmd, []string{})
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Equal(&mockUser1, printer.GetLines()[0])
})
s.Run("Listing all inactive users for given team", func() {
printer.Clean()
email := "example@example.com"
_ = model.User{Username: "ExampleUser", Email: email}
email1 := "example1@example.com"
mockUser1 := model.User{Username: "ExampleUser1", Email: email1, DeleteAt: model.GetMillis()}
email2 := "example2@example.com"
mockUser2 := model.User{Username: "ExampleUser2", Email: email2, DeleteAt: model.GetMillis()}
resultID := "teamId"
team := "teamName"
cmd := ResetListUsersCmd()
cmd.Flags().Set("page", "0")
cmd.Flags().Set("per-page", "1")
cmd.Flags().Set("team", team)
cmd.Flags().Set("all", "true")
s.client.
EXPECT().
GetTeamByName(context.TODO(), team, "").
Return(&model.Team{Id: resultID}, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
GetUsersWithCustomQueryParameters(context.TODO(), 0, 1, "in_team="+resultID, "").
Return([]*model.User{&mockUser1}, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
GetUsersWithCustomQueryParameters(context.TODO(), 1, 1, "in_team="+resultID, "").
Return([]*model.User{&mockUser2}, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
GetUsersWithCustomQueryParameters(context.TODO(), 2, 1, "in_team="+resultID, "").
Return([]*model.User{}, &model.Response{}, nil).
Times(1)
err := listUsersCmdF(s.client, cmd, []string{})
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 2)
s.Require().Equal(&mockUser1, printer.GetLines()[0])
s.Require().Equal(&mockUser2, printer.GetLines()[1])
})
}
func (s *MmctlUnitTestSuite) TestUserDeactivateCmd() {

Просмотреть файл

@@ -29,6 +29,7 @@ Options
--all Fetch all users. --page flag will be ignore if provided
-h, --help help for list
--inactive If supplied, only users which are inactive will be fetch
--page int Page number to fetch for the list of users
--per-page int Number of users to be fetched (default 200)
--team string If supplied, only users belonging to this team will be listed

Просмотреть файл

@@ -1094,7 +1094,7 @@ func (c *Client4) GetUsers(ctx context.Context, page int, perPage int, etag stri
return list, BuildResponse(r), nil
}
// GetUsersWithChannelRoles returns a page of users on the system. Page counting starts at 0.
// GetUsersWithCustomQueryParameters returns a page of users on the system. Page counting starts at 0.
func (c *Client4) GetUsersWithCustomQueryParameters(ctx context.Context, page int, perPage int, queryParameters, etag string) ([]*User, *Response, error) {
query := fmt.Sprintf("?page=%v&per_page=%v&%v", page, perPage, queryParameters)
r, err := c.DoAPIGet(ctx, c.usersRoute()+query, etag)
@@ -1107,7 +1107,7 @@ func (c *Client4) GetUsersWithCustomQueryParameters(ctx context.Context, page in
return list, BuildResponse(r), nil
}
if err := json.NewDecoder(r.Body).Decode(&list); err != nil {
return nil, nil, NewAppError("GetUsers", "api.unmarshal_error", nil, "", http.StatusInternalServerError).Wrap(err)
return nil, nil, NewAppError("GetUsersWithCustomQueryParameters", "api.unmarshal_error", nil, "", http.StatusInternalServerError).Wrap(err)
}
return list, BuildResponse(r), nil
}