Files
soft_usite/migrations/migrate.go
T
2026-05-12 22:34:10 -05:00

698 lines
23 KiB
Go
Executable File

package migrations
import (
"fmt"
"log"
"time"
"github.com/sujit-baniya/fiber-boilerplate/app"
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
// Session structure for managing sessions
type Session struct {
ID uint `gorm:"primaryKey"`
SessionID string `gorm:"unique;not null"`
Data string `gorm:"type:text"`
CreatedAt time.Time
UpdatedAt time.Time
ExpireAt time.Time
}
// Migrate performs the database migrations
func Migrate() {
log.Println("Initiating migration...")
// Migrate the main application models
if err := app.Http.Database.DB.Migrator().AutoMigrate(
&models.Roles{},
&models.Users{},
&models.Modules{},
&models.Submodules{},
&models.Inicio{},
&models.TipoServidor{},
&models.TipoDb{},
&models.Servidor{},
&models.ConxDb{},
&models.ConxSsh{},
&models.ProvServidor{},
&models.QrVcard{},
&models.OssApi{},
&models.VcfVcard{},
&models.DlocalApi{},
// Módulo de Renovaciones
&models.Servicio{},
&models.Cliente{},
&models.PlantillaCorreo{},
&models.NotificacionRegla{},
&models.Contrato{},
&models.NotificacionLog{},
&models.SmtpConfig{},
// Integraciones externas
&models.HostingerConfig{},
&models.CloudflareConfig{},
// Query Runner
&models.QueryHistory{},
// Pasarelas de pago
&models.BoldConfig{},
&models.BoldWebhookLog{},
&models.BoldCallbackLog{},
&models.DlocalPaymentLog{},
// Documentación por SaaS
&models.SaasProducto{},
&models.DocCategoria{},
&models.DocPagina{},
// Integraciones SaaS (dispatcher de pagos)
&models.SaasApiConfig{},
&models.SaasDispatchLog{},
); err != nil {
log.Fatalf("Error during main migration: %v", err)
}
// Open (or create) a SQLite database for sessions
db, err := gorm.Open(sqlite.Open("session.db"), &gorm.Config{})
if err != nil {
log.Fatalf("Error connecting to the database: %v", err)
return
}
// Migrate the Session structure
if err := db.AutoMigrate(&Session{}); err != nil {
log.Fatalf("Error migrating session database: %v", err)
return
}
fmt.Println("Session database created and table migrated successfully.")
// Insertar módulo y submódulos de Renovaciones
SeedRenovaciones()
// Insertar módulo y submódulos de Integraciones externas
SeedIntegraciones()
// Insertar submódulo "Pasarelas de Pago" en el módulo Integraciones
SeedPasarelas()
// Insertar submódulos de SaaS (Productos + Integraciones) en el módulo Integraciones
SeedSaas()
// Insertar submódulo "Statuspage" en el módulo Integraciones
SeedStatuspage()
// Crear plantillas y reglas mínimas si no existen (bienvenida, pago_recibido)
SeedPlantillasBase()
log.Println("Migration Completed...")
}
// SeedStatuspage agrega el submódulo "Statuspage" (Atlassian) al módulo "Integraciones"
// y lo asigna a todos los roles. Es idempotente.
func SeedStatuspage() {
db := app.Http.Database.DB
// Obtener el módulo "Integraciones" (debe existir luego de SeedIntegraciones)
var modulo models.Modules
if err := db.Where("title = ?", "Integraciones").First(&modulo).Error; err != nil {
log.Printf("[SEED] Módulo 'Integraciones' no encontrado para SeedStatuspage: %v", err)
return
}
entries := []struct{ title, desc, url string }{
{"Statuspage", "Monitoreo de estado de servicios vía Atlassian Statuspage", "/app/statuspage"},
}
var insertados []models.Submodules
for _, e := range entries {
var sub models.Submodules
if err := db.Where("url = ?", e.url).First(&sub).Error; err != nil {
sub = models.Submodules{
Title: e.title,
Description: e.desc,
Url: e.url,
ModuleId: modulo.ID,
ModifiedAt: time.Now(),
}
if err := db.Create(&sub).Error; err != nil {
log.Printf("[SEED] Error creando submódulo '%s': %v", e.title, err)
continue
}
log.Printf("[SEED] Submódulo '%s' creado (ID %d)", e.title, sub.ID)
} else {
log.Printf("[SEED] Submódulo '%s' ya existe (ID %d)", sub.Title, sub.ID)
}
insertados = append(insertados, sub)
}
var roles []models.Roles
if err := db.Find(&roles).Error; err != nil {
log.Printf("[SEED] Error obteniendo roles: %v", err)
return
}
for _, rol := range roles {
if err := db.Model(&rol).Association("Submodules").Append(&insertados); err != nil {
log.Printf("[SEED] Error asignando submódulo Statuspage al rol '%s': %v", rol.Name, err)
} else {
log.Printf("[SEED] Submódulo Statuspage asignado al rol '%s'", rol.Name)
}
}
log.Println("[SEED] Seed de Statuspage completado.")
}
// SeedPlantillasBase crea una plantilla mínima y la regla de pago_recibido si no existen.
// Es idempotente — no sobreescribe registros existentes.
func SeedPlantillasBase() {
db := app.Http.Database.DB
plantillasBase := []struct {
nombre string
asunto string
tipo string
cuerpo string
}{
{
nombre: "Pago recibido (base)",
asunto: "Pago recibido — gracias por tu pago",
tipo: "pago",
cuerpo: `<!DOCTYPE html><html><body style="font-family:sans-serif;color:#333;max-width:600px;margin:auto;padding:24px">
<h2 style="color:#5a7d2b">Pago recibido ✔</h2>
<p>Hola <strong>{{.ClienteNombre}}</strong>,</p>
<p>Hemos recibido y confirmado tu pago. Tu servicio ha sido renovado correctamente.</p>
<table style="width:100%;border-collapse:collapse;margin:16px 0">
{{range .Servicios}}
<tr style="border-bottom:1px solid #eee">
<td style="padding:8px">{{.Nombre}}</td>
<td style="padding:8px;text-align:right">{{.Moneda}} {{.Precio}}</td>
<td style="padding:8px;text-align:right;color:#888">Vence: {{.FechaVenc}}</td>
</tr>
{{end}}
</table>
<p style="font-size:13px;color:#888">Si tienes alguna pregunta, responde a este correo.</p>
</body></html>`,
},
{
nombre: "Bienvenida (base)",
asunto: "Bienvenido — tu servicio está activo",
tipo: "bienvenida",
cuerpo: `<!DOCTYPE html><html><body style="font-family:sans-serif;color:#333;max-width:600px;margin:auto;padding:24px">
<h2 style="color:#5a7d2b">¡Bienvenido!</h2>
<p>Hola <strong>{{.ClienteNombre}}</strong>,</p>
<p>Tu servicio ha sido activado. A continuación el detalle:</p>
<table style="width:100%;border-collapse:collapse;margin:16px 0">
{{range .Servicios}}
<tr style="border-bottom:1px solid #eee">
<td style="padding:8px">{{.Nombre}}</td>
<td style="padding:8px;text-align:right">{{.Moneda}} {{.Precio}}</td>
<td style="padding:8px;text-align:right;color:#888">Vence: {{.FechaVenc}}</td>
</tr>
{{end}}
</table>
<p style="font-size:13px;color:#888">Gracias por elegirnos.</p>
</body></html>`,
},
}
for _, p := range plantillasBase {
var existing models.PlantillaCorreo
if err := db.Where("nombre = ?", p.nombre).First(&existing).Error; err != nil {
nueva := models.PlantillaCorreo{
Nombre: p.nombre,
Asunto: p.asunto,
Tipo: p.tipo,
CuerpoHTML: p.cuerpo,
}
if err := db.Create(&nueva).Error; err != nil {
log.Printf("[SEED] Error creando plantilla '%s': %v", p.nombre, err)
continue
}
log.Printf("[SEED] Plantilla '%s' creada (ID %d)", p.nombre, nueva.ID)
} else {
log.Printf("[SEED] Plantilla '%s' ya existe (ID %d)", existing.Nombre, existing.ID)
}
}
// Crear regla pago_recibido si no existe
var reglaExistente models.NotificacionRegla
if err := db.Where("tipo_evento = ?", "pago_recibido").First(&reglaExistente).Error; err != nil {
// Buscar la plantilla de pago
var plantilla models.PlantillaCorreo
if err2 := db.Where("tipo = ?", "pago").First(&plantilla).Error; err2 != nil {
log.Printf("[SEED] No se encontró plantilla de tipo 'pago' para crear regla pago_recibido")
return
}
regla := models.NotificacionRegla{
Nombre: "Confirmación de pago",
TipoEvento: "pago_recibido",
PlantillaID: plantilla.ID,
Activo: true,
AplicaA: "todos",
PasarelaEnlace: "ninguna",
}
if err := db.Create(&regla).Error; err != nil {
log.Printf("[SEED] Error creando regla pago_recibido: %v", err)
} else {
log.Printf("[SEED] Regla 'pago_recibido' creada (ID %d) con plantilla ID %d", regla.ID, plantilla.ID)
}
} else {
log.Printf("[SEED] Regla 'pago_recibido' ya existe (ID %d)", reglaExistente.ID)
}
log.Println("[SEED] SeedPlantillasBase completado.")
}
// MigrateRenovaciones crea/actualiza las tablas del módulo de Renovaciones.
// Es idempotente: GORM AutoMigrate solo añade columnas/tablas nuevas, nunca las borra.
func MigrateRenovaciones() {
db := app.Http.Database.DB
if err := db.AutoMigrate(
&models.Servicio{},
&models.Cliente{},
&models.PlantillaCorreo{},
&models.NotificacionRegla{},
&models.Contrato{}, // incluye columnas enlace_pago y enlace_pago_link_id
&models.NotificacionLog{},
&models.SmtpConfig{},
); err != nil {
log.Printf("[MIGRATE] Error en MigrateRenovaciones: %v", err)
} else {
log.Println("[MIGRATE] Tablas de Renovaciones OK")
}
}
// SeedRenovaciones inserta el módulo "Renovaciones" y sus submódulos si no existen,
// y los asigna a todos los roles presentes en la BD.
func SeedRenovaciones() {
db := app.Http.Database.DB
// 1. Crear/obtener módulo
var modulo models.Modules
result := db.Where("title = ?", "Renovaciones").First(&modulo)
if result.Error != nil {
modulo = models.Modules{
Title: "Renovaciones",
Description: "Gestión de contratos, clientes y notificaciones de vencimiento",
ModifiedAt: time.Now(),
}
if err := db.Create(&modulo).Error; err != nil {
log.Printf("[SEED] Error creando módulo Renovaciones: %v", err)
return
}
log.Printf("[SEED] Módulo 'Renovaciones' creado con ID %d", modulo.ID)
} else {
log.Printf("[SEED] Módulo 'Renovaciones' ya existe (ID %d)", modulo.ID)
}
// 2. Definir submódulos
entries := []struct{ title, desc, url string }{
{"Contratos", "Gestión de contratos y vencimientos", "/app/contratos"},
{"Clientes", "Clientes y datos de contacto", "/app/clientes"},
{"Servicios", "Catálogo de servicios", "/app/servicios"},
{"Plantillas Correo", "Editor de plantillas de correo", "/app/plantillas-correo"},
{"Reglas de Aviso", "Reglas de notificación automática", "/app/reglas-notificacion"},
{"Historial Notif.", "Historial de correos enviados", "/app/historial-notificaciones"},
{"Config. SMTP", "Configuración del servidor de correo", "/app/smtp-config"},
}
var insertados []models.Submodules
for _, e := range entries {
var sub models.Submodules
if err := db.Where("url = ?", e.url).First(&sub).Error; err != nil {
sub = models.Submodules{
Title: e.title,
Description: e.desc,
Url: e.url,
ModuleId: modulo.ID,
ModifiedAt: time.Now(),
}
if err := db.Create(&sub).Error; err != nil {
log.Printf("[SEED] Error creando submódulo '%s': %v", e.title, err)
continue
}
log.Printf("[SEED] Submódulo '%s' creado (ID %d)", e.title, sub.ID)
} else {
// Asegurar que el submódulo apunte al módulo correcto (Renovaciones)
if sub.ModuleId != modulo.ID {
if err := db.Model(&sub).Update("module_id", modulo.ID).Error; err != nil {
log.Printf("[SEED] Error actualizando module_id de '%s': %v", sub.Title, err)
} else {
log.Printf("[SEED] Submódulo '%s' reasignado a módulo Renovaciones", sub.Title)
}
} else {
log.Printf("[SEED] Submódulo '%s' ya existe (ID %d)", sub.Title, sub.ID)
}
}
insertados = append(insertados, sub)
}
// 3. Asignar a todos los roles existentes
var roles []models.Roles
if err := db.Find(&roles).Error; err != nil {
log.Printf("[SEED] Error obteniendo roles: %v", err)
return
}
for _, rol := range roles {
if err := db.Model(&rol).Association("Submodules").Append(&insertados); err != nil {
log.Printf("[SEED] Error asignando submódulos al rol '%s': %v", rol.Name, err)
} else {
log.Printf("[SEED] Submódulos de Renovaciones asignados al rol '%s'", rol.Name)
}
}
log.Println("[SEED] Seed de Renovaciones completado.")
}
// SeedIntegraciones crea el módulo "Integraciones" con los submódulos
// de Hostinger y Cloudflare, y los asigna a todos los roles existentes.
// Es idempotente: si el registro ya existe (por URL) lo reutiliza sin duplicar.
func SeedIntegraciones() {
db := app.Http.Database.DB
// 1. Crear/obtener módulo
var modulo models.Modules
if err := db.Where("title = ?", "Integraciones").First(&modulo).Error; err != nil {
modulo = models.Modules{
Title: "Integraciones",
Description: "Conexión con servicios externos: Hostinger, Cloudflare y más",
ModifiedAt: time.Now(),
}
if err := db.Create(&modulo).Error; err != nil {
log.Printf("[SEED] Error creando módulo Integraciones: %v", err)
return
}
log.Printf("[SEED] Módulo 'Integraciones' creado con ID %d", modulo.ID)
} else {
log.Printf("[SEED] Módulo 'Integraciones' ya existe (ID %d)", modulo.ID)
}
// 2. Definir submódulos
entries := []struct{ title, desc, url string }{
{"Hostinger", "Panel de VPS, dominios, hosting y DNS de Hostinger", "/app/hostinger"},
{"Cloudflare", "Gestión de zonas, DNS, SSL y firewall en Cloudflare", "/app/cloudflare"},
}
var insertados []models.Submodules
for _, e := range entries {
var sub models.Submodules
if err := db.Where("url = ?", e.url).First(&sub).Error; err != nil {
sub = models.Submodules{
Title: e.title,
Description: e.desc,
Url: e.url,
ModuleId: modulo.ID,
ModifiedAt: time.Now(),
}
if err := db.Create(&sub).Error; err != nil {
log.Printf("[SEED] Error creando submódulo '%s': %v", e.title, err)
continue
}
log.Printf("[SEED] Submódulo '%s' creado (ID %d)", e.title, sub.ID)
} else {
if sub.ModuleId != modulo.ID {
if err := db.Model(&sub).Update("module_id", modulo.ID).Error; err != nil {
log.Printf("[SEED] Error actualizando module_id de '%s': %v", sub.Title, err)
} else {
log.Printf("[SEED] Submódulo '%s' reasignado a módulo Integraciones", sub.Title)
}
} else {
log.Printf("[SEED] Submódulo '%s' ya existe (ID %d)", sub.Title, sub.ID)
}
}
insertados = append(insertados, sub)
}
// 3. Asignar a todos los roles existentes
var roles []models.Roles
if err := db.Find(&roles).Error; err != nil {
log.Printf("[SEED] Error obteniendo roles: %v", err)
return
}
for _, rol := range roles {
if err := db.Model(&rol).Association("Submodules").Append(&insertados); err != nil {
log.Printf("[SEED] Error asignando submódulos al rol '%s': %v", rol.Name, err)
} else {
log.Printf("[SEED] Submódulos de Integraciones asignados al rol '%s'", rol.Name)
}
}
log.Println("[SEED] Seed de Integraciones completado.")
}
// SeedPasarelas agrega el submódulo "Pasarelas de Pago" al módulo "Integraciones"
// y lo asigna a todos los roles. Es idempotente.
func SeedPasarelas() {
db := app.Http.Database.DB
// Obtener el módulo "Integraciones" (debe existir luego de SeedIntegraciones)
var modulo models.Modules
if err := db.Where("title = ?", "Integraciones").First(&modulo).Error; err != nil {
log.Printf("[SEED] Módulo 'Integraciones' no encontrado para SeedPasarelas: %v", err)
return
}
entries := []struct{ title, desc, url string }{
{"Pasarelas de Pago", "Configuración de Bold, dLocal y otras pasarelas", "/app/pasarelas-pago"},
}
var insertados []models.Submodules
for _, e := range entries {
var sub models.Submodules
if err := db.Where("url = ?", e.url).First(&sub).Error; err != nil {
sub = models.Submodules{
Title: e.title,
Description: e.desc,
Url: e.url,
ModuleId: modulo.ID,
ModifiedAt: time.Now(),
}
if err := db.Create(&sub).Error; err != nil {
log.Printf("[SEED] Error creando submódulo '%s': %v", e.title, err)
continue
}
log.Printf("[SEED] Submódulo '%s' creado (ID %d)", e.title, sub.ID)
} else {
log.Printf("[SEED] Submódulo '%s' ya existe (ID %d)", sub.Title, sub.ID)
}
insertados = append(insertados, sub)
}
var roles []models.Roles
if err := db.Find(&roles).Error; err != nil {
log.Printf("[SEED] Error obteniendo roles: %v", err)
return
}
for _, rol := range roles {
if err := db.Model(&rol).Association("Submodules").Append(&insertados); err != nil {
log.Printf("[SEED] Error asignando submódulos al rol '%s': %v", rol.Name, err)
} else {
log.Printf("[SEED] Submódulo Pasarelas asignado al rol '%s'", rol.Name)
}
}
log.Println("[SEED] Seed de Pasarelas completado.")
}
// SeedServidores crea el módulo "Servidores" con los submódulos de gestión
// de servidores, conexiones SSH/DB, tipos y el Query Runner. Es idempotente.
func SeedServidores() {
db := app.Http.Database.DB
// 1. Crear/obtener módulo
var modulo models.Modules
if err := db.Where("title = ?", "Servidores").First(&modulo).Error; err != nil {
modulo = models.Modules{
Title: "Servidores",
Description: "Gestión de servidores, conexiones de base de datos y Query Runner",
ModifiedAt: time.Now(),
}
if err := db.Create(&modulo).Error; err != nil {
log.Printf("[SEED] Error creando módulo Servidores: %v", err)
return
}
log.Printf("[SEED] Módulo 'Servidores' creado con ID %d", modulo.ID)
} else {
log.Printf("[SEED] Módulo 'Servidores' ya existe (ID %d)", modulo.ID)
}
// 2. Definir submódulos
entries := []struct{ title, desc, url string }{
{"Servidores", "Lista y gestión de servidores registrados", "/app/servidor"},
{"Conexión DB", "Conexiones de base de datos a servidores", "/app/conexion_db"},
{"Conexión SSH", "Conexiones SSH a servidores", "/app/conexion_ssh"},
{"Tipo DB", "Catálogo de tipos de base de datos", "/app/tipo_db"},
{"Tipo Servidor", "Catálogo de tipos de servidor", "/app/tipo_servidor"},
{"Proveedor Servidor", "Catálogo de proveedores de servidor", "/app/prov_servidor"},
{"Query Runner", "Editor SQL con historial y exportación", "/app/query-runner"},
}
var insertados []models.Submodules
for _, e := range entries {
var sub models.Submodules
if err := db.Where("url = ?", e.url).First(&sub).Error; err != nil {
sub = models.Submodules{
Title: e.title,
Description: e.desc,
Url: e.url,
ModuleId: modulo.ID,
ModifiedAt: time.Now(),
}
if err := db.Create(&sub).Error; err != nil {
log.Printf("[SEED] Error creando submódulo '%s': %v", e.title, err)
continue
}
log.Printf("[SEED] Submódulo '%s' creado (ID %d)", e.title, sub.ID)
} else {
if sub.ModuleId != modulo.ID {
db.Model(&sub).Update("module_id", modulo.ID)
log.Printf("[SEED] Submódulo '%s' reasignado a módulo Servidores", sub.Title)
} else {
log.Printf("[SEED] Submódulo '%s' ya existe (ID %d)", sub.Title, sub.ID)
}
}
insertados = append(insertados, sub)
}
// 3. Asignar a todos los roles existentes
var roles []models.Roles
if err := db.Find(&roles).Error; err != nil {
log.Printf("[SEED] Error obteniendo roles: %v", err)
return
}
for _, rol := range roles {
if err := db.Model(&rol).Association("Submodules").Append(&insertados); err != nil {
log.Printf("[SEED] Error asignando submódulos al rol '%s': %v", rol.Name, err)
} else {
log.Printf("[SEED] Submódulos de Servidores asignados al rol '%s'", rol.Name)
}
}
log.Println("[SEED] Seed de Servidores completado.")
}
// SeedAdministracion crea el módulo "Administración" con sus submódulos
// (Roles, Módulos, Submódulos, Usuarios) y los asigna a todos los roles. Es idempotente.
func SeedAdministracion() {
db := app.Http.Database.DB
var modulo models.Modules
if err := db.Where("title = ?", "Administración").First(&modulo).Error; err != nil {
modulo = models.Modules{
Title: "Administración",
Description: "Gestión de usuarios, roles, módulos y permisos del sistema",
ModifiedAt: time.Now(),
}
if err := db.Create(&modulo).Error; err != nil {
log.Printf("[SEED] Error creando módulo Administración: %v", err)
return
}
log.Printf("[SEED] Módulo 'Administración' creado con ID %d", modulo.ID)
} else {
log.Printf("[SEED] Módulo 'Administración' ya existe (ID %d)", modulo.ID)
}
entries := []struct{ title, desc, url string }{
{"Roles", "Gestión de roles y permisos", "/app/roles"},
{"Módulos", "Gestión de módulos del menú lateral", "/app/modules"},
{"Submódulos", "Gestión de submódulos y URLs", "/app/submodules"},
{"Usuarios", "Gestión de usuarios del sistema", "/app/users"},
}
var insertados []models.Submodules
for _, e := range entries {
var sub models.Submodules
if err := db.Where("url = ?", e.url).First(&sub).Error; err != nil {
sub = models.Submodules{
Title: e.title,
Description: e.desc,
Url: e.url,
ModuleId: modulo.ID,
ModifiedAt: time.Now(),
}
if err := db.Create(&sub).Error; err != nil {
log.Printf("[SEED] Error creando submódulo '%s': %v", e.title, err)
continue
}
log.Printf("[SEED] Submódulo '%s' creado (ID %d)", e.title, sub.ID)
} else {
if sub.ModuleId != modulo.ID {
db.Model(&sub).Update("module_id", modulo.ID)
log.Printf("[SEED] Submódulo '%s' reasignado a módulo Administración", sub.Title)
} else {
log.Printf("[SEED] Submódulo '%s' ya existe (ID %d)", sub.Title, sub.ID)
}
}
insertados = append(insertados, sub)
}
var roles []models.Roles
if err := db.Find(&roles).Error; err != nil {
log.Printf("[SEED] Error obteniendo roles: %v", err)
return
}
for _, rol := range roles {
if err := db.Model(&rol).Association("Submodules").Append(&insertados); err != nil {
log.Printf("[SEED] Error asignando submódulos al rol '%s': %v", rol.Name, err)
} else {
log.Printf("[SEED] Submódulos de Administración asignados al rol '%s'", rol.Name)
}
}
log.Println("[SEED] Seed de Administración completado.")
}
// SeedSaas agrega los submódulos de gestión de productos SaaS e integraciones
// de pago al módulo "Integraciones" ya existente. Es idempotente.
func SeedSaas() {
db := app.Http.Database.DB
// Reutilizar el módulo "Integraciones" (creado por SeedIntegraciones)
var modulo models.Modules
if err := db.Where("title = ?", "Integraciones").First(&modulo).Error; err != nil {
log.Printf("[SEED] Módulo 'Integraciones' no encontrado para SeedSaas: %v", err)
return
}
entries := []struct{ title, desc, url string }{
{"Productos SaaS", "Gestión de productos SaaS y su documentación asociada", "/app/saas"},
{"Integraciones SaaS", "Callbacks de pago hacia APIs externas y logs de despacho", "/app/saas-api"},
}
var insertados []models.Submodules
for _, e := range entries {
var sub models.Submodules
if err := db.Where("url = ?", e.url).First(&sub).Error; err != nil {
sub = models.Submodules{
Title: e.title,
Description: e.desc,
Url: e.url,
ModuleId: modulo.ID,
ModifiedAt: time.Now(),
}
if err := db.Create(&sub).Error; err != nil {
log.Printf("[SEED] Error creando submódulo '%s': %v", e.title, err)
continue
}
log.Printf("[SEED] Submódulo '%s' creado (ID %d)", e.title, sub.ID)
} else {
log.Printf("[SEED] Submódulo '%s' ya existe (ID %d)", sub.Title, sub.ID)
}
insertados = append(insertados, sub)
}
var roles []models.Roles
if err := db.Find(&roles).Error; err != nil {
log.Printf("[SEED] Error obteniendo roles: %v", err)
return
}
for _, rol := range roles {
if err := db.Model(&rol).Association("Submodules").Append(&insertados); err != nil {
log.Printf("[SEED] Error asignando submódulos SaaS al rol '%s': %v", rol.Name, err)
} else {
log.Printf("[SEED] Submódulos SaaS asignados al rol '%s'", rol.Name)
}
}
log.Println("[SEED] Seed de SaaS completado.")
}