package handlers import ( "log" "net/http" "git.gobha.me/xcaliber/chat-switchboard/database" "github.com/gin-gonic/gin" ) // GetModelPreferences returns the user's hidden model list. // GET /api/v1/models/preferences func GetModelPreferences(c *gin.Context) { userID := getUserID(c) rows, err := database.DB.Query(` SELECT model_id, hidden FROM user_model_preferences WHERE user_id = $1 `, userID) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to query preferences"}) return } defer rows.Close() type pref struct { ModelID string `json:"model_id"` Hidden bool `json:"hidden"` } prefs := make([]pref, 0) for rows.Next() { var p pref if err := rows.Scan(&p.ModelID, &p.Hidden); err != nil { continue } prefs = append(prefs, p) } c.JSON(http.StatusOK, gin.H{"preferences": prefs}) } // SetModelPreference sets hidden state for a single model. // PUT /api/v1/models/preferences func SetModelPreference(c *gin.Context) { userID := getUserID(c) var req struct { ModelID string `json:"model_id" binding:"required"` Hidden bool `json:"hidden"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } _, err := database.DB.Exec(` INSERT INTO user_model_preferences (user_id, model_id, hidden, updated_at) VALUES ($1, $2, $3, NOW()) ON CONFLICT (user_id, model_id) DO UPDATE SET hidden = EXCLUDED.hidden, updated_at = NOW() `, userID, req.ModelID, req.Hidden) if err != nil { log.Printf("[WARN] Failed to save model preference for user %s, model %s: %v", userID, req.ModelID, err) c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to save preference: " + err.Error()}) return } c.JSON(http.StatusOK, gin.H{"model_id": req.ModelID, "hidden": req.Hidden}) } // BulkSetModelPreferences sets hidden state for multiple models at once. // POST /api/v1/models/preferences/bulk func BulkSetModelPreferences(c *gin.Context) { userID := getUserID(c) var req struct { ModelIDs []string `json:"model_ids" binding:"required"` Hidden bool `json:"hidden"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } if len(req.ModelIDs) == 0 { c.JSON(http.StatusOK, gin.H{"updated": 0}) return } tx, err := database.DB.Begin() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to begin transaction"}) return } defer tx.Rollback() stmt, err := tx.Prepare(` INSERT INTO user_model_preferences (user_id, model_id, hidden, updated_at) VALUES ($1, $2, $3, NOW()) ON CONFLICT (user_id, model_id) DO UPDATE SET hidden = EXCLUDED.hidden, updated_at = NOW() `) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to prepare statement"}) return } defer stmt.Close() updated := 0 for _, modelID := range req.ModelIDs { if _, err := stmt.Exec(userID, modelID, req.Hidden); err != nil { log.Printf("[WARN] Failed to save preference for model %s: %v", modelID, err) continue } updated++ } if err := tx.Commit(); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to commit"}) return } c.JSON(http.StatusOK, gin.H{"updated": updated}) }