136 lines
3.9 KiB
Go
136 lines
3.9 KiB
Go
package service
|
||
|
||
import (
|
||
"context"
|
||
"crypto/rand"
|
||
"encoding/base64"
|
||
"errors"
|
||
"fmt"
|
||
"tailly_back_v2/internal/domain"
|
||
"tailly_back_v2/internal/repository"
|
||
"time"
|
||
)
|
||
|
||
type SessionService interface {
|
||
InitiateSession(ctx context.Context, device *domain.Device) error
|
||
ConfirmSession(ctx context.Context, token string) (*domain.Session, error)
|
||
GetActiveSessions(ctx context.Context, userID int) ([]*domain.Session, error)
|
||
Terminate(ctx context.Context, userID, sessionID int) error // Изменили сигнатуру
|
||
GetUserSessions(ctx context.Context, userID int) ([]*domain.Session, error) // Добавили этот метод
|
||
}
|
||
|
||
type sessionService struct {
|
||
sessionRepo repository.SessionRepository
|
||
deviceRepo repository.DeviceRepository
|
||
userRepo repository.UserRepository // Добавлено
|
||
mailer MailService
|
||
}
|
||
|
||
func (s *sessionService) GetActiveSessions(ctx context.Context, userID int) ([]*domain.Session, error) {
|
||
// Используем метод репозитория GetActiveByUser, который уже фильтрует активные сессии
|
||
sessions, err := s.sessionRepo.GetActiveByUser(ctx, userID)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to get active sessions: %w", err)
|
||
}
|
||
|
||
// Дополнительная обработка, если нужна
|
||
for _, session := range sessions {
|
||
// Устанавливаем флаг IsCurrent, если нужно
|
||
if session.Device != nil {
|
||
// Можно добавить дополнительную логику проверки текущего устройства
|
||
// Например, сравнение с текущим устройством пользователя
|
||
session.IsCurrent = false // Замените на реальную логику
|
||
}
|
||
}
|
||
|
||
return sessions, nil
|
||
}
|
||
|
||
func NewSessionService(sessionRepo repository.SessionRepository, deviceRepo repository.DeviceRepository, userRepo repository.UserRepository, mailer MailService) SessionService {
|
||
return &sessionService{
|
||
sessionRepo: sessionRepo,
|
||
deviceRepo: deviceRepo,
|
||
userRepo: userRepo,
|
||
mailer: mailer,
|
||
}
|
||
}
|
||
|
||
func (s *sessionService) InitiateSession(ctx context.Context, device *domain.Device) error {
|
||
// Генерация токена подтверждения
|
||
token := make([]byte, 32)
|
||
if _, err := rand.Read(token); err != nil {
|
||
return err
|
||
}
|
||
|
||
device.ConfirmationToken = base64.URLEncoding.EncodeToString(token)
|
||
device.ExpiresAt = time.Now().Add(24 * time.Hour)
|
||
|
||
if err := s.deviceRepo.Save(ctx, device); err != nil {
|
||
return err
|
||
}
|
||
|
||
// Отправка письма
|
||
user, err := s.userRepo.GetByID(ctx, device.UserID)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
return s.mailer.SendSessionConfirmation(
|
||
user.Email,
|
||
device.ConfirmationToken,
|
||
device.IPAddress,
|
||
device.UserAgent,
|
||
)
|
||
}
|
||
|
||
func (s *sessionService) ConfirmSession(ctx context.Context, token string) (*domain.Session, error) {
|
||
device, err := s.deviceRepo.GetByToken(ctx, token)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
if time.Now().After(device.ExpiresAt) {
|
||
return nil, errors.New("confirmation token expired")
|
||
}
|
||
|
||
session := &domain.Session{
|
||
UserID: device.UserID,
|
||
DeviceID: device.ID,
|
||
StartedAt: time.Now(),
|
||
}
|
||
|
||
if err := s.sessionRepo.Save(ctx, session); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return session, nil
|
||
}
|
||
|
||
func (s *sessionService) GetUserSessions(ctx context.Context, userID int) ([]*domain.Session, error) {
|
||
sessions, err := s.sessionRepo.GetActiveByUser(ctx, userID)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
currentSessionID, _ := ctx.Value("sessionID").(int)
|
||
|
||
for _, session := range sessions {
|
||
session.IsCurrent = (session.ID == currentSessionID)
|
||
}
|
||
|
||
return sessions, nil
|
||
}
|
||
|
||
func (s *sessionService) Terminate(ctx context.Context, userID, sessionID int) error {
|
||
session, err := s.sessionRepo.GetByID(ctx, sessionID)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
if session.UserID != userID {
|
||
return errors.New("unauthorized")
|
||
}
|
||
|
||
return s.sessionRepo.Terminate(ctx, sessionID)
|
||
}
|