213 lines
5.6 KiB
Go
213 lines
5.6 KiB
Go
package handlers
|
||
|
||
import (
|
||
"fmt"
|
||
"net/http"
|
||
"strconv"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
"gorm.io/gorm"
|
||
|
||
"smoop-api/internal/dto"
|
||
"smoop-api/internal/models"
|
||
)
|
||
|
||
type TrackersHandler struct {
|
||
db *gorm.DB
|
||
}
|
||
|
||
func NewTrackersHandler(db *gorm.DB) *TrackersHandler { return &TrackersHandler{db: db} }
|
||
|
||
// GET /trackers — list trackers available for user (admin: all)
|
||
func (h *TrackersHandler) List(c *gin.Context) {
|
||
offset, _ := strconv.Atoi(c.DefaultQuery("offset", "0"))
|
||
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "50"))
|
||
if limit <= 0 || limit > 200 {
|
||
limit = 50
|
||
}
|
||
|
||
// Default behavior (fallback if middleware not present): use user context
|
||
isFilter := true
|
||
var userID uint
|
||
|
||
if v, ok := c.Get("filterTrackers"); ok {
|
||
if b, ok2 := v.(bool); ok2 {
|
||
isFilter = b
|
||
}
|
||
}
|
||
if v, ok := c.Get("userID"); ok {
|
||
if id, ok2 := v.(uint); ok2 {
|
||
userID = id
|
||
}
|
||
}
|
||
|
||
// Fallback to claims if middleware wasn’t applied
|
||
if _, exists := c.Get("filterTrackers"); !exists {
|
||
if uc, ok := GetUserContext(c); ok {
|
||
if uc.Role == models.RoleAdmin {
|
||
isFilter = false
|
||
} else {
|
||
isFilter = true
|
||
userID = uc.ID
|
||
}
|
||
} else {
|
||
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
|
||
return
|
||
}
|
||
}
|
||
|
||
var (
|
||
total int64
|
||
list []models.Tracker
|
||
err error
|
||
)
|
||
|
||
if !isFilter {
|
||
// Admin: all trackers
|
||
err = h.db.Model(&models.Tracker{}).Count(&total).Error
|
||
if err == nil {
|
||
err = h.db.Preload("Users").Offset(offset).Limit(limit).Find(&list).Error
|
||
}
|
||
} else {
|
||
// Filtered by userID
|
||
q := h.db.Model(&models.Tracker{}).
|
||
Joins("JOIN user_trackers ut ON ut.tracker_guid = trackers.guid").
|
||
Where("ut.user_id = ?", userID)
|
||
if err = q.Count(&total).Error; err == nil {
|
||
err = h.db.Preload("Users").
|
||
Joins("JOIN user_trackers ut ON ut.tracker_guid = trackers.guid").
|
||
Where("ut.user_id = ?", userID).
|
||
Offset(offset).Limit(limit).
|
||
Find(&list).Error
|
||
}
|
||
}
|
||
|
||
if err != nil {
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": "query failed: " + err.Error()})
|
||
return
|
||
}
|
||
|
||
out := make([]dto.TrackerDto, 0, len(list))
|
||
for _, t := range list {
|
||
out = append(out, dto.MapTracker(t))
|
||
}
|
||
c.JSON(http.StatusOK, dto.TrackerListDto{
|
||
Trackers: out, Offset: offset, Limit: limit, Total: total,
|
||
})
|
||
}
|
||
|
||
// POST /trackers/create — create tracker; optional initial user assignments
|
||
func (h *TrackersHandler) Create(c *gin.Context) {
|
||
var req dto.CreateTrackerDto
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
t := models.Tracker{GUID: req.GUID, Name: req.Name}
|
||
if err := h.db.Create(&t).Error; err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "tracker exists?"})
|
||
return
|
||
}
|
||
// optional users
|
||
if len(req.UserIDs) > 0 {
|
||
users, err := h.fetchUsers(req.UserIDs)
|
||
if err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
if err := h.db.Model(&t).Association("Users").Append(&users); err != nil {
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": "link failed"})
|
||
return
|
||
}
|
||
}
|
||
var withUsers models.Tracker
|
||
if err := h.db.Preload("Users").Where("guid = ?", t.GUID).First(&withUsers).Error; err != nil {
|
||
c.JSON(http.StatusCreated, dto.TrackerDto{GUID: t.GUID, Name: t.Name})
|
||
return
|
||
}
|
||
c.JSON(http.StatusCreated, dto.MapTracker(withUsers))
|
||
}
|
||
|
||
// POST /trackers/:guid/rename — rename tracker
|
||
func (h *TrackersHandler) Rename(c *gin.Context) {
|
||
guid := c.Param("guid")
|
||
var t models.Tracker
|
||
if err := h.db.Where("guid = ?", guid).First(&t).Error; err != nil {
|
||
c.JSON(http.StatusNotFound, gin.H{"error": "tracker not found"})
|
||
return
|
||
}
|
||
var req dto.RenameTrackerDto
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
t.Name = req.Name
|
||
if err := h.db.Save(&t).Error; err != nil {
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": "save failed"})
|
||
return
|
||
}
|
||
c.JSON(http.StatusCreated, dto.TrackerDto{GUID: t.GUID, Name: t.Name})
|
||
}
|
||
|
||
// POST /trackers/:guid/set_users — replace full user list (admin)
|
||
func (h *TrackersHandler) SetUsers(c *gin.Context) {
|
||
guid := c.Param("guid")
|
||
var t models.Tracker
|
||
if err := h.db.Where("guid = ?", guid).First(&t).Error; err != nil {
|
||
c.JSON(http.StatusNotFound, gin.H{"error": "tracker not found"})
|
||
return
|
||
}
|
||
var req dto.SetTrackerUsersDto
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
users := []models.User{}
|
||
if len(req.UserIDs) > 0 {
|
||
found, err := h.fetchUsers(req.UserIDs)
|
||
if err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
users = found
|
||
}
|
||
if err := h.db.Model(&t).Association("Users").Clear(); err != nil {
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": "clear failed"})
|
||
return
|
||
}
|
||
if len(users) > 0 {
|
||
if err := h.db.Model(&t).Association("Users").Append(&users); err != nil {
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": "link failed"})
|
||
return
|
||
}
|
||
}
|
||
var withUsers models.Tracker
|
||
_ = h.db.Preload("Users").Where("guid = ?", t.GUID).First(&withUsers).Error
|
||
c.JSON(http.StatusCreated, dto.MapTracker(withUsers))
|
||
}
|
||
|
||
// local helper (same as devices.go)
|
||
func (h *TrackersHandler) fetchUsers(ids []uint) ([]models.User, error) {
|
||
unique := make(map[uint]struct{}, len(ids))
|
||
clean := make([]uint, 0, len(ids))
|
||
for _, id := range ids {
|
||
if id != 0 {
|
||
if _, ok := unique[id]; !ok {
|
||
unique[id] = struct{}{}
|
||
clean = append(clean, id)
|
||
}
|
||
}
|
||
}
|
||
if len(clean) == 0 {
|
||
return nil, nil
|
||
}
|
||
var users []models.User
|
||
if err := h.db.Find(&users, clean).Error; err != nil {
|
||
return nil, err
|
||
}
|
||
if len(users) != len(clean) {
|
||
return nil, fmt.Errorf("some users not found")
|
||
}
|
||
return users, nil
|
||
}
|