diff --git a/sql/03_action_token.sql b/sql/03_action_token.sql new file mode 100644 index 0000000..532d0eb --- /dev/null +++ b/sql/03_action_token.sql @@ -0,0 +1,9 @@ +create table if not exists action_tokens ( + id int generated always as identity, + user_id int, + value text + target int, + expiration timestamp, + + primary key(id) +); \ No newline at end of file diff --git a/src/core/models/action_token.go b/src/core/models/action_token.go index a8b01d5..15d5991 100644 --- a/src/core/models/action_token.go +++ b/src/core/models/action_token.go @@ -1,5 +1,7 @@ package models +import "time" + type ActionTokenTarget int const ( @@ -8,8 +10,9 @@ const ( ) type ActionTokenDTO struct { - Id string - UserId string - Value string - Target ActionTokenTarget + Id string + UserId string + Value string + Target ActionTokenTarget + Expiration time.Time } diff --git a/src/core/repos/action_token.go b/src/core/repos/action_token.go index b8c20a7..64a4873 100644 --- a/src/core/repos/action_token.go +++ b/src/core/repos/action_token.go @@ -4,6 +4,7 @@ import ( "backend/src/core/models" "backend/src/integrations" "context" + "database/sql" ) type ActionTokenRepo interface { @@ -24,10 +25,10 @@ type actionTokenRepo struct { func (a *actionTokenRepo) CreateActionToken(ctx context.Context, dto models.ActionTokenDTO) (*models.ActionTokenDTO, error) { query := ` insert into - action_tokens (user_id, value, target) - values ($1, $2, $3) + action_tokens (user_id, value, target, expiration) + values ($1, $2, $3, $4) returning id;` - row := a.db.QueryRowContext(ctx, query, dto.UserId, dto.Value, dto.Target) + row := a.db.QueryRowContext(ctx, query, dto.UserId, dto.Value, dto.Target, dto.Expiration) id := "" if err := row.Scan(&id); err != nil { @@ -46,12 +47,18 @@ func (a *actionTokenRepo) PopActionToken(ctx context.Context, userId, value stri query := ` delete from action_tokens - where user_id=$1 and value=$2 and target=$3 + where + user_id=$1 and value=$2 and target=$3 + and CURRENT_TIMESTAMP < expiration returning id;` row := a.db.QueryRowContext(ctx, query, userId, value, target) id := "" - if err := row.Scan(&id); err != nil { + err := row.Scan(&id) + if err == sql.ErrNoRows { + return nil, nil + } + if err != nil { return nil, err } diff --git a/src/core/services/user_service.go b/src/core/services/user_service.go index e909a57..2142fde 100644 --- a/src/core/services/user_service.go +++ b/src/core/services/user_service.go @@ -122,9 +122,10 @@ func (u *userService) HelpPasswordForgot(ctx context.Context, userId string) err actionToken, err := u.deps.ActionTokenRepo.CreateActionToken( ctx, models.ActionTokenDTO{ - UserId: user.Id, - Value: uuid.New().String(), - Target: models.ActionTokenTargetForgotPassword, + UserId: user.Id, + Value: uuid.New().String(), + Target: models.ActionTokenTargetForgotPassword, + Expiration: time.Now().Add(1 * time.Hour), }, ) if err != nil {