Complete tasks 4.1-4.2: Page management service and HTTP endpoints

- Implemented PageService with full CRUD operations
- Added GetPages, CreatePage, UpdatePage, DeletePage, ReorderPages methods
- Cascade deletion of widgets when page is deleted
- Prevention of last page deletion
- Created page HTTP endpoints (GET, POST, PUT, DELETE, reorder)
- HTMX-friendly HTML fragment responses
- Comprehensive unit tests for service and handlers
- Updated dashboard to use PageService and create default pages
This commit is contained in:
2026-02-19 00:08:05 -05:00
parent 9f07b0c6f9
commit 299ac03939
16 changed files with 1572 additions and 31 deletions

View File

@@ -6,10 +6,67 @@ import (
"net/http"
"net/http/httptest"
"testing"
"time"
"custom-start-page/internal/middleware"
"custom-start-page/internal/models"
)
// mockPageService is a mock implementation of PageService for testing
type mockPageService struct {
pages []*models.Page
err error
}
func (m *mockPageService) GetPages(ctx context.Context, userID string) ([]*models.Page, error) {
if m.err != nil {
return nil, m.err
}
return m.pages, nil
}
func (m *mockPageService) CreatePage(ctx context.Context, userID, name string) (*models.Page, error) {
if m.err != nil {
return nil, m.err
}
page := &models.Page{
ID: "new-page-id",
UserID: userID,
Name: name,
Order: len(m.pages),
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
m.pages = append(m.pages, page)
return page, nil
}
func (m *mockPageService) CreateDefaultPage(ctx context.Context, userID string) (*models.Page, error) {
return m.CreatePage(ctx, userID, "Home")
}
func (m *mockPageService) UpdatePage(ctx context.Context, userID, pageID, name string) (*models.Page, error) {
if m.err != nil {
return nil, m.err
}
for _, page := range m.pages {
if page.ID == pageID && page.UserID == userID {
page.Name = name
page.UpdatedAt = time.Now()
return page, nil
}
}
return nil, nil
}
func (m *mockPageService) DeletePage(ctx context.Context, userID, pageID string) error {
return m.err
}
func (m *mockPageService) ReorderPages(ctx context.Context, userID string, pageOrder []string) error {
return m.err
}
// createMockDashboardTemplate creates a simple mock template for testing
func createMockDashboardTemplate() *template.Template {
tmpl := template.New("dashboard.html")
@@ -21,8 +78,21 @@ func createMockDashboardTemplate() *template.Template {
func TestHandleDashboard_WithAuthenticatedUser(t *testing.T) {
// Setup
mockTemplate := createMockDashboardTemplate()
mockPages := []*models.Page{
{
ID: "page-1",
UserID: "test-user-123",
Name: "Home",
Order: 0,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
},
}
mockService := &mockPageService{pages: mockPages}
handler := &DashboardHandler{
templates: mockTemplate,
pageService: mockService,
templates: mockTemplate,
}
// Create request with user ID in context
@@ -50,8 +120,11 @@ func TestHandleDashboard_WithAuthenticatedUser(t *testing.T) {
func TestHandleDashboard_WithoutUserID(t *testing.T) {
// Setup
mockTemplate := createMockDashboardTemplate()
mockService := &mockPageService{}
handler := &DashboardHandler{
templates: mockTemplate,
pageService: mockService,
templates: mockTemplate,
}
// Create request without user ID in context