From 324eeed1c5301efdf112932e05def6e29411b700 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Thu, 14 Mar 2024 15:53:26 +0530 Subject: [PATCH] [cli] Add admin list-user cmd --- cli/cmd/admin.go | 21 +++++++++++++++++++-- cli/internal/api/admin.go | 22 ++++++++++++++++++++++ cli/internal/api/models/user_details.go | 11 ++++++++--- cli/pkg/admin_actions.go | 20 ++++++++++++++++++++ 4 files changed, 69 insertions(+), 5 deletions(-) diff --git a/cli/cmd/admin.go b/cli/cmd/admin.go index 0e41bbfe2..d46fcfbf7 100644 --- a/cli/cmd/admin.go +++ b/cli/cmd/admin.go @@ -52,9 +52,25 @@ var _disable2faCmd = &cobra.Command{ }, } +var _listUsers = &cobra.Command{ + Use: "list-users", + Short: "List all users", + RunE: func(cmd *cobra.Command, args []string) error { + recoverWithLog() + var flags = &model.AdminActionForUser{} + cmd.Flags().VisitAll(func(f *pflag.Flag) { + if f.Name == "admin-user" { + flags.AdminEmail = f.Value.String() + } + }) + return ctrl.ListUsers(context.Background(), *flags) + }, +} + var _updateFreeUserStorage = &cobra.Command{ Use: "update-subscription", - Short: "Update subscription for the free user", + Short: "Update subscription for user", + Long: "Update subscription for the free user. If you want to apply specific limits, use the `--no-limit False` flag", RunE: func(cmd *cobra.Command, args []string) error { recoverWithLog() var flags = &model.AdminActionForUser{} @@ -80,11 +96,12 @@ func init() { _ = _userDetailsCmd.MarkFlagRequired("user") _userDetailsCmd.Flags().StringP("admin-user", "a", "", "The email of the admin user. (required)") _userDetailsCmd.Flags().StringP("user", "u", "", "The email of the user to fetch details for. (required)") + _listUsers.Flags().StringP("admin-user", "a", "", "The email of the admin user. (required)") _disable2faCmd.Flags().StringP("admin-user", "a", "", "The email of the admin user. (required)") _disable2faCmd.Flags().StringP("user", "u", "", "The email of the user to disable 2FA for. (required)") _updateFreeUserStorage.Flags().StringP("admin-user", "a", "", "The email of the admin user. (required)") _updateFreeUserStorage.Flags().StringP("user", "u", "", "The email of the user to update subscription for. (required)") // add a flag with no value --no-limit _updateFreeUserStorage.Flags().String("no-limit", "True", "When true, sets 100TB as storage limit, and expiry to current date + 100 years") - _adminCmd.AddCommand(_userDetailsCmd, _disable2faCmd, _updateFreeUserStorage) + _adminCmd.AddCommand(_userDetailsCmd, _disable2faCmd, _updateFreeUserStorage, _listUsers) } diff --git a/cli/internal/api/admin.go b/cli/internal/api/admin.go index 1c0b2c50a..0f21e2d82 100644 --- a/cli/internal/api/admin.go +++ b/cli/internal/api/admin.go @@ -25,6 +25,28 @@ func (c *Client) GetUserIdFromEmail(ctx context.Context, email string) (*models. } return &res, nil } + +func (c *Client) ListUsers(ctx context.Context) ([]models.User, error) { + var res struct { + Users []models.User `json:"users"` + } + r, err := c.restClient.R(). + SetContext(ctx). + SetQueryParam("sinceTime", "0"). + SetResult(&res). + Get("/admin/users/") + if err != nil { + return nil, err + } + if r.IsError() { + return nil, &ApiError{ + StatusCode: r.StatusCode(), + Message: r.String(), + } + } + return res.Users, nil +} + func (c *Client) UpdateFreePlanSub(ctx context.Context, userDetails *models.UserDetails, storageInBytes int64, expiryTimeInMicro int64) error { var res interface{} if userDetails.Subscription.ProductID != "free" { diff --git a/cli/internal/api/models/user_details.go b/cli/internal/api/models/user_details.go index 259ff972b..6a5310d7d 100644 --- a/cli/internal/api/models/user_details.go +++ b/cli/internal/api/models/user_details.go @@ -1,9 +1,7 @@ package models type UserDetails struct { - User struct { - ID int64 `json:"id"` - } `json:"user"` + User User `json:"user"` Usage int64 `json:"usage"` Email string `json:"email"` @@ -14,3 +12,10 @@ type UserDetails struct { PaymentProvider string `json:"paymentProvider"` } `json:"subscription"` } + +type User struct { + ID int64 + Email string `json:"email"` + Hash string `json:"hash"` + CreationTime int64 `json:"creationTime"` +} diff --git a/cli/pkg/admin_actions.go b/cli/pkg/admin_actions.go index c9ec00667..a5d182973 100644 --- a/cli/pkg/admin_actions.go +++ b/cli/pkg/admin_actions.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "github.com/ente-io/cli/internal" + "github.com/ente-io/cli/internal/api" "github.com/ente-io/cli/pkg/model" "github.com/ente-io/cli/utils" "log" @@ -24,6 +25,25 @@ func (c *ClICtrl) GetUserId(ctx context.Context, params model.AdminActionForUser return nil } +func (c *ClICtrl) ListUsers(ctx context.Context, params model.AdminActionForUser) error { + accountCtx, err := c.buildAdminContext(ctx, params.AdminEmail) + if err != nil { + return err + } + users, err := c.Client.ListUsers(accountCtx) + if err != nil { + if apiErr, ok := err.(*api.ApiError); ok && apiErr.StatusCode == 400 && strings.Contains(apiErr.Message, "Token is too old") { + fmt.Printf("Old admin token, please re-authenticate using `ente account add` \n") + return nil + } + return err + } + for _, user := range users { + fmt.Printf("Email: %s, ID: %d, Created: %s\n", user.Email, user.ID, time.UnixMicro(user.CreationTime).Format("2006-01-02")) + } + return nil +} + func (c *ClICtrl) UpdateFreeStorage(ctx context.Context, params model.AdminActionForUser, noLimit bool) error { accountCtx, err := c.buildAdminContext(ctx, params.AdminEmail) if err != nil {