all repos

onasty @ e21d37bab459675c3789549338bb699769f1687b

a one-time notes service

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

Smirnov Oleksandr Smirnov Oleksandr
ss2316544@gmail.com
refactor: use models in verification tokes repo (#113)..., 1 year ago
1
package vertokrepo
2
3
import (
4
	"context"
5
	"time"
6
7
	"github.com/gofrs/uuid/v5"
8
	"github.com/henvic/pgq"
9
	"github.com/olexsmir/onasty/internal/models"
10
	"github.com/olexsmir/onasty/internal/store/psqlutil"
11
)
12
13
type VerificationTokenStorer interface {
14
	Create(ctx context.Context, token models.VerificationToken) error
15
16
	GetUserIDByTokenAndMarkAsUsed(
17
		ctx context.Context,
18
		token string,
19
		usedAT time.Time,
20
	) (uuid.UUID, error)
21
22
	GetTokenOrUpdateTokenByUserID(
23
		ctx context.Context,
24
		userID uuid.UUID,
25
		token string,
26
		tokenExpirationTime time.Time,
27
	) (string, error)
28
}
29
30
var _ VerificationTokenStorer = (*VerificationTokenRepo)(nil)
31
32
type VerificationTokenRepo struct {
33
	db *psqlutil.DB
34
}
35
36
func New(db *psqlutil.DB) *VerificationTokenRepo {
37
	return &VerificationTokenRepo{
38
		db: db,
39
	}
40
}
41
42
func (r *VerificationTokenRepo) Create(
43
	ctx context.Context,
44
	token models.VerificationToken,
45
) error {
46
	query, aggs, err := pgq.
47
		Insert("verification_tokens").
48
		Columns("user_id", "token", "created_at", "expires_at").
49
		Values(token.UserID, token.Token, token.CreatedAt, token.ExpiresAt).
50
		SQL()
51
	if err != nil {
52
		return err
53
	}
54
55
	_, err = r.db.Exec(ctx, query, aggs...)
56
	return err
57
}
58
59
func (r *VerificationTokenRepo) GetUserIDByTokenAndMarkAsUsed(
60
	ctx context.Context,
61
	token string,
62
	usedAt time.Time,
63
) (uuid.UUID, error) {
64
	tx, err := r.db.Begin(ctx)
65
	if err != nil {
66
		return uuid.Nil, err
67
	}
68
	defer tx.Rollback(ctx) //nolint:errcheck
69
70
	var isUsed bool
71
	err = tx.QueryRow(ctx, "select used_at is not null from verification_tokens where token = $1", token).
72
		Scan(&isUsed)
73
	if err != nil {
74
		return uuid.Nil, err
75
	}
76
77
	if isUsed {
78
		return uuid.Nil, models.ErrUserIsAlreadyVerified
79
	}
80
81
	query := `--sql
82
update verification_tokens
83
set used_at = $1
84
where token = $2
85
returning user_id`
86
87
	var userID uuid.UUID
88
	err = tx.QueryRow(ctx, query, usedAt, token).Scan(&userID)
89
	if err != nil {
90
		return uuid.Nil, err
91
	}
92
93
	return userID, tx.Commit(ctx)
94
}
95
96
func (r *VerificationTokenRepo) GetTokenOrUpdateTokenByUserID(
97
	ctx context.Context,
98
	userID uuid.UUID,
99
	token string,
100
	tokenExpirationTime time.Time,
101
) (string, error) {
102
	query := `--sql
103
insert into verification_tokens (user_id, token, expires_at)
104
values ($1, $2, $3)
105
on conflict (user_id)
106
  do update set
107
    token = $2,
108
    expires_at = $3
109
returning token`
110
111
	var res string
112
	err := r.db.QueryRow(ctx, query, userID, token, tokenExpirationTime).Scan(&res)
113
	return res, err
114
}