package admin import ( "net/http" "time" "github.com/gin-gonic/gin" "github.com/google/uuid" "golang.org/x/crypto/bcrypt" "gorm.io/gorm" "github.com/llamalink/llamalink/internal/api/middleware" "github.com/llamalink/llamalink/internal/db" ) type MeHandler struct { db *gorm.DB } func NewMeHandler(db *gorm.DB) *MeHandler { return &MeHandler{db: db} } func (h *MeHandler) Me(c *gin.Context) { claims := middleware.GetAdminClaims(c) if claims == nil { c.JSON(http.StatusUnauthorized, gin.H{"error": gin.H{"code": "unauthorized", "message": "Not authenticated"}}) return } var user db.AdminUser if err := h.db.Where("username = ?", claims.Username).First(&user).Error; err != nil { c.JSON(http.StatusUnauthorized, gin.H{"error": gin.H{"code": "unauthorized", "message": "User not found"}}) return } c.JSON(http.StatusOK, gin.H{ "id": user.ID, "username": user.Username, "is_active": user.IsActive, "created_at": user.CreatedAt, "last_login_at": user.LastLoginAt, }) } type ChangePasswordRequest struct { CurrentPassword string `json:"current_password" binding:"required"` NewPassword string `json:"new_password" binding:"required,min=8"` } func (h *MeHandler) ChangePassword(c *gin.Context) { claims := middleware.GetAdminClaims(c) if claims == nil { c.JSON(http.StatusUnauthorized, gin.H{"error": gin.H{"code": "unauthorized", "message": "Not authenticated"}}) return } var req ChangePasswordRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": gin.H{"code": "validation_error", "message": "current_password and new_password required (min 8 chars)"}}) return } userID, err := uuid.Parse(claims.Subject) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": gin.H{"code": "invalid_request", "message": "Invalid token claims"}}) return } var user db.AdminUser if err := h.db.Where("id = ?", userID).First(&user).Error; err != nil { c.JSON(http.StatusNotFound, gin.H{"error": gin.H{"code": "not_found", "message": "User not found"}}) return } if err := bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(req.CurrentPassword)); err != nil { c.JSON(http.StatusUnauthorized, gin.H{"error": gin.H{"code": "invalid_credentials", "message": "Current password is incorrect"}}) return } newHash, err := bcrypt.GenerateFromPassword([]byte(req.NewPassword), bcrypt.DefaultCost) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": gin.H{"code": "internal_error", "message": "Failed to hash password"}}) return } h.db.Model(&user).Updates(map[string]interface{}{ "password_hash": string(newHash), "updated_at": time.Now(), }) c.Status(http.StatusOK) }