package handlers import ( "net/http" "strings" "github.com/gin-gonic/gin" "golang.org/x/crypto/bcrypt" "sproutgate-backend/internal/auth" ) func (h *Handler) UpdateProfile(c *gin.Context) { token := bearerToken(c.GetHeader("Authorization")) if token == "" { c.JSON(http.StatusUnauthorized, gin.H{"error": "missing token"}) return } claims, err := auth.ParseToken(h.store.JWTSecret(), h.store.JWTIssuer(), token) if err != nil { c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid token"}) return } var req updateProfileRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"}) return } user, found, err := h.store.GetUser(claims.Account) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to load user"}) return } if !found { c.JSON(http.StatusUnauthorized, gin.H{"error": "user not found"}) return } if abortIfUserBanned(c, user) { return } if req.Password != nil && strings.TrimSpace(*req.Password) != "" { hash, err := bcrypt.GenerateFromPassword([]byte(*req.Password), bcrypt.DefaultCost) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to hash password"}) return } user.PasswordHash = string(hash) } if req.Username != nil { user.Username = *req.Username } if req.Phone != nil { user.Phone = *req.Phone } if req.AvatarURL != nil { user.AvatarURL = *req.AvatarURL } if req.WebsiteURL != nil { wu, err := normalizePublicWebsiteURL(*req.WebsiteURL) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } user.WebsiteURL = wu } if req.Bio != nil { user.Bio = *req.Bio } if err := h.store.SaveUser(user); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to save user"}) return } c.JSON(http.StatusOK, gin.H{"user": user.OwnerPublic()}) }