refactor(backend): migrate db.DB to db.Conn PoolProxy across all handlers
Replace direct *pgxpool.Pool usage with PoolProxy wrapper across the entire backend: - db.DB renamed to db.Conn (*pgxpool.Pool -> *PoolProxy) - JWT functions now accept context.Context instead of using context.Background() - Handler DB calls route through PoolProxy for per-test transaction support - Fixture/helper/testdb functions accept Querier interface for decoupling - Query ordering fixed in bookings handlers: COUNT after data query to avoid pgx conn busy - Time truncation fixed: time.Date instead of Truncate(24*time.Hour) for week start calc - testmain_test.go files updated with SeedBaseline and NewPoolProxy Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
+14
-14
@@ -35,11 +35,11 @@ func generateJTI() (string, error) {
|
||||
}
|
||||
|
||||
// RevokeJTI adds a JTI to the revoked set in PostgreSQL
|
||||
func RevokeJTI(jti string, expiresAt time.Time) {
|
||||
if db.DB == nil {
|
||||
func RevokeJTI(ctx context.Context, jti string, expiresAt time.Time) {
|
||||
if db.Conn == nil {
|
||||
return
|
||||
}
|
||||
_, err := db.DB.Exec(context.Background(),
|
||||
_, err := db.Conn.Exec(ctx,
|
||||
`INSERT INTO revoked_jtis (jti, expires_at) VALUES ($1, $2)
|
||||
ON CONFLICT (jti) DO NOTHING`,
|
||||
jti, expiresAt)
|
||||
@@ -53,12 +53,12 @@ func RevokeJTI(jti string, expiresAt time.Time) {
|
||||
// Returns false if the DB is not initialized (unit tests, startup) — treating
|
||||
// the token as valid is the safer default for availability over security during
|
||||
// startup, and revoked checks are quickly re-evaluated on each request.
|
||||
func IsJTIRevoked(jti string) bool {
|
||||
if db.DB == nil {
|
||||
func IsJTIRevoked(ctx context.Context, jti string) bool {
|
||||
if db.Conn == nil {
|
||||
return false
|
||||
}
|
||||
var exists bool
|
||||
err := db.DB.QueryRow(context.Background(),
|
||||
err := db.Conn.QueryRow(ctx,
|
||||
`SELECT EXISTS(SELECT 1 FROM revoked_jtis WHERE jti = $1 AND expires_at > NOW())`,
|
||||
jti).Scan(&exists)
|
||||
if err != nil {
|
||||
@@ -68,11 +68,11 @@ func IsJTIRevoked(jti string) bool {
|
||||
}
|
||||
|
||||
// CleanupRevokedJTIs removes expired entries from PostgreSQL
|
||||
func CleanupRevokedJTIs() {
|
||||
if db.DB == nil {
|
||||
func CleanupRevokedJTIs(ctx context.Context) {
|
||||
if db.Conn == nil {
|
||||
return
|
||||
}
|
||||
_, err := db.DB.Exec(context.Background(),
|
||||
_, err := db.Conn.Exec(ctx,
|
||||
`DELETE FROM revoked_jtis WHERE expires_at < NOW()`)
|
||||
if err != nil {
|
||||
fmt.Printf("WARN: Failed to cleanup revoked JTIs: %v\n", err)
|
||||
@@ -85,7 +85,7 @@ func StartJTICleanup() {
|
||||
ticker := time.NewTicker(30 * time.Minute)
|
||||
defer ticker.Stop()
|
||||
for range ticker.C {
|
||||
CleanupRevokedJTIs()
|
||||
CleanupRevokedJTIs(context.Background())
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -145,7 +145,7 @@ func VerifyToken(tokenString string, ctx context.Context) (userID string, role s
|
||||
return "", "", "", fmt.Errorf("invalid jti claim")
|
||||
}
|
||||
|
||||
if IsJTIRevoked(jti) {
|
||||
if IsJTIRevoked(ctx, jti) {
|
||||
return "", "", "", fmt.Errorf("token revoked")
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ func generateRefreshTokenString() (string, error) {
|
||||
|
||||
// GenerateRefreshToken creates a refresh token stored in the database
|
||||
// Returns the opaque token string to return to the client
|
||||
func GenerateRefreshToken(userID string, role string) (string, error) {
|
||||
func GenerateRefreshToken(ctx context.Context, userID string, role string) (string, error) {
|
||||
token, err := generateRefreshTokenString()
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -176,7 +176,7 @@ func GenerateRefreshToken(userID string, role string) (string, error) {
|
||||
RETURNING id`
|
||||
|
||||
var tokenID int64
|
||||
err = db.DB.QueryRow(context.Background(), query, userID, token, role).Scan(&tokenID)
|
||||
err = db.Conn.QueryRow(ctx, query, userID, token, role).Scan(&tokenID)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to store refresh token: %w", err)
|
||||
}
|
||||
@@ -194,7 +194,7 @@ func VerifyRefreshToken(ctx context.Context, tokenString string) (userID string,
|
||||
AND NOT revoked
|
||||
RETURNING user_id, role`
|
||||
|
||||
err = db.DB.QueryRow(ctx, query, tokenString).Scan(&userID, &role)
|
||||
err = db.Conn.QueryRow(ctx, query, tokenString).Scan(&userID, &role)
|
||||
if err != nil {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return "", "", fmt.Errorf("invalid or expired refresh token")
|
||||
|
||||
Reference in New Issue
Block a user