Simplified the database layer by removing custom interface wrappers and using standard library *sql.DB and *sql.Tx types directly. Changes: - Removed DBConnection and DBTransaction interfaces from database.go - Removed NewDBConnection() wrapper function - Updated TokenGenerator to use *sql.DB instead of DBConnection - Updated all validation and revocation methods to accept *sql.Tx - Updated TableManager to work with *sql.DB directly - Updated all tests to use db.Begin() instead of custom wrappers - Fixed GeneratorConfig.DB field (was DBConn) - Updated documentation in doc.go with correct API usage Benefits: - Simpler API with fewer abstractions - Works directly with database/sql standard library - Compatible with GORM (via gormDB.DB()) and Bun (share same *sql.DB) - Easier to understand and maintain - No unnecessary wrapper layers Breaking changes: - GeneratorConfig.DBConn renamed to GeneratorConfig.DB - Removed NewDBConnection() function - pass *sql.DB directly - ValidateAccess/ValidateRefresh now accept *sql.Tx instead of DBTransaction - Token.Revoke/CheckNotRevoked now accept *sql.Tx instead of DBTransaction 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
109 lines
3.5 KiB
Go
109 lines
3.5 KiB
Go
package hws
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// Error to use with Server.ThrowError
|
|
type HWSError struct {
|
|
StatusCode int // HTTP Status code
|
|
Message string // Error message
|
|
Error error // Error
|
|
Level ErrorLevel // Error level to use for logging. Defaults to Error
|
|
RenderErrorPage bool // If true, the servers ErrorPage will be rendered
|
|
}
|
|
|
|
type ErrorLevel string
|
|
|
|
const (
|
|
ErrorDEBUG ErrorLevel = "Debug"
|
|
ErrorINFO ErrorLevel = "Info"
|
|
ErrorWARN ErrorLevel = "Warn"
|
|
ErrorERROR ErrorLevel = "Error"
|
|
ErrorFATAL ErrorLevel = "Fatal"
|
|
ErrorPANIC ErrorLevel = "Panic"
|
|
)
|
|
|
|
// ErrorPageFunc is a function that returns an ErrorPage with the specified HTTP Status code
|
|
// This will be called by the server when it needs to render an error page
|
|
type ErrorPageFunc func(errorCode int) (ErrorPage, error)
|
|
|
|
// ErrorPage must implement a Render() function that takes in a context and ResponseWriter,
|
|
// and should write a reponse as output to the ResponseWriter.
|
|
// Server.ThrowError will call the Render() function on the current request
|
|
type ErrorPage interface {
|
|
Render(ctx context.Context, w io.Writer) error
|
|
}
|
|
|
|
// TODO: add test for ErrorPageFunc that returns an error
|
|
func (server *Server) AddErrorPage(pageFunc ErrorPageFunc) error {
|
|
rr := httptest.NewRecorder()
|
|
req := httptest.NewRequest("GET", "/", nil)
|
|
page, err := pageFunc(http.StatusInternalServerError)
|
|
if err != nil {
|
|
return errors.Wrap(err, "An error occured when trying to get the error page")
|
|
}
|
|
err = page.Render(req.Context(), rr)
|
|
if err != nil {
|
|
return errors.Wrap(err, "An error occured when trying to render the error page")
|
|
}
|
|
if len(rr.Header()) == 0 && rr.Body.String() == "" {
|
|
return errors.New("Render method of the error page did not write anything to the response writer")
|
|
}
|
|
|
|
server.errorPage = pageFunc
|
|
return nil
|
|
}
|
|
|
|
// ThrowError will write the HTTP status code to the response headers, and log
|
|
// the error with the level specified by the HWSError.
|
|
// If HWSError.RenderErrorPage is true, the error page will be rendered to the ResponseWriter
|
|
// and the request chain should be terminated.
|
|
func (server *Server) ThrowError(w http.ResponseWriter, r *http.Request, error HWSError) error {
|
|
if error.StatusCode <= 0 {
|
|
return errors.New("HWSError.StatusCode cannot be 0.")
|
|
}
|
|
if error.Message == "" {
|
|
return errors.New("HWSError.Message cannot be empty")
|
|
}
|
|
if error.Error == nil {
|
|
return errors.New("HWSError.Error cannot be nil")
|
|
}
|
|
if r == nil {
|
|
return errors.New("Request cannot be nil")
|
|
}
|
|
if !server.IsReady() {
|
|
return errors.New("ThrowError called before server started")
|
|
}
|
|
w.WriteHeader(error.StatusCode)
|
|
server.LogError(error)
|
|
if server.errorPage == nil {
|
|
server.LogError(HWSError{Message: "No error page provided", Error: nil, Level: ErrorDEBUG})
|
|
return nil
|
|
}
|
|
if error.RenderErrorPage {
|
|
server.LogError(HWSError{Message: "Error page rendering", Error: nil, Level: ErrorDEBUG})
|
|
errPage, err := server.errorPage(error.StatusCode)
|
|
if err != nil {
|
|
server.LogError(HWSError{Message: "Failed to get a valid error page", Error: err})
|
|
}
|
|
err = errPage.Render(r.Context(), w)
|
|
if err != nil {
|
|
server.LogError(HWSError{Message: "Failed to render error page", Error: err})
|
|
}
|
|
} else {
|
|
server.LogError(HWSError{Message: "Error page specified not to render", Error: nil, Level: ErrorDEBUG})
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (server *Server) ThrowFatal(w http.ResponseWriter, err error) {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
server.LogFatal(err)
|
|
}
|