228 lines
4.2 KiB
Go
228 lines
4.2 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"errors"
|
|
"tailly_back_v2/internal/domain"
|
|
)
|
|
|
|
var (
|
|
ErrRecoveryRequestNotFound = errors.New("recovery request not found")
|
|
ErrRecoveryMethodNotFound = errors.New("recovery method not found")
|
|
)
|
|
|
|
type RecoveryRepository interface {
|
|
SaveRequest(ctx context.Context, req *domain.RecoveryRequest) error
|
|
GetRequestByToken(ctx context.Context, token string) (*domain.RecoveryRequest, error)
|
|
UpdateRequest(ctx context.Context, req *domain.RecoveryRequest) error
|
|
GetMethods(ctx context.Context, userID int) ([]*domain.RecoveryMethod, error)
|
|
SaveMethod(ctx context.Context, method *domain.RecoveryMethod) error
|
|
}
|
|
|
|
type recoveryRepository struct {
|
|
db *sql.DB
|
|
}
|
|
|
|
func NewRecoveryRepository(db *sql.DB) RecoveryRepository {
|
|
return &recoveryRepository{db: db}
|
|
}
|
|
|
|
func (r *recoveryRepository) SaveRequest(ctx context.Context, req *domain.RecoveryRequest) error {
|
|
query := `
|
|
INSERT INTO recovery_requests (
|
|
user_id,
|
|
token,
|
|
new_device_id,
|
|
status,
|
|
created_at,
|
|
expires_at
|
|
)
|
|
VALUES ($1, $2, $3, $4, $5, $6)
|
|
RETURNING id
|
|
`
|
|
|
|
var deviceID interface{}
|
|
if req.NewDevice != nil {
|
|
deviceID = req.NewDevice.ID
|
|
} else {
|
|
deviceID = nil
|
|
}
|
|
|
|
err := r.db.QueryRowContext(ctx, query,
|
|
req.UserID,
|
|
req.Token,
|
|
deviceID,
|
|
req.Status,
|
|
req.CreatedAt,
|
|
req.ExpiresAt,
|
|
).Scan(&req.ID)
|
|
|
|
return err
|
|
}
|
|
|
|
func (r *recoveryRepository) GetRequestByToken(ctx context.Context, token string) (*domain.RecoveryRequest, error) {
|
|
query := `
|
|
SELECT
|
|
r.id,
|
|
r.user_id,
|
|
r.token,
|
|
r.status,
|
|
r.created_at,
|
|
r.expires_at,
|
|
d.id,
|
|
d.user_id,
|
|
d.name,
|
|
d.ip_address,
|
|
d.user_agent,
|
|
d.created_at
|
|
FROM recovery_requests r
|
|
LEFT JOIN devices d ON r.new_device_id = d.id
|
|
WHERE r.token = $1
|
|
`
|
|
|
|
req := &domain.RecoveryRequest{}
|
|
var device domain.Device
|
|
var deviceID sql.NullInt64
|
|
|
|
err := r.db.QueryRowContext(ctx, query, token).Scan(
|
|
&req.ID,
|
|
&req.UserID,
|
|
&req.Token,
|
|
&req.Status,
|
|
&req.CreatedAt,
|
|
&req.ExpiresAt,
|
|
&deviceID,
|
|
&device.UserID,
|
|
&device.Name,
|
|
&device.IPAddress,
|
|
&device.UserAgent,
|
|
&device.CreatedAt,
|
|
)
|
|
|
|
if err == sql.ErrNoRows {
|
|
return nil, ErrRecoveryRequestNotFound
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if deviceID.Valid {
|
|
device.ID = int(deviceID.Int64)
|
|
req.NewDevice = &device
|
|
}
|
|
|
|
return req, nil
|
|
}
|
|
|
|
func (r *recoveryRepository) UpdateRequest(ctx context.Context, req *domain.RecoveryRequest) error {
|
|
query := `
|
|
UPDATE recovery_requests
|
|
SET
|
|
status = $1,
|
|
new_device_id = $2
|
|
WHERE id = $3
|
|
`
|
|
|
|
var deviceID interface{}
|
|
if req.NewDevice != nil {
|
|
deviceID = req.NewDevice.ID
|
|
} else {
|
|
deviceID = nil
|
|
}
|
|
|
|
_, err := r.db.ExecContext(ctx, query,
|
|
req.Status,
|
|
deviceID,
|
|
req.ID,
|
|
)
|
|
|
|
return err
|
|
}
|
|
|
|
func (r *recoveryRepository) GetMethods(ctx context.Context, userID int) ([]*domain.RecoveryMethod, error) {
|
|
query := `
|
|
SELECT
|
|
id,
|
|
user_id,
|
|
method_type,
|
|
value,
|
|
is_primary,
|
|
verified_at,
|
|
created_at
|
|
FROM recovery_methods
|
|
WHERE user_id = $1
|
|
ORDER BY is_primary DESC, created_at ASC
|
|
`
|
|
|
|
rows, err := r.db.QueryContext(ctx, query, userID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
var methods []*domain.RecoveryMethod
|
|
for rows.Next() {
|
|
var method domain.RecoveryMethod
|
|
var verifiedAt sql.NullTime
|
|
|
|
err := rows.Scan(
|
|
&method.ID,
|
|
&method.UserID,
|
|
&method.MethodType,
|
|
&method.Value,
|
|
&method.IsPrimary,
|
|
&verifiedAt,
|
|
&method.CreatedAt,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if verifiedAt.Valid {
|
|
method.VerifiedAt = verifiedAt.Time
|
|
}
|
|
|
|
methods = append(methods, &method)
|
|
}
|
|
|
|
if len(methods) == 0 {
|
|
return nil, ErrRecoveryMethodNotFound
|
|
}
|
|
|
|
return methods, nil
|
|
}
|
|
|
|
func (r *recoveryRepository) SaveMethod(ctx context.Context, method *domain.RecoveryMethod) error {
|
|
query := `
|
|
INSERT INTO recovery_methods (
|
|
user_id,
|
|
method_type,
|
|
value,
|
|
is_primary,
|
|
verified_at,
|
|
created_at
|
|
)
|
|
VALUES ($1, $2, $3, $4, $5, $6)
|
|
RETURNING id
|
|
`
|
|
|
|
var verifiedAt interface{}
|
|
if !method.VerifiedAt.IsZero() {
|
|
verifiedAt = method.VerifiedAt
|
|
} else {
|
|
verifiedAt = nil
|
|
}
|
|
|
|
err := r.db.QueryRowContext(ctx, query,
|
|
method.UserID,
|
|
method.MethodType,
|
|
method.Value,
|
|
method.IsPrimary,
|
|
verifiedAt,
|
|
method.CreatedAt,
|
|
).Scan(&method.ID)
|
|
|
|
return err
|
|
}
|