- Replace deprecated `golang.org/x/crypto/ssh/terminal` with `golang.org/x/term` - Update `terminal.ReadPassword()` calls to use `term.ReadPassword()` - Remove unnecessary version of `golang.org/x/sys` in go.sum - Ensure compatibility with latest terminal package recommendations
213 lines
5.4 KiB
Go
213 lines
5.4 KiB
Go
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)
|
|
}
|