refactor: remove dead code across server, templ pages, and client modules

Deadcode-verified removals (RTA reachability from main, cross-checked
with -test and textual xrefs):

Go server:
- whole files: middleware/transaction.go, middleware/error_handler.go,
  middleware/password_validator.go (live registration machinery kept),
  handlers/sync.go, sync/offline.go
- unrouted endpoints: auth UpdateUsername/UpdateEmail, timezone
  settings handler, OPDS RegisterOPDS, Kobo LibrarySync handler,
  ReaderHandler.ShowReader, JSON-data twins on collections/library
- duplicate book-matching handlers (book_matching.go Handler twins,
  matching.go MatchingHandler twins), superseded helpers
  (router.parseUUID, handlers.ValidateDeviceToken, normalizePath,
  userExists, generateLockID)

Templ/client:
- never-routed pages: api_explorer.templ, queue.templ and their
  client modules api-explorer.ts, api-explorer-docs.ts, queue.ts
- fully orphaned wrapper modules events.ts, dom.ts
- broken clearSyncQueue (called a nonexistent endpoint) and the
  hidden, never-populated sync-queue section on the devices page
- 166+ unused exports demoted to private (knip-verified); ~85 truly
  dead declarations removed via tsc noUnusedLocals fixpoint
- stale 'interactive API Explorer' claims dropped from docs

The docs drift-gate package (internal/docs), templ-bound modules
(dashboard, stats, header, index, login, profile*, bookshelf,
collections, toast-error), sqlc-generated code, and web/static are
intentionally untouched.
This commit is contained in:
John O'Keefe committed 2026-10-25 11:06:08 -04:00
1 parent 8733e83f1f
commit 8631aa00bf
107 files changed
+689 -3443

No files matched your search

-1
View File
@@ -8,7 +8,6 @@ import (
"strings"
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v5"
)
-128
View File
@@ -2,45 +2,17 @@ package middleware
import (
"bookhoard/internal/database"
"context"
"net/http"
"net/http/httptest"
"testing"
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v5"
"github.com/stretchr/testify/assert"
)
// Mock database for testing device auth middleware
type mockDeviceDB struct {
device database.Devices
err error
}
func (m *mockDeviceDB) GetDeviceByAuthToken(ctx context.Context, token string) (database.Devices, error) {
return m.device, m.err
}
func TestDeviceAuth_Authenticate_BearerToken(t *testing.T) {
deviceID := uuid.New()
userID := uuid.New()
authToken := "test_bearer_token_123"
mockDB := &mockDeviceDB{
device: database.Devices{
ID: pgtype.UUID{Bytes: [16]byte(deviceID), Valid: true},
UserID: pgtype.UUID{Bytes: [16]byte(userID), Valid: true},
DeviceName: "Test KOReader Device",
DeviceType: "koreader",
AuthToken: authToken,
SyncEnabled: pgtype.Bool{Bool: true, Valid: true},
AutoSync: pgtype.Bool{Bool: true, Valid: true},
},
err: nil,
}
middleware := &DeviceAuthMiddleware{
// Can't use mockDB directly due to interface mismatch
// In real scenario, would use a mock database or test database
@@ -70,7 +42,6 @@ func TestDeviceAuth_Authenticate_BearerToken(t *testing.T) {
// Would call handler(c) and assert results
_ = handler
_ = c
_ = mockDB
// Test implementation would verify:
// 1. Bearer token is extracted correctly
@@ -125,102 +96,3 @@ func TestDeviceAuth_GetRequestType(t *testing.T) {
})
}
}
func TestDeviceAuth_HasPermission(t *testing.T) {
middleware := &DeviceAuthMiddleware{}
tests := []struct {
name string
deviceType string
permission string
expected bool
}{
{
name: "KOReader progress permission",
deviceType: "koreader",
permission: "sync:progress",
expected: true,
},
{
name: "KOReader annotations permission",
deviceType: "koreader",
permission: "sync:annotations",
expected: true,
},
{
name: "KOReader metadata permission",
deviceType: "koreader",
permission: "sync:metadata",
expected: true,
},
{
name: "Kobo progress permission",
deviceType: "kobo",
permission: "sync:progress",
expected: true,
},
{
name: "Kobo annotations permission",
deviceType: "kobo",
permission: "sync:annotations",
expected: true,
},
{
name: "Web device manage permission",
deviceType: "web",
permission: "device:manage",
expected: true,
},
{
name: "KOReader without manage permission",
deviceType: "koreader",
permission: "device:manage",
expected: false,
},
{
name: "Unknown device type",
deviceType: "unknown",
permission: "sync:progress",
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := middleware.hasPermission(tt.deviceType, tt.permission)
assert.Equal(t, tt.expected, result)
})
}
}
func TestDeviceAuth_UpdateLastSeen(t *testing.T) {
// This test verifies the middleware structure
// In practice, UpdateLastSeen requires a database connection
middleware := &DeviceAuthMiddleware{}
e := echo.New()
req := httptest.NewRequest("GET", "/api/sync/koreader/progress", nil)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
deviceID := uuid.New()
c.Set("device_id", [16]byte(deviceID))
next := func(c *echo.Context) error {
// Simulate successful handler execution
return c.JSON(http.StatusOK, map[string]string{"status": "ok"})
}
handler := middleware.UpdateLastSeen(next)
// Note: Without a real database, this will fail when trying to update
// This test verifies the middleware structure and flow
// In production, would use a test database
_ = handler
_ = c
// Verify the device_id was set correctly in context
deviceIDBytes, ok := c.Get("device_id").([16]byte)
assert.True(t, ok, "device_id should be set in context")
assert.Equal(t, [16]byte(deviceID), deviceIDBytes, "device_id should match")
}
@@ -146,17 +146,6 @@ func (drl *DeviceRateLimiter) GetRemainingRequests(deviceID string, requestType
return remaining
}
func (drl *DeviceRateLimiter) Reset(deviceID string) {
drl.mu.Lock()
defer drl.mu.Unlock()
for key := range drl.requests {
if len(key) > len(deviceID) && key[:len(deviceID)] == deviceID {
delete(drl.requests, key)
}
}
}
func (drl *DeviceRateLimiter) cleanupOldEntries() {
for range drl.cleanup.C {
drl.mu.Lock()
+5 -155
View File
@@ -7,127 +7,6 @@ import (
"github.com/stretchr/testify/assert"
)
func TestPasswordValidator_ValidatePassword(t *testing.T) {
tests := []struct {
name string
password string
wantValid bool
}{
{
name: "valid password with all requirements",
password: "Test@Pass123!",
wantValid: true,
},
{
name: "valid password with special chars",
password: "MyP@ssw0rd#2024",
wantValid: true,
},
{
name: "too short",
password: "Test1!",
wantValid: false,
},
{
name: "no uppercase",
password: "test@pass123!",
wantValid: false,
},
{
name: "no lowercase",
password: "TEST@PASS123!",
wantValid: false,
},
{
name: "no number",
password: "Test@Password!",
wantValid: false,
},
{
name: "no special character",
password: "TestPassword123",
wantValid: false,
},
{
name: "empty string",
password: "",
wantValid: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidatePassword(tt.password)
if tt.wantValid {
assert.NoError(t, err)
} else {
assert.Error(t, err)
}
})
}
}
func TestPasswordValidator_ErrorMessages(t *testing.T) {
tests := []struct {
name string
password string
expectedInError string
}{
{
name: "too short error",
password: "Short1!",
expectedInError: "at least 8 characters",
},
{
name: "no uppercase error",
password: "alllower123!",
expectedInError: "uppercase letter",
},
{
name: "no lowercase error",
password: "ALLUPPER123!",
expectedInError: "lowercase letter",
},
{
name: "no number error",
password: "NoNumbers!",
expectedInError: "number",
},
{
name: "no special char error",
password: "NoSpecialChars123",
expectedInError: "special character",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidatePassword(tt.password)
assert.Error(t, err)
assert.Contains(t, err.Error(), tt.expectedInError)
})
}
}
func TestGetPasswordRequirements(t *testing.T) {
requirements := GetPasswordRequirements()
assert.NotEmpty(t, requirements)
assert.Greater(t, len(requirements), 3)
// Check for common requirements
requirementText := ""
for _, req := range requirements {
requirementText += req + " "
}
assert.Contains(t, requirementText, "8")
assert.Contains(t, requirementText, "uppercase")
assert.Contains(t, requirementText, "lowercase")
assert.Contains(t, requirementText, "number")
assert.Contains(t, requirementText, "special")
}
func TestLoginAttemptTracker_RecordFailedAttempt(t *testing.T) {
tracker := NewLoginAttemptTracker(3, 5*time.Minute, 5*time.Minute)
@@ -231,13 +110,6 @@ func TestDeviceRateLimiter_CheckRateLimit(t *testing.T) {
// Get remaining requests
remaining := limiter.GetRemainingRequests(deviceID, requestType, config)
assert.Equal(t, 0, remaining)
// Reset and verify
limiter.Reset(deviceID)
// Should be allowed again
allowed = limiter.CheckRateLimit(deviceID, requestType, config)
assert.True(t, allowed, "Request after reset should be allowed")
}
func TestDeviceRateLimiter_DifferentDevices(t *testing.T) {
@@ -285,34 +157,12 @@ func TestDeviceRateLimiter_GetRemainingRequests(t *testing.T) {
}
func TestNewRateLimiter(t *testing.T) {
config := DefaultRateLimiterConfig()
config := RateLimiterConfig{
Enabled: true,
RequestsPerMinute: 60,
CleanupInterval: time.Minute,
}
limiter := NewRateLimiter(config)
assert.NotNil(t, limiter)
}
func TestHTTPError_Error(t *testing.T) {
err := NewHTTPError(404, "Not Found", nil)
assert.NotNil(t, err)
assert.Equal(t, 404, err.Code)
assert.Equal(t, "Not Found", err.Message)
}
func TestHTTPError_ErrorWithInternal(t *testing.T) {
internalErr := assert.AnError
err := NewHTTPError(500, "Internal Error", internalErr)
assert.Equal(t, "Internal Error: assert.AnError general error for testing", err.Error())
assert.Equal(t, 500, err.Code)
assert.Equal(t, "Internal Error", err.Message)
assert.Equal(t, internalErr, err.Err)
}
func TestNewHTTPError(t *testing.T) {
err := NewHTTPError(404, "Not Found", nil)
assert.NotNil(t, err)
assert.Equal(t, 404, err.Code)
assert.Equal(t, "Not Found", err.Message)
}
+6 -64
View File
@@ -2,7 +2,6 @@ package middleware
import (
"bookhoard/internal/database"
"fmt"
"regexp"
"sync"
@@ -45,11 +44,6 @@ func (v *PasswordValidator) rules() database.PasswordRules {
return database.PasswordRules{MinLength: 8, Upper: true, Lower: true, Number: true, Special: true}
}
// Validate checks if a password meets the configured complexity requirements.
func (v *PasswordValidator) Validate(fl validator.FieldLevel) bool {
return v.CheckPassword(fl.Field().String())
}
// CheckPassword applies the active rules to a single password.
func (v *PasswordValidator) CheckPassword(password string) bool {
r := v.rules()
@@ -71,61 +65,9 @@ func (v *PasswordValidator) CheckPassword(password string) bool {
return true
}
// GetPasswordRequirements returns a human-readable list of the active password
// requirements, driven by the configured rules when a registry is wired.
func GetPasswordRequirements() []string {
return defaultPasswordValidator.Requirements()
}
// Requirements returns the human-readable list for the receiver's active rules.
func (v *PasswordValidator) Requirements() []string {
r := v.rules()
var out []string
out = append(out, fmt.Sprintf("At least %d characters long", r.MinLength))
if r.Upper {
out = append(out, "At least one uppercase letter (A-Z)")
}
if r.Lower {
out = append(out, "At least one lowercase letter (a-z)")
}
if r.Number {
out = append(out, "At least one number (0-9)")
}
if r.Special {
out = append(out, "At least one special character (!@#$%^&*()_+-=[]{}|;':\",./<>?)")
}
return out
}
// ValidatePassword checks a password against the default (hardcoded) rules and
// returns an error describing the first unmet requirement. Retained for callers
// that don't have access to a configured PasswordValidator instance.
func ValidatePassword(password string) error {
v := defaultPasswordValidator
r := v.rules()
if len(password) < r.MinLength {
return fmt.Errorf("password must be at least %d characters long", r.MinLength)
}
if r.Upper && !regexp.MustCompile(`[A-Z]`).MatchString(password) {
return fmt.Errorf("password must contain at least one uppercase letter")
}
if r.Lower && !regexp.MustCompile(`[a-z]`).MatchString(password) {
return fmt.Errorf("password must contain at least one lowercase letter")
}
if r.Number && !regexp.MustCompile(`[0-9]`).MatchString(password) {
return fmt.Errorf("password must contain at least one number")
}
if r.Special && !specialRegex().MatchString(password) {
return fmt.Errorf("password must contain at least one special character")
}
return nil
}
// defaultPasswordValidator is used by the package-level helpers
// (GetPasswordRequirements, ValidatePassword) and as the fallback inside
// RegisterPasswordValidation when no registry has been wired. Callers that want
// live rule updates should construct their own PasswordValidator and call
// SetSettings.
// defaultPasswordValidator backs the passwordcomplex struct tag registered by
// RegisterPasswordValidation. Callers that want live rule updates should
// construct their own PasswordValidator and call SetSettings.
var defaultPasswordValidator = &PasswordValidator{}
// RegisterPasswordValidation registers the password validator with the
@@ -138,9 +80,9 @@ func RegisterPasswordValidation(v *validator.Validate) error {
}
// SetDefaultPasswordSettings wires the settings registry into the package-level
// default validator so that the struct-tag validator (used by echo's
// CustomValidator) and ValidatePassword follow live configuration. Intended to
// be called once at startup.
// default validator so that the passwordcomplex struct-tag validator (used by
// echo's CustomValidator) follows live configuration. Intended to be called
// once at startup.
func SetDefaultPasswordSettings(s *database.SettingsRegistry) {
defaultPasswordValidator.SetSettings(s)
}
-9
View File
@@ -15,15 +15,6 @@ type RateLimiterConfig struct {
CleanupInterval time.Duration
}
// DefaultRateLimiterConfig returns sensible defaults
func DefaultRateLimiterConfig() RateLimiterConfig {
return RateLimiterConfig{
Enabled: true,
RequestsPerMinute: 10,
CleanupInterval: 5 * time.Minute,
}
}
// RateLimiter tracks request counts per IP
type RateLimiter struct {
mu sync.RWMutex