first commit, i i have no idea what i have done
This commit is contained in:
250
server/internal/handlers/devices.go
Normal file
250
server/internal/handlers/devices.go
Normal file
@@ -0,0 +1,250 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"smoop-api/internal/dto"
|
||||
"smoop-api/internal/models"
|
||||
)
|
||||
|
||||
type DevicesHandler struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewDevicesHandler(db *gorm.DB) *DevicesHandler { return &DevicesHandler{db: db} }
|
||||
|
||||
func (h *DevicesHandler) 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
|
||||
}
|
||||
|
||||
var total int64
|
||||
h.db.Model(&models.Device{}).Count(&total)
|
||||
|
||||
var devs []models.Device
|
||||
if err := h.db.Preload("Users").Offset(offset).Limit(limit).Find(&devs).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "query failed"})
|
||||
return
|
||||
}
|
||||
|
||||
out := make([]dto.DeviceDto, 0, len(devs))
|
||||
for _, d := range devs {
|
||||
out = append(out, dto.MapDevice(d))
|
||||
}
|
||||
c.JSON(http.StatusOK, dto.DeviceListDto{Devices: out, Offset: offset, Limit: limit, Total: total})
|
||||
}
|
||||
|
||||
func (h *DevicesHandler) Create(c *gin.Context) {
|
||||
var req dto.CreateDeviceDto
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
d := models.Device{GUID: req.GUID, Name: req.Name}
|
||||
if err := h.db.Create(&d).Error; err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "device exists?"})
|
||||
return
|
||||
}
|
||||
// Optional initial user assignments
|
||||
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(&d).Association("Users").Append(&users); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "link failed"})
|
||||
return
|
||||
}
|
||||
}
|
||||
// Return with users
|
||||
var withUsers models.Device
|
||||
if err := h.db.Preload("Users").Where("guid = ?", d.GUID).First(&withUsers).Error; err != nil {
|
||||
c.JSON(http.StatusCreated, dto.DeviceDto{GUID: d.GUID, Name: d.Name})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusCreated, dto.MapDevice(withUsers))
|
||||
}
|
||||
|
||||
func (h *DevicesHandler) Rename(c *gin.Context) {
|
||||
guid := c.Param("guid")
|
||||
var d models.Device
|
||||
if err := h.db.Where("guid = ?", guid).First(&d).Error; err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "device not found"})
|
||||
return
|
||||
}
|
||||
var req dto.RenameDeviceDto
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
d.Name = req.Name
|
||||
if err := h.db.Save(&d).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "save failed"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusCreated, dto.DeviceDto{GUID: d.GUID, Name: d.Name})
|
||||
}
|
||||
|
||||
func (h *DevicesHandler) AddToUser(c *gin.Context) {
|
||||
guid := c.Param("guid")
|
||||
var d models.Device
|
||||
if err := h.db.Where("guid = ?", guid).First(&d).Error; err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "device not found"})
|
||||
return
|
||||
}
|
||||
var req dto.EditDeviceToUserRelationDto
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
ids := req.UserIDs
|
||||
if req.UserID != 0 {
|
||||
ids = append(ids, req.UserID)
|
||||
}
|
||||
if len(ids) == 0 {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "userIds or userId required"})
|
||||
return
|
||||
}
|
||||
|
||||
users, err := h.fetchUsers(ids)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
if err := h.db.Model(&d).Association("Users").Append(&users); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "link failed"})
|
||||
return
|
||||
}
|
||||
var withUsers models.Device
|
||||
_ = h.db.Preload("Users").Where("guid = ?", d.GUID).First(&withUsers).Error
|
||||
c.JSON(http.StatusCreated, dto.MapDevice(withUsers))
|
||||
}
|
||||
|
||||
// SetUsers replaces the users of a device with the provided list.
|
||||
// Passing an empty list clears all assignments (covers the "no user assigned" case).
|
||||
func (h *DevicesHandler) SetUsers(c *gin.Context) {
|
||||
guid := c.Param("guid")
|
||||
var d models.Device
|
||||
if err := h.db.Where("guid = ?", guid).First(&d).Error; err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "device not found"})
|
||||
return
|
||||
}
|
||||
var req dto.SetDeviceUsersDto
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
// Load users (if any)
|
||||
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
|
||||
}
|
||||
// Replace association: Clear() then Append(new)
|
||||
if err := h.db.Model(&d).Association("Users").Clear(); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "clear failed"})
|
||||
return
|
||||
}
|
||||
if len(users) > 0 {
|
||||
if err := h.db.Model(&d).Association("Users").Append(&users); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "link failed"})
|
||||
return
|
||||
}
|
||||
}
|
||||
var withUsers models.Device
|
||||
_ = h.db.Preload("Users").Where("guid = ?", d.GUID).First(&withUsers).Error
|
||||
c.JSON(http.StatusCreated, dto.MapDevice(withUsers))
|
||||
}
|
||||
|
||||
func (h *DevicesHandler) RemoveFromUser(c *gin.Context) {
|
||||
guid := c.Param("guid")
|
||||
var d models.Device
|
||||
if err := h.db.Where("guid = ?", guid).First(&d).Error; err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "device not found"})
|
||||
return
|
||||
}
|
||||
var req dto.RemoveDeviceUsersDto
|
||||
_ = c.ShouldBindJSON(&req) // ignore error; we support query fallback
|
||||
|
||||
ids := make([]uint, 0, len(req.UserIDs)+1)
|
||||
if req.UserID != 0 {
|
||||
ids = append(ids, req.UserID)
|
||||
}
|
||||
if len(req.UserIDs) > 0 {
|
||||
ids = append(ids, req.UserIDs...)
|
||||
}
|
||||
// query fallback
|
||||
if len(ids) == 0 {
|
||||
if q := strings.TrimSpace(c.Query("userId")); q != "" {
|
||||
if n, err := strconv.Atoi(q); err == nil && n > 0 {
|
||||
ids = append(ids, uint(n))
|
||||
}
|
||||
}
|
||||
if q := strings.TrimSpace(c.Query("userIds")); q != "" {
|
||||
for _, p := range strings.Split(q, ",") {
|
||||
p = strings.TrimSpace(p)
|
||||
if n, err := strconv.Atoi(p); err == nil && n > 0 {
|
||||
ids = append(ids, uint(n))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(ids) == 0 {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "userIds or userId required"})
|
||||
return
|
||||
}
|
||||
|
||||
users, err := h.fetchUsers(ids)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
if len(users) == 0 {
|
||||
c.JSON(http.StatusOK, dto.DeviceDto{GUID: d.GUID, Name: d.Name})
|
||||
return
|
||||
}
|
||||
if err := h.db.Model(&d).Association("Users").Delete(&users); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "unlink failed"})
|
||||
return
|
||||
}
|
||||
var withUsers models.Device
|
||||
_ = h.db.Preload("Users").Where("guid = ?", d.GUID).First(&withUsers).Error
|
||||
c.JSON(http.StatusOK, dto.MapDevice(withUsers))
|
||||
}
|
||||
|
||||
func (h *DevicesHandler) 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
|
||||
}
|
||||
Reference in New Issue
Block a user