// service/avatar_service.go package service import ( "api_bb/internal/repository" "api_bb/pkg/logger" "fmt" "io" "mime/multipart" "os" "path/filepath" "strings" "time" "go.uber.org/zap" ) type AvatarService interface { UploadAvatar(userID uint, file multipart.File, header *multipart.FileHeader) (string, error) DeleteAvatar(userID uint) error GetAvatarPath(userID uint) (string, error) } type avatarService struct { userRepo repository.UserRepository logger logger.LoggerInterface } func NewAvatarService(userRepo repository.UserRepository, log logger.LoggerInterface) AvatarService { return &avatarService{ userRepo: userRepo, logger: log.With(zap.String("service", "avatar")), } } func (s *avatarService) UploadAvatar(userID uint, file multipart.File, header *multipart.FileHeader) (string, error) { // Проверяем пользователя user, err := s.userRepo.FindByID(userID) if err != nil { return "", fmt.Errorf("user not found") } // Создаем директорию для аватаров если не существует uploadDir := "./uploads/avatars" if err := os.MkdirAll(uploadDir, 0755); err != nil { return "", fmt.Errorf("failed to create upload directory: %v", err) } // Генерируем уникальное имя файла fileExt := filepath.Ext(header.Filename) fileName := fmt.Sprintf("avatar_%d_%d%s", userID, time.Now().Unix(), fileExt) filePath := filepath.Join(uploadDir, fileName) // Создаем файл dst, err := os.Create(filePath) if err != nil { return "", fmt.Errorf("failed to create file: %v", err) } defer dst.Close() // Копируем содержимое if _, err := io.Copy(dst, file); err != nil { return "", fmt.Errorf("failed to save file: %v", err) } // Удаляем старый аватар если существует if user.Avatar != "" { oldPath := strings.TrimPrefix(user.Avatar, "/") if _, err := os.Stat(oldPath); err == nil { os.Remove(oldPath) } } // Сохраняем путь в БД avatarPath := "/uploads/avatars/" + fileName if err := s.userRepo.UpdateAvatar(userID, avatarPath); err != nil { // Если не удалось сохранить в БД, удаляем загруженный файл os.Remove(filePath) return "", fmt.Errorf("failed to update avatar in database: %v", err) } return avatarPath, nil } func (s *avatarService) DeleteAvatar(userID uint) error { user, err := s.userRepo.FindByID(userID) if err != nil { return fmt.Errorf("user not found") } if user.Avatar == "" { return nil // Аватара нет, ничего не делаем } // Удаляем файл filePath := strings.TrimPrefix(user.Avatar, "/") if _, err := os.Stat(filePath); err == nil { if err := os.Remove(filePath); err != nil { s.logger.Warn("Failed to delete avatar file", zap.Error(err)) } } // Очищаем поле в БД return s.userRepo.UpdateAvatar(userID, "") } func (s *avatarService) GetAvatarPath(userID uint) (string, error) { user, err := s.userRepo.FindByID(userID) if err != nil { return "", err } return user.Avatar, nil }