mirror of
https://github.com/Dvorinka/Bookra.git
synced 2026-06-05 04:52:59 +00:00
cleanup
This commit is contained in:
@@ -0,0 +1,224 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
Email string `json:"email"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
PasswordHash *string `json:"-"`
|
||||
EmailVerified bool `json:"email_verified"`
|
||||
Provider string `json:"provider"`
|
||||
ProviderID *string `json:"provider_id,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
LastLoginAt *time.Time `json:"last_login_at,omitempty"`
|
||||
}
|
||||
|
||||
type MagicLink struct {
|
||||
Token string `json:"token"`
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
Email string `json:"email"`
|
||||
Used bool `json:"used"`
|
||||
ExpiresAt time.Time `json:"expires_at"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
func (db *DB) GetUserByEmail(ctx context.Context, email string) (*User, error) {
|
||||
var user User
|
||||
var name, passwordHash, providerID *string
|
||||
var lastLoginAt *time.Time
|
||||
|
||||
err := db.QueryRow(ctx, `
|
||||
SELECT id, email, name, password_hash, email_verified, provider, provider_id, created_at, updated_at, last_login_at
|
||||
FROM users
|
||||
WHERE email = $1
|
||||
`, email).Scan(
|
||||
&user.ID, &user.Email, &name, &passwordHash,
|
||||
&user.EmailVerified, &user.Provider, &providerID,
|
||||
&user.CreatedAt, &user.UpdatedAt, &lastLoginAt,
|
||||
)
|
||||
if err == pgx.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user.Name = name
|
||||
user.PasswordHash = passwordHash
|
||||
user.ProviderID = providerID
|
||||
user.LastLoginAt = lastLoginAt
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
func (db *DB) GetUserByID(ctx context.Context, id uuid.UUID) (*User, error) {
|
||||
var user User
|
||||
var name, passwordHash, providerID *string
|
||||
var lastLoginAt *time.Time
|
||||
|
||||
err := db.QueryRow(ctx, `
|
||||
SELECT id, email, name, password_hash, email_verified, provider, provider_id, created_at, updated_at, last_login_at
|
||||
FROM users
|
||||
WHERE id = $1
|
||||
`, id).Scan(
|
||||
&user.ID, &user.Email, &name, &passwordHash,
|
||||
&user.EmailVerified, &user.Provider, &providerID,
|
||||
&user.CreatedAt, &user.UpdatedAt, &lastLoginAt,
|
||||
)
|
||||
if err == pgx.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user.Name = name
|
||||
user.PasswordHash = passwordHash
|
||||
user.ProviderID = providerID
|
||||
user.LastLoginAt = lastLoginAt
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
func (db *DB) GetUserByProviderID(ctx context.Context, provider, providerID string) (*User, error) {
|
||||
var user User
|
||||
var name, passwordHash *string
|
||||
var lastLoginAt *time.Time
|
||||
|
||||
err := db.QueryRow(ctx, `
|
||||
SELECT id, email, name, password_hash, email_verified, provider, provider_id, created_at, updated_at, last_login_at
|
||||
FROM users
|
||||
WHERE provider = $1 AND provider_id = $2
|
||||
`, provider, providerID).Scan(
|
||||
&user.ID, &user.Email, &name, &passwordHash,
|
||||
&user.EmailVerified, &user.Provider, &user.ProviderID,
|
||||
&user.CreatedAt, &user.UpdatedAt, &lastLoginAt,
|
||||
)
|
||||
if err == pgx.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user.Name = name
|
||||
user.PasswordHash = passwordHash
|
||||
user.LastLoginAt = lastLoginAt
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
func (db *DB) CreateUser(ctx context.Context, user *User) (*User, error) {
|
||||
if user.ID == uuid.Nil {
|
||||
user.ID = uuid.Must(uuid.NewV7())
|
||||
}
|
||||
now := time.Now()
|
||||
user.CreatedAt = now
|
||||
user.UpdatedAt = now
|
||||
|
||||
_, err := db.pool.Exec(ctx, `
|
||||
INSERT INTO users (id, email, name, password_hash, email_verified, provider, provider_id, created_at, updated_at)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $8)
|
||||
`, user.ID, user.Email, user.Name, user.PasswordHash, user.EmailVerified, user.Provider, user.ProviderID, now)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create user: %w", err)
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (db *DB) UpdateUser(ctx context.Context, user *User) error {
|
||||
user.UpdatedAt = time.Now()
|
||||
|
||||
_, err := db.pool.Exec(ctx, `
|
||||
UPDATE users
|
||||
SET email = $2, name = $3, password_hash = $4, email_verified = $5,
|
||||
provider = $6, provider_id = $7, updated_at = $8, last_login_at = $9
|
||||
WHERE id = $1
|
||||
`, user.ID, user.Email, user.Name, user.PasswordHash, user.EmailVerified,
|
||||
user.Provider, user.ProviderID, user.UpdatedAt, user.LastLoginAt)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) UpdateLastLogin(ctx context.Context, userID uuid.UUID) error {
|
||||
_, err := db.pool.Exec(ctx, `
|
||||
UPDATE users SET last_login_at = NOW(), updated_at = NOW() WHERE id = $1
|
||||
`, userID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) CreateMagicLink(ctx context.Context, token string, email string, userID uuid.UUID, expiresAt time.Time) error {
|
||||
_, err := db.pool.Exec(ctx, `
|
||||
INSERT INTO magic_links (token, user_id, email, expires_at, created_at)
|
||||
VALUES ($1, $2, $3, $4, NOW())
|
||||
`, token, userID, email, expiresAt)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) GetMagicLink(ctx context.Context, token string) (*MagicLink, error) {
|
||||
var ml MagicLink
|
||||
var userID uuid.UUID
|
||||
|
||||
err := db.QueryRow(ctx, `
|
||||
SELECT token, user_id, email, used, expires_at, created_at
|
||||
FROM magic_links
|
||||
WHERE token = $1
|
||||
`, token).Scan(&ml.Token, &userID, &ml.Email, &ml.Used, &ml.ExpiresAt, &ml.CreatedAt)
|
||||
if err == pgx.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ml.UserID = userID
|
||||
return &ml, nil
|
||||
}
|
||||
|
||||
func (db *DB) MarkMagicLinkUsed(ctx context.Context, token string) error {
|
||||
_, err := db.pool.Exec(ctx, `UPDATE magic_links SET used = true WHERE token = $1`, token)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) PutKV(ctx context.Context, key string, value any) error {
|
||||
payload, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshal kv value: %w", err)
|
||||
}
|
||||
|
||||
_, err = db.pool.Exec(ctx, `
|
||||
INSERT INTO stripe_kv (key, value, created_at, updated_at)
|
||||
VALUES ($1, $2, NOW(), NOW())
|
||||
ON CONFLICT (key) DO UPDATE
|
||||
SET value = EXCLUDED.value, updated_at = NOW()
|
||||
`, key, payload)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) GetKV(ctx context.Context, key string, dest any) (bool, error) {
|
||||
var payload []byte
|
||||
err := db.QueryRow(ctx, `
|
||||
SELECT value
|
||||
FROM stripe_kv
|
||||
WHERE key = $1
|
||||
`, key).Scan(&payload)
|
||||
if err == pgx.ErrNoRows {
|
||||
return false, nil
|
||||
}
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if err := json.Unmarshal(payload, dest); err != nil {
|
||||
return false, fmt.Errorf("unmarshal kv value: %w", err)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
Reference in New Issue
Block a user