turash/bugulma/backend/cmd/cli/cmd/user.go
Damir Mukimov 02fad6713c refactor(docs/locales): rename project from 'Tуган Як'/'Tugan Yak' to 'Turash' across docs, locales and test fixtures
- Update locales (ru, tt, en) to use 'Turash' and 'Turash AI'
- Update metadata, index.html, and pixel-art README
- Replace example credentials/emails from @tuganyak.dev -> @turash.dev
- Update admin defaults and migration seed to use new admin@turash.dev
- Update docs mentioning the old name
2025-12-15 05:42:16 +01:00

279 lines
7.3 KiB
Go

package cmd
import (
"context"
"fmt"
"log"
"time"
"bugulma/backend/cmd/cli/internal"
"bugulma/backend/internal/domain"
"bugulma/backend/internal/repository"
"github.com/google/uuid"
"github.com/spf13/cobra"
"golang.org/x/crypto/bcrypt"
)
var (
userEmail string
userPassword string
userName string
userRole string
resetMode bool
setupMode bool
)
var userCmd = &cobra.Command{
Use: "user",
Short: "User management operations",
Long: `Manage user accounts including password resets and bulk user setup.
Supports creating users, resetting passwords, and setting up default users.`,
}
var userCreateCmd = &cobra.Command{
Use: "create",
Short: "Create a new user account",
Long: `Create a new user account with the specified email, password, and role.
If no password is provided, it will be generated randomly.`,
RunE: runUserCreate,
}
var userResetPasswordCmd = &cobra.Command{
Use: "reset-password",
Short: "Reset a user's password",
Long: `Reset a user's password. Generates a bcrypt hash that can be used
to update the user's password in the database.`,
RunE: runUserResetPassword,
}
var userSetupCmd = &cobra.Command{
Use: "setup",
Short: "Set up default users",
Long: `Create default users for each role if they don't exist.
Creates admin, regular user, content manager, and viewer accounts.
Existing users are updated if their roles differ.`,
RunE: runUserSetup,
}
func init() {
// Create command flags
userCreateCmd.Flags().StringVarP(&userEmail, "email", "e", "", "User email (required)")
userCreateCmd.Flags().StringVarP(&userPassword, "password", "p", "", "User password (if not provided, will be prompted)")
userCreateCmd.Flags().StringVarP(&userName, "name", "n", "", "User name (required)")
userCreateCmd.Flags().StringVarP(&userRole, "role", "r", "user", "User role (admin, user, content_manager, viewer)")
userCreateCmd.MarkFlagRequired("email")
userCreateCmd.MarkFlagRequired("name")
// Reset password command flags
userResetPasswordCmd.Flags().StringVarP(&userPassword, "password", "p", "", "New password (required)")
userResetPasswordCmd.MarkFlagRequired("password")
// Add subcommands
userCmd.AddCommand(userCreateCmd)
userCmd.AddCommand(userResetPasswordCmd)
userCmd.AddCommand(userSetupCmd)
}
func runUserCreate(cmd *cobra.Command, args []string) error {
cfg, err := getConfig()
if err != nil {
return fmt.Errorf("failed to load config: %w", err)
}
// Connect to database
db, err := internal.ConnectPostgres(cfg)
if err != nil {
return fmt.Errorf("failed to connect to database: %w", err)
}
userRepo := repository.NewUserRepository(db)
ctx := context.Background()
// Validate role
var role domain.UserRole
switch userRole {
case "admin":
role = domain.UserRoleAdmin
case "user":
role = domain.UserRoleUser
case "content_manager":
role = domain.UserRoleContentManager
case "viewer":
role = domain.UserRoleViewer
default:
return fmt.Errorf("invalid role: %s. Must be one of: admin, user, content_manager, viewer", userRole)
}
// Check if user exists
existing, err := userRepo.GetByEmail(ctx, userEmail)
if err == nil && existing != nil {
return fmt.Errorf("user with email %s already exists", userEmail)
}
// Hash password
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(userPassword), bcrypt.DefaultCost)
if err != nil {
return fmt.Errorf("failed to hash password: %w", err)
}
// Create user
user := &domain.User{
ID: uuid.New().String(),
Email: userEmail,
Name: userName,
Password: string(hashedPassword),
Role: role,
IsActive: true,
Permissions: "[]",
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
if err := userRepo.Create(ctx, user); err != nil {
return fmt.Errorf("failed to create user: %w", err)
}
if isVerbose() {
fmt.Printf("✓ Created user %s (%s) with role %s\n", userEmail, userName, role)
}
return nil
}
func runUserResetPassword(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return fmt.Errorf("email argument is required")
}
email := args[0]
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(userPassword), bcrypt.DefaultCost)
if err != nil {
return fmt.Errorf("failed to hash password: %w", err)
}
fmt.Println("-- Run this SQL to update the user password:")
fmt.Printf("UPDATE users SET password = '%s' WHERE email = '%s';\n", string(hashedPassword), email)
if isVerbose() {
fmt.Printf("✓ Generated password hash for user: %s\n", email)
fmt.Printf("Password: %s\n", userPassword)
}
return nil
}
func runUserSetup(cmd *cobra.Command, args []string) error {
cfg, err := getConfig()
if err != nil {
return fmt.Errorf("failed to load config: %w", err)
}
// Connect to database
db, err := internal.ConnectPostgres(cfg)
if err != nil {
return fmt.Errorf("failed to connect to database: %w", err)
}
userRepo := repository.NewUserRepository(db)
ctx := context.Background()
// Define users for each role
users := []struct {
email string
name string
password string
role domain.UserRole
}{
{
email: "admin@turash.dev",
name: "Admin User",
password: "admin123",
role: domain.UserRoleAdmin,
},
{
email: "user@turash.dev",
name: "Regular User",
password: "user123",
role: domain.UserRoleUser,
},
{
email: "content@turash.dev",
name: "Content Manager",
password: "content123",
role: domain.UserRoleContentManager,
},
{
email: "viewer@turash.dev",
name: "Viewer User",
password: "viewer123",
role: domain.UserRoleViewer,
},
}
for _, u := range users {
// Check if user exists
existing, err := userRepo.GetByEmail(ctx, u.email)
if err == nil && existing != nil {
// Update role if different
if existing.Role != u.role {
if isVerbose() {
fmt.Printf("Updating user %s: role %s -> %s\n", u.email, existing.Role, u.role)
}
if err := userRepo.UpdateRole(ctx, existing.ID, u.role); err != nil {
log.Printf("Failed to update role for %s: %v", u.email, err)
continue
}
if !isQuiet() {
fmt.Printf("✓ Updated role for %s to %s\n", u.email, u.role)
}
} else {
if !isQuiet() {
fmt.Printf("✓ User %s already exists with role %s\n", u.email, u.role)
}
}
continue
}
// Create new user
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(u.password), bcrypt.DefaultCost)
if err != nil {
log.Printf("Failed to hash password for %s: %v", u.email, err)
continue
}
user := &domain.User{
ID: uuid.New().String(),
Email: u.email,
Name: u.name,
Password: string(hashedPassword),
Role: u.role,
IsActive: true,
Permissions: "[]",
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
if err := userRepo.Create(ctx, user); err != nil {
log.Printf("Failed to create user %s: %v", u.email, err)
continue
}
if !isQuiet() {
fmt.Printf("✓ Created user %s with role %s (password: %s)\n", u.email, u.role, u.password)
}
}
if !isQuiet() {
fmt.Println("\nAll users setup complete!")
fmt.Println("\nLogin credentials:")
fmt.Println(" Admin: admin@turash.dev / admin123")
fmt.Println(" User: user@turash.dev / user123")
fmt.Println(" Content Mgr: content@turash.dev / content123")
fmt.Println(" Viewer: viewer@turash.dev / viewer123")
}
return nil
}