160 lines
3.0 KiB
Go
160 lines
3.0 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"errors"
|
|
"tailly_back_v2/internal/domain"
|
|
"time"
|
|
)
|
|
|
|
var (
|
|
ErrSessionNotFound = errors.New("session not found")
|
|
)
|
|
|
|
type SessionRepository interface {
|
|
Save(ctx context.Context, session *domain.Session) error
|
|
GetByID(ctx context.Context, id int) (*domain.Session, error)
|
|
GetActiveByUser(ctx context.Context, userID int) ([]*domain.Session, error)
|
|
Terminate(ctx context.Context, id int) error
|
|
TerminateAllForUser(ctx context.Context, userID int) error
|
|
}
|
|
|
|
type sessionRepository struct {
|
|
db *sql.DB
|
|
}
|
|
|
|
func NewSessionRepository(db *sql.DB) SessionRepository {
|
|
return &sessionRepository{db: db}
|
|
}
|
|
|
|
func (r *sessionRepository) Save(ctx context.Context, session *domain.Session) error {
|
|
query := `
|
|
INSERT INTO sessions (
|
|
user_id,
|
|
device_id,
|
|
started_at
|
|
)
|
|
VALUES ($1, $2, $3)
|
|
RETURNING id
|
|
`
|
|
|
|
err := r.db.QueryRowContext(ctx, query,
|
|
session.UserID,
|
|
session.DeviceID,
|
|
session.StartedAt,
|
|
).Scan(&session.ID)
|
|
|
|
return err
|
|
}
|
|
|
|
func (r *sessionRepository) GetByID(ctx context.Context, id int) (*domain.Session, error) {
|
|
query := `
|
|
SELECT
|
|
id,
|
|
user_id,
|
|
device_id,
|
|
started_at,
|
|
ended_at
|
|
FROM sessions
|
|
WHERE id = $1
|
|
`
|
|
|
|
session := &domain.Session{}
|
|
var endedAt sql.NullTime
|
|
|
|
err := r.db.QueryRowContext(ctx, query, id).Scan(
|
|
&session.ID,
|
|
&session.UserID,
|
|
&session.DeviceID,
|
|
&session.StartedAt,
|
|
&endedAt,
|
|
)
|
|
|
|
if err == sql.ErrNoRows {
|
|
return nil, ErrSessionNotFound
|
|
}
|
|
|
|
if endedAt.Valid {
|
|
session.EndedAt = endedAt.Time
|
|
}
|
|
|
|
return session, err
|
|
}
|
|
|
|
func (r *sessionRepository) GetActiveByUser(ctx context.Context, userID int) ([]*domain.Session, error) {
|
|
query := `
|
|
SELECT
|
|
s.id,
|
|
s.user_id,
|
|
s.device_id,
|
|
s.started_at,
|
|
s.ended_at,
|
|
d.name as device_name,
|
|
d.ip_address,
|
|
d.user_agent
|
|
FROM sessions s
|
|
JOIN devices d ON s.device_id = d.id
|
|
WHERE s.user_id = $1 AND s.ended_at IS NULL
|
|
ORDER BY s.started_at DESC
|
|
`
|
|
|
|
rows, err := r.db.QueryContext(ctx, query, userID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
var sessions []*domain.Session
|
|
for rows.Next() {
|
|
var session domain.Session
|
|
var endedAt sql.NullTime
|
|
var device domain.Device
|
|
|
|
err := rows.Scan(
|
|
&session.ID,
|
|
&session.UserID,
|
|
&session.DeviceID,
|
|
&session.StartedAt,
|
|
&endedAt,
|
|
&device.Name,
|
|
&device.IPAddress,
|
|
&device.UserAgent,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if endedAt.Valid {
|
|
session.EndedAt = endedAt.Time
|
|
}
|
|
|
|
session.Device = &device
|
|
sessions = append(sessions, &session)
|
|
}
|
|
|
|
return sessions, nil
|
|
}
|
|
|
|
func (r *sessionRepository) Terminate(ctx context.Context, id int) error {
|
|
query := `
|
|
UPDATE sessions
|
|
SET ended_at = $1
|
|
WHERE id = $2
|
|
`
|
|
|
|
_, err := r.db.ExecContext(ctx, query, time.Now(), id)
|
|
return err
|
|
}
|
|
|
|
func (r *sessionRepository) TerminateAllForUser(ctx context.Context, userID int) error {
|
|
query := `
|
|
UPDATE sessions
|
|
SET ended_at = $1
|
|
WHERE user_id = $2 AND ended_at IS NULL
|
|
`
|
|
|
|
_, err := r.db.ExecContext(ctx, query, time.Now(), userID)
|
|
return err
|
|
}
|