package cli import ( "bufio" "fmt" "log" "os" "strings" "syscall" "attune-heart-therapy/internal/config" "attune-heart-therapy/internal/database" "attune-heart-therapy/internal/services" "github.com/joho/godotenv" "github.com/spf13/cobra" "golang.org/x/term" ) var adminCmd = &cobra.Command{ Use: "admin", Short: "Admin management commands", Long: "Commands for managing admin accounts and operations", } var createAdminCmd = &cobra.Command{ Use: "create-admin", Short: "Create a new admin account", Long: "Create a new admin account with email and password parameters", Run: runCreateAdmin, } // Command flags var ( adminEmail string adminPassword string adminFirstName string adminLastName string interactive bool ) func runCreateAdmin(cmd *cobra.Command, args []string) { // Load environment variables if err := godotenv.Load(); err != nil { log.Println("No .env file found, using system environment variables") } // Load configuration cfg, err := config.Load() if err != nil { log.Fatalf("Failed to load configuration: %v", err) } // Initialize database connection db, err := database.New(cfg) if err != nil { log.Fatalf("Failed to connect to database: %v", err) } defer db.Close() // Get repositories repos := db.GetRepositories() // Initialize services jwtService := services.NewJWTService(cfg.JWT.Secret, cfg.JWT.Expiration) notificationService := services.NewNotificationService(repos.Notification, cfg) userService := services.NewUserService(repos.User, jwtService, notificationService) // Get admin details if interactive || adminEmail == "" || adminPassword == "" { if err := getAdminDetailsInteractively(); err != nil { log.Fatalf("Failed to get admin details: %v", err) } } // Validate required fields if err := validateAdminInput(); err != nil { log.Fatalf("Validation failed: %v", err) } // Create admin account if err := createAdminAccount(userService); err != nil { log.Fatalf("Failed to create admin account: %v", err) } fmt.Printf("Admin account created successfully for: %s\n", adminEmail) } func getAdminDetailsInteractively() error { reader := bufio.NewReader(os.Stdin) // Get email if adminEmail == "" { fmt.Print("Enter admin email: ") email, err := reader.ReadString('\n') if err != nil { return fmt.Errorf("failed to read email: %w", err) } adminEmail = strings.TrimSpace(email) } // Get first name if adminFirstName == "" { fmt.Print("Enter admin first name: ") firstName, err := reader.ReadString('\n') if err != nil { return fmt.Errorf("failed to read first name: %w", err) } adminFirstName = strings.TrimSpace(firstName) } // Get last name if adminLastName == "" { fmt.Print("Enter admin last name: ") lastName, err := reader.ReadString('\n') if err != nil { return fmt.Errorf("failed to read last name: %w", err) } adminLastName = strings.TrimSpace(lastName) } // Get password securely if adminPassword == "" { fmt.Print("Enter admin password: ") passwordBytes, err := term.ReadPassword(int(syscall.Stdin)) if err != nil { return fmt.Errorf("failed to read password: %w", err) } adminPassword = string(passwordBytes) fmt.Println() // Add newline after password input // Confirm password fmt.Print("Confirm admin password: ") confirmPasswordBytes, err := term.ReadPassword(int(syscall.Stdin)) if err != nil { return fmt.Errorf("failed to read password confirmation: %w", err) } confirmPassword := string(confirmPasswordBytes) fmt.Println() // Add newline after password confirmation if adminPassword != confirmPassword { return fmt.Errorf("passwords do not match") } } return nil } func validateAdminInput() error { if adminEmail == "" { return fmt.Errorf("email is required") } if adminFirstName == "" { return fmt.Errorf("first name is required") } if adminLastName == "" { return fmt.Errorf("last name is required") } if adminPassword == "" { return fmt.Errorf("password is required") } if len(adminPassword) < 8 { return fmt.Errorf("password must be at least 8 characters long") } // Basic email validation if !strings.Contains(adminEmail, "@") || !strings.Contains(adminEmail, ".") { return fmt.Errorf("invalid email format") } return nil } func createAdminAccount(userService services.UserService) error { // Create admin request adminRequest := services.CreateAdminRequest{ FirstName: adminFirstName, LastName: adminLastName, Email: adminEmail, Password: adminPassword, } // Create admin account using the user service adminUser, err := userService.CreateAdmin(adminRequest) if err != nil { return fmt.Errorf("failed to create admin account: %w", err) } // Log success (adminUser contains the created user info) _ = adminUser return nil } func init() { // Add flags to create-admin command createAdminCmd.Flags().StringVarP(&adminEmail, "email", "e", "", "Admin email address") createAdminCmd.Flags().StringVarP(&adminPassword, "password", "p", "", "Admin password") createAdminCmd.Flags().StringVarP(&adminFirstName, "first-name", "f", "", "Admin first name") createAdminCmd.Flags().StringVarP(&adminLastName, "last-name", "l", "", "Admin last name") createAdminCmd.Flags().BoolVarP(&interactive, "interactive", "i", false, "Interactive mode for entering admin details") // Add subcommands to admin command adminCmd.AddCommand(createAdminCmd) // Add admin command to root rootCmd.AddCommand(adminCmd) }