Add admin settings page with seed data and limitations toggle
- Add settings handler with endpoints for: - GET/PUT /api/admin/settings (enable_limitations toggle) - POST /api/admin/settings/seed-lookups (run 001_lookups.sql) - POST /api/admin/settings/seed-test-data (run 002_test_data.sql) - Add settings page to admin panel with: - Toggle switch to enable/disable subscription limitations - Button to seed lookup data (categories, priorities, etc.) - Button to seed test data (with warning for non-production use) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
128
internal/admin/handlers/settings_handler.go
Normal file
128
internal/admin/handlers/settings_handler.go
Normal file
@@ -0,0 +1,128 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/treytartt/mycrib-api/internal/models"
|
||||
)
|
||||
|
||||
// AdminSettingsHandler handles system settings management
|
||||
type AdminSettingsHandler struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
// NewAdminSettingsHandler creates a new handler
|
||||
func NewAdminSettingsHandler(db *gorm.DB) *AdminSettingsHandler {
|
||||
return &AdminSettingsHandler{db: db}
|
||||
}
|
||||
|
||||
// SettingsResponse represents the settings response
|
||||
type SettingsResponse struct {
|
||||
EnableLimitations bool `json:"enable_limitations"`
|
||||
}
|
||||
|
||||
// GetSettings handles GET /api/admin/settings
|
||||
func (h *AdminSettingsHandler) GetSettings(c *gin.Context) {
|
||||
var settings models.SubscriptionSettings
|
||||
if err := h.db.First(&settings, 1).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
// Create default settings
|
||||
settings = models.SubscriptionSettings{ID: 1, EnableLimitations: false}
|
||||
h.db.Create(&settings)
|
||||
} else {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch settings"})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, SettingsResponse{
|
||||
EnableLimitations: settings.EnableLimitations,
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateSettingsRequest represents the update request
|
||||
type UpdateSettingsRequest struct {
|
||||
EnableLimitations *bool `json:"enable_limitations"`
|
||||
}
|
||||
|
||||
// UpdateSettings handles PUT /api/admin/settings
|
||||
func (h *AdminSettingsHandler) UpdateSettings(c *gin.Context) {
|
||||
var req UpdateSettingsRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
var settings models.SubscriptionSettings
|
||||
if err := h.db.First(&settings, 1).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
settings = models.SubscriptionSettings{ID: 1}
|
||||
} else {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch settings"})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if req.EnableLimitations != nil {
|
||||
settings.EnableLimitations = *req.EnableLimitations
|
||||
}
|
||||
|
||||
if err := h.db.Save(&settings).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update settings"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, SettingsResponse{
|
||||
EnableLimitations: settings.EnableLimitations,
|
||||
})
|
||||
}
|
||||
|
||||
// SeedLookups handles POST /api/admin/settings/seed-lookups
|
||||
func (h *AdminSettingsHandler) SeedLookups(c *gin.Context) {
|
||||
if err := h.runSeedFile("001_lookups.sql"); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to seed lookups: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Lookup data seeded successfully"})
|
||||
}
|
||||
|
||||
// SeedTestData handles POST /api/admin/settings/seed-test-data
|
||||
func (h *AdminSettingsHandler) SeedTestData(c *gin.Context) {
|
||||
if err := h.runSeedFile("002_test_data.sql"); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to seed test data: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Test data seeded successfully"})
|
||||
}
|
||||
|
||||
// runSeedFile executes a seed SQL file
|
||||
func (h *AdminSettingsHandler) runSeedFile(filename string) error {
|
||||
// Check multiple possible locations
|
||||
possiblePaths := []string{
|
||||
filepath.Join("seeds", filename),
|
||||
filepath.Join("./seeds", filename),
|
||||
filepath.Join("/app/seeds", filename),
|
||||
}
|
||||
|
||||
var sqlContent []byte
|
||||
var err error
|
||||
for _, path := range possiblePaths {
|
||||
sqlContent, err = os.ReadFile(path)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return h.db.Exec(string(sqlContent)).Error
|
||||
}
|
||||
@@ -249,6 +249,16 @@ func SetupRoutes(router *gin.Engine, db *gorm.DB, cfg *config.Config, deps *Depe
|
||||
notifPrefs.DELETE("/:id", notifPrefsHandler.Delete)
|
||||
notifPrefs.GET("/user/:user_id", notifPrefsHandler.GetByUser)
|
||||
}
|
||||
|
||||
// System settings management
|
||||
settingsHandler := handlers.NewAdminSettingsHandler(db)
|
||||
settings := protected.Group("/settings")
|
||||
{
|
||||
settings.GET("", settingsHandler.GetSettings)
|
||||
settings.PUT("", settingsHandler.UpdateSettings)
|
||||
settings.POST("/seed-lookups", settingsHandler.SeedLookups)
|
||||
settings.POST("/seed-test-data", settingsHandler.SeedTestData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user