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:
@@ -55,7 +55,7 @@ func (s *ContractorService) GetContractor(contractorID, userID uint) (*responses
|
||||
}
|
||||
|
||||
// ListContractors lists all contractors accessible to a user
|
||||
func (s *ContractorService) ListContractors(userID uint) (*responses.ContractorListResponse, error) {
|
||||
func (s *ContractorService) ListContractors(userID uint) ([]responses.ContractorResponse, error) {
|
||||
residences, err := s.residenceRepo.FindByUser(userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -67,7 +67,7 @@ func (s *ContractorService) ListContractors(userID uint) (*responses.ContractorL
|
||||
}
|
||||
|
||||
if len(residenceIDs) == 0 {
|
||||
return &responses.ContractorListResponse{Count: 0, Results: []responses.ContractorResponse{}}, nil
|
||||
return []responses.ContractorResponse{}, nil
|
||||
}
|
||||
|
||||
contractors, err := s.contractorRepo.FindByUser(residenceIDs)
|
||||
@@ -75,8 +75,7 @@ func (s *ContractorService) ListContractors(userID uint) (*responses.ContractorL
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp := responses.NewContractorListResponse(contractors)
|
||||
return &resp, nil
|
||||
return responses.NewContractorListResponse(contractors), nil
|
||||
}
|
||||
|
||||
// CreateContractor creates a new contractor
|
||||
@@ -234,8 +233,8 @@ func (s *ContractorService) DeleteContractor(contractorID, userID uint) error {
|
||||
return s.contractorRepo.Delete(contractorID)
|
||||
}
|
||||
|
||||
// ToggleFavorite toggles the favorite status of a contractor
|
||||
func (s *ContractorService) ToggleFavorite(contractorID, userID uint) (*responses.ToggleFavoriteResponse, error) {
|
||||
// ToggleFavorite toggles the favorite status of a contractor and returns the updated contractor
|
||||
func (s *ContractorService) ToggleFavorite(contractorID, userID uint) (*responses.ContractorResponse, error) {
|
||||
contractor, err := s.contractorRepo.FindByID(contractorID)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
@@ -253,24 +252,23 @@ func (s *ContractorService) ToggleFavorite(contractorID, userID uint) (*response
|
||||
return nil, ErrContractorAccessDenied
|
||||
}
|
||||
|
||||
newStatus, err := s.contractorRepo.ToggleFavorite(contractorID)
|
||||
_, err = s.contractorRepo.ToggleFavorite(contractorID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
message := "Contractor removed from favorites"
|
||||
if newStatus {
|
||||
message = "Contractor added to favorites"
|
||||
// Re-fetch the contractor to get the updated state with all relations
|
||||
contractor, err = s.contractorRepo.FindByID(contractorID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &responses.ToggleFavoriteResponse{
|
||||
Message: message,
|
||||
IsFavorite: newStatus,
|
||||
}, nil
|
||||
resp := responses.NewContractorResponse(contractor)
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
// GetContractorTasks gets all tasks for a contractor
|
||||
func (s *ContractorService) GetContractorTasks(contractorID, userID uint) (*responses.TaskListResponse, error) {
|
||||
func (s *ContractorService) GetContractorTasks(contractorID, userID uint) ([]responses.TaskResponse, error) {
|
||||
contractor, err := s.contractorRepo.FindByID(contractorID)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
@@ -293,8 +291,7 @@ func (s *ContractorService) GetContractorTasks(contractorID, userID uint) (*resp
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp := responses.NewTaskListResponse(tasks)
|
||||
return &resp, nil
|
||||
return responses.NewTaskListResponse(tasks), nil
|
||||
}
|
||||
|
||||
// GetSpecialties returns all contractor specialties
|
||||
|
||||
Reference in New Issue
Block a user