all repos

onasty @ 320377a28130c71ac735eb3f6a77827256aa72bc

a one-time notes service

onasty/internal/store/psql/sessionrepo/sessionrepo.go (view raw)

Olexandr Smirnov Olexandr Smirnov
ss2316544@gmail.com
docs: add missing code comments (#185)..., 9 months ago
1
package sessionrepo
2
3
import (
4
	"context"
5
	"errors"
6
	"time"
7
8
	"github.com/gofrs/uuid/v5"
9
	"github.com/henvic/pgq"
10
	"github.com/jackc/pgx/v5"
11
	"github.com/olexsmir/onasty/internal/models"
12
	"github.com/olexsmir/onasty/internal/store/psqlutil"
13
)
14
15
type SessionStorer interface {
16
	// Set creates new session associated with user.
17
	Set(ctx context.Context, usedID uuid.UUID, refreshToken string, expiresAt time.Time) error
18
19
	// GetUserIDByRefreshToken returns user ID associated with the refresh token.
20
	GetUserIDByRefreshToken(ctx context.Context, refreshToken string) (uuid.UUID, error)
21
22
	// Update updates refresh token with newer.
23
	Update(ctx context.Context, userID uuid.UUID, refreshToken string, newRefreshToken string) error
24
25
	// Delete deletes session by user ID and their refresh token.
26
	Delete(ctx context.Context, userID uuid.UUID, refreshToken string) error
27
28
	// DeleteAllByUserID deletes all sessions associated with user.
29
	DeleteAllByUserID(ctx context.Context, userID uuid.UUID) error
30
}
31
32
var _ SessionStorer = (*SessionRepo)(nil)
33
34
type SessionRepo struct {
35
	db *psqlutil.DB
36
}
37
38
func New(db *psqlutil.DB) *SessionRepo {
39
	return &SessionRepo{
40
		db: db,
41
	}
42
}
43
44
func (s *SessionRepo) Set(
45
	ctx context.Context,
46
	userID uuid.UUID,
47
	refreshToken string,
48
	expiresAt time.Time,
49
) error {
50
	query, args, err := pgq.
51
		Insert("sessions").
52
		Columns("user_id", "refresh_token", "expires_at").
53
		Values(userID, refreshToken, expiresAt).
54
		SQL()
55
	if err != nil {
56
		return err
57
	}
58
59
	_, err = s.db.Exec(ctx, query, args...)
60
	return err
61
}
62
63
func (s *SessionRepo) Update(
64
	ctx context.Context,
65
	userID uuid.UUID,
66
	refreshToken string,
67
	newRefreshToken string,
68
) error {
69
	query := `--sql
70
update sessions
71
set refresh_token = $1
72
where
73
  user_id = $2
74
  and refresh_token = $3
75
  -- and expires_at < now()
76
`
77
78
	res, err := s.db.Exec(ctx, query, newRefreshToken, userID, refreshToken)
79
	if res.RowsAffected() != 1 {
80
		return models.ErrSessionNotFound
81
	}
82
83
	return err
84
}
85
86
func (s *SessionRepo) GetUserIDByRefreshToken(
87
	ctx context.Context,
88
	refreshToken string,
89
) (uuid.UUID, error) {
90
	query, args, err := pgq.
91
		Select("user_id").
92
		From("sessions").
93
		Where(pgq.Eq{"refresh_token": refreshToken}).
94
		SQL()
95
	if err != nil {
96
		return uuid.UUID{}, err
97
	}
98
99
	var userID uuid.UUID
100
	err = s.db.QueryRow(ctx, query, args...).Scan(&userID)
101
	if errors.Is(err, pgx.ErrNoRows) {
102
		return uuid.UUID{}, models.ErrUserNotFound
103
	}
104
105
	return userID, err
106
}
107
108
func (s *SessionRepo) Delete(ctx context.Context, userID uuid.UUID, refreshToken string) error {
109
	query := `--sql
110
DELETE FROM sessions
111
WHERE user_id = $1
112
  AND refresh_token = $2`
113
114
	_, err := s.db.Exec(ctx, query, userID, refreshToken)
115
	return err
116
}
117
118
func (s *SessionRepo) DeleteAllByUserID(ctx context.Context, userID uuid.UUID) error {
119
	query := `--sql
120
delete from sessions
121
where user_id = $1`
122
123
	_, err := s.db.Exec(ctx, query, userID)
124
	return err
125
}