Complete rewrite of Django REST API to Go with: - Gin web framework for HTTP routing - GORM for database operations - GoAdmin for admin panel - Gorush integration for push notifications - Redis for caching and job queues Features implemented: - User authentication (login, register, logout, password reset) - Residence management (CRUD, sharing, share codes) - Task management (CRUD, kanban board, completions) - Contractor management (CRUD, specialties) - Document management (CRUD, warranties) - Notifications (preferences, push notifications) - Subscription management (tiers, limits) Infrastructure: - Docker Compose for local development - Database migrations and seed data - Admin panel for data management 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
152 lines
4.5 KiB
Go
152 lines
4.5 KiB
Go
package repositories
|
|
|
|
import (
|
|
"gorm.io/gorm"
|
|
|
|
"github.com/treytartt/mycrib-api/internal/models"
|
|
)
|
|
|
|
// ContractorRepository handles database operations for contractors
|
|
type ContractorRepository struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
// NewContractorRepository creates a new contractor repository
|
|
func NewContractorRepository(db *gorm.DB) *ContractorRepository {
|
|
return &ContractorRepository{db: db}
|
|
}
|
|
|
|
// FindByID finds a contractor by ID with preloaded relations
|
|
func (r *ContractorRepository) FindByID(id uint) (*models.Contractor, error) {
|
|
var contractor models.Contractor
|
|
err := r.db.Preload("CreatedBy").
|
|
Preload("Specialties").
|
|
Preload("Tasks").
|
|
Where("id = ? AND is_active = ?", id, true).
|
|
First(&contractor).Error
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &contractor, nil
|
|
}
|
|
|
|
// FindByResidence finds all contractors for a residence
|
|
func (r *ContractorRepository) FindByResidence(residenceID uint) ([]models.Contractor, error) {
|
|
var contractors []models.Contractor
|
|
err := r.db.Preload("CreatedBy").
|
|
Preload("Specialties").
|
|
Where("residence_id = ? AND is_active = ?", residenceID, true).
|
|
Order("is_favorite DESC, name ASC").
|
|
Find(&contractors).Error
|
|
return contractors, err
|
|
}
|
|
|
|
// FindByUser finds all contractors accessible to a user
|
|
func (r *ContractorRepository) FindByUser(residenceIDs []uint) ([]models.Contractor, error) {
|
|
var contractors []models.Contractor
|
|
err := r.db.Preload("CreatedBy").
|
|
Preload("Specialties").
|
|
Preload("Residence").
|
|
Where("residence_id IN ? AND is_active = ?", residenceIDs, true).
|
|
Order("is_favorite DESC, name ASC").
|
|
Find(&contractors).Error
|
|
return contractors, err
|
|
}
|
|
|
|
// Create creates a new contractor
|
|
func (r *ContractorRepository) Create(contractor *models.Contractor) error {
|
|
return r.db.Create(contractor).Error
|
|
}
|
|
|
|
// Update updates a contractor
|
|
func (r *ContractorRepository) Update(contractor *models.Contractor) error {
|
|
return r.db.Save(contractor).Error
|
|
}
|
|
|
|
// Delete soft-deletes a contractor
|
|
func (r *ContractorRepository) Delete(id uint) error {
|
|
return r.db.Model(&models.Contractor{}).
|
|
Where("id = ?", id).
|
|
Update("is_active", false).Error
|
|
}
|
|
|
|
// ToggleFavorite toggles the favorite status of a contractor
|
|
func (r *ContractorRepository) ToggleFavorite(id uint) (bool, error) {
|
|
var contractor models.Contractor
|
|
if err := r.db.First(&contractor, id).Error; err != nil {
|
|
return false, err
|
|
}
|
|
|
|
newStatus := !contractor.IsFavorite
|
|
err := r.db.Model(&models.Contractor{}).
|
|
Where("id = ?", id).
|
|
Update("is_favorite", newStatus).Error
|
|
|
|
return newStatus, err
|
|
}
|
|
|
|
// GetTasksForContractor gets all tasks associated with a contractor
|
|
func (r *ContractorRepository) GetTasksForContractor(contractorID uint) ([]models.Task, error) {
|
|
var tasks []models.Task
|
|
err := r.db.Preload("Category").
|
|
Preload("Priority").
|
|
Preload("Status").
|
|
Where("contractor_id = ?", contractorID).
|
|
Order("due_date ASC NULLS LAST").
|
|
Find(&tasks).Error
|
|
return tasks, err
|
|
}
|
|
|
|
// SetSpecialties sets the specialties for a contractor
|
|
func (r *ContractorRepository) SetSpecialties(contractorID uint, specialtyIDs []uint) error {
|
|
var contractor models.Contractor
|
|
if err := r.db.First(&contractor, contractorID).Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
// Clear existing specialties
|
|
if err := r.db.Model(&contractor).Association("Specialties").Clear(); err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(specialtyIDs) == 0 {
|
|
return nil
|
|
}
|
|
|
|
// Add new specialties
|
|
var specialties []models.ContractorSpecialty
|
|
if err := r.db.Where("id IN ?", specialtyIDs).Find(&specialties).Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
return r.db.Model(&contractor).Association("Specialties").Append(specialties)
|
|
}
|
|
|
|
// CountByResidence counts contractors in a residence
|
|
func (r *ContractorRepository) CountByResidence(residenceID uint) (int64, error) {
|
|
var count int64
|
|
err := r.db.Model(&models.Contractor{}).
|
|
Where("residence_id = ? AND is_active = ?", residenceID, true).
|
|
Count(&count).Error
|
|
return count, err
|
|
}
|
|
|
|
// === Specialty Operations ===
|
|
|
|
// GetAllSpecialties returns all contractor specialties
|
|
func (r *ContractorRepository) GetAllSpecialties() ([]models.ContractorSpecialty, error) {
|
|
var specialties []models.ContractorSpecialty
|
|
err := r.db.Order("display_order, name").Find(&specialties).Error
|
|
return specialties, err
|
|
}
|
|
|
|
// FindSpecialtyByID finds a specialty by ID
|
|
func (r *ContractorRepository) FindSpecialtyByID(id uint) (*models.ContractorSpecialty, error) {
|
|
var specialty models.ContractorSpecialty
|
|
err := r.db.First(&specialty, id).Error
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &specialty, nil
|
|
}
|