introduced central package registry by package init function

This commit is contained in:
2026-03-16 16:36:47 +01:00
parent 261a6294cb
commit 4f5029e656
22 changed files with 622 additions and 91 deletions
+14
View File
@@ -0,0 +1,14 @@
package appsystem
import "bamort/registry"
// init self-registers the appsystem module with the central registry.
// main.go blank-imports this package to trigger this function.
func init() {
// Protected API routes (/api/version, /api/systeminfo).
registry.RegisterRoutes(RegisterRoutes)
// Public routes (/api/public/version, /api/public/systeminfo).
registry.RegisterPublicRoutes(RegisterPublicRoutes)
//registry.RegisterMigration(MigrateStructure)
}
+14
View File
@@ -0,0 +1,14 @@
package character
import "bamort/registry"
// init self-registers the character module with the central registry.
// main.go blank-imports this package to trigger this function.
func init() {
// Protected API routes (/api/version, /api/systeminfo).
registry.RegisterRoutes(RegisterRoutes)
// Public routes (/api/public/version, /api/public/systeminfo).
registry.RegisterPublicRoutes(RegisterPublicRoutes)
//registry.RegisterMigration(MigrateStructure)
}
+5
View File
@@ -88,3 +88,8 @@ func RegisterRoutes(r *gin.RouterGroup) {
charGrp.POST("/calculate-static-fields", CalculateStaticFields) // Berechnung ohne Würfelwürfe
charGrp.POST("/calculate-rolled-field", CalculateRolledField) // Berechnung mit Würfelwürfen
}
// RegisterPublicRoutes registers public config routes (no auth required)
func RegisterPublicRoutes(r *gin.Engine) {
// Public version endpoint - no authentication required
}
+35 -22
View File
@@ -1,19 +1,21 @@
package main
import (
"bamort/appsystem"
"bamort/character"
_ "bamort/appsystem"
_ "bamort/character"
"bamort/config"
"bamort/database"
"bamort/equipment"
"bamort/gsmaster"
"bamort/importer"
_ "bamort/equipment"
_ "bamort/gsmaster"
_ "bamort/importer"
"bamort/logger"
"bamort/maintenance"
_ "bamort/maintenance"
"bamort/pdfrender"
_ "bamort/pdfrender"
"bamort/registry"
"bamort/router"
"bamort/transfer"
"bamort/user"
_ "bamort/transfer"
_ "bamort/user"
"github.com/gin-gonic/gin"
)
@@ -81,26 +83,37 @@ func main() {
r := gin.Default()
router.SetupGin(r)
// Routes registrieren
// Routes registrieren (alle Module via registry)
logger.Debug("Registriere API-Routen...")
protected := router.BaseRouterGrp(r)
// Register your module routes
user.RegisterRoutes(protected)
gsmaster.RegisterRoutes(protected)
character.RegisterRoutes(protected)
equipment.RegisterRoutes(protected)
maintenance.RegisterRoutes(protected)
importer.RegisterRoutes(protected)
pdfrender.RegisterRoutes(protected)
transfer.RegisterRoutes(protected)
appsystem.RegisterRoutes(protected)
registry.RunAllRoutes(protected)
// Register public routes (no authentication)
pdfrender.RegisterPublicRoutes(r)
appsystem.RegisterPublicRoutes(r)
// Öffentliche Routen registrieren
registry.RunAllPublicRoutes(r)
logger.Info("API-Routen erfolgreich registriert")
/*
// Routes registrieren
logger.Debug("Registriere API-Routen...")
protected := router.BaseRouterGrp(r)
// Register your module routes
user.RegisterRoutes(protected)
gsmaster.RegisterRoutes(protected)
character.RegisterRoutes(protected)
equipment.RegisterRoutes(protected)
maintenance.RegisterRoutes(protected)
importer.RegisterRoutes(protected)
pdfrender.RegisterRoutes(protected)
transfer.RegisterRoutes(protected)
appsystem.RegisterRoutes(protected)
// Register public routes (no authentication)
pdfrender.RegisterPublicRoutes(r)
appsystem.RegisterPublicRoutes(r)
*/
logger.Info("API-Routen erfolgreich registriert")
// Server starten
serverAddress := cfg.GetServerAddress()
logger.Info("Server startet auf Adresse: %s", serverAddress)
+14
View File
@@ -0,0 +1,14 @@
package database
import "bamort/registry"
// init self-registers the character module with the central registry.
// main.go blank-imports this package to trigger this function.
func init() {
// Protected API routes (/api/version, /api/systeminfo).
registry.RegisterRoutes(RegisterRoutes)
// Public routes (/api/public/version, /api/public/systeminfo).
registry.RegisterPublicRoutes(RegisterPublicRoutes)
registry.RegisterMigration(MigrateStructure)
}
+15
View File
@@ -0,0 +1,15 @@
package database
import (
"github.com/gin-gonic/gin"
)
func RegisterRoutes(r *gin.RouterGroup) {
route := r.Group("/database")
route.GET("/setupcheck", SetupCheck)
}
// RegisterPublicRoutes registers public config routes (no auth required)
func RegisterPublicRoutes(r *gin.Engine) {
// Public version endpoint - no authentication required
}
+14
View File
@@ -0,0 +1,14 @@
package equipment
import "bamort/registry"
// init self-registers the character module with the central registry.
// main.go blank-imports this package to trigger this function.
func init() {
// Protected API routes (/api/version, /api/systeminfo).
registry.RegisterRoutes(RegisterRoutes)
// Public routes (/api/public/version, /api/public/systeminfo).
registry.RegisterPublicRoutes(RegisterPublicRoutes)
//registry.RegisterMigration(MigrateStructure)
}
+5
View File
@@ -19,3 +19,8 @@ func RegisterRoutes(r *gin.RouterGroup) {
weaponGrp.PUT("/:waffe_id", UpdateWaffe)
weaponGrp.DELETE("/:waffe_id", DeleteWaffe)
}
// RegisterPublicRoutes registers public config routes (no auth required)
func RegisterPublicRoutes(r *gin.Engine) {
// Public version endpoint - no authentication required
}
+14
View File
@@ -0,0 +1,14 @@
package gamesystem
import "bamort/registry"
// init self-registers the character module with the central registry.
// main.go blank-imports this package to trigger this function.
func init() {
// Protected API routes (/api/version, /api/systeminfo).
registry.RegisterRoutes(RegisterRoutes)
// Public routes (/api/public/version, /api/public/systeminfo).
registry.RegisterPublicRoutes(RegisterPublicRoutes)
registry.RegisterMigration(MigrateStructure)
}
+15
View File
@@ -0,0 +1,15 @@
package gamesystem
import (
"github.com/gin-gonic/gin"
)
func RegisterRoutes(r *gin.RouterGroup) {
//route := r.Group("/database")
//route.GET("/setupcheck", SetupCheck)
}
// RegisterPublicRoutes registers public config routes (no auth required)
func RegisterPublicRoutes(r *gin.Engine) {
// Public version endpoint - no authentication required
}
+14
View File
@@ -0,0 +1,14 @@
package gsmaster
import "bamort/registry"
// init self-registers the character module with the central registry.
// main.go blank-imports this package to trigger this function.
func init() {
// Protected API routes (/api/version, /api/systeminfo).
registry.RegisterRoutes(RegisterRoutes)
// Public routes (/api/public/version, /api/public/systeminfo).
registry.RegisterPublicRoutes(RegisterPublicRoutes)
//registry.RegisterMigration(MigrateStructure)
}
+7 -54
View File
@@ -1,62 +1,15 @@
package gsmaster
import (
"bamort/user"
"github.com/gin-gonic/gin"
)
func RegisterRoutes(r *gin.RouterGroup) {
maintGrp := r.Group("/maintenance")
maintGrp.GET("", GetMasterData)
maintGrp.GET("/skills", GetMDSkills)
maintGrp.GET("/skills-enhanced", GetEnhancedMDSkills) // New enhanced endpoint
maintGrp.GET("/skills/:id", GetMDSkill)
maintGrp.GET("/skills-enhanced/:id", GetEnhancedMDSkill) // New enhanced endpoint
maintGrp.GET("/weaponskills", GetMDWeaponSkills)
maintGrp.GET("/weaponskills-enhanced", GetEnhancedMDWeaponSkills) // New enhanced endpoint
maintGrp.GET("/weaponskills/:id", GetMDWeaponSkill)
maintGrp.GET("/weaponskills-enhanced/:id", GetEnhancedMDWeaponSkill) // New enhanced endpoint
maintGrp.GET("/spells", GetMDSpells)
maintGrp.GET("/spells-enhanced", GetEnhancedMDSpells) // New enhanced endpoint
maintGrp.GET("/spells/:id", GetMDSpell)
maintGrp.GET("/spells-enhanced/:id", GetEnhancedMDSpell) // New enhanced endpoint
maintGrp.GET("/equipment", GetMDEquipments)
maintGrp.GET("/equipment-enhanced", GetEnhancedMDEquipment) // New enhanced endpoint
maintGrp.GET("/equipment/:id", GetMDEquipment)
maintGrp.GET("/equipment-enhanced/:id", GetEnhancedMDEquipmentItem) // New enhanced endpoint
maintGrp.GET("/weapons", GetMDWeapons)
maintGrp.GET("/weapons-enhanced", GetEnhancedMDWeapons) // New enhanced endpoint
maintGrp.GET("/weapons/:id", GetMDWeapon)
maintGrp.GET("/weapons-enhanced/:id", GetEnhancedMDWeapon) // New enhanced endpoint
maintGrp.Use(user.RequireMaintainer())
{
maintGrp.POST("/skills-enhanced", CreateEnhancedMDSkill) // Create new skill
maintGrp.PUT("/skills/:id", UpdateMDSkill)
maintGrp.PUT("/skills-enhanced/:id", UpdateEnhancedMDSkill) // New enhanced endpoint
maintGrp.POST("/skills", AddSkill)
maintGrp.DELETE("/skills/:id", DeleteMDSkill)
maintGrp.PUT("/weaponskills/:id", UpdateMDWeaponSkill)
maintGrp.PUT("/weaponskills-enhanced/:id", UpdateEnhancedMDWeaponSkill) // New enhanced endpoint
maintGrp.POST("/weaponskills", AddWeaponSkill)
maintGrp.DELETE("/weaponskills/:id", DeleteMDWeaponSkill)
maintGrp.PUT("/spells/:id", UpdateMDSpell)
maintGrp.PUT("/spells-enhanced/:id", UpdateEnhancedMDSpell) // New enhanced endpoint
maintGrp.POST("/spells", AddSpell)
maintGrp.DELETE("/spells/:id", DeleteMDSpell)
maintGrp.PUT("/equipment/:id", UpdateMDEquipment)
maintGrp.PUT("/equipment-enhanced/:id", UpdateEnhancedMDEquipmentItem) // New enhanced endpoint
maintGrp.POST("/equipment", AddEquipment)
maintGrp.DELETE("/equipment/:id", DeleteMDEquipment)
maintGrp.PUT("/weapons/:id", UpdateMDWeapon)
maintGrp.PUT("/weapons-enhanced/:id", UpdateEnhancedMDWeapon) // New enhanced endpoint
maintGrp.POST("/weapons", AddWeapon)
maintGrp.DELETE("/weapons/:id", DeleteMDWeapon)
}
//route := r.Group("/database")
//route.GET("/setupcheck", SetupCheck)
}
// RegisterPublicRoutes registers public config routes (no auth required)
func RegisterPublicRoutes(r *gin.Engine) {
// Public version endpoint - no authentication required
}
+13
View File
@@ -0,0 +1,13 @@
package importer
import "bamort/registry"
// init self-registers the character module with the central registry.
// main.go blank-imports this package to trigger this function.
func init() {
// Protected API routes (/api/version, /api/systeminfo).
registry.RegisterRoutes(RegisterRoutes)
// Public routes (/api/public/version, /api/public/systeminfo).
registry.RegisterPublicRoutes(RegisterPublicRoutes)
}
+5
View File
@@ -18,3 +18,8 @@ func RegisterRoutes(r *gin.RouterGroup) {
exportGrp.GET("/csv/:id", ExportCharacterCSVHandler)
exportGrp.GET("/spells/csv", ExportSpellsCSVHandler)
}
// RegisterPublicRoutes registers public config routes (no auth required)
func RegisterPublicRoutes(r *gin.Engine) {
// Public version endpoint - no authentication required
}
+14
View File
@@ -0,0 +1,14 @@
package maintenance
import "bamort/registry"
// init self-registers the maintenance module with the central registry.
// main.go blank-imports this package to trigger this function.
func init() {
// Protected API routes (/api/version, /api/systeminfo).
registry.RegisterRoutes(RegisterRoutes)
// Public routes (/api/public/version, /api/public/systeminfo).
registry.RegisterPublicRoutes(RegisterPublicRoutes)
//registry.RegisterMigration(MigrateStructure)
}
+5
View File
@@ -35,3 +35,8 @@ func RegisterRoutes(r *gin.RouterGroup) {
*/
}
}
// RegisterPublicRoutes registers public config routes (no auth required)
func RegisterPublicRoutes(r *gin.Engine) {
// Public version endpoint - no authentication required
}
+14
View File
@@ -0,0 +1,14 @@
package models
import "bamort/registry"
// init self-registers the character module with the central registry.
// main.go blank-imports this package to trigger this function.
func init() {
// Protected API routes (/api/version, /api/systeminfo).
//registry.RegisterRoutes(RegisterRoutes)
// Public routes (/api/public/version, /api/public/systeminfo).
//registry.RegisterPublicRoutes(RegisterPublicRoutes)
registry.RegisterMigration(MigrateStructure)
}
+14
View File
@@ -0,0 +1,14 @@
package pdfrender
import "bamort/registry"
// init self-registers the character module with the central registry.
// main.go blank-imports this package to trigger this function.
func init() {
// Protected API routes (/api/version, /api/systeminfo).
registry.RegisterRoutes(RegisterRoutes)
// Public routes (/api/public/version, /api/public/systeminfo).
registry.RegisterPublicRoutes(RegisterPublicRoutes)
//registry.RegisterMigration(MigrateStructure)
}
+101
View File
@@ -0,0 +1,101 @@
// Package registry provides a central module self-registration mechanism.
// Modules register their routes and migrations via init() functions,
// keeping each module self-contained without direct cross-module imports.
// main.go blank-imports each module to trigger its init() and then calls
// the Run* helpers here to wire everything together.
package registry
import (
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
// MigrateFunc is a function that runs database migrations for a module.
type MigrateFunc func(db ...*gorm.DB) error
// RouteFunc registers protected routes on an API router group.
type RouteFunc func(r *gin.RouterGroup)
// PublicRouteFunc registers public routes directly on the gin engine.
type PublicRouteFunc func(r *gin.Engine)
// BaseRouteFunc registers base routes (login, register, etc.) on the gin engine.
type BaseRouteFunc func(r *gin.Engine)
// AuthMiddlewareProvider returns a gin.HandlerFunc used for JWT authentication.
type AuthMiddlewareProvider func() gin.HandlerFunc
var (
routeFuncs []RouteFunc
publicRouteFuncs []PublicRouteFunc
baseRouteFuncs []BaseRouteFunc
migrateFuncs []MigrateFunc
authProvider AuthMiddlewareProvider
)
// RegisterRoutes adds a module's protected route registrar to the registry.
func RegisterRoutes(fn RouteFunc) {
routeFuncs = append(routeFuncs, fn)
}
// RegisterPublicRoutes adds a module's public route registrar to the registry.
func RegisterPublicRoutes(fn PublicRouteFunc) {
publicRouteFuncs = append(publicRouteFuncs, fn)
}
// RegisterBaseRoutes adds a module's unauthenticated base route registrar
// (e.g. login, register, password-reset) to the registry.
func RegisterBaseRoutes(fn BaseRouteFunc) {
baseRouteFuncs = append(baseRouteFuncs, fn)
}
// RegisterMigration adds a module's migration function to the registry.
func RegisterMigration(fn MigrateFunc) {
migrateFuncs = append(migrateFuncs, fn)
}
// SetAuthMiddleware sets the authentication middleware provider.
// Only one module (user) should call this.
func SetAuthMiddleware(fn AuthMiddlewareProvider) {
authProvider = fn
}
// GetAuthMiddleware returns the registered auth middleware handler.
// Falls back to a no-op pass-through when none has been registered.
func GetAuthMiddleware() gin.HandlerFunc {
if authProvider != nil {
return authProvider()
}
return func(c *gin.Context) { c.Next() }
}
// RunAllBaseRoutes calls all registered base route functions on the engine.
func RunAllBaseRoutes(r *gin.Engine) {
for _, fn := range baseRouteFuncs {
fn(r)
}
}
// RunAllRoutes calls all registered protected route functions on the router group.
func RunAllRoutes(r *gin.RouterGroup) {
for _, fn := range routeFuncs {
fn(r)
}
}
// RunAllPublicRoutes calls all registered public route functions on the engine.
func RunAllPublicRoutes(r *gin.Engine) {
for _, fn := range publicRouteFuncs {
fn(r)
}
}
// RunAllMigrations runs every registered migration function with the provided DB.
func RunAllMigrations(db *gorm.DB) error {
for _, fn := range migrateFuncs {
if err := fn(db); err != nil {
return err
}
}
return nil
}
+277
View File
@@ -0,0 +1,277 @@
package registry
import (
"errors"
"net/http"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
// resetRegistry clears all registered functions so each test starts with a
// clean slate. Only callable from within the registry package (_test.go).
func resetRegistry() {
routeFuncs = nil
publicRouteFuncs = nil
baseRouteFuncs = nil
migrateFuncs = nil
authProvider = nil
}
func newTestEngine() *gin.Engine {
gin.SetMode(gin.TestMode)
return gin.New()
}
func newTestDB(t *testing.T) *gorm.DB {
t.Helper()
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
require.NoError(t, err)
return db
}
// ---------------------------------------------------------------------------
// RegisterRoutes / RunAllRoutes
// ---------------------------------------------------------------------------
func TestRegisterRoutes_SingleFunc_IsCalled(t *testing.T) {
resetRegistry()
called := false
RegisterRoutes(func(r *gin.RouterGroup) {
called = true
r.GET("/ping", func(c *gin.Context) { c.Status(http.StatusOK) })
})
engine := newTestEngine()
RunAllRoutes(engine.Group("/api"))
assert.True(t, called)
w := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodGet, "/api/ping", nil)
engine.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
}
func TestRegisterRoutes_MultipleFuncs_AllCalled(t *testing.T) {
resetRegistry()
count := 0
for i := 0; i < 3; i++ {
RegisterRoutes(func(r *gin.RouterGroup) { count++ })
}
RunAllRoutes(newTestEngine().Group("/api"))
assert.Equal(t, 3, count)
}
func TestRunAllRoutes_NoFuncs_DoesNotPanic(t *testing.T) {
resetRegistry()
assert.NotPanics(t, func() { RunAllRoutes(newTestEngine().Group("/api")) })
}
// ---------------------------------------------------------------------------
// RegisterPublicRoutes / RunAllPublicRoutes
// ---------------------------------------------------------------------------
func TestRegisterPublicRoutes_SingleFunc_IsCalled(t *testing.T) {
resetRegistry()
called := false
RegisterPublicRoutes(func(r *gin.Engine) {
called = true
r.GET("/health", func(c *gin.Context) { c.Status(http.StatusOK) })
})
engine := newTestEngine()
RunAllPublicRoutes(engine)
assert.True(t, called)
w := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodGet, "/health", nil)
engine.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
}
func TestRunAllPublicRoutes_NoFuncs_DoesNotPanic(t *testing.T) {
resetRegistry()
assert.NotPanics(t, func() { RunAllPublicRoutes(newTestEngine()) })
}
// ---------------------------------------------------------------------------
// RegisterBaseRoutes / RunAllBaseRoutes
// ---------------------------------------------------------------------------
func TestRegisterBaseRoutes_SingleFunc_IsCalled(t *testing.T) {
resetRegistry()
called := false
RegisterBaseRoutes(func(r *gin.Engine) {
called = true
r.POST("/login", func(c *gin.Context) { c.Status(http.StatusOK) })
})
engine := newTestEngine()
RunAllBaseRoutes(engine)
assert.True(t, called)
w := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodPost, "/login", nil)
engine.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
}
func TestRunAllBaseRoutes_NoFuncs_DoesNotPanic(t *testing.T) {
resetRegistry()
assert.NotPanics(t, func() { RunAllBaseRoutes(newTestEngine()) })
}
// ---------------------------------------------------------------------------
// SetAuthMiddleware / GetAuthMiddleware
// ---------------------------------------------------------------------------
func TestGetAuthMiddleware_NoProvider_ReturnsPassThrough(t *testing.T) {
resetRegistry()
mw := GetAuthMiddleware()
require.NotNil(t, mw)
engine := newTestEngine()
engine.Use(mw)
engine.GET("/test", func(c *gin.Context) { c.Status(http.StatusOK) })
w := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodGet, "/test", nil)
engine.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code, "pass-through should not block requests")
}
func TestSetAuthMiddleware_ProviderIsUsed(t *testing.T) {
resetRegistry()
providerCalled := false
SetAuthMiddleware(func() gin.HandlerFunc {
providerCalled = true
return func(c *gin.Context) {
c.Header("X-Auth", "ok")
c.Next()
}
})
mw := GetAuthMiddleware()
assert.True(t, providerCalled)
engine := newTestEngine()
engine.Use(mw)
engine.GET("/secure", func(c *gin.Context) { c.Status(http.StatusOK) })
w := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodGet, "/secure", nil)
engine.ServeHTTP(w, req)
assert.Equal(t, "ok", w.Header().Get("X-Auth"))
}
func TestSetAuthMiddleware_OverwritesPreviousProvider(t *testing.T) {
resetRegistry()
SetAuthMiddleware(func() gin.HandlerFunc {
return func(c *gin.Context) { c.Header("X-Version", "first"); c.Next() }
})
SetAuthMiddleware(func() gin.HandlerFunc {
return func(c *gin.Context) { c.Header("X-Version", "second"); c.Next() }
})
engine := newTestEngine()
engine.Use(GetAuthMiddleware())
engine.GET("/v", func(c *gin.Context) { c.Status(http.StatusOK) })
w := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodGet, "/v", nil)
engine.ServeHTTP(w, req)
assert.Equal(t, "second", w.Header().Get("X-Version"), "last registration wins")
}
// ---------------------------------------------------------------------------
// RegisterMigration / RunAllMigrations
// ---------------------------------------------------------------------------
func TestRunAllMigrations_NoFuncs_ReturnsNil(t *testing.T) {
resetRegistry()
assert.NoError(t, RunAllMigrations(newTestDB(t)))
}
func TestRunAllMigrations_SingleFunc_IsCalled(t *testing.T) {
resetRegistry()
called := false
RegisterMigration(func(d ...*gorm.DB) error {
called = true
return nil
})
require.NoError(t, RunAllMigrations(newTestDB(t)))
assert.True(t, called)
}
func TestRunAllMigrations_ReceivesCorrectDB(t *testing.T) {
resetRegistry()
db := newTestDB(t)
var received *gorm.DB
RegisterMigration(func(d ...*gorm.DB) error {
if len(d) > 0 {
received = d[0]
}
return nil
})
require.NoError(t, RunAllMigrations(db))
assert.Same(t, db, received, "RunAllMigrations should pass the provided DB instance")
}
func TestRunAllMigrations_MultipleFuncs_AllCalled(t *testing.T) {
resetRegistry()
count := 0
for i := 0; i < 3; i++ {
RegisterMigration(func(d ...*gorm.DB) error { count++; return nil })
}
require.NoError(t, RunAllMigrations(newTestDB(t)))
assert.Equal(t, 3, count)
}
func TestRunAllMigrations_FirstErrorAbortsChain(t *testing.T) {
resetRegistry()
secondCalled := false
RegisterMigration(func(d ...*gorm.DB) error { return errors.New("migration failed") })
RegisterMigration(func(d ...*gorm.DB) error { secondCalled = true; return nil })
err := RunAllMigrations(newTestDB(t))
assert.Error(t, err)
assert.False(t, secondCalled, "subsequent migrations must not run after an error")
}
func TestRunAllMigrations_AutoMigratesModel(t *testing.T) {
resetRegistry()
db := newTestDB(t)
type SampleModel struct {
gorm.Model
Name string
}
RegisterMigration(func(d ...*gorm.DB) error {
return d[0].AutoMigrate(&SampleModel{})
})
require.NoError(t, RunAllMigrations(db))
assert.True(t, db.Migrator().HasTable(&SampleModel{}), "table should exist after migration")
}
+8 -10
View File
@@ -1,22 +1,20 @@
package router
import (
"bamort/user"
"bamort/registry"
"github.com/gin-gonic/gin"
)
// BaseRouterGrp registers all base (unauthenticated) routes from every module
// and returns the protected /api router group secured with the registered auth
// middleware. Modules self-register via their init() functions; no direct
// module imports are required here.
func BaseRouterGrp(r *gin.Engine) *gin.RouterGroup {
// Routes
r.POST("/register", user.RegisterUser)
r.POST("/login", user.LoginUser)
// Password Reset Routes (unprotected)
r.POST("/password-reset/request", user.RequestPasswordReset)
r.GET("/password-reset/validate/:token", user.ValidateResetToken)
r.POST("/password-reset/reset", user.ResetPassword)
// Call all base-route registrars (login, register, password-reset, …)
registry.RunAllBaseRoutes(r)
protected := r.Group("/api")
protected.Use(user.AuthMiddleware())
protected.Use(registry.GetAuthMiddleware())
return protected
}
+5 -5
View File
@@ -24,11 +24,11 @@ func SetupGin(r *gin.Engine) {
} else {
allowedOrigins := []string{
config.Cfg.FrontendURL,
"http://localhost:5173", // Development frontend
"http://192.168.0.48:5173", // Development frontend
"http://192.168.0.36:5173", // Development frontend
"https://bamort.trokan.de", // Production frontend
"http://wails.localhost", // Wails desktop WebView
"http://localhost:5173", // Development frontend
"http://192.168.0.48:5173", // Development frontend
"http://192.168.0.36:5173", // Development frontend
"https://conorga.trokan.de", // Production frontend
"http://wails.localhost", // Wails desktop WebView
}
corsConfig = cors.Config{
AllowOrigins: allowedOrigins,