refactor(handlers): migrate remaining backend handlers to clock.Now() and transaction patterns

Apply clock.Now() migration, transaction wrapping, and minor refactors across admin, scheduling, today, user, auth handler, notifications, webhooks, services, portfolio, ratelimit, testutils, and main.go.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-06-24 23:43:50 +01:00
co-authored by Sisyphus
parent 7b24f8e484
commit e4b9003439
36 changed files with 1923 additions and 590 deletions
@@ -20,6 +20,7 @@ import (
"testing"
"time"
"crussell/clock"
"crussell/db"
"crussell/testutils"
"crussell/handlers/bookings"
@@ -98,7 +99,7 @@ func TestAdminBookings_UpdateServices_ReplaceServices(t *testing.T) {
service2 := createSecondService(t, tx, ctx, "Service Two", 45, 55.00)
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, time.Now().Add(24*time.Hour), "confirmed")
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, clock.Now().Add(24*time.Hour), "confirmed")
handler := http.HandlerFunc(bookings.UpdateBookingServicesHandler)
reqBody := map[string]interface{}{
@@ -147,7 +148,7 @@ func TestAdminBookings_UpdateServices_AddService(t *testing.T) {
service2 := createSecondService(t, tx, ctx, "Service Two", 30, 40.00)
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, time.Now().Add(24*time.Hour), "confirmed")
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, clock.Now().Add(24*time.Hour), "confirmed")
handler := http.HandlerFunc(bookings.UpdateBookingServicesHandler)
reqBody := map[string]interface{}{
@@ -194,7 +195,7 @@ func TestAdminBookings_UpdateServices_RemoveService(t *testing.T) {
service2 := createSecondService(t, tx, ctx, "Service Two", 30, 40.00)
// Create booking with service1
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, time.Now().Add(24*time.Hour), "confirmed")
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, clock.Now().Add(24*time.Hour), "confirmed")
// Manually add service2 to the booking
@@ -249,7 +250,7 @@ func TestAdminBookings_UpdateServices_WithPriceOverride(t *testing.T) {
t.Fatalf("failed to create test service: %v", err)
}
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, time.Now().Add(24*time.Hour), "confirmed")
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, clock.Now().Add(24*time.Hour), "confirmed")
handler := http.HandlerFunc(bookings.UpdateBookingServicesHandler)
reqBody := map[string]interface{}{
@@ -302,7 +303,7 @@ func TestAdminBookings_UpdateServices_WithDurationOverride(t *testing.T) {
t.Fatalf("failed to create test service: %v", err)
}
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, time.Now().Add(24*time.Hour), "confirmed")
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, clock.Now().Add(24*time.Hour), "confirmed")
handler := http.HandlerFunc(bookings.UpdateBookingServicesHandler)
reqBody := map[string]interface{}{
@@ -355,7 +356,7 @@ func TestAdminBookings_UpdateServices_WithBothOverrides(t *testing.T) {
t.Fatalf("failed to create test service: %v", err)
}
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, time.Now().Add(24*time.Hour), "confirmed")
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, clock.Now().Add(24*time.Hour), "confirmed")
handler := http.HandlerFunc(bookings.UpdateBookingServicesHandler)
reqBody := map[string]interface{}{
@@ -409,7 +410,7 @@ func TestAdminBookings_UpdateServices_UpdateNotes(t *testing.T) {
t.Fatalf("failed to create test service: %v", err)
}
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, time.Now().Add(24*time.Hour), "confirmed")
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, clock.Now().Add(24*time.Hour), "confirmed")
handler := http.HandlerFunc(bookings.UpdateBookingServicesHandler)
reqBody := map[string]interface{}{
@@ -456,7 +457,7 @@ func TestAdminBookings_UpdateServices_MultipleOverrides(t *testing.T) {
service2 := createSecondService(t, tx, ctx, "Service Two", 45, 55.00)
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, time.Now().Add(24*time.Hour), "confirmed")
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, clock.Now().Add(24*time.Hour), "confirmed")
handler := http.HandlerFunc(bookings.UpdateBookingServicesHandler)
reqBody := map[string]interface{}{
@@ -578,7 +579,7 @@ func TestAdminBookings_UpdateServices_EmptyServiceIDs(t *testing.T) {
t.Fatalf("failed to create test service: %v", err)
}
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, time.Now().Add(24*time.Hour), "confirmed")
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, clock.Now().Add(24*time.Hour), "confirmed")
handler := http.HandlerFunc(bookings.UpdateBookingServicesHandler)
reqBody := map[string]interface{}{
@@ -611,7 +612,7 @@ func TestAdminBookings_UpdateServices_InvalidServiceID(t *testing.T) {
t.Fatalf("failed to create test service: %v", err)
}
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, time.Now().Add(24*time.Hour), "confirmed")
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, clock.Now().Add(24*time.Hour), "confirmed")
handler := http.HandlerFunc(bookings.UpdateBookingServicesHandler)
reqBody := map[string]interface{}{
@@ -644,7 +645,7 @@ func TestAdminBookings_UpdateServices_ServiceNotFound(t *testing.T) {
t.Fatalf("failed to create test service: %v", err)
}
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, time.Now().Add(24*time.Hour), "confirmed")
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, clock.Now().Add(24*time.Hour), "confirmed")
handler := http.HandlerFunc(bookings.UpdateBookingServicesHandler)
reqBody := map[string]interface{}{
@@ -677,7 +678,7 @@ func TestAdminBookings_UpdateServices_NegativePriceOverride(t *testing.T) {
t.Fatalf("failed to create test service: %v", err)
}
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, time.Now().Add(24*time.Hour), "confirmed")
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, clock.Now().Add(24*time.Hour), "confirmed")
handler := http.HandlerFunc(bookings.UpdateBookingServicesHandler)
reqBody := map[string]interface{}{
@@ -716,7 +717,7 @@ func TestAdminBookings_UpdateServices_ZeroDurationOverride(t *testing.T) {
t.Fatalf("failed to create test service: %v", err)
}
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, time.Now().Add(24*time.Hour), "confirmed")
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, clock.Now().Add(24*time.Hour), "confirmed")
handler := http.HandlerFunc(bookings.UpdateBookingServicesHandler)
reqBody := map[string]interface{}{
@@ -759,7 +760,7 @@ func TestAdminBookings_UpdateServices_CompletedBookingRejected(t *testing.T) {
t.Fatalf("failed to create test service: %v", err)
}
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, time.Now().Add(-1*time.Hour), "completed")
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, clock.Now().Add(-1*time.Hour), "completed")
handler := http.HandlerFunc(bookings.UpdateBookingServicesHandler)
reqBody := map[string]interface{}{
@@ -792,7 +793,7 @@ func TestAdminBookings_UpdateServices_CancelledBookingRejected(t *testing.T) {
t.Fatalf("failed to create test service: %v", err)
}
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, time.Now().Add(24*time.Hour), "client_cancelled")
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, clock.Now().Add(24*time.Hour), "client_cancelled")
handler := http.HandlerFunc(bookings.UpdateBookingServicesHandler)
reqBody := map[string]interface{}{
@@ -825,7 +826,7 @@ func TestAdminBookings_UpdateServices_NoShowBookingRejected(t *testing.T) {
t.Fatalf("failed to create test service: %v", err)
}
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, time.Now().Add(24*time.Hour), "no_show")
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, clock.Now().Add(24*time.Hour), "no_show")
handler := http.HandlerFunc(bookings.UpdateBookingServicesHandler)
reqBody := map[string]interface{}{
@@ -858,7 +859,7 @@ func TestAdminBookings_UpdateServices_WeCancelledBookingRejected(t *testing.T) {
t.Fatalf("failed to create test service: %v", err)
}
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, time.Now().Add(24*time.Hour), "we_cancelled")
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, clock.Now().Add(24*time.Hour), "we_cancelled")
handler := http.HandlerFunc(bookings.UpdateBookingServicesHandler)
reqBody := map[string]interface{}{
@@ -900,7 +901,7 @@ func TestAdminBookings_UpdateServices_OverlapWithNextBooking(t *testing.T) {
// Create a long-duration service for the overlap test
longService := createSecondService(t, tx, ctx, "Long Service", 300, 100.00) // 5 hours
now := time.Now()
now := clock.Now()
// Booking 1 at 10:00 tomorrow
booking1Start := now.Add(24 * time.Hour).Truncate(24 * time.Hour).Add(10 * time.Hour)
bookingID1 := createBookingWithStartTime(t, tx, ctx, userID, service1, booking1Start, "confirmed")
@@ -945,7 +946,7 @@ func TestAdminBookings_UpdateServices_NoOverlapSucceeds(t *testing.T) {
service2 := createSecondService(t, tx, ctx, "Service Two", 30, 40.00)
now := time.Now()
now := clock.Now()
// Booking 1 at 10:00 tomorrow
booking1Start := now.Add(24 * time.Hour).Truncate(24 * time.Hour).Add(10 * time.Hour)
bookingID1 := createBookingWithStartTime(t, tx, ctx, userID, service1, booking1Start, "confirmed")
@@ -991,7 +992,7 @@ func TestAdminBookings_UpdateServices_NoNextBookingSucceeds(t *testing.T) {
longService := createSecondService(t, tx, ctx, "Long Service", 300, 100.00)
// Only booking for the day — no next booking to conflict with
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, time.Now().Add(24*time.Hour), "confirmed")
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, clock.Now().Add(24*time.Hour), "confirmed")
handler := http.HandlerFunc(bookings.UpdateBookingServicesHandler)
reqBody := map[string]interface{}{
@@ -1030,7 +1031,7 @@ func TestAdminBookings_UpdateServices_ResponseShape(t *testing.T) {
t.Fatalf("failed to create test service: %v", err)
}
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, time.Now().Add(24*time.Hour), "confirmed")
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, clock.Now().Add(24*time.Hour), "confirmed")
handler := http.HandlerFunc(bookings.UpdateBookingServicesHandler)
reqBody := map[string]interface{}{
@@ -1098,7 +1099,7 @@ func TestAdminBookings_UpdateServices_PendingBooking(t *testing.T) {
t.Fatalf("failed to create test service: %v", err)
}
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, time.Now().Add(24*time.Hour), "pending")
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, clock.Now().Add(24*time.Hour), "pending")
handler := http.HandlerFunc(bookings.UpdateBookingServicesHandler)
reqBody := map[string]interface{}{
@@ -1133,7 +1134,7 @@ func TestAdminBookings_UpdateServices_InProgressBooking(t *testing.T) {
t.Fatalf("failed to create test service: %v", err)
}
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, time.Now().Add(-30*time.Minute), "in_progress")
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, clock.Now().Add(-30*time.Minute), "in_progress")
handler := http.HandlerFunc(bookings.UpdateBookingServicesHandler)
reqBody := map[string]interface{}{
@@ -1168,7 +1169,7 @@ func TestAdminBookings_UpdateServices_ClearNotes(t *testing.T) {
t.Fatalf("failed to create test service: %v", err)
}
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, time.Now().Add(24*time.Hour), "confirmed")
bookingID := createBookingWithStartTime(t, tx, ctx, userID, service1, clock.Now().Add(24*time.Hour), "confirmed")
handler := http.HandlerFunc(bookings.UpdateBookingServicesHandler)
reqBody := map[string]interface{}{