diff options
| -rw-r--r-- | cmd/admin.go | 89 | ||||
| -rw-r--r-- | internal/client/admin.go | 23 | ||||
| -rw-r--r-- | internal/formatter/admin.go | 47 | ||||
| -rw-r--r-- | internal/models/admin.go | 7 |
4 files changed, 164 insertions, 2 deletions
diff --git a/cmd/admin.go b/cmd/admin.go index 5ef98ca..d4ab1e9 100644 --- a/cmd/admin.go +++ b/cmd/admin.go @@ -63,6 +63,13 @@ var adminStatsCmd = &cobra.Command{ RunE: runAdminStats, } +var adminEditCmd = &cobra.Command{ + Use: "edit [api_key]", + Short: "Edit account properties", + Args: cobra.ExactArgs(1), + RunE: runAdminEdit, +} + func init() { rootCmd.AddCommand(adminCmd) adminCmd.AddCommand(adminListCmd) @@ -72,11 +79,21 @@ func init() { adminCmd.AddCommand(adminSetCreditsCmd) adminCmd.AddCommand(adminDisableCmd) adminCmd.AddCommand(adminStatsCmd) + adminCmd.AddCommand(adminEditCmd) adminCreateCmd.Flags().IntP("credits", "c", 0, "Initial credits") adminCreateCmd.Flags().BoolP("unlimited", "u", false, "Unlimited credits") adminCreateCmd.Flags().BoolP("premium", "p", false, "Premium account (enables skiptrace access)") adminDisableCmd.Flags().BoolP("enable", "e", false, "Enable account instead of disable") + + adminEditCmd.Flags().StringP("name", "n", "", "Update account name") + adminEditCmd.Flags().IntP("credits", "c", -1, "Set credits amount") + adminEditCmd.Flags().BoolP("unlimited", "u", false, "Set unlimited credits") + adminEditCmd.Flags().BoolP("no-unlimited", "", false, "Remove unlimited credits") + adminEditCmd.Flags().BoolP("premium", "p", false, "Set premium account") + adminEditCmd.Flags().BoolP("no-premium", "", false, "Remove premium account") + adminEditCmd.Flags().BoolP("disable", "d", false, "Disable account") + adminEditCmd.Flags().BoolP("enable", "e", false, "Enable account") } func getAdminClient(cmd *cobra.Command) (*client.Client, error) { @@ -272,3 +289,75 @@ func runAdminStats(cmd *cobra.Command, args []string) error { printOutput(output) return nil } + +func runAdminEdit(cmd *cobra.Command, args []string) error { + c, err := getAdminClient(cmd) + if err != nil { + return err + } + + req := &models.AccountUpdateRequest{} + + name, _ := cmd.Flags().GetString("name") + if name != "" { + req.Name = &name + } + + credits, _ := cmd.Flags().GetInt("credits") + if credits >= 0 { + req.Credits = &credits + } + + unlimited, _ := cmd.Flags().GetBool("unlimited") + if unlimited { + req.Unlimited = &unlimited + } + + noUnlimited, _ := cmd.Flags().GetBool("no-unlimited") + if noUnlimited { + req.Unlimited = &noUnlimited + } + + premium, _ := cmd.Flags().GetBool("premium") + if premium { + req.IsPremium = &premium + } + + noPremium, _ := cmd.Flags().GetBool("no-premium") + if noPremium { + req.IsPremium = &noPremium + } + + disable, _ := cmd.Flags().GetBool("disable") + if disable { + req.Disabled = &disable + } + + enable, _ := cmd.Flags().GetBool("enable") + if enable { + falseVal := false + req.Disabled = &falseVal + } + + if req.Name == nil && req.Credits == nil && req.Unlimited == nil && + req.IsPremium == nil && req.Disabled == nil { + return fmt.Errorf("no changes specified — use --name, --credits, --unlimited, --no-unlimited, --premium, --no-premium, --disable, or --enable") + } + + response, err := c.UpdateAccount(args[0], req) + if err != nil { + return err + } + + if err := checkError(response.Error); err != nil { + return err + } + + output, err := formatter.FormatAccountUpdated(response.Account, response.Message, IsJSONOutput()) + if err != nil { + return err + } + + printOutput(output) + return nil +} diff --git a/internal/client/admin.go b/internal/client/admin.go index bf8c5ce..c776b7c 100644 --- a/internal/client/admin.go +++ b/internal/client/admin.go @@ -123,6 +123,29 @@ func (c *Client) ToggleAccount(apiKey string, enable bool) (*models.AdminRespons return &response, nil } +func (c *Client) UpdateAccount(apiKey string, req *models.AccountUpdateRequest) (*models.AdminResponse, error) { + path := fmt.Sprintf("/admin/accounts/%s", url.PathEscape(apiKey)) + data, err := c.Patch(path, req) + if err != nil { + return nil, err + } + + var account models.Account + if err := json.Unmarshal(data, &account); err == nil && account.APIKey != "" { + return &models.AdminResponse{ + Success: true, + Account: &account, + }, nil + } + + var response models.AdminResponse + if err := json.Unmarshal(data, &response); err != nil { + return nil, fmt.Errorf("failed to parse admin response: %w", err) + } + + return &response, nil +} + func (c *Client) GetAccountStats() (*models.AccountStatsResponse, error) { data, err := c.Get("/me", nil) if err != nil { diff --git a/internal/formatter/admin.go b/internal/formatter/admin.go index 12ffcd0..16b8041 100644 --- a/internal/formatter/admin.go +++ b/internal/formatter/admin.go @@ -122,6 +122,53 @@ func FormatAccountCreated(account *models.Account, message string, asJSON bool) return sb.String(), nil } +func FormatAccountUpdated(account *models.Account, message string, asJSON bool) (string, error) { + if asJSON { + response := map[string]interface{}{ + "account": account, + "message": message, + } + err := PrintColorizedJSON(response) + if err != nil { + return "", fmt.Errorf("failed to marshal JSON: %w", err) + } + return "", nil + } + + var sb strings.Builder + sb.WriteString(fmt.Sprintf("\n%s\n\n", Bold(Green("✓ Account updated successfully!")))) + + if account != nil && account.Name != "" { + sb.WriteString(fmt.Sprintf("%s %s\n", Cyan("Name:"), Bold(account.Name))) + } else { + sb.WriteString(fmt.Sprintf("%s %s\n", Cyan("Message:"), message)) + } + + if account != nil { + sb.WriteString(fmt.Sprintf("%s %s\n", Cyan("API Key:"), Dim(account.APIKey))) + + if account.Unlimited { + sb.WriteString(fmt.Sprintf("%s %s\n", Cyan("Credits:"), Green("Unlimited"))) + } else { + sb.WriteString(fmt.Sprintf("%s %s\n", Cyan("Credits:"), FormatCredits(int64(account.Credits)))) + } + + premiumStr := Gray("No") + if account.IsPremium { + premiumStr = Magenta("Yes") + } + sb.WriteString(fmt.Sprintf("%s %s\n", Cyan("Premium:"), premiumStr)) + + statusStr := Green("Active") + if account.Disabled { + statusStr = Red("Disabled") + } + sb.WriteString(fmt.Sprintf("%s %s\n", Cyan("Status:"), statusStr)) + } + + return sb.String(), nil +} + func FormatAccountDeleted(message string, asJSON bool) (string, error) { if asJSON { response := map[string]string{"message": message} diff --git a/internal/models/admin.go b/internal/models/admin.go index ee551f3..7d774a8 100644 --- a/internal/models/admin.go +++ b/internal/models/admin.go @@ -21,8 +21,11 @@ type AccountCreateRequest struct { } type AccountUpdateRequest struct { - Credits int `json:"credits,omitempty"` - Disabled bool `json:"disabled"` + Name *string `json:"name,omitempty"` + Credits *int `json:"credits,omitempty"` + Unlimited *bool `json:"unlimited,omitempty"` + IsPremium *bool `json:"is_premium,omitempty"` + Disabled *bool `json:"disabled,omitempty"` } type AddCreditsRequest struct { |
