Initial commit: Эфир мессенджер
This commit is contained in:
125
internal/service/user_service.go
Normal file
125
internal/service/user_service.go
Normal file
@@ -0,0 +1,125 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"messenger/internal/models"
|
||||
"messenger/internal/pkg/logger"
|
||||
"messenger/internal/pkg/validator"
|
||||
"messenger/internal/repository"
|
||||
)
|
||||
|
||||
type UserService struct {
|
||||
userRepo repository.UserRepository
|
||||
profileRepo repository.ProfileRepository
|
||||
}
|
||||
|
||||
func NewUserService(userRepo repository.UserRepository, profileRepo repository.ProfileRepository) *UserService {
|
||||
return &UserService{
|
||||
userRepo: userRepo,
|
||||
profileRepo: profileRepo,
|
||||
}
|
||||
}
|
||||
|
||||
// GetProfile возвращает профиль пользователя
|
||||
func (s *UserService) GetProfile(ctx context.Context, userID int64) (*models.ProfileWithUser, error) {
|
||||
user, err := s.userRepo.FindByID(ctx, userID)
|
||||
if err != nil {
|
||||
logger.Error("Failed to get user", "error", err)
|
||||
return nil, errors.New("internal server error")
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
return nil, errors.New("user not found")
|
||||
}
|
||||
|
||||
profile, err := s.profileRepo.FindByUserID(ctx, userID)
|
||||
if err != nil {
|
||||
logger.Error("Failed to get profile", "error", err)
|
||||
// Профиль может отсутствовать - не ошибка
|
||||
profile = &models.Profile{UserID: userID}
|
||||
}
|
||||
|
||||
return &models.ProfileWithUser{
|
||||
User: user.ToSafe(),
|
||||
DisplayName: profile.DisplayName,
|
||||
Bio: profile.Bio,
|
||||
AvatarURL: profile.AvatarURL,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateProfile обновляет профиль пользователя
|
||||
func (s *UserService) UpdateProfile(ctx context.Context, userID int64, displayName, bio *string) error {
|
||||
// Валидация
|
||||
if displayName != nil && !validator.ValidateDisplayName(*displayName) {
|
||||
return errors.New("display name too long (max 100 characters)")
|
||||
}
|
||||
|
||||
if bio != nil && !validator.ValidateBio(*bio) {
|
||||
return errors.New("bio too long (max 500 characters)")
|
||||
}
|
||||
|
||||
profile := &models.Profile{
|
||||
UserID: userID,
|
||||
DisplayName: displayName,
|
||||
Bio: bio,
|
||||
}
|
||||
|
||||
if err := s.profileRepo.Update(ctx, profile); err != nil {
|
||||
logger.Error("Failed to update profile", "error", err)
|
||||
return errors.New("failed to update profile")
|
||||
}
|
||||
|
||||
logger.Info("Profile updated", "user_id", userID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateAvatar обновляет аватар пользователя
|
||||
func (s *UserService) UpdateAvatar(ctx context.Context, userID int64, avatarURL *string) error {
|
||||
if err := s.profileRepo.UpdateAvatar(ctx, userID, avatarURL); err != nil {
|
||||
logger.Error("Failed to update avatar", "error", err)
|
||||
return errors.New("failed to update avatar")
|
||||
}
|
||||
|
||||
logger.Info("Avatar updated", "user_id", userID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SearchUsers ищет пользователей по логину
|
||||
func (s *UserService) SearchUsers(ctx context.Context, query string, limit int) ([]*models.SafeUser, error) {
|
||||
if limit <= 0 || limit > 100 {
|
||||
limit = 20
|
||||
}
|
||||
|
||||
users, err := s.userRepo.SearchByLogin(ctx, query, limit)
|
||||
if err != nil {
|
||||
logger.Error("Failed to search users", "error", err)
|
||||
return nil, errors.New("internal server error")
|
||||
}
|
||||
|
||||
safeUsers := make([]*models.SafeUser, len(users))
|
||||
for i, user := range users {
|
||||
safeUsers[i] = user.ToSafe()
|
||||
}
|
||||
|
||||
return safeUsers, nil
|
||||
}
|
||||
|
||||
// GetUserByID возвращает безопасное представление пользователя
|
||||
func (s *UserService) GetUserByID(ctx context.Context, userID int64) (*models.SafeUser, error) {
|
||||
user, err := s.userRepo.FindByID(ctx, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
return nil, errors.New("user not found")
|
||||
}
|
||||
|
||||
return user.ToSafe(), nil
|
||||
}
|
||||
|
||||
// GetUserByLogin возвращает пользователя по логину
|
||||
func (s *UserService) GetUserByLogin(ctx context.Context, login string) (*models.User, error) {
|
||||
return s.userRepo.FindByLogin(ctx, login)
|
||||
}
|
||||
Reference in New Issue
Block a user