Files
tm_back/migrations/001_dual_user_system.go
T
2025-07-27 16:20:21 +03:30

337 lines
8.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/google/uuid"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"golang.org/x/crypto/bcrypt"
"tm/internal/domain"
)
const (
DefaultMongoURI = "mongodb://localhost:27017"
DefaultDBName = "tender_management"
)
func main() {
// Get database connection details from environment or use defaults
mongoURI := DefaultMongoURI
if uri := getEnv("MONGO_URI"); uri != "" {
mongoURI = uri
}
dbName := DefaultDBName
if name := getEnv("DB_NAME"); name != "" {
dbName = name
}
fmt.Println("🚀 Starting database migration for dual user system...")
fmt.Printf("📊 Database: %s\n", dbName)
fmt.Printf("🔗 URI: %s\n", mongoURI)
// Connect to MongoDB
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
client, err := mongo.Connect(ctx, options.Client().ApplyURI(mongoURI))
if err != nil {
log.Fatal("❌ Failed to connect to MongoDB:", err)
}
defer client.Disconnect(context.Background())
// Ping to verify connection
if err = client.Ping(ctx, nil); err != nil {
log.Fatal("❌ Failed to ping MongoDB:", err)
}
fmt.Println("✅ Connected to MongoDB successfully")
db := client.Database(dbName)
// Run migrations
if err := createCustomersCollection(db); err != nil {
log.Fatal("❌ Failed to create customers collection:", err)
}
if err := createUsersCollection(db); err != nil {
log.Fatal("❌ Failed to create users collection:", err)
}
if err := createSampleData(db); err != nil {
log.Fatal("❌ Failed to create sample data:", err)
}
fmt.Println("🎉 Database migration completed successfully!")
}
// createCustomersCollection creates the customers collection with indexes
func createCustomersCollection(db *mongo.Database) error {
fmt.Println("📝 Creating customers collection...")
collection := db.Collection("customers")
// Create indexes
indexes := []mongo.IndexModel{
{
Keys: bson.D{{"email", 1}},
Options: options.Index().SetUnique(true).SetName("email_unique"),
},
{
Keys: bson.D{{"company_id", 1}},
Options: options.Index().SetName("company_id_idx"),
},
{
Keys: bson.D{{"is_active", 1}},
Options: options.Index().SetName("is_active_idx"),
},
{
Keys: bson.D{{"created_at", -1}},
Options: options.Index().SetName("created_at_desc_idx"),
},
{
Keys: bson.D{{"role", 1}},
Options: options.Index().SetName("role_idx"),
},
}
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
_, err := collection.Indexes().CreateMany(ctx, indexes)
if err != nil {
return fmt.Errorf("failed to create customer indexes: %w", err)
}
fmt.Println("✅ Customers collection created with indexes")
return nil
}
// createUsersCollection creates the panel users collection with indexes
func createUsersCollection(db *mongo.Database) error {
fmt.Println("📝 Creating users collection...")
collection := db.Collection("users")
// Create indexes
indexes := []mongo.IndexModel{
{
Keys: bson.D{{"email", 1}},
Options: options.Index().SetUnique(true).SetName("email_unique"),
},
{
Keys: bson.D{{"role", 1}},
Options: options.Index().SetName("role_idx"),
},
{
Keys: bson.D{{"is_active", 1}},
Options: options.Index().SetName("is_active_idx"),
},
{
Keys: bson.D{{"department", 1}},
Options: options.Index().SetName("department_idx"),
},
{
Keys: bson.D{{"created_at", -1}},
Options: options.Index().SetName("created_at_desc_idx"),
},
{
Keys: bson.D{{"created_by", 1}},
Options: options.Index().SetName("created_by_idx"),
},
}
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
_, err := collection.Indexes().CreateMany(ctx, indexes)
if err != nil {
return fmt.Errorf("failed to create user indexes: %w", err)
}
fmt.Println("✅ Users collection created with indexes")
return nil
}
// createSampleData creates sample admin user and test customer
func createSampleData(db *mongo.Database) error {
fmt.Println("📝 Creating sample data...")
// Create sample admin user
if err := createSampleAdmin(db); err != nil {
return fmt.Errorf("failed to create sample admin: %w", err)
}
// Create sample customer
if err := createSampleCustomer(db); err != nil {
return fmt.Errorf("failed to create sample customer: %w", err)
}
fmt.Println("✅ Sample data created successfully")
return nil
}
// createSampleAdmin creates a sample admin user
func createSampleAdmin(db *mongo.Database) error {
collection := db.Collection("users")
// Check if admin already exists
ctx := context.Background()
count, err := collection.CountDocuments(ctx, bson.M{"email": "admin@tendermanagement.com"})
if err != nil {
return err
}
if count > 0 {
fmt.Println("️ Sample admin user already exists, skipping...")
return nil
}
// Hash password for admin
hashedPassword, err := bcrypt.GenerateFromPassword([]byte("admin123!"), bcrypt.DefaultCost)
if err != nil {
return err
}
now := time.Now()
adminID := uuid.New()
admin := bson.M{
"_id": adminID,
"email": "admin@tendermanagement.com",
"password": string(hashedPassword),
"first_name": "System",
"last_name": "Administrator",
"role": domain.UserRoleAdmin,
"department": "IT",
"is_active": true,
"permissions": []string{
"manage_users",
"manage_tenders",
"manage_companies",
"manage_customers",
"view_reports",
"manage_system",
"manage_sources",
},
"created_at": now,
"updated_at": now,
}
_, err = collection.InsertOne(ctx, admin)
if err != nil {
return err
}
fmt.Println("👤 Sample admin user created:")
fmt.Println(" 📧 Email: admin@tendermanagement.com")
fmt.Println(" 🔑 Password: admin123!")
fmt.Println(" 🛡️ Role: admin")
return nil
}
// createSampleCustomer creates a sample customer
func createSampleCustomer(db *mongo.Database) error {
collection := db.Collection("customers")
// Check if customer already exists
ctx := context.Background()
count, err := collection.CountDocuments(ctx, bson.M{"email": "customer@example.com"})
if err != nil {
return err
}
if count > 0 {
fmt.Println("️ Sample customer already exists, skipping...")
return nil
}
// Hash password for customer
hashedPassword, err := bcrypt.GenerateFromPassword([]byte("customer123!"), bcrypt.DefaultCost)
if err != nil {
return err
}
now := time.Now()
companyID := uuid.New()
customerID := uuid.New()
// Create sample company first
companyCollection := db.Collection("companies")
company := bson.M{
"_id": companyID,
"name": "Sample Company Ltd",
"description": "A sample company for testing",
"industry": "Technology",
"country": "United States",
"website": "https://example.com",
"keywords": []string{"technology", "software", "consulting"},
"products": []string{"software development", "consulting"},
"services": []string{"web development", "mobile apps"},
"created_at": now,
"updated_at": now,
}
_, err = companyCollection.InsertOne(ctx, company)
if err != nil {
return err
}
// Create customer
customer := bson.M{
"_id": customerID,
"email": "customer@example.com",
"password": string(hashedPassword),
"first_name": "John",
"last_name": "Doe",
"phone": "+1234567890",
"role": domain.CustomerRoleUser,
"company_id": companyID,
"is_active": true,
"is_verified": true,
"device_tokens": []string{},
"preferences": bson.M{
"language": "en",
"notification_settings": bson.M{
"new_tenders": true,
"deadline_reminder": true,
"status_updates": true,
"system_alerts": true,
},
"tender_alerts": true,
"email_notifications": true,
"push_notifications": true,
"preferred_categories": []string{},
},
"created_at": now,
"updated_at": now,
}
_, err = collection.InsertOne(ctx, customer)
if err != nil {
return err
}
fmt.Println("👤 Sample customer created:")
fmt.Println(" 📧 Email: customer@example.com")
fmt.Println(" 🔑 Password: customer123!")
fmt.Println(" 🏢 Company: Sample Company Ltd")
fmt.Println(" 📱 Role: customer_user")
return nil
}
// Helper functions
func getEnv(key string) string {
// Simple environment variable getter
// In a real implementation, you might use os.Getenv()
return ""
}