This commit is contained in:
Tomas Dvorak
2026-03-13 14:34:19 +01:00
parent 84a8acf944
commit 30d70a6aeb
126 changed files with 27297 additions and 29069 deletions
+12 -84
View File
@@ -5,9 +5,11 @@ import (
"log"
"time"
_ "fotbal-club/database/goosemigrations"
"fotbal-club/internal/config"
"fotbal-club/internal/models"
"github.com/pressly/goose/v3"
"golang.org/x/crypto/bcrypt"
"gorm.io/driver/postgres"
"gorm.io/gorm"
@@ -109,94 +111,20 @@ func WithTransaction(ctx context.Context, fn func(tx *gorm.DB) error) error {
// MigrateDB runs database migrations for all models
func MigrateDB(db *gorm.DB) error {
// Enable UUID extension
err := db.Exec(`CREATE EXTENSION IF NOT EXISTS "uuid-ossp";`).Error
sqlDB, err := db.DB()
if err != nil {
return err
}
// Run migrations for all models
return db.AutoMigrate(
&models.User{},
&models.Article{},
&models.Category{},
&models.Team{},
&models.Player{},
&models.Sponsor{},
&models.Banner{},
&models.Settings{},
&models.MatchOverride{},
&models.TeamLogoOverride{},
&models.ContactMessage{},
&models.ContactCategory{},
&models.Contact{},
&models.NewsletterSubscription{},
&models.VisitorEvent{},
&models.ArticleTeamLink{},
&models.ArticleMatchLink{},
&models.CompetitionAlias{},
&models.EmailLog{},
&models.EmailEvent{},
&models.NewsletterSentLog{},
&models.MatchNotification{},
&models.BlogNotification{},
&models.PasswordReset{},
&models.AboutPage{},
// Add event tables so public endpoints don't fail before any writes occur
&models.Event{},
&models.EventAttachment{},
&models.UploadedFile{},
&models.FileUsage{},
&models.ShortLink{},
&models.LinkClick{},
&models.Comment{},
&models.CommentReaction{},
&models.CommentBan{},
&models.UnbanRequest{},
&models.CommentReport{},
&models.UserProfile{},
&models.PointsTransaction{},
&models.Achievement{},
&models.UserAchievement{},
&models.RewardItem{},
&models.RewardRedemption{},
// E-shop core models
&models.EshopProductCategory{},
&models.EshopProduct{},
&models.EshopProductVariant{},
&models.EshopCart{},
&models.EshopCartItem{},
&models.EshopOrder{},
&models.EshopOrderItem{},
&models.EshopPayment{},
&models.EshopShippingLabel{},
&models.EshopSettings{},
// Financial management models
&models.Budget{},
&models.Sponsorship{},
&models.SponsorshipPayment{},
&models.SponsorshipDocument{},
&models.Expense{},
&models.ExpenseDocument{},
&models.FinancialReport{},
&models.FinancialSettings{},
// Invoice system models
&models.Invoice{},
&models.InvoiceItem{},
&models.InvoicePayment{},
&models.InvoiceCustomer{},
&models.InvoiceTemplate{},
&models.InvoiceSettings{},
&models.InvoiceSequence{},
// Facility management models
&models.Facility{},
&models.FacilityAvailabilityRule{},
&models.FacilityBooking{},
&models.FacilityEquipment{},
&models.FacilityMaintenance{},
&models.WeatherCondition{},
&models.FacilityBookingTemplate{},
)
goose.SetLogger(log.New(log.Writer(), "[goose] ", log.LstdFlags))
if err := goose.SetDialect("postgres"); err != nil {
return err
}
if err := goose.UpContext(context.Background(), sqlDB, "database/goosemigrations"); err != nil {
return err
}
return nil
}
// SeedDB populates the database with initial data
+96 -74
View File
@@ -1,9 +1,11 @@
package logger
import (
"fmt"
"os"
"strings"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
// Log levels
@@ -14,106 +16,126 @@ const (
LevelError = "ERROR"
)
// Logger is the interface for logging
// Logger represents a leveled zap-backed logger while preserving the package API.
type Logger struct {
level zap.AtomicLevel
sugar *zap.SugaredLogger
}
var (
// DefaultLogger is the default logger instance
// DefaultLogger is the default logger instance.
DefaultLogger = NewLogger(LevelInfo)
)
// Logger represents a simple logger
type Logger struct {
level string
}
// NewLogger creates a new logger instance with the specified log level
func NewLogger(level string) *Logger {
return &Logger{level: level}
}
// SetLevel changes the logger level at runtime
func (l *Logger) SetLevel(level string) {
func parseLevel(level string) zapcore.Level {
switch strings.ToUpper(strings.TrimSpace(level)) {
case LevelDebug, LevelInfo, LevelWarn, LevelError:
l.level = strings.ToUpper(strings.TrimSpace(level))
case LevelDebug:
return zap.DebugLevel
case LevelWarn:
return zap.WarnLevel
case LevelError:
return zap.ErrorLevel
default:
// keep previous
return zap.InfoLevel
}
}
// SetLevel changes the default logger level at runtime
func newZapLogger(level zap.AtomicLevel) *zap.SugaredLogger {
cfg := zap.NewProductionConfig()
cfg.Encoding = "console"
cfg.Level = level
cfg.OutputPaths = []string{"stderr"}
cfg.ErrorOutputPaths = []string{"stderr"}
cfg.DisableStacktrace = true
cfg.EncoderConfig.TimeKey = "ts"
cfg.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
cfg.EncoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
cfg.EncoderConfig.EncodeDuration = zapcore.StringDurationEncoder
cfg.EncoderConfig.CallerKey = ""
logger, err := cfg.Build()
if err != nil {
fallback := zap.New(
zapcore.NewCore(
zapcore.NewConsoleEncoder(zap.NewProductionEncoderConfig()),
zapcore.Lock(os.Stderr),
level,
),
)
return fallback.Sugar()
}
return logger.Sugar()
}
// NewLogger creates a new logger instance with the specified log level.
func NewLogger(level string) *Logger {
atomicLevel := zap.NewAtomicLevelAt(parseLevel(level))
return &Logger{
level: atomicLevel,
sugar: newZapLogger(atomicLevel),
}
}
// SetLevel changes the logger level at runtime.
func (l *Logger) SetLevel(level string) {
if l == nil {
return
}
l.level.SetLevel(parseLevel(level))
}
func (l *Logger) logWithFormat(logFn func(string, ...interface{}), plainFn func(...interface{}), message string, args ...interface{}) {
if len(args) == 0 {
plainFn(message)
return
}
logFn(message, args...)
}
// Debug logs a debug message.
func (l *Logger) Debug(message string, args ...interface{}) {
l.logWithFormat(l.sugar.Debugf, l.sugar.Debug, message, args...)
}
// Info logs an info message.
func (l *Logger) Info(message string, args ...interface{}) {
l.logWithFormat(l.sugar.Infof, l.sugar.Info, message, args...)
}
// Warn logs a warning message.
func (l *Logger) Warn(message string, args ...interface{}) {
l.logWithFormat(l.sugar.Warnf, l.sugar.Warn, message, args...)
}
// Error logs an error message.
func (l *Logger) Error(message string, args ...interface{}) {
l.logWithFormat(l.sugar.Errorf, l.sugar.Error, message, args...)
}
// SetLevel changes the default logger level at runtime.
func SetLevel(level string) {
if DefaultLogger != nil {
DefaultLogger.SetLevel(level)
}
}
// Debug logs a debug message
func (l *Logger) Debug(message string, args ...interface{}) {
if l.shouldLog(LevelDebug) {
l.log(LevelDebug, message, args...)
}
}
// Info logs an info message
func (l *Logger) Info(message string, args ...interface{}) {
if l.shouldLog(LevelInfo) {
l.log(LevelInfo, message, args...)
}
}
// Warn logs a warning message
func (l *Logger) Warn(message string, args ...interface{}) {
if l.shouldLog(LevelWarn) {
l.log(LevelWarn, message, args...)
}
}
// Error logs an error message
func (l *Logger) Error(message string, args ...interface{}) {
if l.shouldLog(LevelError) {
l.log(LevelError, message, args...)
}
}
// shouldLog checks if the log level is enabled
func (l *Logger) shouldLog(level string) bool {
levels := map[string]int{
LevelDebug: 0,
LevelInfo: 1,
LevelWarn: 2,
LevelError: 3,
}
return levels[level] >= levels[l.level]
}
// log writes the log message to stderr
func (l *Logger) log(level, message string, args ...interface{}) {
msg := message
if len(args) > 0 {
msg = fmt.Sprintf(message, args...)
}
fmt.Fprintf(os.Stderr, "[%s] %s\n", level, msg)
}
// Package level functions
// Debug logs a debug message using the default logger
// Debug logs a debug message using the default logger.
func Debug(message string, args ...interface{}) {
DefaultLogger.Debug(message, args...)
}
// Info logs an info message using the default logger
// Info logs an info message using the default logger.
func Info(message string, args ...interface{}) {
DefaultLogger.Info(message, args...)
}
// Warn logs a warning message using the default logger
// Warn logs a warning message using the default logger.
func Warn(message string, args ...interface{}) {
DefaultLogger.Warn(message, args...)
}
// Error logs an error message using the default logger
// Error logs an error message using the default logger.
func Error(message string, args ...interface{}) {
DefaultLogger.Error(message, args...)
}