Fix nbtb, add tests

This commit is contained in:
2026-03-04 20:11:51 +00:00
parent 29b9776a93
commit 7c3f922725
7 changed files with 522 additions and 12 deletions
+7 -8
View File
@@ -245,12 +245,12 @@ type TimeSlot struct {
}
type DayAvailableHours struct {
Date string `json:"date"`
Weekday int `json:"weekday"`
IsOpen bool `json:"isOpen"`
Slots []TimeSlot `json:"slots"`
Source string `json:"source"`
Blockers []TimeSlot `json:"blockers,omitempty"`
Date string `json:"date"`
Weekday int `json:"weekday"`
IsOpen bool `json:"isOpen"`
Slots []TimeSlot `json:"slots"`
Source string `json:"source"`
Blockers []TimeSlot `json:"blockers,omitempty"`
}
// --- GetAvailableHours (with bookings, UK-local) ---
@@ -373,8 +373,7 @@ func GetAvailableHours(w http.ResponseWriter, r *http.Request) {
StartTime: blocker.StartTime.Format("15:04"),
EndTime: endTime.Format("15:04"),
EndTime: endTime.Format("15:04"),
})
}
@@ -24,6 +24,7 @@ import (
"net/http/httptest"
"strconv"
"testing"
"time"
"crussell/db"
"crussell/mw"
@@ -557,3 +558,149 @@ func TestScheduling_UpdateExceptionalApplications_NonAdmin(t *testing.T) {
t.Errorf("expected status 403, got %d. body: %s", w.Code, w.Body.String())
}
}
// =============================================================================
// Time Blocker Tests for GetAvailableHours
// =============================================================================
// TestScheduling_GetAvailableHours_WithBlocker_NonAdmin verifies that non-admin
// users do NOT see blocked time slots in their available hours.
func TestScheduling_GetAvailableHours_WithBlocker_NonAdmin(t *testing.T) {
cleanup := setupTestDB(t)
defer cleanup()
// Create a time blocker for 2026-03-16 10:00-11:00 (Monday - an open day)
ukLocation, _ := time.LoadLocation("Europe/London")
blockerTime := time.Date(2026, 3, 16, 10, 0, 0, 0, ukLocation)
_, err := db.DB.Exec(context.Background(), `
INSERT INTO time_blockers (start_time, duration_minutes, description, created_by)
VALUES ($1, 60, 'Staff Meeting', NULL)
`, blockerTime)
if err != nil {
t.Fatalf("failed to create time blocker: %v", err)
}
// Make request as non-admin user
handler := http.HandlerFunc(GetAvailableHours)
req := httptest.NewRequest("GET", "/api/scheduling/available-hours?start=2026-03-16&end=2026-03-16", nil)
// Set non-admin context
ctx := context.WithValue(req.Context(), mw.UserIDKey, "user001")
ctx = context.WithValue(ctx, mw.UserRoleKey, "verified_email")
req = req.WithContext(ctx)
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)
if w.Code != http.StatusOK {
t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
}
var response []DayAvailableHours
if err := json.Unmarshal(w.Body.Bytes(), &response); err != nil {
t.Fatalf("failed to unmarshal response: %v", err)
}
if len(response) == 0 {
t.Fatal("expected at least one day in response")
}
// Find the day with the blocker (2026-03-16)
var targetDay *DayAvailableHours
for i := range response {
if response[i].Date == "2026-03-16" {
targetDay = &response[i]
break
}
}
if targetDay == nil {
t.Fatal("expected day 2026-03-16 in response")
}
// Verify blocker is NOT visible in blockers field for non-admin
if len(targetDay.Blockers) > 0 {
t.Error("expected blockers field to be empty for non-admin users")
}
// Verify 10:00-11:00 slot is NOT available (subtracted due to blocker)
for _, slot := range targetDay.Slots {
if slot.StartTime == "10:00" {
t.Error("expected 10:00 slot to be blocked and not available")
}
}
}
// TestScheduling_GetAvailableHours_WithBlocker_Admin verifies that admin users
// CAN see blocked time slots in the blockers field.
func TestScheduling_GetAvailableHours_WithBlocker_Admin(t *testing.T) {
cleanup := setupTestDB(t)
defer cleanup()
// Create a time blocker for 2026-03-16 10:00-11:00 (Monday - open day)
ukLocation, _ := time.LoadLocation("Europe/London")
blockerTime := time.Date(2026, 3, 16, 10, 0, 0, 0, ukLocation)
_, err := db.DB.Exec(context.Background(), `
INSERT INTO time_blockers (start_time, duration_minutes, description, created_by)
VALUES ($1, 60, 'Staff Meeting', NULL)
`, blockerTime)
if err != nil {
t.Fatalf("failed to create time blocker: %v", err)
}
// Make request as admin user
handler := http.HandlerFunc(GetAvailableHours)
req := httptest.NewRequest("GET", "/api/scheduling/available-hours?start=2026-03-16&end=2026-03-16", nil)
// Set admin context
ctx := context.WithValue(req.Context(), mw.UserIDKey, "admin001")
ctx = context.WithValue(ctx, mw.UserRoleKey, "admin")
req = req.WithContext(ctx)
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)
if w.Code != http.StatusOK {
t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
}
var response []DayAvailableHours
if err := json.Unmarshal(w.Body.Bytes(), &response); err != nil {
t.Fatalf("failed to unmarshal response: %v", err)
}
if len(response) == 0 {
t.Fatal("expected at least one day in response")
}
// Find the day with the blocker (2026-03-16)
var targetDay *DayAvailableHours
for i := range response {
if response[i].Date == "2026-03-16" {
targetDay = &response[i]
break
}
}
if targetDay == nil {
t.Fatal("expected day 2026-03-16 in response")
}
// Verify blocker IS visible in blockers field for admin
if len(targetDay.Blockers) == 0 {
t.Error("expected blockers field to contain the blocker for admin users")
} else {
// Verify the blocker time range
found := false
for _, blocker := range targetDay.Blockers {
if blocker.StartTime == "10:00" && blocker.EndTime == "11:00" {
found = true
break
}
}
if !found {
t.Error("expected blocker 10:00-11:00 in blockers field")
}
}
}