Add PDF reports, file uploads, admin auth, and comprehensive tests
Features: - PDF service for generating task reports with ReportLab-style formatting - Storage service for file uploads (local and S3-compatible) - Admin authentication middleware with JWT support - Admin user model and repository Infrastructure: - Updated Docker configuration for admin panel builds - Email service enhancements for task notifications - Updated router with admin and file upload routes - Environment configuration updates Tests: - Unit tests for handlers (auth, residence, task) - Unit tests for models (user, residence, task) - Unit tests for repositories (user, residence, task) - Unit tests for services (residence, task) - Integration test setup - Test utilities for mocking database and services Database: - Admin user seed data - Updated test data seeds 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -29,6 +29,7 @@ var (
|
||||
type ResidenceService struct {
|
||||
residenceRepo *repositories.ResidenceRepository
|
||||
userRepo *repositories.UserRepository
|
||||
taskRepo *repositories.TaskRepository
|
||||
config *config.Config
|
||||
}
|
||||
|
||||
@@ -41,6 +42,11 @@ func NewResidenceService(residenceRepo *repositories.ResidenceRepository, userRe
|
||||
}
|
||||
}
|
||||
|
||||
// SetTaskRepository sets the task repository (used for task statistics)
|
||||
func (s *ResidenceService) SetTaskRepository(taskRepo *repositories.TaskRepository) {
|
||||
s.taskRepo = taskRepo
|
||||
}
|
||||
|
||||
// GetResidence gets a residence by ID with access check
|
||||
func (s *ResidenceService) GetResidence(residenceID, userID uint) (*responses.ResidenceResponse, error) {
|
||||
// Check access
|
||||
@@ -65,27 +71,53 @@ func (s *ResidenceService) GetResidence(residenceID, userID uint) (*responses.Re
|
||||
}
|
||||
|
||||
// ListResidences lists all residences accessible to a user
|
||||
func (s *ResidenceService) ListResidences(userID uint) (*responses.ResidenceListResponse, error) {
|
||||
func (s *ResidenceService) ListResidences(userID uint) ([]responses.ResidenceResponse, error) {
|
||||
residences, err := s.residenceRepo.FindByUser(userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp := responses.NewResidenceListResponse(residences)
|
||||
return &resp, nil
|
||||
return responses.NewResidenceListResponse(residences), nil
|
||||
}
|
||||
|
||||
// GetMyResidences returns residences with additional details (tasks, completions, etc.)
|
||||
// This is the "my-residences" endpoint that returns richer data
|
||||
func (s *ResidenceService) GetMyResidences(userID uint) (*responses.ResidenceListResponse, error) {
|
||||
func (s *ResidenceService) GetMyResidences(userID uint) (*responses.MyResidencesResponse, error) {
|
||||
residences, err := s.residenceRepo.FindByUser(userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO: In Phase 4, this will include tasks and completions
|
||||
resp := responses.NewResidenceListResponse(residences)
|
||||
return &resp, nil
|
||||
residenceResponses := responses.NewResidenceListResponse(residences)
|
||||
|
||||
// Build summary with real task statistics
|
||||
summary := responses.TotalSummary{
|
||||
TotalResidences: len(residences),
|
||||
}
|
||||
|
||||
// Get task statistics if task repository is available
|
||||
if s.taskRepo != nil && len(residences) > 0 {
|
||||
// Collect residence IDs
|
||||
residenceIDs := make([]uint, len(residences))
|
||||
for i, r := range residences {
|
||||
residenceIDs[i] = r.ID
|
||||
}
|
||||
|
||||
// Get aggregated statistics
|
||||
stats, err := s.taskRepo.GetTaskStatistics(residenceIDs)
|
||||
if err == nil && stats != nil {
|
||||
summary.TotalTasks = stats.TotalTasks
|
||||
summary.TotalPending = stats.TotalPending
|
||||
summary.TotalOverdue = stats.TotalOverdue
|
||||
summary.TasksDueNextWeek = stats.TasksDueNextWeek
|
||||
summary.TasksDueNextMonth = stats.TasksDueNextMonth
|
||||
}
|
||||
}
|
||||
|
||||
return &responses.MyResidencesResponse{
|
||||
Residences: residenceResponses,
|
||||
Summary: summary,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateResidence creates a new residence
|
||||
|
||||
Reference in New Issue
Block a user