mirror of
https://github.com/TracksApp/tracks.git
synced 2025-12-16 15:20:13 +01:00
Features added: - Automatic creation of default admin user on first startup (login: admin, password: admin) - Admin-only endpoint POST /api/admin/users for creating new users - Admin users can set is_admin flag when creating users - Non-admin users are blocked from accessing admin endpoints Implementation: - Added CreateDefaultAdmin() function in internal/database/database.go - Checks if any users exist, creates admin only if database is empty - Admin user: login "admin", password "admin", is_admin true - Added CreateUser() method to auth service for admin user creation - Added CreateUser() handler to auth handler - Added /api/admin/users endpoint with AuthMiddleware + AdminMiddleware - Updated README_GOLANG.md with: - Default admin credentials - Instructions for creating additional users - Admin API documentation Security: - Default admin password should be changed after first login - AdminMiddleware ensures only users with is_admin=true can access admin routes - Non-admin users receive 403 Forbidden when accessing admin endpoints Tested: - Default admin creation on startup ✓ - Admin login with default credentials ✓ - Admin can create new users ✓ - New users can login ✓ - Non-admin users blocked from admin endpoints ✓
145 lines
3.1 KiB
Go
145 lines
3.1 KiB
Go
package database
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"time"
|
|
|
|
"github.com/TracksApp/tracks/internal/config"
|
|
"github.com/TracksApp/tracks/internal/models"
|
|
"gorm.io/driver/sqlite"
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/logger"
|
|
)
|
|
|
|
// DB is the global database instance
|
|
var DB *gorm.DB
|
|
|
|
// Initialize sets up the database connection
|
|
func Initialize(cfg *config.DatabaseConfig) error {
|
|
db, err := gorm.Open(sqlite.Open(cfg.Name), &gorm.Config{
|
|
Logger: logger.Default.LogMode(logger.Info),
|
|
NowFunc: func() time.Time {
|
|
return time.Now().UTC()
|
|
},
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("failed to connect to database: %w", err)
|
|
}
|
|
|
|
// Set connection pool settings
|
|
sqlDB, err := db.DB()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get database instance: %w", err)
|
|
}
|
|
|
|
sqlDB.SetMaxIdleConns(10)
|
|
sqlDB.SetMaxOpenConns(100)
|
|
sqlDB.SetConnMaxLifetime(time.Hour)
|
|
|
|
DB = db
|
|
|
|
log.Println("Database connection established")
|
|
return nil
|
|
}
|
|
|
|
// AutoMigrate runs database migrations
|
|
func AutoMigrate() error {
|
|
if DB == nil {
|
|
return fmt.Errorf("database not initialized")
|
|
}
|
|
|
|
log.Println("Running database migrations...")
|
|
|
|
err := DB.AutoMigrate(
|
|
&models.User{},
|
|
&models.Preference{},
|
|
&models.Context{},
|
|
&models.Project{},
|
|
&models.Todo{},
|
|
&models.RecurringTodo{},
|
|
&models.Tag{},
|
|
&models.Tagging{},
|
|
&models.Dependency{},
|
|
&models.Note{},
|
|
&models.Attachment{},
|
|
)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("failed to run migrations: %w", err)
|
|
}
|
|
|
|
log.Println("Database migrations completed")
|
|
return nil
|
|
}
|
|
|
|
// Close closes the database connection
|
|
func Close() error {
|
|
if DB == nil {
|
|
return nil
|
|
}
|
|
|
|
sqlDB, err := DB.DB()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return sqlDB.Close()
|
|
}
|
|
|
|
// GetDB returns the database instance
|
|
func GetDB() *gorm.DB {
|
|
return DB
|
|
}
|
|
|
|
// CreateDefaultAdmin creates a default admin user if no users exist
|
|
func CreateDefaultAdmin() error {
|
|
if DB == nil {
|
|
return fmt.Errorf("database not initialized")
|
|
}
|
|
|
|
// Check if any users exist
|
|
var count int64
|
|
if err := DB.Model(&models.User{}).Count(&count).Error; err != nil {
|
|
return fmt.Errorf("failed to count users: %w", err)
|
|
}
|
|
|
|
// If users exist, don't create default admin
|
|
if count > 0 {
|
|
log.Println("Users already exist, skipping default admin creation")
|
|
return nil
|
|
}
|
|
|
|
log.Println("Creating default admin user (login: admin, password: admin)")
|
|
|
|
// Create default admin user
|
|
admin := models.User{
|
|
Login: "admin",
|
|
FirstName: "Admin",
|
|
LastName: "User",
|
|
IsAdmin: true,
|
|
AuthType: models.AuthTypeDatabase,
|
|
Token: "default-admin-token",
|
|
}
|
|
|
|
// Set password
|
|
if err := admin.SetPassword("admin"); err != nil {
|
|
return fmt.Errorf("failed to set admin password: %w", err)
|
|
}
|
|
|
|
// Save admin user
|
|
if err := DB.Create(&admin).Error; err != nil {
|
|
return fmt.Errorf("failed to create admin user: %w", err)
|
|
}
|
|
|
|
// Create default preference for admin
|
|
preference := models.Preference{
|
|
UserID: admin.ID,
|
|
}
|
|
if err := DB.Create(&preference).Error; err != nil {
|
|
return fmt.Errorf("failed to create admin preference: %w", err)
|
|
}
|
|
|
|
log.Printf("Default admin user created successfully (ID: %d)", admin.ID)
|
|
return nil
|
|
}
|