Compare commits

..

2 Commits

3 changed files with 98 additions and 53 deletions

View File

@@ -280,17 +280,36 @@ type voteResult struct {
index int index int
} }
func generateRandomIdentifier() string {
const length = 12
const chars = "abcdefghijklmnopqrstuvwxyz0123456789"
identifier := make([]byte, length)
for i := range identifier {
num, _ := rand.Int(rand.Reader, big.NewInt(int64(len(chars))))
identifier[i] = chars[num.Int64()]
}
return string(identifier)
}
func (p *ParallelProcessor) createSingleUser(userRepo repositories.UserRepository, index int) (database.User, error) { func (p *ParallelProcessor) createSingleUser(userRepo repositories.UserRepository, index int) (database.User, error) {
username := fmt.Sprintf("user_%d", index)
email := fmt.Sprintf("user_%d@goyco.local", index)
password := "password123" password := "password123"
randomID := generateRandomIdentifier()
username := fmt.Sprintf("user_%s", randomID)
email := fmt.Sprintf("user_%s@goyco.local", randomID)
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil { if err != nil {
return database.User{}, fmt.Errorf("hash password: %w", err) return database.User{}, fmt.Errorf("hash password: %w", err)
} }
user := &database.User{ const maxRetries = 10
for attempt := 0; attempt < maxRetries; attempt++ {
user, err := userRepo.GetByEmail(email)
if err == nil {
return *user, nil
}
user = &database.User{
Username: username, Username: username,
Email: email, Email: email,
Password: string(hashedPassword), Password: string(hashedPassword),
@@ -298,12 +317,18 @@ func (p *ParallelProcessor) createSingleUser(userRepo repositories.UserRepositor
} }
if err := userRepo.Create(user); err != nil { if err := userRepo.Create(user); err != nil {
return database.User{}, fmt.Errorf("create user: %w", err) randomID = generateRandomIdentifier()
username = fmt.Sprintf("user_%s", randomID)
email = fmt.Sprintf("user_%s@goyco.local", randomID)
continue
} }
return *user, nil return *user, nil
} }
return database.User{}, fmt.Errorf("failed to create user after %d attempts", maxRetries)
}
func (p *ParallelProcessor) createSinglePost(postRepo repositories.PostRepository, authorID uint, index int) (database.Post, error) { func (p *ParallelProcessor) createSinglePost(postRepo repositories.PostRepository, authorID uint, index int) (database.Post, error) {
sampleTitles := []string{ sampleTitles := []string{
"Amazing JavaScript Framework", "Amazing JavaScript Framework",
@@ -347,11 +372,14 @@ func (p *ParallelProcessor) createSinglePost(postRepo repositories.PostRepositor
} }
domain := sampleDomains[index%len(sampleDomains)] domain := sampleDomains[index%len(sampleDomains)]
path := generateRandomPath() randomID := generateRandomIdentifier()
path := fmt.Sprintf("/article/%s", randomID)
url := fmt.Sprintf("https://%s%s", domain, path) url := fmt.Sprintf("https://%s%s", domain, path)
content := fmt.Sprintf("Autogenerated seed post #%d\n\nThis is sample content for testing purposes. The post discusses %s and provides valuable insights.", index, title) content := fmt.Sprintf("Autogenerated seed post #%d\n\nThis is sample content for testing purposes. The post discusses %s and provides valuable insights.", index, title)
const maxRetries = 10
for attempt := 0; attempt < maxRetries; attempt++ {
post := &database.Post{ post := &database.Post{
Title: title, Title: title,
URL: url, URL: url,
@@ -363,12 +391,18 @@ func (p *ParallelProcessor) createSinglePost(postRepo repositories.PostRepositor
} }
if err := postRepo.Create(post); err != nil { if err := postRepo.Create(post); err != nil {
return database.Post{}, fmt.Errorf("create post: %w", err) randomID = generateRandomIdentifier()
path = fmt.Sprintf("/article/%s", randomID)
url = fmt.Sprintf("https://%s%s", domain, path)
continue
} }
return *post, nil return *post, nil
} }
return database.Post{}, fmt.Errorf("failed to create post after %d attempts", maxRetries)
}
func (p *ParallelProcessor) createVotesForPost(voteRepo repositories.VoteRepository, users []database.User, post database.Post, avgVotesPerPost int) (int, error) { func (p *ParallelProcessor) createVotesForPost(voteRepo repositories.VoteRepository, users []database.User, post database.Post, avgVotesPerPost int) (int, error) {
voteCount, _ := rand.Int(rand.Reader, big.NewInt(int64(avgVotesPerPost*2)+1)) voteCount, _ := rand.Int(rand.Reader, big.NewInt(int64(avgVotesPerPost*2)+1))
numVotes := int(voteCount.Int64()) numVotes := int(voteCount.Int64())
@@ -406,8 +440,8 @@ func (p *ParallelProcessor) createVotesForPost(voteRepo repositories.VoteReposit
Type: voteType, Type: voteType,
} }
if err := voteRepo.Create(vote); err != nil { if err := voteRepo.CreateOrUpdate(vote); err != nil {
return totalVotes, fmt.Errorf("create vote: %w", err) return totalVotes, fmt.Errorf("create or update vote: %w", err)
} }
totalVotes++ totalVotes++

View File

@@ -8,11 +8,12 @@ import (
"math/big" "math/big"
"os" "os"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
"goyco/internal/config" "goyco/internal/config"
"goyco/internal/database" "goyco/internal/database"
"goyco/internal/repositories" "goyco/internal/repositories"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
) )
func HandleSeedCommand(cfg *config.Config, name string, args []string) error { func HandleSeedCommand(cfg *config.Config, name string, args []string) error {
@@ -169,12 +170,12 @@ func seedDatabase(userRepo repositories.UserRepository, postRepo repositories.Po
} }
if IsJSONOutput() { if IsJSONOutput() {
outputJSON(map[string]interface{}{ outputJSON(map[string]any{
"action": "seed_completed", "action": "seed_completed",
"users": len(allUsers), "users": len(allUsers),
"posts": len(posts), "posts": len(posts),
"votes": votes, "votes": votes,
"seed_user": map[string]interface{}{ "seed_user": map[string]any{
"id": seedUser.ID, "id": seedUser.ID,
"username": seedUser.Username, "username": seedUser.Username,
}, },
@@ -188,20 +189,23 @@ func seedDatabase(userRepo repositories.UserRepository, postRepo repositories.Po
} }
func ensureSeedUser(userRepo repositories.UserRepository) (*database.User, error) { func ensureSeedUser(userRepo repositories.UserRepository) (*database.User, error) {
seedUsername := "seed_admin"
seedEmail := "seed_admin@goyco.local"
seedPassword := "seed-password" seedPassword := "seed-password"
randomID := generateRandomIdentifier()
user, err := userRepo.GetByEmail(seedEmail) seedUsername := fmt.Sprintf("seed_admin_%s", randomID)
if err == nil { seedEmail := fmt.Sprintf("seed_admin_%s@goyco.local", randomID)
return user, nil
}
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(seedPassword), bcrypt.DefaultCost) hashedPassword, err := bcrypt.GenerateFromPassword([]byte(seedPassword), bcrypt.DefaultCost)
if err != nil { if err != nil {
return nil, fmt.Errorf("hash password: %w", err) return nil, fmt.Errorf("hash password: %w", err)
} }
const maxRetries = 10
for range maxRetries {
user, err := userRepo.GetByEmail(seedEmail)
if err == nil {
return user, nil
}
user = &database.User{ user = &database.User{
Username: seedUsername, Username: seedUsername,
Email: seedEmail, Email: seedEmail,
@@ -210,12 +214,18 @@ func ensureSeedUser(userRepo repositories.UserRepository) (*database.User, error
} }
if err := userRepo.Create(user); err != nil { if err := userRepo.Create(user); err != nil {
return nil, fmt.Errorf("create seed user: %w", err) randomID = generateRandomIdentifier()
seedUsername = fmt.Sprintf("seed_admin_%s", randomID)
seedEmail = fmt.Sprintf("seed_admin_%s@goyco.local", randomID)
continue
} }
return user, nil return user, nil
} }
return nil, fmt.Errorf("failed to create seed user after %d attempts", maxRetries)
}
func createRandomUsers(userRepo repositories.UserRepository, count int) ([]database.User, error) { func createRandomUsers(userRepo repositories.UserRepository, count int) ([]database.User, error) {
var users []database.User var users []database.User

View File

@@ -1,6 +1,7 @@
package commands package commands
import ( import (
"strings"
"testing" "testing"
"gorm.io/driver/sqlite" "gorm.io/driver/sqlite"
@@ -30,12 +31,12 @@ func TestSeedCommand(t *testing.T) {
t.Fatalf("Failed to ensure seed user: %v", err) t.Fatalf("Failed to ensure seed user: %v", err)
} }
if seedUser.Username != "seed_admin" { if !strings.HasPrefix(seedUser.Username, "seed_admin_") {
t.Errorf("Expected username 'seed_admin', got '%s'", seedUser.Username) t.Errorf("Expected username to start with 'seed_admin_', got '%s'", seedUser.Username)
} }
if seedUser.Email != "seed_admin@goyco.local" { if !strings.HasPrefix(seedUser.Email, "seed_admin_") || !strings.HasSuffix(seedUser.Email, "@goyco.local") {
t.Errorf("Expected email 'seed_admin@goyco.local', got '%s'", seedUser.Email) t.Errorf("Expected email to start with 'seed_admin_' and end with '@goyco.local', got '%s'", seedUser.Email)
} }
if !seedUser.EmailVerified { if !seedUser.EmailVerified {