improve sql queries and tables

This commit is contained in:
Sergey Chubaryan 2025-02-21 17:35:25 +03:00
parent 162e7e2f50
commit 3d1fe25dcb
9 changed files with 93 additions and 59 deletions

View File

@ -2,13 +2,11 @@ package models
import "time"
type ActionTokenTarget int
type ActionTokenTarget string
const (
_ ActionTokenTarget = iota
ActionTokenTargetForgotPassword
ActionTokenTargetLogin2FA
ActionTokenVerifyEmail
ActionTokenTargetRestorePassword ActionTokenTarget = "restore"
ActionTokenTargetVerifyEmail ActionTokenTarget = "verify"
)
type ActionTokenDTO struct {

View File

@ -13,7 +13,7 @@ import (
type ShortlinkDTO struct {
Id string
Url string
Expiration time.Time
ExpiresAt time.Time
}
type ShortlinkRepo interface {
@ -35,8 +35,8 @@ func (u *shortlinkRepo) AddShortlink(ctx context.Context, dto ShortlinkDTO) erro
_, span := u.tracer.Start(ctx, "postgres::AddShortlink")
defer span.End()
query := `insert into shortlinks (id, url, expiration) values ($1, $2, $3);`
_, err := u.db.ExecContext(ctx, query, dto.Id, dto.Url, dto.Expiration)
query := `insert into shortlinks (url, expires_at) values ($1, $2);`
_, err := u.db.ExecContext(ctx, query, dto.Url, dto.ExpiresAt)
return err
}
@ -44,14 +44,14 @@ func (u *shortlinkRepo) GetShortlink(ctx context.Context, id string) (*Shortlink
_, span := u.tracer.Start(ctx, "postgres::GetShortlink")
defer span.End()
query := `select url, expiration from shortlinks where id = $1;`
query := `select url, expires_at from shortlinks where id = $1;`
row := u.db.QueryRowContext(ctx, query, id)
if err := row.Err(); err != nil {
return nil, err
}
dto := &ShortlinkDTO{Id: id}
err := row.Scan(&dto.Url, &dto.Expiration)
err := row.Scan(&dto.Url, &dto.ExpiresAt)
if err == nil {
return dto, nil
}

View File

@ -10,16 +10,10 @@ import (
"go.opentelemetry.io/otel/trace"
)
// type userDAO struct {
// Id string `json:"id"`
// Login string `json:"login"`
// Secret string `json:"secret"`
// Name string `json:"name"`
// }
type UserRepo interface {
CreateUser(ctx context.Context, dto models.UserDTO) (*models.UserDTO, error)
UpdateUser(ctx context.Context, userId string, dto models.UserUpdateDTO) error
DeactivateUser(ctx context.Context, userId string) error
SetUserEmailVerified(ctx context.Context, userId string) error
GetUserById(ctx context.Context, id string) (*models.UserDTO, error)
GetUserByEmail(ctx context.Context, login string) (*models.UserDTO, error)
@ -67,6 +61,19 @@ func (u *userRepo) UpdateUser(ctx context.Context, userId string, dto models.Use
return nil
}
func (u *userRepo) DeactivateUser(ctx context.Context, userId string) error {
_, span := u.tracer.Start(ctx, "postgres::DeactivateUser")
defer span.End()
query := `update users set active=false where id = $1;`
_, err := u.db.ExecContext(ctx, query, userId)
if err != nil {
return err
}
return nil
}
func (u *userRepo) SetUserEmailVerified(ctx context.Context, userId string) error {
_, span := u.tracer.Start(ctx, "postgres::SetUserEmailVerified")
defer span.End()

View File

@ -50,7 +50,7 @@ func (s *shortlinkService) CreateShortlink(ctx context.Context, url string) (str
dto := repos.ShortlinkDTO{
Id: id,
Url: url,
Expiration: expiration,
ExpiresAt: expiration,
}
if err := s.repo.AddShortlink(ctx, dto); err != nil {
return "", err
@ -73,7 +73,7 @@ func (s *shortlinkService) GetShortlink(ctx context.Context, id string) (string,
if link == nil {
return "", ErrShortlinkNotexist
}
if time.Now().After(link.Expiration) {
if time.Now().After(link.ExpiresAt) {
return "", ErrShortlinkExpired
}

View File

@ -133,7 +133,7 @@ func (u *userService) AuthenticateUser(ctx context.Context, email, password stri
}
func (u *userService) VerifyEmail(ctx context.Context, actionToken string) error {
token, err := u.deps.ActionTokenRepo.GetActionToken(ctx, actionToken, models.ActionTokenVerifyEmail)
token, err := u.deps.ActionTokenRepo.GetActionToken(ctx, actionToken, models.ActionTokenTargetVerifyEmail)
if err != nil {
return err
}
@ -162,7 +162,7 @@ func (u *userService) SendEmailForgotPassword(ctx context.Context, email string)
models.ActionTokenDTO{
UserId: user.Id,
Value: uuid.New().String(),
Target: models.ActionTokenTargetForgotPassword,
Target: models.ActionTokenTargetRestorePassword,
Expiration: time.Now().Add(15 * time.Minute),
},
)
@ -179,7 +179,7 @@ func (u *userService) sendEmailVerifyUser(ctx context.Context, userId, email str
models.ActionTokenDTO{
UserId: userId,
Value: uuid.New().String(),
Target: models.ActionTokenVerifyEmail,
Target: models.ActionTokenTargetVerifyEmail,
Expiration: time.Now().Add(1 * time.Hour),
},
)
@ -207,7 +207,7 @@ func (u *userService) SendEmailVerifyUser(ctx context.Context, email string) err
}
func (u *userService) ChangePasswordWithToken(ctx context.Context, actionToken, newPassword string) error {
token, err := u.deps.ActionTokenRepo.GetActionToken(ctx, actionToken, models.ActionTokenTargetForgotPassword)
token, err := u.deps.ActionTokenRepo.GetActionToken(ctx, actionToken, models.ActionTokenTargetRestorePassword)
if err != nil {
return err
}

18
sql/00_common.sql Normal file
View File

@ -0,0 +1,18 @@
create or replace function trg_proc_row_updated()
returns trigger as $$
begin
if new is distinct from old then
new.updated_at = now();
end if;
return new;
end;
$$ language plpgsql;
create or replace function trg_proc_row_created()
returns trigger as $$
begin
new.created_at = now();
new.updated_at = now();
return new;
end;
$$ language plpgsql;

View File

@ -4,38 +4,20 @@ create table if not exists users (
secret varchar(256) not null,
full_name varchar(256) not null,
email_verified boolean not null default false,
active boolean,
created_at timestamp,
updated_at timestamp
);
create index if not exists idx_users_email on users(email);
create or replace function set_created_at()
returns trigger as $$
begin
new.created_at = now();
new.updated_at = now();
return new;
end;
$$ language plpgsql;
create or replace trigger trg_user_created
before insert on users
for each row
execute function set_created_at();
create or replace function set_updated_at()
returns trigger as $$
begin
if new is distinct from old then
new.updated_at = now();
end if;
return new;
end;
$$ language plpgsql;
execute function trg_proc_row_created();
create or replace trigger trg_user_updated
before update on users
for each row
when(new is distinct from old)
execute function set_updated_at();
execute function trg_proc_row_updated();

View File

@ -1,5 +1,17 @@
create table if not exists shortlinks (
id text primary key,
url text,
expiration date
);
id int generated always as identity,
url text not null,
expires_at timestamp not null,
created_at timestamp,
updated_at timestamp
create or replace trigger trg_shortlink_created
before insert on shortlinks
for each row
when new is distinct from old
execute function trg_proc_row_created();
create or replace trigger trg_shortlink_updated
before update on shortlinks
for each row when new is distinct from old
execute function trg_proc_row_updated();

View File

@ -1,9 +1,26 @@
create table if not exists action_tokens (
id int generated always as identity,
user_id int,
value text,
target int,
expiration timestamp,
id int primary key generated always as identity,
user_id int references users(id),
value text not null,
target text not null,
expires_at timestamp not null,
created_at timestamp,
updated_at timestamp
primary key(id)
constraint pk_action_tokens_id primary key(id),
constraint check chk_action_tokens_target target in ('verify', 'restore')
);
create index if not exists idx_action_tokens_value on actions_tokens(value);
create or replace trigger trg_action_token_created
before insert on action_tokens
for each row
when new is distinct from old
execute function trg_proc_row_created();
create or replace trigger trg_action_token_updated
before update on action_tokens
for each row
when new is distinct from old
execute function trg_proc_row_updated();