tailly_back_v2/internal/service/session_service.go
madipo2611 0d4b8b203e v0.0.2
2025-05-01 12:17:42 +03:00

104 lines
2.4 KiB
Go

package service
import (
"context"
"crypto/rand"
"encoding/base64"
"errors"
"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)
TerminateSession(ctx context.Context, sessionID int) error
}
type sessionService struct {
sessionRepo repository.SessionRepository
deviceRepo repository.DeviceRepository
mailer MailService
}
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)
}