backend-service/internal/cli/admin.go

214 lines
5.5 KiB
Go
Raw Normal View History

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)
jitsiService := services.NewJitsiService(&cfg.Jitsi)
notificationService := services.NewNotificationService(repos.Notification, cfg, jitsiService)
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)
}