194 lines
5.1 KiB
Go
194 lines
5.1 KiB
Go
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,
|
|
},
|
|
})
|
|
}
|