package handlers import ( "net/http" "os" "strings" "gauth-central/internal/database" "gauth-central/internal/models" "gauth-central/pkg/utils" "github.com/gin-gonic/gin" ) type AvatarHandler struct{} func NewAvatarHandler() *AvatarHandler { return &AvatarHandler{} } // UploadAvatar godoc // @Summary Upload user avatar // @Tags User // @Security ApiKeyAuth // @Accept multipart/form-data // @Produce json // @Param avatar formData file true "Avatar image file" // @Success 200 {object} map[string]interface{} // @Router /user/avatar [post] func (h *AvatarHandler) UploadAvatar(c *gin.Context) { userID := c.GetString("user_id") if userID == "" { c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"}) return } // Parse multipart form file, err := c.FormFile("avatar") if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "No file uploaded"}) return } // Validate file size (max 5MB) if file.Size > 5*1024*1024 { c.JSON(http.StatusBadRequest, gin.H{"error": "File size exceeds 5MB limit"}) return } // Get user to check for old avatar var user models.User if err := database.DB.Where("id = ?", userID).First(&user).Error; err != nil { c.JSON(http.StatusNotFound, gin.H{"error": "User not found"}) return } // Delete old avatar file if exists and is not from OAuth if user.Avatar != "" && strings.HasPrefix(user.Avatar, "/uploads/") { oldPath := "." + user.Avatar os.Remove(oldPath) // Ignore error if file doesn't exist } // Use utils.SaveOptimizedImage avatarURL, err := utils.SaveOptimizedImage(file, "./uploads/avatars", userID, nil) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save avatar: " + err.Error()}) return } // Update avatar URL if err := database.DB.Model(&user).Update("avatar", avatarURL).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update avatar"}) return } c.JSON(http.StatusOK, gin.H{ "message": "Avatar uploaded successfully", "avatar_url": avatarURL, "user": gin.H{ "id": user.ID, "username": user.UserName, "email": user.Email, "avatar": avatarURL, }, }) } // DeleteAvatar godoc // @Summary Delete user avatar // @Tags User // @Security ApiKeyAuth // @Produce json // @Success 200 {object} map[string]interface{} // @Router /user/avatar [delete] func (h *AvatarHandler) DeleteAvatar(c *gin.Context) { userID := c.GetString("user_id") if userID == "" { c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"}) return } var user models.User if err := database.DB.Where("id = ?", userID).First(&user).Error; err != nil { c.JSON(http.StatusNotFound, gin.H{"error": "User not found"}) return } // Delete avatar file if it's a local upload if user.Avatar != "" && strings.HasPrefix(user.Avatar, "/uploads/") { filepath := "." + user.Avatar os.Remove(filepath) // Ignore error if file doesn't exist } // Set avatar to empty string if err := database.DB.Model(&user).Update("avatar", "").Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete avatar"}) return } c.JSON(http.StatusOK, gin.H{ "message": "Avatar deleted successfully", "user": gin.H{ "id": user.ID, "username": user.UserName, "email": user.Email, "avatar": "", }, }) } // AdminUploadAvatar godoc // @Summary Upload avatar for any user (Admin only) // @Tags Admin - User Management // @Security ApiKeyAuth // @Accept multipart/form-data // @Produce json // @Param id path string true "User ID" // @Param avatar formData file true "Avatar image file" // @Success 200 {object} map[string]interface{} // @Router /admin/users/{id}/avatar [post] func (h *AvatarHandler) AdminUploadAvatar(c *gin.Context) { userID := c.Param("id") // Parse multipart form file, err := c.FormFile("avatar") if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "No file uploaded"}) return } // Validate file size (max 5MB) if file.Size > 5*1024*1024 { c.JSON(http.StatusBadRequest, gin.H{"error": "File size exceeds 5MB limit"}) return } // Get user to check for old avatar var user models.User if err := database.DB.Where("id = ?", userID).First(&user).Error; err != nil { c.JSON(http.StatusNotFound, gin.H{"error": "User not found"}) return } // Delete old avatar file if exists and is not from OAuth if user.Avatar != "" && strings.HasPrefix(user.Avatar, "/uploads/") { oldPath := "." + user.Avatar os.Remove(oldPath) // Ignore error if file doesn't exist } // Use utils.SaveOptimizedImage avatarURL, err := utils.SaveOptimizedImage(file, "./uploads/avatars", userID, nil) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save avatar: " + err.Error()}) return } // Update avatar URL if err := database.DB.Model(&user).Update("avatar", avatarURL).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update avatar"}) return } c.JSON(http.StatusOK, gin.H{ "message": "Avatar uploaded successfully", "avatar_url": avatarURL, "user": gin.H{ "id": user.ID, "username": user.UserName, "email": user.Email, "avatar": avatarURL, }, }) }