Address production-readiness review: clearer errors, safer votes, and ops hardening.
Distinguish auth/lookup failures, make votes idempotent on visible questions, bound shutdown, page admin users, LRU throttle, trusted-proxy CIDRs, avatar cleanup, versioned migrations, and session cleanup logging.
This commit is contained in:
@@ -10,14 +10,17 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const deleteExpiredSessions = `-- name: DeleteExpiredSessions :exec
|
||||
const deleteExpiredSessions = `-- name: DeleteExpiredSessions :execrows
|
||||
DELETE FROM sessions
|
||||
WHERE expiry <= now()
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteExpiredSessions(ctx context.Context) error {
|
||||
_, err := q.db.ExecContext(ctx, deleteExpiredSessions)
|
||||
return err
|
||||
func (q *Queries) DeleteExpiredSessions(ctx context.Context) (int64, error) {
|
||||
result, err := q.db.ExecContext(ctx, deleteExpiredSessions)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return result.RowsAffected()
|
||||
}
|
||||
|
||||
const deleteSession = `-- name: DeleteSession :exec
|
||||
|
||||
@@ -129,10 +129,27 @@ func (q *Queries) GetUserRole(ctx context.Context, id string) (string, error) {
|
||||
const listUsers = `-- name: ListUsers :many
|
||||
SELECT id, username, name, role, avatar_url, state, created_at
|
||||
FROM users
|
||||
ORDER BY created_at ASC
|
||||
LIMIT $1
|
||||
WHERE (
|
||||
$1 = ''
|
||||
OR username ILIKE '%' || $1 || '%'
|
||||
OR name ILIKE '%' || $1 || '%'
|
||||
)
|
||||
AND (
|
||||
$2 = ''
|
||||
OR created_at < $2
|
||||
OR (created_at = $2 AND id < $3)
|
||||
)
|
||||
ORDER BY created_at DESC, id DESC
|
||||
LIMIT $4
|
||||
`
|
||||
|
||||
type ListUsersParams struct {
|
||||
Search interface{}
|
||||
CursorCreated interface{}
|
||||
CursorID string
|
||||
RowLimit int32
|
||||
}
|
||||
|
||||
type ListUsersRow struct {
|
||||
ID string
|
||||
Username string
|
||||
@@ -143,8 +160,13 @@ type ListUsersRow struct {
|
||||
CreatedAt string
|
||||
}
|
||||
|
||||
func (q *Queries) ListUsers(ctx context.Context, rowLimit int32) ([]ListUsersRow, error) {
|
||||
rows, err := q.db.QueryContext(ctx, listUsers, rowLimit)
|
||||
func (q *Queries) ListUsers(ctx context.Context, arg ListUsersParams) ([]ListUsersRow, error) {
|
||||
rows, err := q.db.QueryContext(ctx, listUsers,
|
||||
arg.Search,
|
||||
arg.CursorCreated,
|
||||
arg.CursorID,
|
||||
arg.RowLimit,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -42,20 +42,41 @@ func (q *Queries) GetVote(ctx context.Context, arg GetVoteParams) (int32, error)
|
||||
return value, err
|
||||
}
|
||||
|
||||
const upsertVote = `-- name: UpsertVote :exec
|
||||
INSERT INTO votes (user_id, question_id, value)
|
||||
VALUES ($1, $2, $3)
|
||||
ON CONFLICT (user_id, question_id) DO UPDATE
|
||||
SET value = excluded.value
|
||||
const questionIsVisible = `-- name: QuestionIsVisible :one
|
||||
SELECT EXISTS(
|
||||
SELECT 1 FROM questions WHERE id = $1 AND hidden = 0
|
||||
)::bool
|
||||
`
|
||||
|
||||
type UpsertVoteParams struct {
|
||||
func (q *Queries) QuestionIsVisible(ctx context.Context, id string) (bool, error) {
|
||||
row := q.db.QueryRowContext(ctx, questionIsVisible, id)
|
||||
var column_1 bool
|
||||
err := row.Scan(&column_1)
|
||||
return column_1, err
|
||||
}
|
||||
|
||||
const upsertVoteOnVisible = `-- name: UpsertVoteOnVisible :execrows
|
||||
INSERT INTO votes (user_id, question_id, value)
|
||||
SELECT $1, $2, $3
|
||||
FROM questions q
|
||||
WHERE q.id = $2 AND q.hidden = 0
|
||||
ON CONFLICT (user_id, question_id) DO UPDATE
|
||||
SET value = excluded.value
|
||||
WHERE EXISTS (
|
||||
SELECT 1 FROM questions q2 WHERE q2.id = excluded.question_id AND q2.hidden = 0
|
||||
)
|
||||
`
|
||||
|
||||
type UpsertVoteOnVisibleParams struct {
|
||||
UserID string
|
||||
QuestionID string
|
||||
Value int32
|
||||
}
|
||||
|
||||
func (q *Queries) UpsertVote(ctx context.Context, arg UpsertVoteParams) error {
|
||||
_, err := q.db.ExecContext(ctx, upsertVote, arg.UserID, arg.QuestionID, arg.Value)
|
||||
return err
|
||||
func (q *Queries) UpsertVoteOnVisible(ctx context.Context, arg UpsertVoteOnVisibleParams) (int64, error) {
|
||||
result, err := q.db.ExecContext(ctx, upsertVoteOnVisible, arg.UserID, arg.QuestionID, arg.Value)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return result.RowsAffected()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user