-
-
-
-
-
+
+
+
+
+
+
+
+
+
+ Admin
+
+
+ Settings
+
+
+
+ Logout
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/server/internal/handlers/users.go b/server/internal/handlers/users.go
index bfb7b92..ac959d0 100644
--- a/server/internal/handlers/users.go
+++ b/server/internal/handlers/users.go
@@ -96,3 +96,30 @@ func (h *UsersHandler) Create(c *gin.Context) {
}
c.JSON(http.StatusCreated, dto.MapUser(u))
}
+
+// DELETE /users/:id (admin) — delete user and clear device relations
+func (h *UsersHandler) Delete(c *gin.Context) {
+ idStr := c.Param("id")
+ id, _ := strconv.Atoi(idStr)
+ if id <= 0 {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
+ return
+ }
+ var u models.User
+ if err := h.db.Preload("Devices").First(&u, id).Error; err != nil {
+ c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
+ return
+ }
+ // optional safeguard: prevent self-delete; uncomment if desired
+ // if ClaimUserID(MustClaims(c)) == u.ID { c.JSON(http.StatusBadRequest, gin.H{"error":"cannot delete yourself"}); return }
+ if err := h.db.Transaction(func(tx *gorm.DB) error {
+ if err := tx.Model(&u).Association("Devices").Clear(); err != nil {
+ return err
+ }
+ return tx.Delete(&u).Error
+ }); err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "delete failed"})
+ return
+ }
+ c.Status(http.StatusNoContent)
+}
diff --git a/server/internal/router/router.go b/server/internal/router/router.go
index f3c3408..3bb05ac 100644
--- a/server/internal/router/router.go
+++ b/server/internal/router/router.go
@@ -41,6 +41,7 @@ func Build(db *gorm.DB, minio *minio.Client, cfg *config.Config) *gin.Engine {
r.POST("/users/:id/set_role", authMW, adminOnly, usersH.SetRole)
r.GET("/users", authMW, adminOnly, usersH.List)
r.POST("/users/create", authMW, adminOnly, usersH.Create)
+ r.DELETE("/users/:id", authMW, adminOnly, usersH.Delete)
r.GET("/devices", authMW, middleware.DeviceAccessFilter(), devH.List)
r.POST("/devices/create", authMW, devH.Create)