[cli] Admin APIs for list-users, disable-2fa, & delete-user (#1104)
## Description Also made it optional to pass the admin-user when there's only one account is configured. ## Tests Tested locally
This commit is contained in:
commit
ffae4ae99b
21 changed files with 264 additions and 29 deletions
1
cli/.gitattributes
vendored
Normal file
1
cli/.gitattributes
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
docs/generated/*.md linguist-generated=true
|
|
@ -29,6 +29,9 @@ var _userDetailsCmd = &cobra.Command{
|
|||
flags.UserEmail = f.Value.String()
|
||||
}
|
||||
})
|
||||
if flags.UserEmail == "" {
|
||||
return fmt.Errorf("user email is required")
|
||||
}
|
||||
return ctrl.GetUserId(context.Background(), *flags)
|
||||
},
|
||||
}
|
||||
|
@ -47,14 +50,55 @@ var _disable2faCmd = &cobra.Command{
|
|||
flags.UserEmail = f.Value.String()
|
||||
}
|
||||
})
|
||||
fmt.Println("Not supported yet")
|
||||
return nil
|
||||
if flags.UserEmail == "" {
|
||||
return fmt.Errorf("user email is required")
|
||||
}
|
||||
return ctrl.Disable2FA(context.Background(), *flags)
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
var _deleteUser = &cobra.Command{
|
||||
Use: "delete-user",
|
||||
Short: "Delete a user",
|
||||
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()
|
||||
}
|
||||
if f.Name == "user" {
|
||||
flags.UserEmail = f.Value.String()
|
||||
}
|
||||
})
|
||||
if flags.UserEmail == "" {
|
||||
return fmt.Errorf("user email is required")
|
||||
}
|
||||
return ctrl.DeleteUser(context.Background(), *flags)
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
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{}
|
||||
|
@ -70,6 +114,9 @@ var _updateFreeUserStorage = &cobra.Command{
|
|||
noLimit = strings.ToLower(f.Value.String()) == "true"
|
||||
}
|
||||
})
|
||||
if flags.UserEmail == "" {
|
||||
return fmt.Errorf("user email is required")
|
||||
}
|
||||
return ctrl.UpdateFreeStorage(context.Background(), *flags, noLimit)
|
||||
},
|
||||
}
|
||||
|
@ -78,13 +125,16 @@ func init() {
|
|||
rootCmd.AddCommand(_adminCmd)
|
||||
_ = _userDetailsCmd.MarkFlagRequired("admin-user")
|
||||
_ = _userDetailsCmd.MarkFlagRequired("user")
|
||||
_userDetailsCmd.Flags().StringP("admin-user", "a", "", "The email of the admin user. (required)")
|
||||
_userDetailsCmd.Flags().StringP("admin-user", "a", "", "The email of the admin user. ")
|
||||
_userDetailsCmd.Flags().StringP("user", "u", "", "The email of the user to fetch details for. (required)")
|
||||
_disable2faCmd.Flags().StringP("admin-user", "a", "", "The email of the admin user. (required)")
|
||||
_listUsers.Flags().StringP("admin-user", "a", "", "The email of the admin user. ")
|
||||
_disable2faCmd.Flags().StringP("admin-user", "a", "", "The email of the admin user. ")
|
||||
_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)")
|
||||
_deleteUser.Flags().StringP("admin-user", "a", "", "The email of the admin user. ")
|
||||
_deleteUser.Flags().StringP("user", "u", "", "The email of the user to delete. (required)")
|
||||
_updateFreeUserStorage.Flags().StringP("admin-user", "a", "", "The email of the admin user.")
|
||||
_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, _deleteUser)
|
||||
}
|
||||
|
|
2
cli/docs/generated/ente.md
generated
2
cli/docs/generated/ente.md
generated
|
@ -25,4 +25,4 @@ ente [flags]
|
|||
* [ente export](ente_export.md) - Starts the export process
|
||||
* [ente version](ente_version.md) - Prints the current version
|
||||
|
||||
###### Auto generated by spf13/cobra on 13-Mar-2024
|
||||
###### Auto generated by spf13/cobra on 14-Mar-2024
|
||||
|
|
2
cli/docs/generated/ente_account.md
generated
2
cli/docs/generated/ente_account.md
generated
|
@ -16,4 +16,4 @@ Manage account settings
|
|||
* [ente account list](ente_account_list.md) - list configured accounts
|
||||
* [ente account update](ente_account_update.md) - Update an existing account's export directory
|
||||
|
||||
###### Auto generated by spf13/cobra on 13-Mar-2024
|
||||
###### Auto generated by spf13/cobra on 14-Mar-2024
|
||||
|
|
2
cli/docs/generated/ente_account_add.md
generated
2
cli/docs/generated/ente_account_add.md
generated
|
@ -16,4 +16,4 @@ ente account add [flags]
|
|||
|
||||
* [ente account](ente_account.md) - Manage account settings
|
||||
|
||||
###### Auto generated by spf13/cobra on 13-Mar-2024
|
||||
###### Auto generated by spf13/cobra on 14-Mar-2024
|
||||
|
|
2
cli/docs/generated/ente_account_get-token.md
generated
2
cli/docs/generated/ente_account_get-token.md
generated
|
@ -18,4 +18,4 @@ ente account get-token [flags]
|
|||
|
||||
* [ente account](ente_account.md) - Manage account settings
|
||||
|
||||
###### Auto generated by spf13/cobra on 13-Mar-2024
|
||||
###### Auto generated by spf13/cobra on 14-Mar-2024
|
||||
|
|
2
cli/docs/generated/ente_account_list.md
generated
2
cli/docs/generated/ente_account_list.md
generated
|
@ -16,4 +16,4 @@ ente account list [flags]
|
|||
|
||||
* [ente account](ente_account.md) - Manage account settings
|
||||
|
||||
###### Auto generated by spf13/cobra on 13-Mar-2024
|
||||
###### Auto generated by spf13/cobra on 14-Mar-2024
|
||||
|
|
2
cli/docs/generated/ente_account_update.md
generated
2
cli/docs/generated/ente_account_update.md
generated
|
@ -19,4 +19,4 @@ ente account update [flags]
|
|||
|
||||
* [ente account](ente_account.md) - Manage account settings
|
||||
|
||||
###### Auto generated by spf13/cobra on 13-Mar-2024
|
||||
###### Auto generated by spf13/cobra on 14-Mar-2024
|
||||
|
|
6
cli/docs/generated/ente_admin.md
generated
6
cli/docs/generated/ente_admin.md
generated
|
@ -15,8 +15,10 @@ Commands for admin actions like disable or enabling 2fa, bumping up the storage
|
|||
### SEE ALSO
|
||||
|
||||
* [ente](ente.md) - CLI tool for exporting your photos from ente.io
|
||||
* [ente admin delete-user](ente_admin_delete-user.md) - Delete a user
|
||||
* [ente admin disable-2fa](ente_admin_disable-2fa.md) - Disable 2fa for a user
|
||||
* [ente admin get-user-id](ente_admin_get-user-id.md) - Get user id
|
||||
* [ente admin update-subscription](ente_admin_update-subscription.md) - Update subscription for the free user
|
||||
* [ente admin list-users](ente_admin_list-users.md) - List all users
|
||||
* [ente admin update-subscription](ente_admin_update-subscription.md) - Update subscription for user
|
||||
|
||||
###### Auto generated by spf13/cobra on 13-Mar-2024
|
||||
###### Auto generated by spf13/cobra on 14-Mar-2024
|
||||
|
|
21
cli/docs/generated/ente_admin_delete-user.md
generated
Normal file
21
cli/docs/generated/ente_admin_delete-user.md
generated
Normal file
|
@ -0,0 +1,21 @@
|
|||
## ente admin delete-user
|
||||
|
||||
Delete a user
|
||||
|
||||
```
|
||||
ente admin delete-user [flags]
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
-a, --admin-user string The email of the admin user.
|
||||
-h, --help help for delete-user
|
||||
-u, --user string The email of the user to delete. (required)
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [ente admin](ente_admin.md) - Commands for admin actions
|
||||
|
||||
###### Auto generated by spf13/cobra on 14-Mar-2024
|
4
cli/docs/generated/ente_admin_disable-2fa.md
generated
4
cli/docs/generated/ente_admin_disable-2fa.md
generated
|
@ -9,7 +9,7 @@ ente admin disable-2fa [flags]
|
|||
### Options
|
||||
|
||||
```
|
||||
-a, --admin-user string The email of the admin user. (required)
|
||||
-a, --admin-user string The email of the admin user.
|
||||
-h, --help help for disable-2fa
|
||||
-u, --user string The email of the user to disable 2FA for. (required)
|
||||
```
|
||||
|
@ -18,4 +18,4 @@ ente admin disable-2fa [flags]
|
|||
|
||||
* [ente admin](ente_admin.md) - Commands for admin actions
|
||||
|
||||
###### Auto generated by spf13/cobra on 13-Mar-2024
|
||||
###### Auto generated by spf13/cobra on 14-Mar-2024
|
||||
|
|
4
cli/docs/generated/ente_admin_get-user-id.md
generated
4
cli/docs/generated/ente_admin_get-user-id.md
generated
|
@ -9,7 +9,7 @@ ente admin get-user-id [flags]
|
|||
### Options
|
||||
|
||||
```
|
||||
-a, --admin-user string The email of the admin user. (required)
|
||||
-a, --admin-user string The email of the admin user.
|
||||
-h, --help help for get-user-id
|
||||
-u, --user string The email of the user to fetch details for. (required)
|
||||
```
|
||||
|
@ -18,4 +18,4 @@ ente admin get-user-id [flags]
|
|||
|
||||
* [ente admin](ente_admin.md) - Commands for admin actions
|
||||
|
||||
###### Auto generated by spf13/cobra on 13-Mar-2024
|
||||
###### Auto generated by spf13/cobra on 14-Mar-2024
|
||||
|
|
20
cli/docs/generated/ente_admin_list-users.md
generated
Normal file
20
cli/docs/generated/ente_admin_list-users.md
generated
Normal file
|
@ -0,0 +1,20 @@
|
|||
## ente admin list-users
|
||||
|
||||
List all users
|
||||
|
||||
```
|
||||
ente admin list-users [flags]
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
-a, --admin-user string The email of the admin user.
|
||||
-h, --help help for list-users
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [ente admin](ente_admin.md) - Commands for admin actions
|
||||
|
||||
###### Auto generated by spf13/cobra on 14-Mar-2024
|
10
cli/docs/generated/ente_admin_update-subscription.md
generated
10
cli/docs/generated/ente_admin_update-subscription.md
generated
|
@ -1,6 +1,10 @@
|
|||
## ente admin update-subscription
|
||||
|
||||
Update subscription for the free user
|
||||
Update subscription for user
|
||||
|
||||
### Synopsis
|
||||
|
||||
Update subscription for the free user. If you want to apply specific limits, use the `--no-limit False` flag
|
||||
|
||||
```
|
||||
ente admin update-subscription [flags]
|
||||
|
@ -9,7 +13,7 @@ ente admin update-subscription [flags]
|
|||
### Options
|
||||
|
||||
```
|
||||
-a, --admin-user string The email of the admin user. (required)
|
||||
-a, --admin-user string The email of the admin user.
|
||||
-h, --help help for update-subscription
|
||||
--no-limit string When true, sets 100TB as storage limit, and expiry to current date + 100 years (default "True")
|
||||
-u, --user string The email of the user to update subscription for. (required)
|
||||
|
@ -19,4 +23,4 @@ ente admin update-subscription [flags]
|
|||
|
||||
* [ente admin](ente_admin.md) - Commands for admin actions
|
||||
|
||||
###### Auto generated by spf13/cobra on 13-Mar-2024
|
||||
###### Auto generated by spf13/cobra on 14-Mar-2024
|
||||
|
|
2
cli/docs/generated/ente_auth.md
generated
2
cli/docs/generated/ente_auth.md
generated
|
@ -13,4 +13,4 @@ Authenticator commands
|
|||
* [ente](ente.md) - CLI tool for exporting your photos from ente.io
|
||||
* [ente auth decrypt](ente_auth_decrypt.md) - Decrypt authenticator export
|
||||
|
||||
###### Auto generated by spf13/cobra on 13-Mar-2024
|
||||
###### Auto generated by spf13/cobra on 14-Mar-2024
|
||||
|
|
2
cli/docs/generated/ente_auth_decrypt.md
generated
2
cli/docs/generated/ente_auth_decrypt.md
generated
|
@ -16,4 +16,4 @@ ente auth decrypt [input] [output] [flags]
|
|||
|
||||
* [ente auth](ente_auth.md) - Authenticator commands
|
||||
|
||||
###### Auto generated by spf13/cobra on 13-Mar-2024
|
||||
###### Auto generated by spf13/cobra on 14-Mar-2024
|
||||
|
|
2
cli/docs/generated/ente_export.md
generated
2
cli/docs/generated/ente_export.md
generated
|
@ -16,4 +16,4 @@ ente export [flags]
|
|||
|
||||
* [ente](ente.md) - CLI tool for exporting your photos from ente.io
|
||||
|
||||
###### Auto generated by spf13/cobra on 13-Mar-2024
|
||||
###### Auto generated by spf13/cobra on 14-Mar-2024
|
||||
|
|
2
cli/docs/generated/ente_version.md
generated
2
cli/docs/generated/ente_version.md
generated
|
@ -16,4 +16,4 @@ ente version [flags]
|
|||
|
||||
* [ente](ente.md) - CLI tool for exporting your photos from ente.io
|
||||
|
||||
###### Auto generated by spf13/cobra on 13-Mar-2024
|
||||
###### Auto generated by spf13/cobra on 14-Mar-2024
|
||||
|
|
|
@ -25,6 +25,69 @@ 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) DeleteUser(ctx context.Context, email string) error {
|
||||
|
||||
r, err := c.restClient.R().
|
||||
SetContext(ctx).
|
||||
SetQueryParam("email", email).
|
||||
Delete("/admin/user/delete")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if r.IsError() {
|
||||
return &ApiError{
|
||||
StatusCode: r.StatusCode(),
|
||||
Message: r.String(),
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) Disable2Fa(ctx context.Context, userID int64) error {
|
||||
var res interface{}
|
||||
|
||||
payload := map[string]interface{}{
|
||||
"userID": userID,
|
||||
}
|
||||
r, err := c.restClient.R().
|
||||
SetContext(ctx).
|
||||
SetResult(&res).
|
||||
SetBody(payload).
|
||||
Post("/admin/user/disable-2fa")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if r.IsError() {
|
||||
return &ApiError{
|
||||
StatusCode: r.StatusCode(),
|
||||
Message: r.String(),
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) UpdateFreePlanSub(ctx context.Context, userDetails *models.UserDetails, storageInBytes int64, expiryTimeInMicro int64) error {
|
||||
var res interface{}
|
||||
if userDetails.Subscription.ProductID != "free" {
|
||||
|
|
|
@ -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"`
|
||||
}
|
||||
|
|
|
@ -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,63 @@ 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("Error: 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) DeleteUser(ctx context.Context, params model.AdminActionForUser) error {
|
||||
accountCtx, err := c.buildAdminContext(ctx, params.AdminEmail)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = c.Client.DeleteUser(accountCtx, params.UserEmail)
|
||||
if err != nil {
|
||||
if apiErr, ok := err.(*api.ApiError); ok && apiErr.StatusCode == 400 && strings.Contains(apiErr.Message, "Token is too old") {
|
||||
fmt.Printf("Error: old admin token, please re-authenticate using `ente account add` \n")
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
fmt.Println("Successfully deleted user")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ClICtrl) Disable2FA(ctx context.Context, params model.AdminActionForUser) error {
|
||||
accountCtx, err := c.buildAdminContext(ctx, params.AdminEmail)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
userDetails, err := c.Client.GetUserIdFromEmail(accountCtx, params.UserEmail)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = c.Client.Disable2Fa(accountCtx, userDetails.User.ID)
|
||||
if err != nil {
|
||||
if apiErr, ok := err.(*api.ApiError); ok && apiErr.StatusCode == 400 && strings.Contains(apiErr.Message, "Token is too old") {
|
||||
fmt.Printf("Error: Old admin token, please re-authenticate using `ente account add` \n")
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
fmt.Println("Successfully disabled 2FA for user")
|
||||
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 {
|
||||
|
@ -82,6 +140,9 @@ func (c *ClICtrl) buildAdminContext(ctx context.Context, adminEmail string) (con
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(accounts) == 0 {
|
||||
return nil, fmt.Errorf("no accounts found, use `account add` to add an account")
|
||||
}
|
||||
var acc *model.Account
|
||||
for _, a := range accounts {
|
||||
if a.Email == adminEmail {
|
||||
|
@ -89,6 +150,14 @@ func (c *ClICtrl) buildAdminContext(ctx context.Context, adminEmail string) (con
|
|||
break
|
||||
}
|
||||
}
|
||||
if (len(accounts) > 1) && (acc == nil) {
|
||||
return nil, fmt.Errorf("multiple accounts found, specify the admin email using --admin-user")
|
||||
}
|
||||
if acc == nil && len(accounts) == 1 {
|
||||
acc = &accounts[0]
|
||||
fmt.Printf("Assuming %s as the Admin \n------------\n", acc.Email)
|
||||
}
|
||||
|
||||
if acc == nil {
|
||||
return nil, fmt.Errorf("account not found for %s, use `account list` to list accounts", adminEmail)
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue