Fix nbtb, add tests
This commit is contained in:
@@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user