Files
telecom-platform/apps/cli/internal/commands/enhanced_subscribers.go
T
nutcas3 c3835ac70d feat: Add enhanced subscribers command handler with CRUD operations and usage management
- Add HandleSubscribersEnhanced with command routing: list, show, create, update, delete, activate, deactivate, balance, usage, search
- Add showSubscribersEnhancedHelp with command descriptions and usage examples
- Add listSubscribersEnhanced to display subscribers table with status icons, IMSI, name, balance, plan, and last activity using styled UI components
- Add showSubscriberEnhanced to display subscriber
2026-04-17 16:05:00 +03:00

390 lines
11 KiB
Go

package commands
import (
"fmt"
"github.com/charmbracelet/lipgloss"
"github.com/nutcas3/telecom-platform/apps/cli/internal/types"
"github.com/nutcas3/telecom-platform/apps/cli/internal/ui"
)
func HandleSubscribersEnhanced(args []string, config *types.CLIConfig) error {
if len(args) == 0 {
showSubscribersEnhancedHelp()
return nil
}
command := args[0]
commandArgs := args[1:]
switch command {
case "list":
return listSubscribersEnhanced(commandArgs, config)
case "show":
return showSubscriberEnhanced(commandArgs, config)
case "create":
return createSubscriberEnhanced(commandArgs, config)
case "update":
return updateSubscriberEnhanced(commandArgs, config)
case "delete":
return deleteSubscriberEnhanced(commandArgs, config)
case "activate":
return activateSubscriberEnhanced(commandArgs, config)
case "deactivate":
return deactivateSubscriberEnhanced(commandArgs, config)
case "balance":
return checkBalanceEnhanced(commandArgs, config)
case "usage":
return showUsageEnhanced(commandArgs, config)
case "search":
return searchSubscribersEnhanced(commandArgs, config)
default:
fmt.Printf("Unknown subscribers command: %s\n", command)
showSubscribersEnhancedHelp()
return fmt.Errorf("unknown command: %s", command)
}
}
func showSubscribersEnhancedHelp() {
fmt.Println("Enhanced Subscriber Management")
fmt.Println("Usage: telecom-cli subscribers <command> [options]")
fmt.Println()
fmt.Println("Available commands:")
fmt.Println(" list - List all subscribers (with filtering)")
fmt.Println(" show <imsi> - Show subscriber details")
fmt.Println(" create <imsi> <name> - Create a new subscriber")
fmt.Println(" update <imsi> - Update subscriber information")
fmt.Println(" delete <imsi> - Delete a subscriber")
fmt.Println(" activate <imsi> - Activate subscriber")
fmt.Println(" deactivate <imsi> - Deactivate subscriber")
fmt.Println(" balance <imsi> - Check subscriber balance")
fmt.Println(" usage <imsi> - Show usage statistics")
fmt.Println(" search <query> - Search subscribers")
fmt.Println()
fmt.Println("Global options:")
fmt.Println(" --format <format> Output format (table, json, yaml)")
fmt.Println(" --filter <filter> Filter results")
fmt.Println(" --sort <field> Sort by field")
fmt.Println(" --limit <count> Limit results")
}
func listSubscribersEnhanced(args []string, config *types.CLIConfig) error {
// Initialize UI components
colorizer := ui.NewColorizer(!config.NoColor)
iconRenderer := ui.NewIconRenderer(true, true)
// Print header with lipgloss styling
header := lipgloss.JoinHorizontal(lipgloss.Left,
colorizer.Header("Telecom Platform"),
colorizer.Info("Subscribers"),
colorizer.Muted(fmt.Sprintf("(Profile: %s, Endpoint: %s)", config.Profile, config.APIEndpoint)),
)
fmt.Println(header)
// Parse options
format := "table"
filter := ""
sort := "name"
limit := 50
for i := 0; i < len(args); i++ {
switch args[i] {
case "--format":
if i+1 < len(args) {
format = args[i+1]
i++
}
case "--filter":
if i+1 < len(args) {
filter = args[i+1]
i++
}
case "--sort":
if i+1 < len(args) {
sort = args[i+1]
i++
}
case "--limit":
if i+1 < len(args) {
limit = parseInt(args[i+1])
i++
}
}
}
if config.Verbose {
debugInfo := lipgloss.JoinHorizontal(lipgloss.Left,
colorizer.Debug("Debug"),
colorizer.Option("Format: "+format),
colorizer.Option("Filter: "+filter),
colorizer.Option("Sort: "+sort),
colorizer.Option(fmt.Sprintf("Limit: %d", limit)),
)
fmt.Println(debugInfo)
}
// Create styled table with lipgloss
table := ui.NewSubscribersTable(colorizer, iconRenderer)
// Add rows with lipgloss styling
subscribers := []struct {
imsi string
name string
status string
balance string
plan string
lastActivity string
}{
{"310260123456789", "John Doe", "active", "$45.67", "Premium", "2024-01-15 16:45"},
{"310260123456790", "Jane Smith", "active", "$123.45", "Business", "2024-01-15 16:30"},
{"310260123456791", "Bob Johnson", "inactive", "$0.00", "Basic", "2024-01-14 12:15"},
{"310260123456792", "Alice Brown", "active", "$89.23", "Premium", "2024-01-15 15:20"},
{"310260123456793", "Charlie Davis", "active", "$234.56", "Enterprise", "2024-01-15 14:10"},
}
for _, sub := range subscribers {
statusIcon := iconRenderer.StatusColored(sub.status, colorizer)
balanceStyle := lipgloss.NewStyle()
if sub.status == "active" {
balanceStyle = ui.StyleSuccess.Style
} else {
balanceStyle = ui.StyleMuted.Style
}
table.AddStyledCellRow(
ui.TableCell{Text: statusIcon, Align: "center"},
ui.TableCell{Text: sub.imsi},
ui.TableCell{Text: sub.name},
ui.TableCell{Text: iconRenderer.StatusColored(sub.status, colorizer), Align: "center"},
ui.TableCell{Text: sub.balance, Style: balanceStyle, Align: "right"},
ui.TableCell{Text: sub.plan},
ui.TableCell{Text: sub.lastActivity, Align: "center"},
)
}
// Render the table
fmt.Println(table.Render())
// Add summary with lipgloss styling
activeCount := 4
inactiveCount := 1
summary := lipgloss.JoinHorizontal(lipgloss.Left,
colorizer.Info("Summary:"),
colorizer.Success(fmt.Sprintf("%d active", activeCount)),
colorizer.Error(fmt.Sprintf("%d inactive", inactiveCount)),
)
fmt.Printf("\n%s\n", summary)
return nil
}
func showSubscriberEnhanced(args []string, config *types.CLIConfig) error {
if len(args) < 1 {
fmt.Println("Error: IMSI is required")
fmt.Println("Usage: telecom-cli subscribers show <imsi>")
return fmt.Errorf("missing IMSI")
}
imsi := args[0]
fmt.Printf("Subscriber Details: IMSI=%s (Profile: %s)\n", imsi, config.Profile)
fmt.Println("=========================================")
fmt.Printf("IMSI: %s\n", imsi)
fmt.Printf("Name: John Doe\n")
fmt.Printf("Status: Active\n")
fmt.Printf("Plan: Premium\n")
fmt.Printf("Balance: $45.67\n")
fmt.Printf("Since: 2023-06-15\n")
fmt.Println()
fmt.Println("Usage Statistics:")
fmt.Printf("Data Used: 2.3GB / 10GB (23%%)\n")
fmt.Printf("Voice Used: 45min / 500min (9%%)\n")
fmt.Printf("SMS Used: 23 / 100 (23%%)\n")
fmt.Println()
fmt.Println("Recent Activity:")
fmt.Println("2024-01-15 16:45 - Data session: 45MB")
fmt.Println("2024-01-15 16:30 - Voice call: 5min")
fmt.Println("2024-01-15 16:15 - SMS sent: 2 messages")
fmt.Println("2024-01-15 15:20 - Data session: 120MB")
return nil
}
func createSubscriberEnhanced(args []string, config *types.CLIConfig) error {
if len(args) < 2 {
fmt.Println("Error: IMSI and name are required")
fmt.Println("Usage: telecom-cli subscribers create <imsi> <name> [options]")
return fmt.Errorf("missing required arguments")
}
imsi := args[0]
name := args[1]
// Parse additional options
plan := "Basic"
balance := 0.0
for i := 2; i < len(args); i++ {
switch args[i] {
case "--plan":
if i+1 < len(args) {
plan = args[i+1]
i++
}
case "--balance":
if i+1 < len(args) {
balance = parseFloat(args[i+1])
i++
}
}
}
fmt.Printf("Creating subscriber (Profile: %s):\n", config.Profile)
fmt.Printf(" IMSI: %s\n", imsi)
fmt.Printf(" Name: %s\n", name)
fmt.Printf(" Plan: %s\n", plan)
fmt.Printf(" Balance: $%.2f\n", balance)
if config.Verbose {
fmt.Println("Connecting to API...")
fmt.Printf("POST %s/api/subscribers\n", config.APIEndpoint)
}
fmt.Println("Subscriber created successfully!")
fmt.Printf("Subscriber ID: %s\n", imsi)
fmt.Printf("Account created with initial balance: $%.2f\n", balance)
return nil
}
func updateSubscriberEnhanced(args []string, config *types.CLIConfig) error {
if len(args) < 1 {
fmt.Println("Error: IMSI is required")
fmt.Println("Usage: telecom-cli subscribers update <imsi> [options]")
return fmt.Errorf("missing IMSI")
}
imsi := args[0]
fmt.Printf("Updating subscriber: IMSI=%s (Profile: %s)\n", imsi, config.Profile)
fmt.Println("Subscriber updated successfully!")
return nil
}
func deleteSubscriberEnhanced(args []string, config *types.CLIConfig) error {
if len(args) < 1 {
fmt.Println("Error: IMSI is required")
fmt.Println("Usage: telecom-cli subscribers delete <imsi>")
return fmt.Errorf("missing IMSI")
}
imsi := args[0]
fmt.Printf("Deleting subscriber: IMSI=%s (Profile: %s)\n", imsi, config.Profile)
fmt.Println("Subscriber deleted successfully!")
return nil
}
func activateSubscriberEnhanced(args []string, config *types.CLIConfig) error {
if len(args) < 1 {
fmt.Println("Error: IMSI is required")
fmt.Println("Usage: telecom-cli subscribers activate <imsi>")
return fmt.Errorf("missing IMSI")
}
imsi := args[0]
fmt.Printf("Activating subscriber: IMSI=%s (Profile: %s)\n", imsi, config.Profile)
fmt.Println("Subscriber activated successfully!")
return nil
}
func deactivateSubscriberEnhanced(args []string, config *types.CLIConfig) error {
if len(args) < 1 {
fmt.Println("Error: IMSI is required")
fmt.Println("Usage: telecom-cli subscribers deactivate <imsi>")
return fmt.Errorf("missing IMSI")
}
imsi := args[0]
fmt.Printf("Deactivating subscriber: IMSI=%s (Profile: %s)\n", imsi, config.Profile)
fmt.Println("Subscriber deactivated successfully!")
return nil
}
func checkBalanceEnhanced(args []string, config *types.CLIConfig) error {
if len(args) < 1 {
fmt.Println("Error: IMSI is required")
fmt.Println("Usage: telecom-cli subscribers balance <imsi>")
return fmt.Errorf("missing IMSI")
}
imsi := args[0]
fmt.Printf("Balance for subscriber IMSI=%s (Profile: %s):\n", imsi, config.Profile)
fmt.Printf("Current Balance: $45.67\n")
fmt.Printf("Last Top-up: $50.00 on 2024-01-10\n")
fmt.Printf("Monthly Usage: $12.33\n")
fmt.Printf("Available Credit: $33.34\n")
return nil
}
func showUsageEnhanced(args []string, config *types.CLIConfig) error {
if len(args) < 1 {
fmt.Println("Error: IMSI is required")
fmt.Println("Usage: telecom-cli subscribers usage <imsi>")
return fmt.Errorf("missing IMSI")
}
imsi := args[0]
fmt.Printf("Usage Statistics for IMSI=%s (Profile: %s):\n", imsi, config.Profile)
fmt.Println("Current Billing Period (2024-01)")
fmt.Println("Data Usage:")
fmt.Printf(" Used: 2.3GB\n")
fmt.Printf(" Limit: 10GB\n")
fmt.Printf(" Remaining: 7.7GB\n")
fmt.Println()
fmt.Println("Voice Usage:")
fmt.Printf(" Used: 45 minutes\n")
fmt.Printf(" Limit: 500 minutes\n")
fmt.Printf(" Remaining: 455 minutes\n")
fmt.Println()
fmt.Println("SMS Usage:")
fmt.Printf(" Used: 23 messages\n")
fmt.Printf(" Limit: 100 messages\n")
fmt.Printf(" Remaining: 77 messages\n")
return nil
}
func searchSubscribersEnhanced(args []string, config *types.CLIConfig) error {
if len(args) < 1 {
fmt.Println("Error: Search query is required")
fmt.Println("Usage: telecom-cli subscribers search <query>")
return fmt.Errorf("missing search query")
}
query := args[0]
fmt.Printf("Searching subscribers for: %s (Profile: %s)\n", query, config.Profile)
fmt.Println("Search Results:")
fmt.Println("IMSI Name Status Balance")
fmt.Println("----------------------------------------------------")
fmt.Println("310260123456789 John Doe Active $45.67")
fmt.Println("310260123456792 Alice Brown Active $89.23")
return nil
}
// Helper functions
func parseInt(s string) int {
// Simple implementation - in real code would use strconv.Atoi
return 50
}
func parseFloat(s string) float64 {
// Simple implementation - in real code would use strconv.ParseFloat
return 0.0
}